Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-15 15:09:30 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-15 15:09:30 +0300
commit33212c8ff1f99cdb896e8fc6f6450882287e0de5 (patch)
treeb29afde4eaf9623cda57ef6520db363d2db8492e
parent03c73563048c1f808a4a3fb302f0dcbba37f5f76 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/boards/stores/actions.js4
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_table_row.vue268
-rw-r--r--app/assets/javascripts/issue_show/components/app.vue1
-rw-r--r--app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql20
-rw-r--r--app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue (renamed from app/assets/javascripts/issue_show/components/incidents/highlight_bar/higlight_bar.vue)17
-rw-r--r--app/assets/javascripts/issue_show/components/incidents/highlight_bar/graphql/queries/get_highlight_bar_info.graphql12
-rw-r--r--app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue54
-rw-r--r--app/assets/javascripts/issue_show/components/title.vue6
-rw-r--r--app/assets/javascripts/packages/details/components/package_title.vue32
-rw-r--r--app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue41
-rw-r--r--app/assets/javascripts/vue_shared/components/alert_details_table.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/registry/metadata_item.vue63
-rw-r--r--app/assets/stylesheets/pages/alert_management/details.scss11
-rw-r--r--app/assets/stylesheets/pages/milestone.scss1
-rw-r--r--app/controllers/repositories/lfs_api_controller.rb2
-rw-r--r--app/graphql/types/alert_management/alert_type.rb6
-rw-r--r--app/helpers/dashboard_helper.rb4
-rw-r--r--app/helpers/nav_helper.rb2
-rw-r--r--app/models/alert_management/alert.rb8
-rw-r--r--app/models/project.rb40
-rw-r--r--app/policies/global_policy.rb1
-rw-r--r--app/presenters/alert_management/alert_presenter.rb36
-rw-r--r--app/presenters/alert_management/prometheus_alert_presenter.rb23
-rw-r--r--app/services/projects/alerting/notify_service.rb30
-rw-r--r--app/services/projects/lfs_pointers/lfs_download_service.rb39
-rw-r--r--app/services/projects/unlink_fork_service.rb31
-rw-r--r--app/views/admin/groups/_form.html.haml6
-rw-r--r--app/views/projects/_deletion_failed.html.haml8
-rw-r--r--app/views/projects/blob/edit.html.haml10
-rw-r--r--app/views/shared/milestones/_description.html.haml4
-rw-r--r--app/workers/issue_placement_worker.rb2
-rw-r--r--app/workers/repository_fork_worker.rb2
-rw-r--r--changelogs/unreleased/13402-close-alert-when-end-time-given.yml5
-rw-r--r--changelogs/unreleased/233649-replace-bootstrap-alerts-in-app-views-admin-groups-_form-html-haml.yml5
-rw-r--r--changelogs/unreleased/233672-replace-bootstrap-alerts-in-app-views-projects-_deletion_failed-ht.yml5
-rw-r--r--changelogs/unreleased/233690-replace-bootstrap-alerts-app-views-projects-blob-edit-html-haml.yml5
-rw-r--r--changelogs/unreleased/247897-properly-style-the-container-registry-metadata.yml5
-rw-r--r--changelogs/unreleased/249040-fix-subscription-without-namespace.yml5
-rw-r--r--changelogs/unreleased/id-link-existing-lfs.yml5
-rw-r--r--changelogs/unreleased/jdb-refactor-parallel-diff-table-row.yml5
-rw-r--r--changelogs/unreleased/jl-milestone-title-spacing.yml5
-rw-r--r--changelogs/unreleased/tr-incident-alert-details.yml5
-rw-r--r--changelogs/unreleased/update-vendored-dockerfile-templates.yml5
-rw-r--r--config/feature_flags/development/additional_snowplow_tracking.yml7
-rw-r--r--config/feature_flags/development/ajax_new_deploy_token.yml7
-rw-r--r--config/feature_flags/development/allow_group_deploy_token.yml7
-rw-r--r--config/feature_flags/development/allow_possible_spam.yml7
-rw-r--r--config/feature_flags/development/allow_unsafe_ruby_regexp.yml7
-rw-r--r--config/feature_flags/development/api_kaminari_count_with_limit.yml7
-rw-r--r--config/feature_flags/development/application_settings_tokens_optional_encryption.yml7
-rw-r--r--config/feature_flags/development/approval_suggestions.yml7
-rw-r--r--config/feature_flags/development/approvals_commented_by.yml7
-rw-r--r--config/feature_flags/development/archive_rate_limit.yml7
-rw-r--r--config/feature_flags/development/artifacts_management_page.yml7
-rw-r--r--config/feature_flags/development/async_commit_diff_files.yml7
-rw-r--r--config/feature_flags/development/auto_create_cluster_management_project.yml7
-rw-r--r--config/feature_flags/development/auto_devops_banner_disabled.yml7
-rw-r--r--config/feature_flags/development/backfill_partitioned_audit_events.yml7
-rw-r--r--config/feature_flags/development/batch_suggestions.yml7
-rw-r--r--config/feature_flags/development/boards_with_swimlanes.yml7
-rw-r--r--config/feature_flags/development/branch_list_keyset_pagination.yml7
-rw-r--r--config/feature_flags/development/branch_push_merge_commit_analyze.yml7
-rw-r--r--config/feature_flags/development/broadcast_issue_updates.yml7
-rw-r--r--config/feature_flags/development/build_service_proxy.yml7
-rw-r--r--config/feature_flags/development/builds.yml7
-rw-r--r--config/feature_flags/development/bulk_update_health_status.yml7
-rw-r--r--config/feature_flags/development/burnup_charts.yml7
-rw-r--r--config/feature_flags/development/chatops.yml7
-rw-r--r--config/feature_flags/development/ci_artifacts_exclude.yml7
-rw-r--r--config/feature_flags/development/ci_build_metadata_config.yml7
-rw-r--r--config/feature_flags/development/ci_bulk_insert_on_create.yml7
-rw-r--r--config/feature_flags/development/ci_daily_code_coverage.yml7
-rw-r--r--config/feature_flags/development/ci_disable_validates_dependencies.yml7
-rw-r--r--config/feature_flags/development/ci_download_daily_code_coverage.yml7
-rw-r--r--config/feature_flags/development/ci_dynamic_child_pipeline.yml7
-rw-r--r--config/feature_flags/development/ci_enable_live_trace.yml7
-rw-r--r--config/feature_flags/development/ci_instance_variables_ui.yml7
-rw-r--r--config/feature_flags/development/ci_job_heartbeats_runner.yml7
-rw-r--r--config/feature_flags/development/ci_job_jwt.yml7
-rw-r--r--config/feature_flags/development/ci_key_autocomplete.yml7
-rw-r--r--config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml7
-rw-r--r--config/feature_flags/development/ci_pipeline_latest.yml7
-rw-r--r--config/feature_flags/development/ci_pipeline_rewind_iid.yml7
-rw-r--r--config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml7
-rw-r--r--config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml7
-rw-r--r--config/feature_flags/development/ci_runners_tokens_optional_encryption.yml7
-rw-r--r--config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml7
-rw-r--r--config/feature_flags/development/ci_store_pipeline_messages.yml7
-rw-r--r--config/feature_flags/development/ci_synchronous_artifact_parsing.yml7
-rw-r--r--config/feature_flags/development/ci_update_queues_for_online_runners.yml7
-rw-r--r--config/feature_flags/development/ci_yaml_limit_size.yml7
-rw-r--r--config/feature_flags/development/cleanup_lfs_during_gc.yml7
-rw-r--r--config/feature_flags/development/cluster_management_project.yml7
-rw-r--r--config/feature_flags/development/clusters_list_redesign.yml7
-rw-r--r--config/feature_flags/development/container_registry_api.yml7
-rw-r--r--config/feature_flags/development/container_registry_cleanup.yml7
-rw-r--r--config/feature_flags/development/container_registry_fast_tag_delete.yml7
-rw-r--r--config/feature_flags/development/context_commits.yml7
-rw-r--r--config/feature_flags/development/create_cloud_run_clusters.yml7
-rw-r--r--config/feature_flags/development/dashboard_pipeline_status.yml7
-rw-r--r--config/feature_flags/development/deploy_from_footer.yml7
-rw-r--r--config/feature_flags/development/deploy_tokens_api.yml7
-rw-r--r--config/feature_flags/development/design_management_allow_dangerous_images.yml7
-rw-r--r--config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml7
-rw-r--r--config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml7
-rw-r--r--config/feature_flags/development/drop_license_management_artifact.yml7
-rw-r--r--config/feature_flags/development/efficient_counter_attribute.yml7
-rw-r--r--config/feature_flags/development/export_lfs_objects_projects.yml7
-rw-r--r--config/feature_flags/development/export_reduce_relation_batch_size.yml7
-rw-r--r--config/feature_flags/development/file_identifier_hash.yml7
-rw-r--r--config/feature_flags/development/filter_pipelines_search.yml7
-rw-r--r--config/feature_flags/development/force_autodevops_on_by_default.yml7
-rw-r--r--config/feature_flags/development/forking.yml7
-rw-r--r--config/feature_flags/development/forward_deployment_enabled.yml7
-rw-r--r--config/feature_flags/development/g_compliance_dashboard_feature.yml7
-rw-r--r--config/feature_flags/development/git_push_create_all_pipelines.yml7
-rw-r--r--config/feature_flags/development/gitaly_catfile-cache.yml7
-rw-r--r--config/feature_flags/development/gitaly_deny_disk_access.yml7
-rw-r--r--config/feature_flags/development/gitaly_enforce_requests_limits.yml7
-rw-r--r--config/feature_flags/development/gitaly_mep_mep.yml7
-rw-r--r--config/feature_flags/development/global_default_branch_name.yml7
-rw-r--r--config/feature_flags/development/go_proxy.yml7
-rw-r--r--config/feature_flags/development/go_proxy_disable_gomod_validation.yml7
-rw-r--r--config/feature_flags/development/grape_gitlab_json.yml7
-rw-r--r--config/feature_flags/development/graphql_board_lists.yml7
-rw-r--r--config/feature_flags/development/graphql_logging.yml7
-rw-r--r--config/feature_flags/development/graphql_lookahead_support.yml7
-rw-r--r--config/feature_flags/development/graphql_milestone_stats.yml7
-rw-r--r--config/feature_flags/development/graphql_release_data.yml7
-rw-r--r--config/feature_flags/development/group_export_ndjson.yml7
-rw-r--r--config/feature_flags/development/group_import_export.yml7
-rw-r--r--config/feature_flags/development/group_import_ndjson.yml7
-rw-r--r--config/feature_flags/development/group_level_integrations.yml7
-rw-r--r--config/feature_flags/development/groups_tokens_optional_encryption.yml7
-rw-r--r--config/feature_flags/development/hide_jump_to_next_unresolved_in_threads.yml7
-rw-r--r--config/feature_flags/development/highlight_current_diff_row.yml7
-rw-r--r--config/feature_flags/development/inactive_policy_condition.yml7
-rw-r--r--config/feature_flags/development/ingress_modsecurity.yml7
-rw-r--r--config/feature_flags/development/invisible_captcha.yml7
-rw-r--r--config/feature_flags/development/invite_email_experiment.yml7
-rw-r--r--config/feature_flags/development/issues.yml7
-rw-r--r--config/feature_flags/development/json_limited_encoder.yml7
-rw-r--r--config/feature_flags/development/json_wrapper_legacy_mode.yml7
-rw-r--r--config/feature_flags/development/junit_pipeline_screenshots_view.yml7
-rw-r--r--config/feature_flags/development/lfs_check.yml7
-rw-r--r--config/feature_flags/development/lfs_link_existing_object.yml7
-rw-r--r--config/feature_flags/development/limit_projects_in_groups_api.yml7
-rw-r--r--config/feature_flags/development/log_import_export_relation_creation.yml7
-rw-r--r--config/feature_flags/development/maintenance_mode.yml7
-rw-r--r--config/feature_flags/development/marginalia.yml7
-rw-r--r--config/feature_flags/development/merge_orchestration_service.yml7
-rw-r--r--config/feature_flags/development/merge_red_head_comments_position_on_demand.yml7
-rw-r--r--config/feature_flags/development/merge_ref_auto_sync.yml7
-rw-r--r--config/feature_flags/development/merge_ref_auto_sync_lock.yml7
-rw-r--r--config/feature_flags/development/merge_request_draft_filter.yml7
-rw-r--r--config/feature_flags/development/merge_request_rebase_nowait_lock.yml7
-rw-r--r--config/feature_flags/development/merge_request_short_pipeline_serializer.yml7
-rw-r--r--config/feature_flags/development/merge_request_widget_graphql.yml7
-rw-r--r--config/feature_flags/development/merge_requests.yml7
-rw-r--r--config/feature_flags/development/metrics_dashboard.yml7
-rw-r--r--config/feature_flags/development/migrate_bio_to_user_details.yml7
-rw-r--r--config/feature_flags/development/migrate_user_mentions.yml7
-rw-r--r--config/feature_flags/development/modifed_path_ci_variables.yml7
-rw-r--r--config/feature_flags/development/monaco_blobs.yml7
-rw-r--r--config/feature_flags/development/monaco_ci.yml7
-rw-r--r--config/feature_flags/development/mr_commit_neighbor_nav.yml7
-rw-r--r--config/feature_flags/development/multi_select_board.yml7
-rw-r--r--config/feature_flags/development/multiline_comments.yml7
-rw-r--r--config/feature_flags/development/new_pipeline_form.yml7
-rw-r--r--config/feature_flags/development/new_release_page.yml7
-rw-r--r--config/feature_flags/development/new_variables_ui.yml7
-rw-r--r--config/feature_flags/development/not_issuable_queries.yml7
-rw-r--r--config/feature_flags/development/notes_create_service_tracking.yml7
-rw-r--r--config/feature_flags/development/oj_json.yml7
-rw-r--r--config/feature_flags/development/optimized_timebox_queries.yml7
-rw-r--r--config/feature_flags/development/packages_coming_soon.yml7
-rw-r--r--config/feature_flags/development/pages.yml7
-rw-r--r--config/feature_flags/development/paginated_notes.yml7
-rw-r--r--config/feature_flags/development/periodic_project_authorization_recalculation.yml7
-rw-r--r--config/feature_flags/development/phabricator_import.yml7
-rw-r--r--config/feature_flags/development/pipelines_security_report_summary.yml7
-rw-r--r--config/feature_flags/development/product_analytics.yml7
-rw-r--r--config/feature_flags/development/prohibit_hexadecimal_branch_names.yml7
-rw-r--r--config/feature_flags/development/project_export_as_ndjson.yml7
-rw-r--r--config/feature_flags/development/project_import_ndjson.yml7
-rw-r--r--config/feature_flags/development/project_list_filter_bar.yml7
-rw-r--r--config/feature_flags/development/project_statistics_sync.yml7
-rw-r--r--config/feature_flags/development/project_transactionless_destroy.yml7
-rw-r--r--config/feature_flags/development/projects_tokens_optional_encryption.yml7
-rw-r--r--config/feature_flags/development/prometheus_computed_alerts.yml7
-rw-r--r--config/feature_flags/development/reactive_caching_limit_environment.yml7
-rw-r--r--config/feature_flags/development/real_time_issue_sidebar.yml7
-rw-r--r--config/feature_flags/development/release_asset_link_editing.yml7
-rw-r--r--config/feature_flags/development/release_asset_link_type.yml7
-rw-r--r--config/feature_flags/development/release_evidence.yml7
-rw-r--r--config/feature_flags/development/release_evidence_collection.yml7
-rw-r--r--config/feature_flags/development/release_issue_summary.yml7
-rw-r--r--config/feature_flags/development/release_mr_issue_urls.yml7
-rw-r--r--config/feature_flags/development/release_show_page.yml7
-rw-r--r--config/feature_flags/development/remove_legacy_github_client.yml7
-rw-r--r--config/feature_flags/development/repack_after_shard_migration.yml7
-rw-r--r--config/feature_flags/development/repository.yml7
-rw-r--r--config/feature_flags/development/repository_archive_hotlinking_interception.yml7
-rw-r--r--config/feature_flags/development/resource_access_token.yml7
-rw-r--r--config/feature_flags/development/rugged_commit_is_ancestor.yml7
-rw-r--r--config/feature_flags/development/rugged_commit_tree_entry.yml7
-rw-r--r--config/feature_flags/development/rugged_find_commit.yml7
-rw-r--r--config/feature_flags/development/rugged_list_commits_by_oid.yml7
-rw-r--r--config/feature_flags/development/rugged_tree_entries.yml7
-rw-r--r--config/feature_flags/development/rugged_tree_entry.yml7
-rw-r--r--config/feature_flags/development/safezip_use_rubyzip.yml7
-rw-r--r--config/feature_flags/development/save_raw_usage_data.yml7
-rw-r--r--config/feature_flags/development/schema_linting.yml7
-rw-r--r--config/feature_flags/development/serverless_domain.yml7
-rw-r--r--config/feature_flags/development/service_desk_custom_address.yml7
-rw-r--r--config/feature_flags/development/settings_operations_prometheus_service.yml7
-rw-r--r--config/feature_flags/development/similarity_search.yml7
-rw-r--r--config/feature_flags/development/snippet_multiple_files.yml7
-rw-r--r--config/feature_flags/development/snippets.yml7
-rw-r--r--config/feature_flags/development/snippets_binary_blob.yml7
-rw-r--r--config/feature_flags/development/snippets_edit_vue.yml7
-rw-r--r--config/feature_flags/development/snippets_vue.yml7
-rw-r--r--config/feature_flags/development/soft_email_confirmation.yml7
-rw-r--r--config/feature_flags/development/specialized_project_authorization_project_share_worker.yml7
-rw-r--r--config/feature_flags/development/specialized_project_authorization_workers.yml7
-rw-r--r--config/feature_flags/development/sql_set_operators.yml7
-rw-r--r--config/feature_flags/development/squash_options.yml7
-rw-r--r--config/feature_flags/development/sse_image_uploads.yml7
-rw-r--r--config/feature_flags/development/store_mentioned_users_to_db.yml7
-rw-r--r--config/feature_flags/development/suggest_pipeline.yml7
-rw-r--r--config/feature_flags/development/track_resource_state_change_events.yml7
-rw-r--r--config/feature_flags/development/track_unique_visits.yml7
-rw-r--r--config/feature_flags/development/tribute_autocomplete.yml7
-rw-r--r--config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml7
-rw-r--r--config/feature_flags/development/usage_data_g_compliance_dashboard.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_alert_assigned.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_alert_todo.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_assigned.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_closed.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_comment.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_created.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_relate.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_reopened.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_todo.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml7
-rw-r--r--config/feature_flags/development/use_workhorse_s3_client.yml7
-rw-r--r--config/feature_flags/development/user_mode_in_session.yml7
-rw-r--r--config/feature_flags/development/user_time_settings.yml7
-rw-r--r--config/feature_flags/development/users_search.yml7
-rw-r--r--config/feature_flags/development/validate_import_decompressed_archive_size.yml7
-rw-r--r--config/feature_flags/development/view_diffs_file_by_file.yml7
-rw-r--r--config/feature_flags/development/vue_issuable_sidebar.yml7
-rw-r--r--config/feature_flags/development/vue_issuables_list.yml7
-rw-r--r--config/feature_flags/development/web_ide_primary_edit.yml7
-rw-r--r--config/feature_flags/development/webauthn.yml7
-rw-r--r--config/feature_flags/development/webperf_experiment.yml7
-rw-r--r--config/feature_flags/development/whats_new_drawer.yml7
-rw-r--r--config/feature_flags/development/widget_visibility_polling.yml7
-rw-r--r--config/feature_flags/development/wiki.yml7
-rw-r--r--config/feature_flags/development/wiki_events_on_git_push.yml7
-rw-r--r--config/feature_flags/development/wiki_front_matter.yml7
-rw-r--r--config/feature_flags/development/workhorse_archive_cache_disabled.yml7
-rw-r--r--doc/api/project_templates.md2
-rw-r--r--doc/api/search.md5
-rw-r--r--doc/api/templates/dockerfiles.md2
-rw-r--r--doc/operations/incident_management/generic_alerts.md1
-rw-r--r--doc/operations/incident_management/incidents.md23
-rw-r--r--doc/raketasks/cleanup.md4
-rw-r--r--doc/system_hooks/system_hooks.md2
-rw-r--r--doc/topics/git/how_to_install_git/index.md16
-rw-r--r--lib/gitlab/alert_management/alert_params.rb1
-rw-r--r--lib/gitlab/alerting/notification_payload_parser.rb11
-rw-r--r--lib/gitlab/checks/lfs_integrity.rb2
-rw-r--r--lib/gitlab/cleanup/orphan_lfs_file_references.rb8
-rw-r--r--lib/gitlab/import_export/lfs_saver.rb2
-rw-r--r--lib/gitlab/pages/settings.rb2
-rw-r--r--locale/gitlab.pot15
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/component/select2.rb8
-rw-r--r--qa/qa/page/merge_request/show.rb4
-rw-r--r--qa/qa/page/project/settings/advanced.rb22
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb15
-rw-r--r--rubocop/cop/avoid_route_redirect_leading_slash.rb4
-rw-r--r--spec/frontend/boards/mock_data.js12
-rw-r--r--spec/frontend/boards/stores/actions_spec.js42
-rw-r--r--spec/frontend/diffs/components/parallel_diff_table_row_spec.js258
-rw-r--r--spec/frontend/issue_show/components/app_spec.js25
-rw-r--r--spec/frontend/issue_show/components/incident_tabs_spec.js47
-rw-r--r--spec/frontend/issue_show/components/incidents/highlight_bar_spec.js (renamed from spec/frontend/issue_show/components/highlight_bar_spec.js)14
-rw-r--r--spec/frontend/issue_show/components/incidents/incident_tabs_spec.js101
-rw-r--r--spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap68
-rw-r--r--spec/frontend/packages/details/components/package_title_spec.js26
-rw-r--r--spec/frontend/registry/explorer/components/list_page/registry_header_spec.js16
-rw-r--r--spec/frontend/vue_shared/components/registry/metadata_item_spec.js101
-rw-r--r--spec/lib/gitlab/alert_management/alert_params_spec.rb1
-rw-r--r--spec/lib/gitlab/alerting/notification_payload_parser_spec.rb6
-rw-r--r--spec/lib/gitlab/checks/lfs_integrity_spec.rb20
-rw-r--r--spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb38
-rw-r--r--spec/lib/gitlab/pages/settings_spec.rb15
-rw-r--r--spec/models/alert_management/alert_spec.rb18
-rw-r--r--spec/models/project_spec.rb109
-rw-r--r--spec/policies/global_policy_spec.rb18
-rw-r--r--spec/presenters/alert_management/alert_presenter_spec.rb121
-rw-r--r--spec/presenters/alert_management/prometheus_alert_presenter_spec.rb74
-rw-r--r--spec/services/alert_management/create_alert_issue_service_spec.rb2
-rw-r--r--spec/services/projects/alerting/notify_service_spec.rb63
-rw-r--r--spec/services/projects/lfs_pointers/lfs_download_service_spec.rb57
-rw-r--r--spec/services/projects/lfs_pointers/lfs_link_service_spec.rb6
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb38
-rw-r--r--spec/workers/repository_fork_worker_spec.rb2
-rw-r--r--vendor/Dockerfile/Binary.Dockerfile2
-rw-r--r--vendor/Dockerfile/Golang.Dockerfile2
-rw-r--r--yarn.lock8
316 files changed, 3033 insertions, 825 deletions
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index 248e06ba264..4b81d9c73ef 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -263,13 +263,13 @@ export default {
commit(types.MOVE_ISSUE, { originalIssue, fromListId, toListId, moveBeforeId, moveAfterId });
const { boardId } = state.endpoints;
- const [groupPath, project] = issuePath.split(/[/#]/);
+ const [fullProjectPath] = issuePath.split(/[#]/);
gqlClient
.mutate({
mutation: issueMoveListMutation,
variables: {
- projectPath: `${groupPath}/${project}`,
+ projectPath: fullProjectPath,
boardId: fullBoardId(boardId),
iid: issueIid,
fromListId: getIdFromGraphQLId(fromListId),
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
index 8fe802cf1f5..582424b884a 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
@@ -1,8 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import $ from 'jquery';
-import { GlTooltipDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
-import DiffTableCell from './diff_table_cell.vue';
+import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import {
MATCH_LINE_TYPE,
NEW_LINE_TYPE,
@@ -13,11 +12,16 @@ import {
PARALLEL_DIFF_VIEW_TYPE,
NEW_NO_NEW_LINE_TYPE,
EMPTY_CELL_TYPE,
+ LINE_HOVER_CLASS_NAME,
} from '../constants';
+import { __ } from '~/locale';
+import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
+import DiffGutterAvatars from './diff_gutter_avatars.vue';
export default {
components: {
- DiffTableCell,
+ GlIcon,
+ DiffGutterAvatars,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -51,10 +55,12 @@ export default {
return {
isLeftHover: false,
isRightHover: false,
+ isCommentButtonRendered: false,
};
},
computed: {
...mapGetters('diffs', ['fileLineCoverage']),
+ ...mapGetters(['isLoggedIn']),
...mapState({
isHighlighted(state) {
if (this.isCommented) return true;
@@ -66,12 +72,15 @@ export default {
return lineCode ? lineCode === state.diffs.highlightedRow : false;
},
}),
- isContextLine() {
+ isContextLineLeft() {
return this.line.left && this.line.left.type === CONTEXT_LINE_TYPE;
},
+ isContextLineRight() {
+ return this.line.right && this.line.right.type === CONTEXT_LINE_TYPE;
+ },
classNameMap() {
return {
- [CONTEXT_LINE_CLASS_NAME]: this.isContextLine,
+ [CONTEXT_LINE_CLASS_NAME]: this.isContextLineLeft,
[PARALLEL_DIFF_VIEW_TYPE]: true,
};
},
@@ -98,6 +107,129 @@ export default {
coverageState() {
return this.fileLineCoverage(this.filePath, this.line.right.new_line);
},
+ classNameMapCellLeft() {
+ const { type } = this.line.left;
+
+ return [
+ type,
+ {
+ hll: this.isHighlighted,
+ [LINE_HOVER_CLASS_NAME]:
+ this.isLoggedIn && this.isLeftHover && !this.isContextLineLeft && !this.isMetaLineLeft,
+ },
+ ];
+ },
+ classNameMapCellRight() {
+ const { type } = this.line.right;
+
+ return [
+ type,
+ {
+ hll: this.isHighlighted,
+ [LINE_HOVER_CLASS_NAME]:
+ this.isLoggedIn &&
+ this.isRightHover &&
+ !this.isContextLineRight &&
+ !this.isMetaLineRight,
+ },
+ ];
+ },
+ addCommentTooltipLeft() {
+ const brokenSymlinks = this.line.left.commentsDisabled;
+ let tooltip = __('Add a comment to this line');
+
+ if (brokenSymlinks) {
+ if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
+ tooltip = __(
+ 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
+ );
+ } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
+ tooltip = __(
+ 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
+ );
+ }
+ }
+
+ return tooltip;
+ },
+ addCommentTooltipRight() {
+ const brokenSymlinks = this.line.right.commentsDisabled;
+ let tooltip = __('Add a comment to this line');
+
+ if (brokenSymlinks) {
+ if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
+ tooltip = __(
+ 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
+ );
+ } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
+ tooltip = __(
+ 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
+ );
+ }
+ }
+
+ return tooltip;
+ },
+ shouldRenderCommentButton() {
+ if (!this.isCommentButtonRendered) {
+ return false;
+ }
+
+ if (this.isLoggedIn) {
+ const isDiffHead = parseBoolean(getParameterByName('diff_head'));
+ return !isDiffHead || gon.features?.mergeRefHeadComments;
+ }
+
+ return false;
+ },
+ shouldShowCommentButtonLeft() {
+ return (
+ this.isLeftHover &&
+ !this.isContextLineLeft &&
+ !this.isMetaLineLeft &&
+ !this.hasDiscussionsLeft
+ );
+ },
+ shouldShowCommentButtonRight() {
+ return (
+ this.isRightHover &&
+ !this.isContextLineRight &&
+ !this.isMetaLineRight &&
+ !this.hasDiscussionsRight
+ );
+ },
+ hasDiscussionsLeft() {
+ return this.line.left.discussions && this.line.left.discussions.length > 0;
+ },
+ hasDiscussionsRight() {
+ return this.line.right.discussions && this.line.right.discussions.length > 0;
+ },
+ lineHrefOld() {
+ return `#${this.line.left.line_code || ''}`;
+ },
+ lineHrefNew() {
+ return `#${this.line.right.line_code || ''}`;
+ },
+ lineCode() {
+ return (
+ (this.line.left && this.line.left.line_code) ||
+ (this.line.right && this.line.right.line_code)
+ );
+ },
+ isMetaLineLeft() {
+ const { type } = this.line.left;
+
+ return (
+ type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE
+ );
+ },
+ isMetaLineRight() {
+ const { type } = this.line.right;
+
+ return (
+ type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE
+ );
+ },
},
created() {
this.newLineType = NEW_LINE_TYPE;
@@ -106,9 +238,26 @@ export default {
},
mounted() {
this.scrollToLineIfNeededParallel(this.line);
+ this.unwatchShouldShowCommentButton = this.$watch(
+ vm => [vm.shouldShowCommentButtonLeft, vm.shouldShowCommentButtonRight].join(),
+ newVal => {
+ if (newVal) {
+ this.isCommentButtonRendered = true;
+ this.unwatchShouldShowCommentButton();
+ }
+ },
+ );
+ },
+ beforeDestroy() {
+ this.unwatchShouldShowCommentButton();
},
methods: {
- ...mapActions('diffs', ['scrollToLineIfNeededParallel']),
+ ...mapActions('diffs', [
+ 'scrollToLineIfNeededParallel',
+ 'showCommentForm',
+ 'setHighlightedRow',
+ 'toggleLineDiscussions',
+ ]),
handleMouseMove(e) {
const isHover = e.type === 'mouseover';
const hoveringCell = e.target.closest('td');
@@ -134,6 +283,9 @@ export default {
table.addClass(`${lineClass}-selected`);
}
},
+ handleCommentButton(line) {
+ this.showCommentForm({ lineCode: line.line_code, fileHash: this.fileHash });
+ },
},
};
</script>
@@ -146,18 +298,46 @@ export default {
@mouseout="handleMouseMove"
>
<template v-if="line.left && !isMatchLineLeft">
- <diff-table-cell
- :file-hash="fileHash"
- :line="line.left"
- :line-type="oldLineType"
- :is-bottom="isBottom"
- :is-hover="isLeftHover"
- :is-highlighted="isHighlighted"
- :show-comment-button="true"
- :diff-view-type="parallelDiffViewType"
- line-position="left"
- class="diff-line-num old_line"
- />
+ <td ref="oldTd" :class="classNameMapCellLeft" class="diff-line-num old_line">
+ <span
+ v-if="shouldRenderCommentButton"
+ ref="addNoteTooltipLeft"
+ v-gl-tooltip
+ class="add-diff-note tooltip-wrapper"
+ :title="addCommentTooltipLeft"
+ >
+ <button
+ v-show="shouldShowCommentButtonLeft"
+ ref="addDiffNoteButtonLeft"
+ type="button"
+ class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
+ :disabled="line.left.commentsDisabled"
+ @click="handleCommentButton(line.left)"
+ >
+ <gl-icon :size="12" name="comment" />
+ </button>
+ </span>
+ <a
+ v-if="line.left.old_line"
+ ref="lineNumberRefOld"
+ :data-linenumber="line.left.old_line"
+ :href="lineHrefOld"
+ @click="setHighlightedRow(lineCode)"
+ >
+ </a>
+ <diff-gutter-avatars
+ v-if="hasDiscussionsLeft"
+ :discussions="line.left.discussions"
+ :discussions-expanded="line.left.discussionsExpanded"
+ @toggleLineDiscussions="
+ toggleLineDiscussions({
+ lineCode: line.left.line_code,
+ fileHash,
+ expanded: !line.left.discussionsExpanded,
+ })
+ "
+ />
+ </td>
<td :class="parallelViewLeftLineType" class="line-coverage left-side"></td>
<td
:id="line.left.line_code"
@@ -173,18 +353,46 @@ export default {
<td class="line_content with-coverage parallel left-side empty-cell"></td>
</template>
<template v-if="line.right && !isMatchLineRight">
- <diff-table-cell
- :file-hash="fileHash"
- :line="line.right"
- :line-type="newLineType"
- :is-bottom="isBottom"
- :is-hover="isRightHover"
- :is-highlighted="isHighlighted"
- :show-comment-button="true"
- :diff-view-type="parallelDiffViewType"
- line-position="right"
- class="diff-line-num new_line"
- />
+ <td ref="newTd" :class="classNameMapCellRight" class="diff-line-num new_line">
+ <span
+ v-if="shouldRenderCommentButton"
+ ref="addNoteTooltipRight"
+ v-gl-tooltip
+ class="add-diff-note tooltip-wrapper"
+ :title="addCommentTooltipRight"
+ >
+ <button
+ v-show="shouldShowCommentButtonRight"
+ ref="addDiffNoteButtonRight"
+ type="button"
+ class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
+ :disabled="line.right.commentsDisabled"
+ @click="handleCommentButton(line.right)"
+ >
+ <gl-icon :size="12" name="comment" />
+ </button>
+ </span>
+ <a
+ v-if="line.right.new_line"
+ ref="lineNumberRefNew"
+ :data-linenumber="line.right.new_line"
+ :href="lineHrefNew"
+ @click="setHighlightedRow(lineCode)"
+ >
+ </a>
+ <diff-gutter-avatars
+ v-if="hasDiscussionsRight"
+ :discussions="line.right.discussions"
+ :discussions-expanded="line.right.discussionsExpanded"
+ @toggleLineDiscussions="
+ toggleLineDiscussions({
+ lineCode: line.right.line_code,
+ fileHash,
+ expanded: !line.right.discussionsExpanded,
+ })
+ "
+ />
+ </td>
<td
v-gl-tooltip.hover
:title="coverageState.text"
diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue
index 1cc04003aa6..25b24e66fdc 100644
--- a/app/assets/javascripts/issue_show/components/app.vue
+++ b/app/assets/javascripts/issue_show/components/app.vue
@@ -468,7 +468,6 @@ export default {
<component
:is="descriptionComponent"
- v-if="state.descriptionHtml"
:can-update="canUpdate"
:description-html="state.descriptionHtml"
:description-text="state.descriptionText"
diff --git a/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql
new file mode 100644
index 00000000000..00ddc80432d
--- /dev/null
+++ b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql
@@ -0,0 +1,20 @@
+query getAlert($iid: String!, $fullPath: ID!) {
+ project(fullPath: $fullPath) {
+ issue(iid: $iid) {
+ alertManagementAlert {
+ iid
+ title
+ detailsUrl
+ severity
+ status
+ startedAt
+ eventCount
+ monitoringTool
+ service
+ description
+ endedAt
+ details
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/issue_show/components/incidents/highlight_bar/higlight_bar.vue b/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue
index dbef301856d..a47fe4c84cf 100644
--- a/app/assets/javascripts/issue_show/components/incidents/highlight_bar/higlight_bar.vue
+++ b/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue
@@ -1,28 +1,20 @@
<script>
import { GlLink } from '@gitlab/ui';
import { formatDate } from '~/lib/utils/datetime_utility';
-import getHighlightBarInfo from './graphql/queries/get_highlight_bar_info.graphql';
export default {
components: {
GlLink,
},
- inject: ['fullPath', 'iid'],
- apollo: {
+ props: {
alert: {
- query: getHighlightBarInfo,
- variables() {
- return {
- fullPath: this.fullPath,
- iid: this.iid,
- };
- },
- update: data => data.project?.issue?.alertManagementAlert,
+ type: Object,
+ required: true,
},
},
computed: {
startTime() {
- return formatDate(this.alert.createdAt, 'yyyy-mm-dd Z');
+ return formatDate(this.alert.startedAt, 'yyyy-mm-dd Z');
},
},
};
@@ -30,7 +22,6 @@ export default {
<template>
<div
- v-if="alert"
class="gl-border-solid gl-border-1 gl-border-gray-100 gl-p-5 gl-mb-3 gl-rounded-base gl-display-flex gl-justify-content-space-between"
>
<div class="text-truncate gl-pr-3">
diff --git a/app/assets/javascripts/issue_show/components/incidents/highlight_bar/graphql/queries/get_highlight_bar_info.graphql b/app/assets/javascripts/issue_show/components/incidents/highlight_bar/graphql/queries/get_highlight_bar_info.graphql
deleted file mode 100644
index fe299adf53e..00000000000
--- a/app/assets/javascripts/issue_show/components/incidents/highlight_bar/graphql/queries/get_highlight_bar_info.graphql
+++ /dev/null
@@ -1,12 +0,0 @@
-query getHighlightBarInfo($iid: String!, $fullPath: ID!) {
- project(fullPath: $fullPath) {
- issue(iid: $iid) {
- alertManagementAlert {
- title
- detailsUrl
- createdAt
- eventCount
- }
- }
- }
-}
diff --git a/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue
index e5dde1aaca6..4104ddbf06f 100644
--- a/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue
+++ b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue
@@ -1,25 +1,71 @@
<script>
import { GlTab, GlTabs } from '@gitlab/ui';
import DescriptionComponent from '../description.vue';
-import HighlightBar from './highlight_bar/higlight_bar.vue';
+import HighlightBar from './highlight_bar.vue';
+import createFlash from '~/flash';
+import { s__ } from '~/locale';
+import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
+
+import getAlert from './graphql/queries/get_alert.graphql';
export default {
components: {
+ AlertDetailsTable,
+ DescriptionComponent,
GlTab,
GlTabs,
- DescriptionComponent,
HighlightBar,
},
+ inject: ['fullPath', 'iid'],
+ apollo: {
+ alert: {
+ query: getAlert,
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ iid: this.iid,
+ };
+ },
+ update(data) {
+ return data?.project?.issue?.alertManagementAlert;
+ },
+ error() {
+ createFlash({
+ message: s__('Incident|There was an issue loading alert data. Please try again.'),
+ });
+ },
+ },
+ },
+ data() {
+ return {
+ alert: null,
+ };
+ },
+ computed: {
+ loading() {
+ return this.$apollo.queries.alert.loading;
+ },
+ alertTableFields() {
+ if (this.alert) {
+ const { detailsUrl, __typename, ...restDetails } = this.alert;
+ return restDetails;
+ }
+ return null;
+ },
+ },
};
</script>
<template>
<div>
<gl-tabs content-class="gl-reset-line-height" class="gl-mt-n3" data-testid="incident-tabs">
- <gl-tab :title="__('Summary')">
- <highlight-bar />
+ <gl-tab :title="s__('Incident|Summary')">
+ <highlight-bar v-if="alert" :alert="alert" />
<description-component v-bind="$attrs" />
</gl-tab>
+ <gl-tab v-if="alert" class="alert-management-details" :title="s__('Incident|Alert details')">
+ <alert-details-table :alert="alertTableFields" :loading="loading" />
+ </gl-tab>
</gl-tabs>
</div>
</template>
diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue
index 9c8afdbc266..b03a91716fe 100644
--- a/app/assets/javascripts/issue_show/components/title.vue
+++ b/app/assets/javascripts/issue_show/components/title.vue
@@ -1,6 +1,5 @@
<script>
-/* eslint-disable vue/no-v-html */
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import animateMixin from '../mixins/animate';
import eventHub from '../event_hub';
@@ -10,6 +9,7 @@ export default {
},
directives: {
GlTooltip: GlTooltipDirective,
+ SafeHtml,
},
mixins: [animateMixin],
props: {
@@ -65,13 +65,13 @@ export default {
<template>
<div class="title-container">
<h2
+ v-safe-html="titleHtml"
:class="{
'issue-realtime-pre-pulse': preAnimation,
'issue-realtime-trigger-pulse': pulseAnimation,
}"
class="title qa-title"
dir="auto"
- v-html="titleHtml"
></h2>
<gl-button
v-if="showInlineEditButton && canUpdate"
diff --git a/app/assets/javascripts/packages/details/components/package_title.vue b/app/assets/javascripts/packages/details/components/package_title.vue
index 759c2464bd1..69dd494f11a 100644
--- a/app/assets/javascripts/packages/details/components/package_title.vue
+++ b/app/assets/javascripts/packages/details/components/package_title.vue
@@ -1,10 +1,11 @@
<script>
import { mapState, mapGetters } from 'vuex';
-import { GlIcon, GlLink, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
+import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
import PackageTags from '../../shared/components/package_tags.vue';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
+import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import { __ } from '~/locale';
export default {
@@ -12,9 +13,9 @@ export default {
components: {
TitleArea,
GlIcon,
- GlLink,
GlSprintf,
PackageTags,
+ MetadataItem,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -54,35 +55,24 @@ export default {
</template>
<template v-if="packageTypeDisplay" #metadata_type>
- <gl-icon name="package" class="gl-text-gray-500 gl-mr-3" />
- <span data-testid="package-type" class="gl-font-weight-bold">{{ packageTypeDisplay }}</span>
+ <metadata-item data-testid="package-type" icon="package" :text="packageTypeDisplay" />
</template>
<template #metadata_size>
- <gl-icon name="disk" class="gl-text-gray-500 gl-mr-3" />
- <span data-testid="package-size" class="gl-font-weight-bold">{{ totalSize }}</span>
+ <metadata-item data-testid="package-size" icon="disk" :text="totalSize" />
</template>
<template v-if="packagePipeline" #metadata_pipeline>
- <gl-icon name="review-list" class="gl-text-gray-500 gl-mr-3" />
- <gl-link
+ <metadata-item
data-testid="pipeline-project"
- :href="packagePipeline.project.web_url"
- class="gl-font-weight-bold gl-str-truncated"
- >
- {{ packagePipeline.project.name }}
- </gl-link>
+ icon="review-list"
+ :text="packagePipeline.project.name"
+ :link="packagePipeline.project.web_url"
+ />
</template>
<template v-if="packagePipeline" #metadata_ref>
- <gl-icon name="branch" data-testid="package-ref-icon" class="gl-text-gray-500 gl-mr-3" />
- <span
- v-gl-tooltip
- data-testid="package-ref"
- class="gl-font-weight-bold gl-str-truncated mw-xs"
- :title="packagePipeline.ref"
- >{{ packagePipeline.ref }}</span
- >
+ <metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" />
</template>
<template v-if="hasTagsToDisplay" #metadata_tags>
diff --git a/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue b/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue
index 7d2f642f048..7be68e77def 100644
--- a/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue
+++ b/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue
@@ -1,7 +1,8 @@
<script>
-import { GlSprintf, GlLink, GlIcon } from '@gitlab/ui';
+import { GlSprintf, GlLink } from '@gitlab/ui';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
-import { n__ } from '~/locale';
+import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
+import { n__, sprintf } from '~/locale';
import { approximateDuration, calculateRemainingMilliseconds } from '~/lib/utils/datetime_utility';
import {
@@ -14,10 +15,10 @@ import {
export default {
components: {
- GlIcon,
GlSprintf,
GlLink,
TitleArea,
+ MetadataItem,
},
props: {
expirationPolicy: {
@@ -58,11 +59,12 @@ export default {
},
computed: {
imagesCountText() {
- return n__(
+ const pluralisedString = n__(
'ContainerRegistry|%{count} Image repository',
'ContainerRegistry|%{count} Image repositories',
this.imagesCount,
);
+ return sprintf(pluralisedString, { count: this.imagesCount });
},
timeTillRun() {
const difference = calculateRemainingMilliseconds(this.expirationPolicy?.next_run_at);
@@ -73,7 +75,7 @@ export default {
},
expirationPolicyText() {
return this.expirationPolicyEnabled
- ? EXPIRATION_POLICY_WILL_RUN_IN
+ ? sprintf(EXPIRATION_POLICY_WILL_RUN_IN, { time: this.timeTillRun })
: EXPIRATION_POLICY_DISABLED_TEXT;
},
showExpirationPolicyTip() {
@@ -92,24 +94,21 @@ export default {
<slot name="commands"></slot>
</template>
<template #metadata_count>
- <span v-if="imagesCount" data-testid="images-count">
- <gl-icon class="gl-mr-1" name="container-image" />
- <gl-sprintf :message="imagesCountText">
- <template #count>
- {{ imagesCount }}
- </template>
- </gl-sprintf>
- </span>
+ <metadata-item
+ v-if="imagesCount"
+ data-testid="images-count"
+ icon="container-image"
+ :text="imagesCountText"
+ />
</template>
<template #metadata_exp_policies>
- <span v-if="!hideExpirationPolicyData" data-testid="expiration-policy">
- <gl-icon class="gl-mr-1" name="expire" />
- <gl-sprintf :message="expirationPolicyText">
- <template #time>
- {{ timeTillRun }}
- </template>
- </gl-sprintf>
- </span>
+ <metadata-item
+ v-if="!hideExpirationPolicyData"
+ data-testid="expiration-policy"
+ icon="expire"
+ :text="expirationPolicyText"
+ size="xl"
+ />
</template>
</title-area>
diff --git a/app/assets/javascripts/vue_shared/components/alert_details_table.vue b/app/assets/javascripts/vue_shared/components/alert_details_table.vue
index 2cd71669ecb..395ed0f2033 100644
--- a/app/assets/javascripts/vue_shared/components/alert_details_table.vue
+++ b/app/assets/javascripts/vue_shared/components/alert_details_table.vue
@@ -19,7 +19,7 @@ export default {
},
},
tableHeader: {
- [s__('AlertManagement|Full Alert Payload')]: s__('AlertManagement|Value'),
+ [s__('AlertManagement|Key')]: s__('AlertManagement|Value'),
},
computed: {
items() {
@@ -33,7 +33,7 @@ export default {
</script>
<template>
<gl-table
- class="alert-management-details-table"
+ class="alert-management-details-table gl-mb-0!"
:busy="loading"
:empty-text="s__('AlertManagement|No alert data to display.')"
:items="items"
diff --git a/app/assets/javascripts/vue_shared/components/registry/metadata_item.vue b/app/assets/javascripts/vue_shared/components/registry/metadata_item.vue
new file mode 100644
index 00000000000..8ef623b68eb
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/registry/metadata_item.vue
@@ -0,0 +1,63 @@
+<script>
+import { GlIcon, GlLink } from '@gitlab/ui';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+
+export default {
+ name: 'MetadataItem',
+ components: {
+ GlIcon,
+ GlLink,
+ TooltipOnTruncate,
+ },
+ props: {
+ icon: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ text: {
+ type: String,
+ required: true,
+ },
+ link: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ size: {
+ type: String,
+ required: false,
+ default: 's',
+ validator(value) {
+ return !value || ['xs', 's', 'm', 'l', 'xl'].includes(value);
+ },
+ },
+ },
+ computed: {
+ sizeClass() {
+ return `mw-${this.size}`;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-inline-flex gl-align-items-center">
+ <gl-icon v-if="icon" :name="icon" class="gl-text-gray-500 gl-mr-3" />
+ <tooltip-on-truncate v-if="link" :title="text" class="gl-text-truncate" :class="sizeClass">
+ <gl-link :href="link" class="gl-font-weight-bold">
+ {{ text }}
+ </gl-link>
+ </tooltip-on-truncate>
+ <div
+ v-else
+ data-testid="metadata-item-text"
+ class="gl-font-weight-bold gl-display-inline-flex"
+ :class="sizeClass"
+ >
+ <tooltip-on-truncate :title="text" class="gl-text-truncate">
+ {{ text }}
+ </tooltip-on-truncate>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/stylesheets/pages/alert_management/details.scss b/app/assets/stylesheets/pages/alert_management/details.scss
index 1e6ad81009a..531693a3bbe 100644
--- a/app/assets/stylesheets/pages/alert_management/details.scss
+++ b/app/assets/stylesheets/pages/alert_management/details.scss
@@ -6,7 +6,10 @@
@include gl-border-0;
@include gl-p-5;
border-color: transparent;
- border-bottom: 1px solid $table-border-color;
+
+ &:not(:last-child) {
+ border-bottom: 1px solid $table-border-color;
+ }
&:first-child {
div {
@@ -31,6 +34,12 @@
}
}
}
+
+ &:last-child {
+ &::after {
+ content: none !important;
+ }
+ }
}
}
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index c473cc44637..e9eb79b071c 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -178,7 +178,6 @@ $status-box-line-height: 26px;
.milestone-detail {
border-bottom: 1px solid $border-color;
- padding: 20px 0;
}
@include media-breakpoint-down(xs) {
diff --git a/app/controllers/repositories/lfs_api_controller.rb b/app/controllers/repositories/lfs_api_controller.rb
index f93038f455e..35751a2578f 100644
--- a/app/controllers/repositories/lfs_api_controller.rb
+++ b/app/controllers/repositories/lfs_api_controller.rb
@@ -46,7 +46,7 @@ module Repositories
end
def download_objects!
- existing_oids = project.all_lfs_objects_oids(oids: objects_oids)
+ existing_oids = project.lfs_objects_oids(oids: objects_oids)
objects.each do |object|
if existing_oids.include?(object[:oid])
diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb
index ca0ccf45771..2da97030b88 100644
--- a/app/graphql/types/alert_management/alert_type.rb
+++ b/app/graphql/types/alert_management/alert_type.rb
@@ -6,6 +6,8 @@ module Types
graphql_name 'AlertManagementAlert'
description "Describes an alert from the project's Alert Management"
+ present_using ::AlertManagement::AlertPresenter
+
implements(Types::Notes::NoteableType)
authorize :read_alert_management_alert
@@ -120,10 +122,6 @@ module Types
def notes
object.ordered_notes
end
-
- def runbook
- object.parsed_payload.runbook
- end
end
end
end
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index 0ba03cd90ea..195b3162039 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -58,10 +58,6 @@ module DashboardHelper
links += [:activity, :milestones]
end
- if can?(current_user, :read_instance_statistics)
- links << :analytics
- end
-
links
end
end
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 2318596c63a..578c7ae7923 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -47,7 +47,7 @@ module NavHelper
end
def has_extra_nav_icons?
- Gitlab::Sherlock.enabled? || can?(current_user, :read_instance_statistics) || current_user.admin?
+ Gitlab::Sherlock.enabled? || current_user.admin?
end
def page_has_markdown?
diff --git a/app/models/alert_management/alert.rb b/app/models/alert_management/alert.rb
index d1b5eaecc6a..e9b89af45c6 100644
--- a/app/models/alert_management/alert.rb
+++ b/app/models/alert_management/alert.rb
@@ -118,7 +118,7 @@ module AlertManagement
end
delegate :iid, to: :issue, prefix: true, allow_nil: true
- delegate :metrics_dashboard_url, :details_url, :details, to: :present
+ delegate :details_url, to: :present
scope :for_iid, -> (iid) { where(iid: iid) }
scope :for_status, -> (status) { where(status: status) }
@@ -218,12 +218,6 @@ module AlertManagement
end
end
- def present
- return super(presenter_class: AlertManagement::PrometheusAlertPresenter) if prometheus?
-
- super
- end
-
private
def hook_data
diff --git a/app/models/project.rb b/app/models/project.rb
index b72bf55f879..b931f145260 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1469,46 +1469,6 @@ class Project < ApplicationRecord
forked_from_project || fork_network&.root_project
end
- # TODO: Remove this method once all LfsObjectsProject records are backfilled
- # for forks.
- #
- # See https://gitlab.com/gitlab-org/gitlab/issues/122002 for more info.
- def lfs_storage_project
- @lfs_storage_project ||= begin
- result = self
-
- # TODO: Make this go to the fork_network root immediately
- # dependant on the discussion in: https://gitlab.com/gitlab-org/gitlab-foss/issues/39769
- result = result.fork_source while result&.forked?
-
- result || self
- end
- end
-
- # This will return all `lfs_objects` that are accessible to the project and
- # the fork source. This is needed since older forks won't have access to some
- # LFS objects directly and have to get it from the fork source.
- #
- # TODO: Remove this method once all LfsObjectsProject records are backfilled
- # for forks. At that point, projects can look at their own `lfs_objects`.
- #
- # See https://gitlab.com/gitlab-org/gitlab/issues/122002 for more info.
- def all_lfs_objects
- LfsObject
- .distinct
- .joins(:lfs_objects_projects)
- .where(lfs_objects_projects: { project_id: [self, lfs_storage_project] })
- end
-
- # TODO: Remove this method once all LfsObjectsProject records are backfilled
- # for forks. At that point, projects can look at their own `lfs_objects` so
- # `lfs_objects_oids` can be used instead.
- #
- # See https://gitlab.com/gitlab-org/gitlab/issues/122002 for more info.
- def all_lfs_objects_oids(oids: [])
- oids(all_lfs_objects, oids: oids)
- end
-
def lfs_objects_oids(oids: [])
oids(lfs_objects, oids: oids)
end
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index f294d54fb82..de69636b078 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -98,7 +98,6 @@ class GlobalPolicy < BasePolicy
rule { admin }.policy do
enable :read_custom_attribute
enable :update_custom_attribute
- enable :read_instance_statistics
end
# We can't use `read_statistics` because the user may have different permissions for different projects
diff --git a/app/presenters/alert_management/alert_presenter.rb b/app/presenters/alert_management/alert_presenter.rb
index 8017bc3e0cd..231e90163be 100644
--- a/app/presenters/alert_management/alert_presenter.rb
+++ b/app/presenters/alert_management/alert_presenter.rb
@@ -6,7 +6,10 @@ module AlertManagement
include IncidentManagement::Settings
include ActionView::Helpers::UrlHelper
- MARKDOWN_LINE_BREAK = " \n".freeze
+ MARKDOWN_LINE_BREAK = " \n"
+ HORIZONTAL_LINE = "\n\n---\n\n"
+
+ delegate :metrics_dashboard_url, :runbook, to: :parsed_payload
def initialize(alert, _attributes = {})
super
@@ -16,28 +19,17 @@ module AlertManagement
end
def issue_description
- horizontal_line = "\n\n---\n\n"
-
[
issue_summary_markdown,
alert_markdown,
incident_management_setting.issue_template_content
- ].compact.join(horizontal_line)
+ ].compact.join(HORIZONTAL_LINE)
end
def start_time
started_at&.strftime('%d %B %Y, %-l:%M%p (%Z)')
end
- def issue_summary_markdown
- <<~MARKDOWN.chomp
- #{metadata_list}
- #{alert_details}#{metric_embed_for_alert}
- MARKDOWN
- end
-
- def metrics_dashboard_url; end
-
def details_url
details_project_alert_management_url(project, alert.iid)
end
@@ -49,15 +41,15 @@ module AlertManagement
private
attr_reader :alert, :project
+ delegate :alert_markdown, :full_query, to: :parsed_payload
- def alerting_alert
- strong_memoize(:alerting_alert) do
- Gitlab::Alerting::Alert.new(project: project, payload: alert.payload).present
- end
+ def issue_summary_markdown
+ <<~MARKDOWN.chomp
+ #{metadata_list}
+ #{alert_details}#{metric_embed_for_alert}
+ MARKDOWN
end
- def alert_markdown; end
-
def metadata_list
metadata = []
@@ -90,9 +82,9 @@ module AlertManagement
.join(MARKDOWN_LINE_BREAK)
end
- def metric_embed_for_alert; end
-
- def full_query; end
+ def metric_embed_for_alert
+ "\n[](#{metrics_dashboard_url})" if metrics_dashboard_url
+ end
def list_item(key, value)
"**#{key}:** #{value}".strip
diff --git a/app/presenters/alert_management/prometheus_alert_presenter.rb b/app/presenters/alert_management/prometheus_alert_presenter.rb
deleted file mode 100644
index 0e939a65d42..00000000000
--- a/app/presenters/alert_management/prometheus_alert_presenter.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module AlertManagement
- class PrometheusAlertPresenter < AlertManagement::AlertPresenter
- def metrics_dashboard_url
- alerting_alert.metrics_dashboard_url
- end
-
- private
-
- def alert_markdown
- alerting_alert.alert_markdown
- end
-
- def metric_embed_for_alert
- alerting_alert.metric_embed_for_alert
- end
-
- def full_query
- alerting_alert.full_query
- end
- end
-end
diff --git a/app/services/projects/alerting/notify_service.rb b/app/services/projects/alerting/notify_service.rb
index 1716618f4b9..bfce5f1ad63 100644
--- a/app/services/projects/alerting/notify_service.rb
+++ b/app/services/projects/alerting/notify_service.rb
@@ -42,11 +42,37 @@ module Projects
end
def process_existing_alert(alert)
- alert.register_new_event!
+ if am_alert_params[:ended_at].present?
+ process_resolved_alert(alert)
+ else
+ alert.register_new_event!
+ end
+
+ alert
+ end
+
+ def process_resolved_alert(alert)
+ return unless auto_close_incident?
+
+ if alert.resolve(am_alert_params[:ended_at])
+ close_issue(alert.issue)
+ end
+
+ alert
+ end
+
+ def close_issue(issue)
+ return if issue.blank? || issue.closed?
+
+ ::Issues::CloseService
+ .new(project, User.alert_bot)
+ .execute(issue, system_note: false)
+
+ SystemNoteService.auto_resolve_prometheus_alert(issue, project, User.alert_bot) if issue.reset.closed?
end
def create_alert
- alert = AlertManagement::Alert.create(am_alert_params)
+ alert = AlertManagement::Alert.create(am_alert_params.except(:ended_at))
alert.execute_services if alert.persisted?
SystemNoteService.create_new_alert(alert, 'Generic Alert Endpoint')
diff --git a/app/services/projects/lfs_pointers/lfs_download_service.rb b/app/services/projects/lfs_pointers/lfs_download_service.rb
index 52c73bcff03..d6e5b825e13 100644
--- a/app/services/projects/lfs_pointers/lfs_download_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_download_service.rb
@@ -6,6 +6,9 @@ module Projects
class LfsDownloadService < BaseService
SizeError = Class.new(StandardError)
OidError = Class.new(StandardError)
+ ResponseError = Class.new(StandardError)
+
+ LARGE_FILE_SIZE = 1.megabytes
attr_reader :lfs_download_object
delegate :oid, :size, :credentials, :sanitized_url, to: :lfs_download_object, prefix: :lfs
@@ -19,6 +22,7 @@ module Projects
def execute
return unless project&.lfs_enabled? && lfs_download_object
return error("LFS file with oid #{lfs_oid} has invalid attributes") unless lfs_download_object.valid?
+ return link_existing_lfs_object! if Feature.enabled?(:lfs_link_existing_object, project, default_enabled: true) && lfs_size > LARGE_FILE_SIZE && lfs_object
wrap_download_errors do
download_lfs_file!
@@ -29,7 +33,7 @@ module Projects
def wrap_download_errors(&block)
yield
- rescue SizeError, OidError, StandardError => e
+ rescue SizeError, OidError, ResponseError, StandardError => e
error("LFS file with oid #{lfs_oid} could't be downloaded from #{lfs_sanitized_url}: #{e.message}")
end
@@ -56,15 +60,13 @@ module Projects
def download_and_save_file!(file)
digester = Digest::SHA256.new
- response = Gitlab::HTTP.get(lfs_sanitized_url, download_headers) do |fragment|
+ fetch_file do |fragment|
digester << fragment
file.write(fragment)
raise_size_error! if file.size > lfs_size
end
- raise StandardError, "Received error code #{response.code}" unless response.success?
-
raise_size_error! if file.size != lfs_size
raise_oid_error! if digester.hexdigest != lfs_oid
end
@@ -78,6 +80,12 @@ module Projects
end
end
+ def fetch_file(&block)
+ response = Gitlab::HTTP.get(lfs_sanitized_url, download_headers, &block)
+
+ raise ResponseError, "Received error code #{response.code}" unless response.success?
+ end
+
def with_tmp_file
create_tmp_storage_dir
@@ -123,6 +131,29 @@ module Projects
super
end
+
+ def lfs_object
+ @lfs_object ||= LfsObject.find_by_oid(lfs_oid)
+ end
+
+ def link_existing_lfs_object!
+ existing_file = lfs_object.file.open
+ buffer_size = 0
+ result = fetch_file do |fragment|
+ unless fragment == existing_file.read(fragment.size)
+ break error("LFS file with oid #{lfs_oid} cannot be linked with an existing LFS object")
+ end
+
+ buffer_size += fragment.size
+ break success if buffer_size > LARGE_FILE_SIZE
+ end
+
+ project.lfs_objects << lfs_object
+
+ result
+ ensure
+ existing_file&.close
+ end
end
end
end
diff --git a/app/services/projects/unlink_fork_service.rb b/app/services/projects/unlink_fork_service.rb
index b3cf27373cd..52aea8c51a5 100644
--- a/app/services/projects/unlink_fork_service.rb
+++ b/app/services/projects/unlink_fork_service.rb
@@ -2,21 +2,13 @@
module Projects
class UnlinkForkService < BaseService
- # If a fork is given, it:
- #
- # - Saves LFS objects to the root project
- # - Close existing MRs coming from it
- # - Is removed from the fork network
- #
- # If a root of fork(s) is given, it does the same,
- # but not updating LFS objects (there'll be no related root to cache it).
+ # Close existing MRs coming from the project and remove it from the fork network
def execute
fork_network = @project.fork_network
+ forked_from = @project.forked_from_project
return unless fork_network
- save_lfs_objects
-
merge_requests = fork_network
.merge_requests
.opened
@@ -41,7 +33,7 @@ module Projects
# When the project getting out of the network is a node with parent
# and children, both the parent and the node needs a cache refresh.
- [@project.forked_from_project, @project].compact.each do |project|
+ [forked_from, @project].compact.each do |project|
refresh_forks_count(project)
end
end
@@ -51,22 +43,5 @@ module Projects
def refresh_forks_count(project)
Projects::ForksCountService.new(project).refresh_cache
end
-
- # TODO: Remove this method once all LfsObjectsProject records are backfilled
- # for forks.
- #
- # See https://gitlab.com/gitlab-org/gitlab/issues/122002 for more info.
- def save_lfs_objects
- return unless @project.forked?
-
- lfs_storage_project = @project.lfs_storage_project
-
- return unless lfs_storage_project
- return if lfs_storage_project == @project # that project is being unlinked
-
- lfs_storage_project.lfs_objects.find_each do |lfs_object|
- lfs_object.projects << @project unless lfs_object.projects.include?(@project)
- end
- end
end
end
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 22cf722d117..041b0661d37 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -24,8 +24,10 @@
- if @group.new_record?
.form-group.row
.offset-sm-2.col-sm-10
- .alert.alert-info
- = render 'shared/group_tips'
+ .gl-alert.gl-alert-info
+ = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ = render 'shared/group_tips'
.form-actions
= f.submit _('Create group'), class: "btn btn-success"
= link_to _('Cancel'), admin_groups_path, class: "btn btn-cancel"
diff --git a/app/views/projects/_deletion_failed.html.haml b/app/views/projects/_deletion_failed.html.haml
index 4f3698f91e6..7e65f2f1cef 100644
--- a/app/views/projects/_deletion_failed.html.haml
+++ b/app/views/projects/_deletion_failed.html.haml
@@ -1,6 +1,8 @@
- project = local_assigns.fetch(:project)
- return unless project.delete_error.present?
-.project-deletion-failed-message.alert.alert-warning
- This project was scheduled for deletion, but failed with the following message:
- = project.delete_error
+.project-deletion-failed-message.gl-alert.gl-alert-warning
+ = sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ This project was scheduled for deletion, but failed with the following message:
+ = project.delete_error
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
index 38a1f86930e..9bb4342ffb4 100644
--- a/app/views/projects/blob/edit.html.haml
+++ b/app/views/projects/blob/edit.html.haml
@@ -2,10 +2,12 @@
- page_title _("Edit"), @blob.path, @ref
- if @conflict
- .alert.alert-danger
- Someone edited the file the same time you did. Please check out
- = link_to "the file", project_blob_path(@project, tree_join(@branch_name, @file_path)), target: "_blank", rel: 'noopener noreferrer'
- and make sure your changes will not unintentionally remove theirs.
+ .gl-alert.gl-alert-danger.gl-mb-5.gl-mt-5
+ = sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ Someone edited the file the same time you did. Please check out
+ = link_to "the file", project_blob_path(@project, tree_join(@branch_name, @file_path)), target: "_blank", rel: 'noopener noreferrer', class: 'gl-link'
+ and make sure your changes will not unintentionally remove theirs.
- if editing_ci_config? && show_web_ide_alert?
#js-suggest-web-ide-ci{ data: { dismiss_endpoint: user_callouts_path, feature_id: UserCalloutsHelper::WEB_IDE_ALERT_DISMISSED, edit_path: ide_edit_path } }
diff --git a/app/views/shared/milestones/_description.html.haml b/app/views/shared/milestones/_description.html.haml
index 679931c5fd9..747e22f47ac 100644
--- a/app/views/shared/milestones/_description.html.haml
+++ b/app/views/shared/milestones/_description.html.haml
@@ -1,8 +1,8 @@
.detail-page-description.milestone-detail
- %h2.title{ data: { qa_selector: "milestone_title_content" } }
+ %h2.gl-m-0{ data: { qa_selector: "milestone_title_content" } }
= markdown_field(milestone, :title)
- if milestone.try(:description).present?
%div{ data: { qa_selector: "milestone_description_content" } }
- .description.md
+ .description.md.gl-px-0.gl-pt-4.gl-border-1.gl-border-t-solid.gl-border-gray-100
= markdown_field(milestone, :description)
diff --git a/app/workers/issue_placement_worker.rb b/app/workers/issue_placement_worker.rb
index 4d2074aac3a..06791dfb1e7 100644
--- a/app/workers/issue_placement_worker.rb
+++ b/app/workers/issue_placement_worker.rb
@@ -13,7 +13,7 @@ class IssuePlacementWorker
QUERY_LIMIT = 100
# rubocop: disable CodeReuse/ActiveRecord
- def perform(issue_id)
+ def perform(issue_id, project_id = nil)
issue = Issue.id_in(issue_id).first
return unless issue
diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb
index af8f3927be0..fc7999e7837 100644
--- a/app/workers/repository_fork_worker.rb
+++ b/app/workers/repository_fork_worker.rb
@@ -52,7 +52,7 @@ class RepositoryForkWorker # rubocop:disable Scalability/IdempotentWorker
def link_lfs_objects(source_project, target_project)
Projects::LfsPointers::LfsLinkService
.new(target_project)
- .execute(source_project.all_lfs_objects_oids)
+ .execute(source_project.lfs_objects_oids)
rescue Projects::LfsPointers::LfsLinkService::TooManyOidsError
raise_fork_failure(
source_project,
diff --git a/changelogs/unreleased/13402-close-alert-when-end-time-given.yml b/changelogs/unreleased/13402-close-alert-when-end-time-given.yml
new file mode 100644
index 00000000000..805f447ea5c
--- /dev/null
+++ b/changelogs/unreleased/13402-close-alert-when-end-time-given.yml
@@ -0,0 +1,5 @@
+---
+title: Automatically resolve alert when receiving end time
+merge_request: 41648
+author:
+type: added
diff --git a/changelogs/unreleased/233649-replace-bootstrap-alerts-in-app-views-admin-groups-_form-html-haml.yml b/changelogs/unreleased/233649-replace-bootstrap-alerts-in-app-views-admin-groups-_form-html-haml.yml
new file mode 100644
index 00000000000..bd41506a1b9
--- /dev/null
+++ b/changelogs/unreleased/233649-replace-bootstrap-alerts-in-app-views-admin-groups-_form-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/admin/groups/_form.html.haml
+merge_request: 41375
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233672-replace-bootstrap-alerts-in-app-views-projects-_deletion_failed-ht.yml b/changelogs/unreleased/233672-replace-bootstrap-alerts-in-app-views-projects-_deletion_failed-ht.yml
new file mode 100644
index 00000000000..515bc1a8040
--- /dev/null
+++ b/changelogs/unreleased/233672-replace-bootstrap-alerts-in-app-views-projects-_deletion_failed-ht.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/projects/_deletion_failed.html.haml
+merge_request: 41344
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233690-replace-bootstrap-alerts-app-views-projects-blob-edit-html-haml.yml b/changelogs/unreleased/233690-replace-bootstrap-alerts-app-views-projects-blob-edit-html-haml.yml
new file mode 100644
index 00000000000..fc1ad6fb922
--- /dev/null
+++ b/changelogs/unreleased/233690-replace-bootstrap-alerts-app-views-projects-blob-edit-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/projects/blob/edit.html.haml
+merge_request: 41298
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/247897-properly-style-the-container-registry-metadata.yml b/changelogs/unreleased/247897-properly-style-the-container-registry-metadata.yml
new file mode 100644
index 00000000000..6e850027133
--- /dev/null
+++ b/changelogs/unreleased/247897-properly-style-the-container-registry-metadata.yml
@@ -0,0 +1,5 @@
+---
+title: Update visual styling of container registry metadata
+merge_request: 42202
+author:
+type: changed
diff --git a/changelogs/unreleased/249040-fix-subscription-without-namespace.yml b/changelogs/unreleased/249040-fix-subscription-without-namespace.yml
new file mode 100644
index 00000000000..bf8e8cce7fe
--- /dev/null
+++ b/changelogs/unreleased/249040-fix-subscription-without-namespace.yml
@@ -0,0 +1,5 @@
+---
+title: Fix max seats used not updated in billing summary
+merge_request: 42184
+author:
+type: fixed
diff --git a/changelogs/unreleased/id-link-existing-lfs.yml b/changelogs/unreleased/id-link-existing-lfs.yml
new file mode 100644
index 00000000000..85171658a51
--- /dev/null
+++ b/changelogs/unreleased/id-link-existing-lfs.yml
@@ -0,0 +1,5 @@
+---
+title: Verify only 1mb of existing LFS object to improve LfsDownloadService performance
+merge_request: 41770
+author:
+type: performance
diff --git a/changelogs/unreleased/jdb-refactor-parallel-diff-table-row.yml b/changelogs/unreleased/jdb-refactor-parallel-diff-table-row.yml
new file mode 100644
index 00000000000..0ba328a028b
--- /dev/null
+++ b/changelogs/unreleased/jdb-refactor-parallel-diff-table-row.yml
@@ -0,0 +1,5 @@
+---
+title: Jdb/refactor parallel diff table row
+merge_request: 41606
+author:
+type: performance
diff --git a/changelogs/unreleased/jl-milestone-title-spacing.yml b/changelogs/unreleased/jl-milestone-title-spacing.yml
new file mode 100644
index 00000000000..57923ea5c8b
--- /dev/null
+++ b/changelogs/unreleased/jl-milestone-title-spacing.yml
@@ -0,0 +1,5 @@
+---
+title: Fix spacing and borders in milestone title and description
+merge_request: 40649
+author:
+type: fixed
diff --git a/changelogs/unreleased/tr-incident-alert-details.yml b/changelogs/unreleased/tr-incident-alert-details.yml
new file mode 100644
index 00000000000..6bec63e0336
--- /dev/null
+++ b/changelogs/unreleased/tr-incident-alert-details.yml
@@ -0,0 +1,5 @@
+---
+title: Surface alert details in a tab on incidents
+merge_request: 41850
+author:
+type: added
diff --git a/changelogs/unreleased/update-vendored-dockerfile-templates.yml b/changelogs/unreleased/update-vendored-dockerfile-templates.yml
new file mode 100644
index 00000000000..048689ccca2
--- /dev/null
+++ b/changelogs/unreleased/update-vendored-dockerfile-templates.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade vendored Dockerfile template to buster
+merge_request: 42169
+author: Takuya Noguchi
+type: other
diff --git a/config/feature_flags/development/additional_snowplow_tracking.yml b/config/feature_flags/development/additional_snowplow_tracking.yml
new file mode 100644
index 00000000000..f4f73a0bbd0
--- /dev/null
+++ b/config/feature_flags/development/additional_snowplow_tracking.yml
@@ -0,0 +1,7 @@
+---
+name: additional_snowplow_tracking
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ajax_new_deploy_token.yml b/config/feature_flags/development/ajax_new_deploy_token.yml
new file mode 100644
index 00000000000..cffd589b32b
--- /dev/null
+++ b/config/feature_flags/development/ajax_new_deploy_token.yml
@@ -0,0 +1,7 @@
+---
+name: ajax_new_deploy_token
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/allow_group_deploy_token.yml b/config/feature_flags/development/allow_group_deploy_token.yml
new file mode 100644
index 00000000000..f08614b45e9
--- /dev/null
+++ b/config/feature_flags/development/allow_group_deploy_token.yml
@@ -0,0 +1,7 @@
+---
+name: allow_group_deploy_token
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/allow_possible_spam.yml b/config/feature_flags/development/allow_possible_spam.yml
new file mode 100644
index 00000000000..658e775af91
--- /dev/null
+++ b/config/feature_flags/development/allow_possible_spam.yml
@@ -0,0 +1,7 @@
+---
+name: allow_possible_spam
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/allow_unsafe_ruby_regexp.yml b/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
new file mode 100644
index 00000000000..4d3b13deda2
--- /dev/null
+++ b/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
@@ -0,0 +1,7 @@
+---
+name: allow_unsafe_ruby_regexp
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/api_kaminari_count_with_limit.yml b/config/feature_flags/development/api_kaminari_count_with_limit.yml
new file mode 100644
index 00000000000..0224d606df1
--- /dev/null
+++ b/config/feature_flags/development/api_kaminari_count_with_limit.yml
@@ -0,0 +1,7 @@
+---
+name: api_kaminari_count_with_limit
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/application_settings_tokens_optional_encryption.yml b/config/feature_flags/development/application_settings_tokens_optional_encryption.yml
new file mode 100644
index 00000000000..b9a5b6420d1
--- /dev/null
+++ b/config/feature_flags/development/application_settings_tokens_optional_encryption.yml
@@ -0,0 +1,7 @@
+---
+name: application_settings_tokens_optional_encryption
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/approval_suggestions.yml b/config/feature_flags/development/approval_suggestions.yml
new file mode 100644
index 00000000000..ff66e9fa80c
--- /dev/null
+++ b/config/feature_flags/development/approval_suggestions.yml
@@ -0,0 +1,7 @@
+---
+name: approval_suggestions
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/approvals_commented_by.yml b/config/feature_flags/development/approvals_commented_by.yml
new file mode 100644
index 00000000000..cc34b1d165e
--- /dev/null
+++ b/config/feature_flags/development/approvals_commented_by.yml
@@ -0,0 +1,7 @@
+---
+name: approvals_commented_by
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/archive_rate_limit.yml b/config/feature_flags/development/archive_rate_limit.yml
new file mode 100644
index 00000000000..56e9fcd3f8d
--- /dev/null
+++ b/config/feature_flags/development/archive_rate_limit.yml
@@ -0,0 +1,7 @@
+---
+name: archive_rate_limit
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/artifacts_management_page.yml b/config/feature_flags/development/artifacts_management_page.yml
new file mode 100644
index 00000000000..94d99974859
--- /dev/null
+++ b/config/feature_flags/development/artifacts_management_page.yml
@@ -0,0 +1,7 @@
+---
+name: artifacts_management_page
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/async_commit_diff_files.yml b/config/feature_flags/development/async_commit_diff_files.yml
new file mode 100644
index 00000000000..90aed05e12a
--- /dev/null
+++ b/config/feature_flags/development/async_commit_diff_files.yml
@@ -0,0 +1,7 @@
+---
+name: async_commit_diff_files
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/auto_create_cluster_management_project.yml b/config/feature_flags/development/auto_create_cluster_management_project.yml
new file mode 100644
index 00000000000..ca87e401d4a
--- /dev/null
+++ b/config/feature_flags/development/auto_create_cluster_management_project.yml
@@ -0,0 +1,7 @@
+---
+name: auto_create_cluster_management_project
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/auto_devops_banner_disabled.yml b/config/feature_flags/development/auto_devops_banner_disabled.yml
new file mode 100644
index 00000000000..b74d3c723ee
--- /dev/null
+++ b/config/feature_flags/development/auto_devops_banner_disabled.yml
@@ -0,0 +1,7 @@
+---
+name: auto_devops_banner_disabled
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/backfill_partitioned_audit_events.yml b/config/feature_flags/development/backfill_partitioned_audit_events.yml
new file mode 100644
index 00000000000..ae986c941cb
--- /dev/null
+++ b/config/feature_flags/development/backfill_partitioned_audit_events.yml
@@ -0,0 +1,7 @@
+---
+name: backfill_partitioned_audit_events
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/batch_suggestions.yml b/config/feature_flags/development/batch_suggestions.yml
new file mode 100644
index 00000000000..0ef3c7df01e
--- /dev/null
+++ b/config/feature_flags/development/batch_suggestions.yml
@@ -0,0 +1,7 @@
+---
+name: batch_suggestions
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/boards_with_swimlanes.yml b/config/feature_flags/development/boards_with_swimlanes.yml
new file mode 100644
index 00000000000..e2db136b45c
--- /dev/null
+++ b/config/feature_flags/development/boards_with_swimlanes.yml
@@ -0,0 +1,7 @@
+---
+name: boards_with_swimlanes
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/branch_list_keyset_pagination.yml b/config/feature_flags/development/branch_list_keyset_pagination.yml
new file mode 100644
index 00000000000..11975c67561
--- /dev/null
+++ b/config/feature_flags/development/branch_list_keyset_pagination.yml
@@ -0,0 +1,7 @@
+---
+name: branch_list_keyset_pagination
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/branch_push_merge_commit_analyze.yml b/config/feature_flags/development/branch_push_merge_commit_analyze.yml
new file mode 100644
index 00000000000..f5a695a9ce9
--- /dev/null
+++ b/config/feature_flags/development/branch_push_merge_commit_analyze.yml
@@ -0,0 +1,7 @@
+---
+name: branch_push_merge_commit_analyze
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/broadcast_issue_updates.yml b/config/feature_flags/development/broadcast_issue_updates.yml
new file mode 100644
index 00000000000..2db27dfb2ed
--- /dev/null
+++ b/config/feature_flags/development/broadcast_issue_updates.yml
@@ -0,0 +1,7 @@
+---
+name: broadcast_issue_updates
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/build_service_proxy.yml b/config/feature_flags/development/build_service_proxy.yml
new file mode 100644
index 00000000000..165e3c15f81
--- /dev/null
+++ b/config/feature_flags/development/build_service_proxy.yml
@@ -0,0 +1,7 @@
+---
+name: build_service_proxy
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/builds.yml b/config/feature_flags/development/builds.yml
new file mode 100644
index 00000000000..6c17f2eb962
--- /dev/null
+++ b/config/feature_flags/development/builds.yml
@@ -0,0 +1,7 @@
+---
+name: builds
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/bulk_update_health_status.yml b/config/feature_flags/development/bulk_update_health_status.yml
new file mode 100644
index 00000000000..5553f2e077f
--- /dev/null
+++ b/config/feature_flags/development/bulk_update_health_status.yml
@@ -0,0 +1,7 @@
+---
+name: bulk_update_health_status
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/burnup_charts.yml b/config/feature_flags/development/burnup_charts.yml
new file mode 100644
index 00000000000..9484af49530
--- /dev/null
+++ b/config/feature_flags/development/burnup_charts.yml
@@ -0,0 +1,7 @@
+---
+name: burnup_charts
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/chatops.yml b/config/feature_flags/development/chatops.yml
new file mode 100644
index 00000000000..c548af50aa5
--- /dev/null
+++ b/config/feature_flags/development/chatops.yml
@@ -0,0 +1,7 @@
+---
+name: chatops
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_artifacts_exclude.yml b/config/feature_flags/development/ci_artifacts_exclude.yml
new file mode 100644
index 00000000000..6e9d27efe42
--- /dev/null
+++ b/config/feature_flags/development/ci_artifacts_exclude.yml
@@ -0,0 +1,7 @@
+---
+name: ci_artifacts_exclude
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_build_metadata_config.yml b/config/feature_flags/development/ci_build_metadata_config.yml
new file mode 100644
index 00000000000..add7c963272
--- /dev/null
+++ b/config/feature_flags/development/ci_build_metadata_config.yml
@@ -0,0 +1,7 @@
+---
+name: ci_build_metadata_config
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ci_bulk_insert_on_create.yml b/config/feature_flags/development/ci_bulk_insert_on_create.yml
new file mode 100644
index 00000000000..3227497ecfc
--- /dev/null
+++ b/config/feature_flags/development/ci_bulk_insert_on_create.yml
@@ -0,0 +1,7 @@
+---
+name: ci_bulk_insert_on_create
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_daily_code_coverage.yml b/config/feature_flags/development/ci_daily_code_coverage.yml
new file mode 100644
index 00000000000..c9add1bf460
--- /dev/null
+++ b/config/feature_flags/development/ci_daily_code_coverage.yml
@@ -0,0 +1,7 @@
+---
+name: ci_daily_code_coverage
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_disable_validates_dependencies.yml b/config/feature_flags/development/ci_disable_validates_dependencies.yml
new file mode 100644
index 00000000000..65358a04340
--- /dev/null
+++ b/config/feature_flags/development/ci_disable_validates_dependencies.yml
@@ -0,0 +1,7 @@
+---
+name: ci_disable_validates_dependencies
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ci_download_daily_code_coverage.yml b/config/feature_flags/development/ci_download_daily_code_coverage.yml
new file mode 100644
index 00000000000..d209f2bf9ad
--- /dev/null
+++ b/config/feature_flags/development/ci_download_daily_code_coverage.yml
@@ -0,0 +1,7 @@
+---
+name: ci_download_daily_code_coverage
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_dynamic_child_pipeline.yml b/config/feature_flags/development/ci_dynamic_child_pipeline.yml
new file mode 100644
index 00000000000..ac2afe77743
--- /dev/null
+++ b/config/feature_flags/development/ci_dynamic_child_pipeline.yml
@@ -0,0 +1,7 @@
+---
+name: ci_dynamic_child_pipeline
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_enable_live_trace.yml b/config/feature_flags/development/ci_enable_live_trace.yml
new file mode 100644
index 00000000000..e9fd998f6df
--- /dev/null
+++ b/config/feature_flags/development/ci_enable_live_trace.yml
@@ -0,0 +1,7 @@
+---
+name: ci_enable_live_trace
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ci_instance_variables_ui.yml b/config/feature_flags/development/ci_instance_variables_ui.yml
new file mode 100644
index 00000000000..0671d1a1a7c
--- /dev/null
+++ b/config/feature_flags/development/ci_instance_variables_ui.yml
@@ -0,0 +1,7 @@
+---
+name: ci_instance_variables_ui
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_job_heartbeats_runner.yml b/config/feature_flags/development/ci_job_heartbeats_runner.yml
new file mode 100644
index 00000000000..dcccd1512ed
--- /dev/null
+++ b/config/feature_flags/development/ci_job_heartbeats_runner.yml
@@ -0,0 +1,7 @@
+---
+name: ci_job_heartbeats_runner
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_job_jwt.yml b/config/feature_flags/development/ci_job_jwt.yml
new file mode 100644
index 00000000000..3d18472add4
--- /dev/null
+++ b/config/feature_flags/development/ci_job_jwt.yml
@@ -0,0 +1,7 @@
+---
+name: ci_job_jwt
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_key_autocomplete.yml b/config/feature_flags/development/ci_key_autocomplete.yml
new file mode 100644
index 00000000000..1c6bfa90a9d
--- /dev/null
+++ b/config/feature_flags/development/ci_key_autocomplete.yml
@@ -0,0 +1,7 @@
+---
+name: ci_key_autocomplete
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml b/config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml
new file mode 100644
index 00000000000..8abb52486b6
--- /dev/null
+++ b/config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml
@@ -0,0 +1,7 @@
+---
+name: ci_lint_creates_pipeline_with_dry_run
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_pipeline_latest.yml b/config/feature_flags/development/ci_pipeline_latest.yml
new file mode 100644
index 00000000000..661d0714e53
--- /dev/null
+++ b/config/feature_flags/development/ci_pipeline_latest.yml
@@ -0,0 +1,7 @@
+---
+name: ci_pipeline_latest
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_pipeline_rewind_iid.yml b/config/feature_flags/development/ci_pipeline_rewind_iid.yml
new file mode 100644
index 00000000000..8b6bb378a0a
--- /dev/null
+++ b/config/feature_flags/development/ci_pipeline_rewind_iid.yml
@@ -0,0 +1,7 @@
+---
+name: ci_pipeline_rewind_iid
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml b/config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml
new file mode 100644
index 00000000000..eda5ab00ef1
--- /dev/null
+++ b/config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml
@@ -0,0 +1,7 @@
+---
+name: ci_pipeline_status_omit_commit_sha_in_cache_key
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml b/config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml
new file mode 100644
index 00000000000..d2e25e7bf11
--- /dev/null
+++ b/config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml
@@ -0,0 +1,7 @@
+---
+name: ci_raise_job_rules_without_workflow_rules_warning
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_runners_tokens_optional_encryption.yml b/config/feature_flags/development/ci_runners_tokens_optional_encryption.yml
new file mode 100644
index 00000000000..76689452b2a
--- /dev/null
+++ b/config/feature_flags/development/ci_runners_tokens_optional_encryption.yml
@@ -0,0 +1,7 @@
+---
+name: ci_runners_tokens_optional_encryption
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml b/config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml
new file mode 100644
index 00000000000..a9a79f80512
--- /dev/null
+++ b/config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml
@@ -0,0 +1,7 @@
+---
+name: ci_skip_persistent_ref_existence_check
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ci_store_pipeline_messages.yml b/config/feature_flags/development/ci_store_pipeline_messages.yml
new file mode 100644
index 00000000000..c7235ab2196
--- /dev/null
+++ b/config/feature_flags/development/ci_store_pipeline_messages.yml
@@ -0,0 +1,7 @@
+---
+name: ci_store_pipeline_messages
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_synchronous_artifact_parsing.yml b/config/feature_flags/development/ci_synchronous_artifact_parsing.yml
new file mode 100644
index 00000000000..c5d1a44b61f
--- /dev/null
+++ b/config/feature_flags/development/ci_synchronous_artifact_parsing.yml
@@ -0,0 +1,7 @@
+---
+name: ci_synchronous_artifact_parsing
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_update_queues_for_online_runners.yml b/config/feature_flags/development/ci_update_queues_for_online_runners.yml
new file mode 100644
index 00000000000..f2bce6e14b5
--- /dev/null
+++ b/config/feature_flags/development/ci_update_queues_for_online_runners.yml
@@ -0,0 +1,7 @@
+---
+name: ci_update_queues_for_online_runners
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ci_yaml_limit_size.yml b/config/feature_flags/development/ci_yaml_limit_size.yml
new file mode 100644
index 00000000000..06229c08af5
--- /dev/null
+++ b/config/feature_flags/development/ci_yaml_limit_size.yml
@@ -0,0 +1,7 @@
+---
+name: ci_yaml_limit_size
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/cleanup_lfs_during_gc.yml b/config/feature_flags/development/cleanup_lfs_during_gc.yml
new file mode 100644
index 00000000000..836784b1d9c
--- /dev/null
+++ b/config/feature_flags/development/cleanup_lfs_during_gc.yml
@@ -0,0 +1,7 @@
+---
+name: cleanup_lfs_during_gc
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/cluster_management_project.yml b/config/feature_flags/development/cluster_management_project.yml
new file mode 100644
index 00000000000..9d58efd5194
--- /dev/null
+++ b/config/feature_flags/development/cluster_management_project.yml
@@ -0,0 +1,7 @@
+---
+name: cluster_management_project
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/clusters_list_redesign.yml b/config/feature_flags/development/clusters_list_redesign.yml
new file mode 100644
index 00000000000..1a9ad73eb79
--- /dev/null
+++ b/config/feature_flags/development/clusters_list_redesign.yml
@@ -0,0 +1,7 @@
+---
+name: clusters_list_redesign
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/container_registry_api.yml b/config/feature_flags/development/container_registry_api.yml
new file mode 100644
index 00000000000..b0e128f1c3d
--- /dev/null
+++ b/config/feature_flags/development/container_registry_api.yml
@@ -0,0 +1,7 @@
+---
+name: container_registry_api
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/container_registry_cleanup.yml b/config/feature_flags/development/container_registry_cleanup.yml
new file mode 100644
index 00000000000..a03f530b339
--- /dev/null
+++ b/config/feature_flags/development/container_registry_cleanup.yml
@@ -0,0 +1,7 @@
+---
+name: container_registry_cleanup
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/container_registry_fast_tag_delete.yml b/config/feature_flags/development/container_registry_fast_tag_delete.yml
new file mode 100644
index 00000000000..dddac070355
--- /dev/null
+++ b/config/feature_flags/development/container_registry_fast_tag_delete.yml
@@ -0,0 +1,7 @@
+---
+name: container_registry_fast_tag_delete
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/context_commits.yml b/config/feature_flags/development/context_commits.yml
new file mode 100644
index 00000000000..f615846f6c0
--- /dev/null
+++ b/config/feature_flags/development/context_commits.yml
@@ -0,0 +1,7 @@
+---
+name: context_commits
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/create_cloud_run_clusters.yml b/config/feature_flags/development/create_cloud_run_clusters.yml
new file mode 100644
index 00000000000..30894fd2df1
--- /dev/null
+++ b/config/feature_flags/development/create_cloud_run_clusters.yml
@@ -0,0 +1,7 @@
+---
+name: create_cloud_run_clusters
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/dashboard_pipeline_status.yml b/config/feature_flags/development/dashboard_pipeline_status.yml
new file mode 100644
index 00000000000..241f5fea64f
--- /dev/null
+++ b/config/feature_flags/development/dashboard_pipeline_status.yml
@@ -0,0 +1,7 @@
+---
+name: dashboard_pipeline_status
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/deploy_from_footer.yml b/config/feature_flags/development/deploy_from_footer.yml
new file mode 100644
index 00000000000..8e31ab511b6
--- /dev/null
+++ b/config/feature_flags/development/deploy_from_footer.yml
@@ -0,0 +1,7 @@
+---
+name: deploy_from_footer
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/deploy_tokens_api.yml b/config/feature_flags/development/deploy_tokens_api.yml
new file mode 100644
index 00000000000..d8691842822
--- /dev/null
+++ b/config/feature_flags/development/deploy_tokens_api.yml
@@ -0,0 +1,7 @@
+---
+name: deploy_tokens_api
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/design_management_allow_dangerous_images.yml b/config/feature_flags/development/design_management_allow_dangerous_images.yml
new file mode 100644
index 00000000000..d1d09f154a4
--- /dev/null
+++ b/config/feature_flags/development/design_management_allow_dangerous_images.yml
@@ -0,0 +1,7 @@
+---
+name: design_management_allow_dangerous_images
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml b/config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml
new file mode 100644
index 00000000000..e07b621ed23
--- /dev/null
+++ b/config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml
@@ -0,0 +1,7 @@
+---
+name: design_management_reference_filter_gfm_pipeline
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml b/config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml
new file mode 100644
index 00000000000..193579cd11b
--- /dev/null
+++ b/config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml
@@ -0,0 +1,7 @@
+---
+name: disable_metric_dashboard_refresh_rate
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/drop_license_management_artifact.yml b/config/feature_flags/development/drop_license_management_artifact.yml
new file mode 100644
index 00000000000..59d749154b5
--- /dev/null
+++ b/config/feature_flags/development/drop_license_management_artifact.yml
@@ -0,0 +1,7 @@
+---
+name: drop_license_management_artifact
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/efficient_counter_attribute.yml b/config/feature_flags/development/efficient_counter_attribute.yml
new file mode 100644
index 00000000000..a1b16be7ce8
--- /dev/null
+++ b/config/feature_flags/development/efficient_counter_attribute.yml
@@ -0,0 +1,7 @@
+---
+name: efficient_counter_attribute
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/export_lfs_objects_projects.yml b/config/feature_flags/development/export_lfs_objects_projects.yml
new file mode 100644
index 00000000000..6ef3317de8d
--- /dev/null
+++ b/config/feature_flags/development/export_lfs_objects_projects.yml
@@ -0,0 +1,7 @@
+---
+name: export_lfs_objects_projects
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/export_reduce_relation_batch_size.yml b/config/feature_flags/development/export_reduce_relation_batch_size.yml
new file mode 100644
index 00000000000..b32e2232933
--- /dev/null
+++ b/config/feature_flags/development/export_reduce_relation_batch_size.yml
@@ -0,0 +1,7 @@
+---
+name: export_reduce_relation_batch_size
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/file_identifier_hash.yml b/config/feature_flags/development/file_identifier_hash.yml
new file mode 100644
index 00000000000..681054cf7fa
--- /dev/null
+++ b/config/feature_flags/development/file_identifier_hash.yml
@@ -0,0 +1,7 @@
+---
+name: file_identifier_hash
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/filter_pipelines_search.yml b/config/feature_flags/development/filter_pipelines_search.yml
new file mode 100644
index 00000000000..57bf61552d8
--- /dev/null
+++ b/config/feature_flags/development/filter_pipelines_search.yml
@@ -0,0 +1,7 @@
+---
+name: filter_pipelines_search
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/force_autodevops_on_by_default.yml b/config/feature_flags/development/force_autodevops_on_by_default.yml
new file mode 100644
index 00000000000..352a6d40bd1
--- /dev/null
+++ b/config/feature_flags/development/force_autodevops_on_by_default.yml
@@ -0,0 +1,7 @@
+---
+name: force_autodevops_on_by_default
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/forking.yml b/config/feature_flags/development/forking.yml
new file mode 100644
index 00000000000..d7d0cb79562
--- /dev/null
+++ b/config/feature_flags/development/forking.yml
@@ -0,0 +1,7 @@
+---
+name: forking
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/forward_deployment_enabled.yml b/config/feature_flags/development/forward_deployment_enabled.yml
new file mode 100644
index 00000000000..51cc99e39ae
--- /dev/null
+++ b/config/feature_flags/development/forward_deployment_enabled.yml
@@ -0,0 +1,7 @@
+---
+name: forward_deployment_enabled
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/g_compliance_dashboard_feature.yml b/config/feature_flags/development/g_compliance_dashboard_feature.yml
new file mode 100644
index 00000000000..3390bc18810
--- /dev/null
+++ b/config/feature_flags/development/g_compliance_dashboard_feature.yml
@@ -0,0 +1,7 @@
+---
+name: g_compliance_dashboard_feature
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/git_push_create_all_pipelines.yml b/config/feature_flags/development/git_push_create_all_pipelines.yml
new file mode 100644
index 00000000000..62dbe9bb02f
--- /dev/null
+++ b/config/feature_flags/development/git_push_create_all_pipelines.yml
@@ -0,0 +1,7 @@
+---
+name: git_push_create_all_pipelines
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/gitaly_catfile-cache.yml b/config/feature_flags/development/gitaly_catfile-cache.yml
new file mode 100644
index 00000000000..1fdfacfb4d2
--- /dev/null
+++ b/config/feature_flags/development/gitaly_catfile-cache.yml
@@ -0,0 +1,7 @@
+---
+name: gitaly_catfile-cache
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/gitaly_deny_disk_access.yml b/config/feature_flags/development/gitaly_deny_disk_access.yml
new file mode 100644
index 00000000000..faf9bc6d71f
--- /dev/null
+++ b/config/feature_flags/development/gitaly_deny_disk_access.yml
@@ -0,0 +1,7 @@
+---
+name: gitaly_deny_disk_access
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/gitaly_enforce_requests_limits.yml b/config/feature_flags/development/gitaly_enforce_requests_limits.yml
new file mode 100644
index 00000000000..2e4aa4ab794
--- /dev/null
+++ b/config/feature_flags/development/gitaly_enforce_requests_limits.yml
@@ -0,0 +1,7 @@
+---
+name: gitaly_enforce_requests_limits
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/gitaly_mep_mep.yml b/config/feature_flags/development/gitaly_mep_mep.yml
new file mode 100644
index 00000000000..b657449a436
--- /dev/null
+++ b/config/feature_flags/development/gitaly_mep_mep.yml
@@ -0,0 +1,7 @@
+---
+name: gitaly_mep_mep
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/global_default_branch_name.yml b/config/feature_flags/development/global_default_branch_name.yml
new file mode 100644
index 00000000000..57b324a6da2
--- /dev/null
+++ b/config/feature_flags/development/global_default_branch_name.yml
@@ -0,0 +1,7 @@
+---
+name: global_default_branch_name
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/go_proxy.yml b/config/feature_flags/development/go_proxy.yml
new file mode 100644
index 00000000000..bde614dd84d
--- /dev/null
+++ b/config/feature_flags/development/go_proxy.yml
@@ -0,0 +1,7 @@
+---
+name: go_proxy
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/go_proxy_disable_gomod_validation.yml b/config/feature_flags/development/go_proxy_disable_gomod_validation.yml
new file mode 100644
index 00000000000..5e9671c66d5
--- /dev/null
+++ b/config/feature_flags/development/go_proxy_disable_gomod_validation.yml
@@ -0,0 +1,7 @@
+---
+name: go_proxy_disable_gomod_validation
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/grape_gitlab_json.yml b/config/feature_flags/development/grape_gitlab_json.yml
new file mode 100644
index 00000000000..ab98ed981c9
--- /dev/null
+++ b/config/feature_flags/development/grape_gitlab_json.yml
@@ -0,0 +1,7 @@
+---
+name: grape_gitlab_json
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/graphql_board_lists.yml b/config/feature_flags/development/graphql_board_lists.yml
new file mode 100644
index 00000000000..4e6bf000a8f
--- /dev/null
+++ b/config/feature_flags/development/graphql_board_lists.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_board_lists
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/graphql_logging.yml b/config/feature_flags/development/graphql_logging.yml
new file mode 100644
index 00000000000..cd2a5b109e8
--- /dev/null
+++ b/config/feature_flags/development/graphql_logging.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_logging
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/graphql_lookahead_support.yml b/config/feature_flags/development/graphql_lookahead_support.yml
new file mode 100644
index 00000000000..2c8825f309e
--- /dev/null
+++ b/config/feature_flags/development/graphql_lookahead_support.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_lookahead_support
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/graphql_milestone_stats.yml b/config/feature_flags/development/graphql_milestone_stats.yml
new file mode 100644
index 00000000000..daa72031879
--- /dev/null
+++ b/config/feature_flags/development/graphql_milestone_stats.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_milestone_stats
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/graphql_release_data.yml b/config/feature_flags/development/graphql_release_data.yml
new file mode 100644
index 00000000000..c30fbf7fe13
--- /dev/null
+++ b/config/feature_flags/development/graphql_release_data.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_release_data
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/group_export_ndjson.yml b/config/feature_flags/development/group_export_ndjson.yml
new file mode 100644
index 00000000000..af495df2e48
--- /dev/null
+++ b/config/feature_flags/development/group_export_ndjson.yml
@@ -0,0 +1,7 @@
+---
+name: group_export_ndjson
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/group_import_export.yml b/config/feature_flags/development/group_import_export.yml
new file mode 100644
index 00000000000..8a49fb29e45
--- /dev/null
+++ b/config/feature_flags/development/group_import_export.yml
@@ -0,0 +1,7 @@
+---
+name: group_import_export
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/group_import_ndjson.yml b/config/feature_flags/development/group_import_ndjson.yml
new file mode 100644
index 00000000000..cf438abe8cb
--- /dev/null
+++ b/config/feature_flags/development/group_import_ndjson.yml
@@ -0,0 +1,7 @@
+---
+name: group_import_ndjson
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/group_level_integrations.yml b/config/feature_flags/development/group_level_integrations.yml
new file mode 100644
index 00000000000..961b7cfcf11
--- /dev/null
+++ b/config/feature_flags/development/group_level_integrations.yml
@@ -0,0 +1,7 @@
+---
+name: group_level_integrations
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/groups_tokens_optional_encryption.yml b/config/feature_flags/development/groups_tokens_optional_encryption.yml
new file mode 100644
index 00000000000..2c081e72e52
--- /dev/null
+++ b/config/feature_flags/development/groups_tokens_optional_encryption.yml
@@ -0,0 +1,7 @@
+---
+name: groups_tokens_optional_encryption
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/hide_jump_to_next_unresolved_in_threads.yml b/config/feature_flags/development/hide_jump_to_next_unresolved_in_threads.yml
new file mode 100644
index 00000000000..075f3e135ed
--- /dev/null
+++ b/config/feature_flags/development/hide_jump_to_next_unresolved_in_threads.yml
@@ -0,0 +1,7 @@
+---
+name: hide_jump_to_next_unresolved_in_threads
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/highlight_current_diff_row.yml b/config/feature_flags/development/highlight_current_diff_row.yml
new file mode 100644
index 00000000000..1133680c173
--- /dev/null
+++ b/config/feature_flags/development/highlight_current_diff_row.yml
@@ -0,0 +1,7 @@
+---
+name: highlight_current_diff_row
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/inactive_policy_condition.yml b/config/feature_flags/development/inactive_policy_condition.yml
new file mode 100644
index 00000000000..bf577fb3123
--- /dev/null
+++ b/config/feature_flags/development/inactive_policy_condition.yml
@@ -0,0 +1,7 @@
+---
+name: inactive_policy_condition
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/ingress_modsecurity.yml b/config/feature_flags/development/ingress_modsecurity.yml
new file mode 100644
index 00000000000..cf289bb3d45
--- /dev/null
+++ b/config/feature_flags/development/ingress_modsecurity.yml
@@ -0,0 +1,7 @@
+---
+name: ingress_modsecurity
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/invisible_captcha.yml b/config/feature_flags/development/invisible_captcha.yml
new file mode 100644
index 00000000000..ee38a9c657a
--- /dev/null
+++ b/config/feature_flags/development/invisible_captcha.yml
@@ -0,0 +1,7 @@
+---
+name: invisible_captcha
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/invite_email_experiment.yml b/config/feature_flags/development/invite_email_experiment.yml
new file mode 100644
index 00000000000..3797090724e
--- /dev/null
+++ b/config/feature_flags/development/invite_email_experiment.yml
@@ -0,0 +1,7 @@
+---
+name: invite_email_experiment
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/issues.yml b/config/feature_flags/development/issues.yml
new file mode 100644
index 00000000000..6274767d4e1
--- /dev/null
+++ b/config/feature_flags/development/issues.yml
@@ -0,0 +1,7 @@
+---
+name: issues
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/json_limited_encoder.yml b/config/feature_flags/development/json_limited_encoder.yml
new file mode 100644
index 00000000000..3afed64b4cc
--- /dev/null
+++ b/config/feature_flags/development/json_limited_encoder.yml
@@ -0,0 +1,7 @@
+---
+name: json_limited_encoder
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/json_wrapper_legacy_mode.yml b/config/feature_flags/development/json_wrapper_legacy_mode.yml
new file mode 100644
index 00000000000..dc3da1867e9
--- /dev/null
+++ b/config/feature_flags/development/json_wrapper_legacy_mode.yml
@@ -0,0 +1,7 @@
+---
+name: json_wrapper_legacy_mode
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/junit_pipeline_screenshots_view.yml b/config/feature_flags/development/junit_pipeline_screenshots_view.yml
new file mode 100644
index 00000000000..d9f61b572be
--- /dev/null
+++ b/config/feature_flags/development/junit_pipeline_screenshots_view.yml
@@ -0,0 +1,7 @@
+---
+name: junit_pipeline_screenshots_view
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/lfs_check.yml b/config/feature_flags/development/lfs_check.yml
new file mode 100644
index 00000000000..39e7d9ba6e9
--- /dev/null
+++ b/config/feature_flags/development/lfs_check.yml
@@ -0,0 +1,7 @@
+---
+name: lfs_check
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/lfs_link_existing_object.yml b/config/feature_flags/development/lfs_link_existing_object.yml
new file mode 100644
index 00000000000..f38bb4525ec
--- /dev/null
+++ b/config/feature_flags/development/lfs_link_existing_object.yml
@@ -0,0 +1,7 @@
+---
+name: lfs_link_existing_object
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41770
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249246
+group: group::source code
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/limit_projects_in_groups_api.yml b/config/feature_flags/development/limit_projects_in_groups_api.yml
new file mode 100644
index 00000000000..571c02578d3
--- /dev/null
+++ b/config/feature_flags/development/limit_projects_in_groups_api.yml
@@ -0,0 +1,7 @@
+---
+name: limit_projects_in_groups_api
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/log_import_export_relation_creation.yml b/config/feature_flags/development/log_import_export_relation_creation.yml
new file mode 100644
index 00000000000..bfd4b27752b
--- /dev/null
+++ b/config/feature_flags/development/log_import_export_relation_creation.yml
@@ -0,0 +1,7 @@
+---
+name: log_import_export_relation_creation
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/maintenance_mode.yml b/config/feature_flags/development/maintenance_mode.yml
new file mode 100644
index 00000000000..8fba1216834
--- /dev/null
+++ b/config/feature_flags/development/maintenance_mode.yml
@@ -0,0 +1,7 @@
+---
+name: maintenance_mode
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/marginalia.yml b/config/feature_flags/development/marginalia.yml
new file mode 100644
index 00000000000..9fcfa061bff
--- /dev/null
+++ b/config/feature_flags/development/marginalia.yml
@@ -0,0 +1,7 @@
+---
+name: marginalia
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/merge_orchestration_service.yml b/config/feature_flags/development/merge_orchestration_service.yml
new file mode 100644
index 00000000000..134553e7344
--- /dev/null
+++ b/config/feature_flags/development/merge_orchestration_service.yml
@@ -0,0 +1,7 @@
+---
+name: merge_orchestration_service
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/merge_red_head_comments_position_on_demand.yml b/config/feature_flags/development/merge_red_head_comments_position_on_demand.yml
new file mode 100644
index 00000000000..5effc83b53e
--- /dev/null
+++ b/config/feature_flags/development/merge_red_head_comments_position_on_demand.yml
@@ -0,0 +1,7 @@
+---
+name: merge_red_head_comments_position_on_demand
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/merge_ref_auto_sync.yml b/config/feature_flags/development/merge_ref_auto_sync.yml
new file mode 100644
index 00000000000..cc5ea34eb0e
--- /dev/null
+++ b/config/feature_flags/development/merge_ref_auto_sync.yml
@@ -0,0 +1,7 @@
+---
+name: merge_ref_auto_sync
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/merge_ref_auto_sync_lock.yml b/config/feature_flags/development/merge_ref_auto_sync_lock.yml
new file mode 100644
index 00000000000..d9724712869
--- /dev/null
+++ b/config/feature_flags/development/merge_ref_auto_sync_lock.yml
@@ -0,0 +1,7 @@
+---
+name: merge_ref_auto_sync_lock
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/merge_request_draft_filter.yml b/config/feature_flags/development/merge_request_draft_filter.yml
new file mode 100644
index 00000000000..113194c2a18
--- /dev/null
+++ b/config/feature_flags/development/merge_request_draft_filter.yml
@@ -0,0 +1,7 @@
+---
+name: merge_request_draft_filter
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/merge_request_rebase_nowait_lock.yml b/config/feature_flags/development/merge_request_rebase_nowait_lock.yml
new file mode 100644
index 00000000000..06cbcd3da07
--- /dev/null
+++ b/config/feature_flags/development/merge_request_rebase_nowait_lock.yml
@@ -0,0 +1,7 @@
+---
+name: merge_request_rebase_nowait_lock
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/merge_request_short_pipeline_serializer.yml b/config/feature_flags/development/merge_request_short_pipeline_serializer.yml
new file mode 100644
index 00000000000..c24dd106547
--- /dev/null
+++ b/config/feature_flags/development/merge_request_short_pipeline_serializer.yml
@@ -0,0 +1,7 @@
+---
+name: merge_request_short_pipeline_serializer
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/merge_request_widget_graphql.yml b/config/feature_flags/development/merge_request_widget_graphql.yml
new file mode 100644
index 00000000000..028553a47f8
--- /dev/null
+++ b/config/feature_flags/development/merge_request_widget_graphql.yml
@@ -0,0 +1,7 @@
+---
+name: merge_request_widget_graphql
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/merge_requests.yml b/config/feature_flags/development/merge_requests.yml
new file mode 100644
index 00000000000..05e8a301786
--- /dev/null
+++ b/config/feature_flags/development/merge_requests.yml
@@ -0,0 +1,7 @@
+---
+name: merge_requests
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/metrics_dashboard.yml b/config/feature_flags/development/metrics_dashboard.yml
new file mode 100644
index 00000000000..a252068aa9a
--- /dev/null
+++ b/config/feature_flags/development/metrics_dashboard.yml
@@ -0,0 +1,7 @@
+---
+name: metrics_dashboard
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/migrate_bio_to_user_details.yml b/config/feature_flags/development/migrate_bio_to_user_details.yml
new file mode 100644
index 00000000000..f54e45f9bd3
--- /dev/null
+++ b/config/feature_flags/development/migrate_bio_to_user_details.yml
@@ -0,0 +1,7 @@
+---
+name: migrate_bio_to_user_details
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/migrate_user_mentions.yml b/config/feature_flags/development/migrate_user_mentions.yml
new file mode 100644
index 00000000000..3388fb020ad
--- /dev/null
+++ b/config/feature_flags/development/migrate_user_mentions.yml
@@ -0,0 +1,7 @@
+---
+name: migrate_user_mentions
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/modifed_path_ci_variables.yml b/config/feature_flags/development/modifed_path_ci_variables.yml
new file mode 100644
index 00000000000..a72a5ae56e1
--- /dev/null
+++ b/config/feature_flags/development/modifed_path_ci_variables.yml
@@ -0,0 +1,7 @@
+---
+name: modifed_path_ci_variables
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/monaco_blobs.yml b/config/feature_flags/development/monaco_blobs.yml
new file mode 100644
index 00000000000..bb1215493d5
--- /dev/null
+++ b/config/feature_flags/development/monaco_blobs.yml
@@ -0,0 +1,7 @@
+---
+name: monaco_blobs
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/monaco_ci.yml b/config/feature_flags/development/monaco_ci.yml
new file mode 100644
index 00000000000..5d6ace8d8ad
--- /dev/null
+++ b/config/feature_flags/development/monaco_ci.yml
@@ -0,0 +1,7 @@
+---
+name: monaco_ci
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/mr_commit_neighbor_nav.yml b/config/feature_flags/development/mr_commit_neighbor_nav.yml
new file mode 100644
index 00000000000..5fcacbdd3fe
--- /dev/null
+++ b/config/feature_flags/development/mr_commit_neighbor_nav.yml
@@ -0,0 +1,7 @@
+---
+name: mr_commit_neighbor_nav
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/multi_select_board.yml b/config/feature_flags/development/multi_select_board.yml
new file mode 100644
index 00000000000..35718606d62
--- /dev/null
+++ b/config/feature_flags/development/multi_select_board.yml
@@ -0,0 +1,7 @@
+---
+name: multi_select_board
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/multiline_comments.yml b/config/feature_flags/development/multiline_comments.yml
new file mode 100644
index 00000000000..cb80d381e18
--- /dev/null
+++ b/config/feature_flags/development/multiline_comments.yml
@@ -0,0 +1,7 @@
+---
+name: multiline_comments
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/new_pipeline_form.yml b/config/feature_flags/development/new_pipeline_form.yml
new file mode 100644
index 00000000000..96c7268ded0
--- /dev/null
+++ b/config/feature_flags/development/new_pipeline_form.yml
@@ -0,0 +1,7 @@
+---
+name: new_pipeline_form
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/new_release_page.yml b/config/feature_flags/development/new_release_page.yml
new file mode 100644
index 00000000000..a17438ba949
--- /dev/null
+++ b/config/feature_flags/development/new_release_page.yml
@@ -0,0 +1,7 @@
+---
+name: new_release_page
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/new_variables_ui.yml b/config/feature_flags/development/new_variables_ui.yml
new file mode 100644
index 00000000000..7621b356f5d
--- /dev/null
+++ b/config/feature_flags/development/new_variables_ui.yml
@@ -0,0 +1,7 @@
+---
+name: new_variables_ui
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/not_issuable_queries.yml b/config/feature_flags/development/not_issuable_queries.yml
new file mode 100644
index 00000000000..f6bbceff505
--- /dev/null
+++ b/config/feature_flags/development/not_issuable_queries.yml
@@ -0,0 +1,7 @@
+---
+name: not_issuable_queries
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/notes_create_service_tracking.yml b/config/feature_flags/development/notes_create_service_tracking.yml
new file mode 100644
index 00000000000..38636b7ee53
--- /dev/null
+++ b/config/feature_flags/development/notes_create_service_tracking.yml
@@ -0,0 +1,7 @@
+---
+name: notes_create_service_tracking
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/oj_json.yml b/config/feature_flags/development/oj_json.yml
new file mode 100644
index 00000000000..b7e112ae544
--- /dev/null
+++ b/config/feature_flags/development/oj_json.yml
@@ -0,0 +1,7 @@
+---
+name: oj_json
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/optimized_timebox_queries.yml b/config/feature_flags/development/optimized_timebox_queries.yml
new file mode 100644
index 00000000000..d5301e20f3e
--- /dev/null
+++ b/config/feature_flags/development/optimized_timebox_queries.yml
@@ -0,0 +1,7 @@
+---
+name: optimized_timebox_queries
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/packages_coming_soon.yml b/config/feature_flags/development/packages_coming_soon.yml
new file mode 100644
index 00000000000..0a0d1f989dc
--- /dev/null
+++ b/config/feature_flags/development/packages_coming_soon.yml
@@ -0,0 +1,7 @@
+---
+name: packages_coming_soon
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/pages.yml b/config/feature_flags/development/pages.yml
new file mode 100644
index 00000000000..0afdc891e51
--- /dev/null
+++ b/config/feature_flags/development/pages.yml
@@ -0,0 +1,7 @@
+---
+name: pages
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/paginated_notes.yml b/config/feature_flags/development/paginated_notes.yml
new file mode 100644
index 00000000000..cd98b3b1bbf
--- /dev/null
+++ b/config/feature_flags/development/paginated_notes.yml
@@ -0,0 +1,7 @@
+---
+name: paginated_notes
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/periodic_project_authorization_recalculation.yml b/config/feature_flags/development/periodic_project_authorization_recalculation.yml
new file mode 100644
index 00000000000..90b9babcfca
--- /dev/null
+++ b/config/feature_flags/development/periodic_project_authorization_recalculation.yml
@@ -0,0 +1,7 @@
+---
+name: periodic_project_authorization_recalculation
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/phabricator_import.yml b/config/feature_flags/development/phabricator_import.yml
new file mode 100644
index 00000000000..32ccfed557e
--- /dev/null
+++ b/config/feature_flags/development/phabricator_import.yml
@@ -0,0 +1,7 @@
+---
+name: phabricator_import
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/pipelines_security_report_summary.yml b/config/feature_flags/development/pipelines_security_report_summary.yml
new file mode 100644
index 00000000000..943997f1a4f
--- /dev/null
+++ b/config/feature_flags/development/pipelines_security_report_summary.yml
@@ -0,0 +1,7 @@
+---
+name: pipelines_security_report_summary
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/product_analytics.yml b/config/feature_flags/development/product_analytics.yml
new file mode 100644
index 00000000000..85bef678251
--- /dev/null
+++ b/config/feature_flags/development/product_analytics.yml
@@ -0,0 +1,7 @@
+---
+name: product_analytics
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/prohibit_hexadecimal_branch_names.yml b/config/feature_flags/development/prohibit_hexadecimal_branch_names.yml
new file mode 100644
index 00000000000..d1977765b81
--- /dev/null
+++ b/config/feature_flags/development/prohibit_hexadecimal_branch_names.yml
@@ -0,0 +1,7 @@
+---
+name: prohibit_hexadecimal_branch_names
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/project_export_as_ndjson.yml b/config/feature_flags/development/project_export_as_ndjson.yml
new file mode 100644
index 00000000000..eee61f4ce26
--- /dev/null
+++ b/config/feature_flags/development/project_export_as_ndjson.yml
@@ -0,0 +1,7 @@
+---
+name: project_export_as_ndjson
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/project_import_ndjson.yml b/config/feature_flags/development/project_import_ndjson.yml
new file mode 100644
index 00000000000..a7971d462fe
--- /dev/null
+++ b/config/feature_flags/development/project_import_ndjson.yml
@@ -0,0 +1,7 @@
+---
+name: project_import_ndjson
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/project_list_filter_bar.yml b/config/feature_flags/development/project_list_filter_bar.yml
new file mode 100644
index 00000000000..6040fe9edf5
--- /dev/null
+++ b/config/feature_flags/development/project_list_filter_bar.yml
@@ -0,0 +1,7 @@
+---
+name: project_list_filter_bar
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/project_statistics_sync.yml b/config/feature_flags/development/project_statistics_sync.yml
new file mode 100644
index 00000000000..ece3f1e49df
--- /dev/null
+++ b/config/feature_flags/development/project_statistics_sync.yml
@@ -0,0 +1,7 @@
+---
+name: project_statistics_sync
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/project_transactionless_destroy.yml b/config/feature_flags/development/project_transactionless_destroy.yml
new file mode 100644
index 00000000000..07018632e7a
--- /dev/null
+++ b/config/feature_flags/development/project_transactionless_destroy.yml
@@ -0,0 +1,7 @@
+---
+name: project_transactionless_destroy
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/projects_tokens_optional_encryption.yml b/config/feature_flags/development/projects_tokens_optional_encryption.yml
new file mode 100644
index 00000000000..76d76bca923
--- /dev/null
+++ b/config/feature_flags/development/projects_tokens_optional_encryption.yml
@@ -0,0 +1,7 @@
+---
+name: projects_tokens_optional_encryption
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/prometheus_computed_alerts.yml b/config/feature_flags/development/prometheus_computed_alerts.yml
new file mode 100644
index 00000000000..ddba72b2f46
--- /dev/null
+++ b/config/feature_flags/development/prometheus_computed_alerts.yml
@@ -0,0 +1,7 @@
+---
+name: prometheus_computed_alerts
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/reactive_caching_limit_environment.yml b/config/feature_flags/development/reactive_caching_limit_environment.yml
new file mode 100644
index 00000000000..84db37d1d34
--- /dev/null
+++ b/config/feature_flags/development/reactive_caching_limit_environment.yml
@@ -0,0 +1,7 @@
+---
+name: reactive_caching_limit_environment
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/real_time_issue_sidebar.yml b/config/feature_flags/development/real_time_issue_sidebar.yml
new file mode 100644
index 00000000000..7cbaabe643f
--- /dev/null
+++ b/config/feature_flags/development/real_time_issue_sidebar.yml
@@ -0,0 +1,7 @@
+---
+name: real_time_issue_sidebar
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/release_asset_link_editing.yml b/config/feature_flags/development/release_asset_link_editing.yml
new file mode 100644
index 00000000000..6e6cce2c343
--- /dev/null
+++ b/config/feature_flags/development/release_asset_link_editing.yml
@@ -0,0 +1,7 @@
+---
+name: release_asset_link_editing
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/release_asset_link_type.yml b/config/feature_flags/development/release_asset_link_type.yml
new file mode 100644
index 00000000000..baeb2e59f82
--- /dev/null
+++ b/config/feature_flags/development/release_asset_link_type.yml
@@ -0,0 +1,7 @@
+---
+name: release_asset_link_type
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/release_evidence.yml b/config/feature_flags/development/release_evidence.yml
new file mode 100644
index 00000000000..a19994d51a7
--- /dev/null
+++ b/config/feature_flags/development/release_evidence.yml
@@ -0,0 +1,7 @@
+---
+name: release_evidence
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/release_evidence_collection.yml b/config/feature_flags/development/release_evidence_collection.yml
new file mode 100644
index 00000000000..c5ab8f8e5c0
--- /dev/null
+++ b/config/feature_flags/development/release_evidence_collection.yml
@@ -0,0 +1,7 @@
+---
+name: release_evidence_collection
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/release_issue_summary.yml b/config/feature_flags/development/release_issue_summary.yml
new file mode 100644
index 00000000000..ebd8ef2e4d0
--- /dev/null
+++ b/config/feature_flags/development/release_issue_summary.yml
@@ -0,0 +1,7 @@
+---
+name: release_issue_summary
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/release_mr_issue_urls.yml b/config/feature_flags/development/release_mr_issue_urls.yml
new file mode 100644
index 00000000000..f6abf50f535
--- /dev/null
+++ b/config/feature_flags/development/release_mr_issue_urls.yml
@@ -0,0 +1,7 @@
+---
+name: release_mr_issue_urls
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/release_show_page.yml b/config/feature_flags/development/release_show_page.yml
new file mode 100644
index 00000000000..5a3f1709452
--- /dev/null
+++ b/config/feature_flags/development/release_show_page.yml
@@ -0,0 +1,7 @@
+---
+name: release_show_page
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/remove_legacy_github_client.yml b/config/feature_flags/development/remove_legacy_github_client.yml
new file mode 100644
index 00000000000..adb0c7b5d03
--- /dev/null
+++ b/config/feature_flags/development/remove_legacy_github_client.yml
@@ -0,0 +1,7 @@
+---
+name: remove_legacy_github_client
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/repack_after_shard_migration.yml b/config/feature_flags/development/repack_after_shard_migration.yml
new file mode 100644
index 00000000000..addfcf66537
--- /dev/null
+++ b/config/feature_flags/development/repack_after_shard_migration.yml
@@ -0,0 +1,7 @@
+---
+name: repack_after_shard_migration
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/repository.yml b/config/feature_flags/development/repository.yml
new file mode 100644
index 00000000000..2ae4abc42bc
--- /dev/null
+++ b/config/feature_flags/development/repository.yml
@@ -0,0 +1,7 @@
+---
+name: repository
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/repository_archive_hotlinking_interception.yml b/config/feature_flags/development/repository_archive_hotlinking_interception.yml
new file mode 100644
index 00000000000..bc9efb2e4bc
--- /dev/null
+++ b/config/feature_flags/development/repository_archive_hotlinking_interception.yml
@@ -0,0 +1,7 @@
+---
+name: repository_archive_hotlinking_interception
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/resource_access_token.yml b/config/feature_flags/development/resource_access_token.yml
new file mode 100644
index 00000000000..80c5b2a5eb4
--- /dev/null
+++ b/config/feature_flags/development/resource_access_token.yml
@@ -0,0 +1,7 @@
+---
+name: resource_access_token
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/rugged_commit_is_ancestor.yml b/config/feature_flags/development/rugged_commit_is_ancestor.yml
new file mode 100644
index 00000000000..06f894b79b3
--- /dev/null
+++ b/config/feature_flags/development/rugged_commit_is_ancestor.yml
@@ -0,0 +1,7 @@
+---
+name: rugged_commit_is_ancestor
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/rugged_commit_tree_entry.yml b/config/feature_flags/development/rugged_commit_tree_entry.yml
new file mode 100644
index 00000000000..a0cb28e6ca9
--- /dev/null
+++ b/config/feature_flags/development/rugged_commit_tree_entry.yml
@@ -0,0 +1,7 @@
+---
+name: rugged_commit_tree_entry
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/rugged_find_commit.yml b/config/feature_flags/development/rugged_find_commit.yml
new file mode 100644
index 00000000000..b84e056d9f5
--- /dev/null
+++ b/config/feature_flags/development/rugged_find_commit.yml
@@ -0,0 +1,7 @@
+---
+name: rugged_find_commit
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/rugged_list_commits_by_oid.yml b/config/feature_flags/development/rugged_list_commits_by_oid.yml
new file mode 100644
index 00000000000..10093f2977f
--- /dev/null
+++ b/config/feature_flags/development/rugged_list_commits_by_oid.yml
@@ -0,0 +1,7 @@
+---
+name: rugged_list_commits_by_oid
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/rugged_tree_entries.yml b/config/feature_flags/development/rugged_tree_entries.yml
new file mode 100644
index 00000000000..6ef296c43a6
--- /dev/null
+++ b/config/feature_flags/development/rugged_tree_entries.yml
@@ -0,0 +1,7 @@
+---
+name: rugged_tree_entries
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/rugged_tree_entry.yml b/config/feature_flags/development/rugged_tree_entry.yml
new file mode 100644
index 00000000000..8ae0a71960b
--- /dev/null
+++ b/config/feature_flags/development/rugged_tree_entry.yml
@@ -0,0 +1,7 @@
+---
+name: rugged_tree_entry
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/safezip_use_rubyzip.yml b/config/feature_flags/development/safezip_use_rubyzip.yml
new file mode 100644
index 00000000000..139283d93d2
--- /dev/null
+++ b/config/feature_flags/development/safezip_use_rubyzip.yml
@@ -0,0 +1,7 @@
+---
+name: safezip_use_rubyzip
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/save_raw_usage_data.yml b/config/feature_flags/development/save_raw_usage_data.yml
new file mode 100644
index 00000000000..9556f699b9b
--- /dev/null
+++ b/config/feature_flags/development/save_raw_usage_data.yml
@@ -0,0 +1,7 @@
+---
+name: save_raw_usage_data
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/schema_linting.yml b/config/feature_flags/development/schema_linting.yml
new file mode 100644
index 00000000000..1220b02be0d
--- /dev/null
+++ b/config/feature_flags/development/schema_linting.yml
@@ -0,0 +1,7 @@
+---
+name: schema_linting
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/serverless_domain.yml b/config/feature_flags/development/serverless_domain.yml
new file mode 100644
index 00000000000..160730117d6
--- /dev/null
+++ b/config/feature_flags/development/serverless_domain.yml
@@ -0,0 +1,7 @@
+---
+name: serverless_domain
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/service_desk_custom_address.yml b/config/feature_flags/development/service_desk_custom_address.yml
new file mode 100644
index 00000000000..25cab0059c7
--- /dev/null
+++ b/config/feature_flags/development/service_desk_custom_address.yml
@@ -0,0 +1,7 @@
+---
+name: service_desk_custom_address
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/settings_operations_prometheus_service.yml b/config/feature_flags/development/settings_operations_prometheus_service.yml
new file mode 100644
index 00000000000..de2df4b219d
--- /dev/null
+++ b/config/feature_flags/development/settings_operations_prometheus_service.yml
@@ -0,0 +1,7 @@
+---
+name: settings_operations_prometheus_service
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/similarity_search.yml b/config/feature_flags/development/similarity_search.yml
new file mode 100644
index 00000000000..b7d48c5b986
--- /dev/null
+++ b/config/feature_flags/development/similarity_search.yml
@@ -0,0 +1,7 @@
+---
+name: similarity_search
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/snippet_multiple_files.yml b/config/feature_flags/development/snippet_multiple_files.yml
new file mode 100644
index 00000000000..28520cea19c
--- /dev/null
+++ b/config/feature_flags/development/snippet_multiple_files.yml
@@ -0,0 +1,7 @@
+---
+name: snippet_multiple_files
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/snippets.yml b/config/feature_flags/development/snippets.yml
new file mode 100644
index 00000000000..14f37feaa3f
--- /dev/null
+++ b/config/feature_flags/development/snippets.yml
@@ -0,0 +1,7 @@
+---
+name: snippets
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/snippets_binary_blob.yml b/config/feature_flags/development/snippets_binary_blob.yml
new file mode 100644
index 00000000000..c8d1b5d6ba2
--- /dev/null
+++ b/config/feature_flags/development/snippets_binary_blob.yml
@@ -0,0 +1,7 @@
+---
+name: snippets_binary_blob
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/snippets_edit_vue.yml b/config/feature_flags/development/snippets_edit_vue.yml
new file mode 100644
index 00000000000..c19fca9fa15
--- /dev/null
+++ b/config/feature_flags/development/snippets_edit_vue.yml
@@ -0,0 +1,7 @@
+---
+name: snippets_edit_vue
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/snippets_vue.yml b/config/feature_flags/development/snippets_vue.yml
new file mode 100644
index 00000000000..b3b7e525a6e
--- /dev/null
+++ b/config/feature_flags/development/snippets_vue.yml
@@ -0,0 +1,7 @@
+---
+name: snippets_vue
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/soft_email_confirmation.yml b/config/feature_flags/development/soft_email_confirmation.yml
new file mode 100644
index 00000000000..d471cf442de
--- /dev/null
+++ b/config/feature_flags/development/soft_email_confirmation.yml
@@ -0,0 +1,7 @@
+---
+name: soft_email_confirmation
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/specialized_project_authorization_project_share_worker.yml b/config/feature_flags/development/specialized_project_authorization_project_share_worker.yml
new file mode 100644
index 00000000000..c09c5ad519b
--- /dev/null
+++ b/config/feature_flags/development/specialized_project_authorization_project_share_worker.yml
@@ -0,0 +1,7 @@
+---
+name: specialized_project_authorization_project_share_worker
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/specialized_project_authorization_workers.yml b/config/feature_flags/development/specialized_project_authorization_workers.yml
new file mode 100644
index 00000000000..7fceff532f3
--- /dev/null
+++ b/config/feature_flags/development/specialized_project_authorization_workers.yml
@@ -0,0 +1,7 @@
+---
+name: specialized_project_authorization_workers
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/sql_set_operators.yml b/config/feature_flags/development/sql_set_operators.yml
new file mode 100644
index 00000000000..b8a838a13f1
--- /dev/null
+++ b/config/feature_flags/development/sql_set_operators.yml
@@ -0,0 +1,7 @@
+---
+name: sql_set_operators
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/squash_options.yml b/config/feature_flags/development/squash_options.yml
new file mode 100644
index 00000000000..9ba5129b9a3
--- /dev/null
+++ b/config/feature_flags/development/squash_options.yml
@@ -0,0 +1,7 @@
+---
+name: squash_options
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/sse_image_uploads.yml b/config/feature_flags/development/sse_image_uploads.yml
new file mode 100644
index 00000000000..469af524c87
--- /dev/null
+++ b/config/feature_flags/development/sse_image_uploads.yml
@@ -0,0 +1,7 @@
+---
+name: sse_image_uploads
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/store_mentioned_users_to_db.yml b/config/feature_flags/development/store_mentioned_users_to_db.yml
new file mode 100644
index 00000000000..e19076f2b84
--- /dev/null
+++ b/config/feature_flags/development/store_mentioned_users_to_db.yml
@@ -0,0 +1,7 @@
+---
+name: store_mentioned_users_to_db
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/suggest_pipeline.yml b/config/feature_flags/development/suggest_pipeline.yml
new file mode 100644
index 00000000000..bd467f4bcca
--- /dev/null
+++ b/config/feature_flags/development/suggest_pipeline.yml
@@ -0,0 +1,7 @@
+---
+name: suggest_pipeline
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/track_resource_state_change_events.yml b/config/feature_flags/development/track_resource_state_change_events.yml
new file mode 100644
index 00000000000..3bfde5cf05e
--- /dev/null
+++ b/config/feature_flags/development/track_resource_state_change_events.yml
@@ -0,0 +1,7 @@
+---
+name: track_resource_state_change_events
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/track_unique_visits.yml b/config/feature_flags/development/track_unique_visits.yml
new file mode 100644
index 00000000000..6a60d327e87
--- /dev/null
+++ b/config/feature_flags/development/track_unique_visits.yml
@@ -0,0 +1,7 @@
+---
+name: track_unique_visits
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/tribute_autocomplete.yml b/config/feature_flags/development/tribute_autocomplete.yml
new file mode 100644
index 00000000000..31ee1b932d3
--- /dev/null
+++ b/config/feature_flags/development/tribute_autocomplete.yml
@@ -0,0 +1,7 @@
+---
+name: tribute_autocomplete
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml b/config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml
new file mode 100644
index 00000000000..bfe3356cb8e
--- /dev/null
+++ b/config/feature_flags/development/unlink_fork_network_upon_visibility_decrease.yml
@@ -0,0 +1,7 @@
+---
+name: unlink_fork_network_upon_visibility_decrease
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_g_compliance_dashboard.yml b/config/feature_flags/development/usage_data_g_compliance_dashboard.yml
new file mode 100644
index 00000000000..6f971788d88
--- /dev/null
+++ b/config/feature_flags/development/usage_data_g_compliance_dashboard.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_g_compliance_dashboard
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/usage_data_incident_management_alert_assigned.yml b/config/feature_flags/development/usage_data_incident_management_alert_assigned.yml
new file mode 100644
index 00000000000..22589d00ae0
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_alert_assigned.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_alert_assigned
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml b/config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml
new file mode 100644
index 00000000000..10f987ecd65
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_alert_status_changed
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_alert_todo.yml b/config/feature_flags/development/usage_data_incident_management_alert_todo.yml
new file mode 100644
index 00000000000..67d18480a56
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_alert_todo.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_alert_todo
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_assigned.yml b/config/feature_flags/development/usage_data_incident_management_incident_assigned.yml
new file mode 100644
index 00000000000..1b48fe4ac9c
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_assigned.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_assigned
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml b/config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml
new file mode 100644
index 00000000000..6235382fd59
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_change_confidential
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_closed.yml b/config/feature_flags/development/usage_data_incident_management_incident_closed.yml
new file mode 100644
index 00000000000..4f8f9b951ed
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_closed.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_closed
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_comment.yml b/config/feature_flags/development/usage_data_incident_management_incident_comment.yml
new file mode 100644
index 00000000000..b41c96d3b04
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_comment.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_comment
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_created.yml b/config/feature_flags/development/usage_data_incident_management_incident_created.yml
new file mode 100644
index 00000000000..693cc23dc3b
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_created.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_created
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_relate.yml b/config/feature_flags/development/usage_data_incident_management_incident_relate.yml
new file mode 100644
index 00000000000..70b4c5c3f65
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_relate.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_relate
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_reopened.yml b/config/feature_flags/development/usage_data_incident_management_incident_reopened.yml
new file mode 100644
index 00000000000..ccb108a4a28
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_reopened.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_reopened
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_todo.yml b/config/feature_flags/development/usage_data_incident_management_incident_todo.yml
new file mode 100644
index 00000000000..c517a66a151
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_todo.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_todo
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml b/config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml
new file mode 100644
index 00000000000..da418eb79a4
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_unrelate
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml b/config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml
new file mode 100644
index 00000000000..bbe81fdf3ed
--- /dev/null
+++ b/config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_incident_management_incident_zoom_meeting
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/use_workhorse_s3_client.yml b/config/feature_flags/development/use_workhorse_s3_client.yml
new file mode 100644
index 00000000000..dd152996c0c
--- /dev/null
+++ b/config/feature_flags/development/use_workhorse_s3_client.yml
@@ -0,0 +1,7 @@
+---
+name: use_workhorse_s3_client
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/user_mode_in_session.yml b/config/feature_flags/development/user_mode_in_session.yml
new file mode 100644
index 00000000000..2a373ece4f4
--- /dev/null
+++ b/config/feature_flags/development/user_mode_in_session.yml
@@ -0,0 +1,7 @@
+---
+name: user_mode_in_session
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/user_time_settings.yml b/config/feature_flags/development/user_time_settings.yml
new file mode 100644
index 00000000000..a63f229f903
--- /dev/null
+++ b/config/feature_flags/development/user_time_settings.yml
@@ -0,0 +1,7 @@
+---
+name: user_time_settings
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/users_search.yml b/config/feature_flags/development/users_search.yml
new file mode 100644
index 00000000000..0397ee60225
--- /dev/null
+++ b/config/feature_flags/development/users_search.yml
@@ -0,0 +1,7 @@
+---
+name: users_search
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/validate_import_decompressed_archive_size.yml b/config/feature_flags/development/validate_import_decompressed_archive_size.yml
new file mode 100644
index 00000000000..28876f5180f
--- /dev/null
+++ b/config/feature_flags/development/validate_import_decompressed_archive_size.yml
@@ -0,0 +1,7 @@
+---
+name: validate_import_decompressed_archive_size
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/view_diffs_file_by_file.yml b/config/feature_flags/development/view_diffs_file_by_file.yml
new file mode 100644
index 00000000000..4df755943ab
--- /dev/null
+++ b/config/feature_flags/development/view_diffs_file_by_file.yml
@@ -0,0 +1,7 @@
+---
+name: view_diffs_file_by_file
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/vue_issuable_sidebar.yml b/config/feature_flags/development/vue_issuable_sidebar.yml
new file mode 100644
index 00000000000..d57852c9491
--- /dev/null
+++ b/config/feature_flags/development/vue_issuable_sidebar.yml
@@ -0,0 +1,7 @@
+---
+name: vue_issuable_sidebar
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/vue_issuables_list.yml b/config/feature_flags/development/vue_issuables_list.yml
new file mode 100644
index 00000000000..79ade237824
--- /dev/null
+++ b/config/feature_flags/development/vue_issuables_list.yml
@@ -0,0 +1,7 @@
+---
+name: vue_issuables_list
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/web_ide_primary_edit.yml b/config/feature_flags/development/web_ide_primary_edit.yml
new file mode 100644
index 00000000000..8bea7fd94e7
--- /dev/null
+++ b/config/feature_flags/development/web_ide_primary_edit.yml
@@ -0,0 +1,7 @@
+---
+name: web_ide_primary_edit
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/webauthn.yml b/config/feature_flags/development/webauthn.yml
new file mode 100644
index 00000000000..7b360e884ae
--- /dev/null
+++ b/config/feature_flags/development/webauthn.yml
@@ -0,0 +1,7 @@
+---
+name: webauthn
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/webperf_experiment.yml b/config/feature_flags/development/webperf_experiment.yml
new file mode 100644
index 00000000000..02c2a12cfaf
--- /dev/null
+++ b/config/feature_flags/development/webperf_experiment.yml
@@ -0,0 +1,7 @@
+---
+name: webperf_experiment
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/whats_new_drawer.yml b/config/feature_flags/development/whats_new_drawer.yml
new file mode 100644
index 00000000000..6e31b17e05a
--- /dev/null
+++ b/config/feature_flags/development/whats_new_drawer.yml
@@ -0,0 +1,7 @@
+---
+name: whats_new_drawer
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/widget_visibility_polling.yml b/config/feature_flags/development/widget_visibility_polling.yml
new file mode 100644
index 00000000000..c0c6962a46d
--- /dev/null
+++ b/config/feature_flags/development/widget_visibility_polling.yml
@@ -0,0 +1,7 @@
+---
+name: widget_visibility_polling
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/wiki.yml b/config/feature_flags/development/wiki.yml
new file mode 100644
index 00000000000..9f36fd7c6aa
--- /dev/null
+++ b/config/feature_flags/development/wiki.yml
@@ -0,0 +1,7 @@
+---
+name: wiki
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/wiki_events_on_git_push.yml b/config/feature_flags/development/wiki_events_on_git_push.yml
new file mode 100644
index 00000000000..abab9029bae
--- /dev/null
+++ b/config/feature_flags/development/wiki_events_on_git_push.yml
@@ -0,0 +1,7 @@
+---
+name: wiki_events_on_git_push
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/wiki_front_matter.yml b/config/feature_flags/development/wiki_front_matter.yml
new file mode 100644
index 00000000000..6b388aaa5d2
--- /dev/null
+++ b/config/feature_flags/development/wiki_front_matter.yml
@@ -0,0 +1,7 @@
+---
+name: wiki_front_matter
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/workhorse_archive_cache_disabled.yml b/config/feature_flags/development/workhorse_archive_cache_disabled.yml
new file mode 100644
index 00000000000..b708d21ad89
--- /dev/null
+++ b/config/feature_flags/development/workhorse_archive_cache_disabled.yml
@@ -0,0 +1,7 @@
+---
+name: workhorse_archive_cache_disabled
+introduced_by_url:
+rollout_issue_url:
+group:
+type: development
+default_enabled: false
diff --git a/doc/api/project_templates.md b/doc/api/project_templates.md
index b502b60b513..08f3aefb429 100644
--- a/doc/api/project_templates.md
+++ b/doc/api/project_templates.md
@@ -110,7 +110,7 @@ Example response (Dockerfile):
```json
{
"name": "Binary",
- "content": "# This file is a template, and might need editing before it works on your project.\n# This Dockerfile installs a compiled binary into a bare system.\n# You must either commit your compiled binary into source control (not recommended)\n# or build the binary first as part of a CI/CD pipeline.\n\nFROM buildpack-deps:jessie\n\nWORKDIR /usr/local/bin\n\n# Change `app` to whatever your binary is called\nAdd app .\nCMD [\"./app\"]\n"
+ "content": "# This file is a template, and might need editing before it works on your project.\n# This Dockerfile installs a compiled binary into a bare system.\n# You must either commit your compiled binary into source control (not recommended)\n# or build the binary first as part of a CI/CD pipeline.\n\nFROM buildpack-deps:buster\n\nWORKDIR /usr/local/bin\n\n# Change `app` to whatever your binary is called\nAdd app .\nCMD [\"./app\"]\n"
}
```
diff --git a/doc/api/search.md b/doc/api/search.md
index 532ea0aa3ac..cb90b9a064c 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -23,6 +23,7 @@ GET /search
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `scope` | string | yes | The scope to search in |
| `search` | string | yes | The search query |
+| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, snippet_titles, users.
@@ -397,7 +398,7 @@ GET /groups/:id/search
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `scope` | string | yes | The scope to search in |
| `search` | string | yes | The search query |
-| `state` | string | no | Filtering by state, currently only supported for issues and merge requests. It is ignored for other scopes |
+| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, users.
@@ -742,7 +743,7 @@ GET /projects/:id/search
| `scope` | string | yes | The scope to search in |
| `search` | string | yes | The search query |
| `ref` | string | no | The name of a repository branch or tag to search on. The project's default branch is used by default. This is only applicable for scopes: commits, blobs, and wiki_blobs. |
-| `state` | string | no | Filtering by state, currently only supported for issues and merge requests. It is ignored for other scopes |
+| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
Search the expression within the specified scope. Currently these scopes are supported: issues, merge_requests, milestones, notes, wiki_blobs, commits, blobs, users.
diff --git a/doc/api/templates/dockerfiles.md b/doc/api/templates/dockerfiles.md
index 2fa3d7b7fa1..e579300a2fd 100644
--- a/doc/api/templates/dockerfiles.md
+++ b/doc/api/templates/dockerfiles.md
@@ -124,7 +124,7 @@ Example response:
```json
{
"name": "Binary",
- "content": "# This file is a template, and might need editing before it works on your project.\n# This Dockerfile installs a compiled binary into a bare system.\n# You must either commit your compiled binary into source control (not recommended)\n# or build the binary first as part of a CI/CD pipeline.\n\nFROM buildpack-deps:jessie\n\nWORKDIR /usr/local/bin\n\n# Change `app` to whatever your binary is called\nAdd app .\nCMD [\"./app\"]\n"
+ "content": "# This file is a template, and might need editing before it works on your project.\n# This Dockerfile installs a compiled binary into a bare system.\n# You must either commit your compiled binary into source control (not recommended)\n# or build the binary first as part of a CI/CD pipeline.\n\nFROM buildpack-deps:buster\n\nWORKDIR /usr/local/bin\n\n# Change `app` to whatever your binary is called\nAdd app .\nCMD [\"./app\"]\n"
}
```
diff --git a/doc/operations/incident_management/generic_alerts.md b/doc/operations/incident_management/generic_alerts.md
index dd3ac918767..11d4dbc6924 100644
--- a/doc/operations/incident_management/generic_alerts.md
+++ b/doc/operations/incident_management/generic_alerts.md
@@ -43,6 +43,7 @@ You can customize the payload by sending the following parameters. All fields ot
| `title` | String | The title of the incident. Required. |
| `description` | String | A high-level summary of the problem. |
| `start_time` | DateTime | The time of the incident. If none is provided, a timestamp of the issue will be used. |
+| `end_time` | DateTime | For existing alerts only. When provided, the alert is resolved and the associated incident is closed. |
| `service` | String | The affected service. |
| `monitoring_tool` | String | The name of the associated monitoring tool. |
| `hosts` | String or Array | One or more hosts, as to where this incident occurred. |
diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md
index 5af311c693a..5941bf8e2c6 100644
--- a/doc/operations/incident_management/incidents.md
+++ b/doc/operations/incident_management/incidents.md
@@ -19,12 +19,17 @@ in your project's sidebar. The list contains the following metrics:
or **All** above the incident list.
- **Search** - The Incident list supports a simple free text search, which filters
on the **Title** and **Incident** fields.
-- **Severity** - Severity of a particular incident. Can have one of the following values:
- - `Critical - S1`
- - `High - S2`
- - `Medium - S3`
- - `Low - S4`
- - `Unknown`
+- **Severity** - Severity of a particular incident, which can be one of the following
+ values:
+ - **{severity-critical}** **Critical - S1**
+ - **{severity-high}** **High - S2**
+ - **{severity-medium}** **Medium - S3**
+ - **{severity-low}** **Low - S4**
+ - **{severity-unknown}** **Unknown**
+
+ NOTE: **Note:**
+ Editing incident severity on the incident details page was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229402) in GitLab 13.4.
+
- **Incident** - The description of the incident, which attempts to capture the
most meaningful data.
- **Date created** - How long ago the incident was created. This field uses the
@@ -32,10 +37,10 @@ in your project's sidebar. The list contains the following metrics:
tooltip depending on the user's locale.
- **Assignees** - The user assigned to the incident.
- **Published** - Displays a green check mark (**{check-circle}**) if the incident is published
- to a [Status Page](./status_page.md).. **(ULTIMATE)**
+ to a [Status Page](status_page.md). **(ULTIMATE)**
The Incident list displays incidents sorted by incident created date.
-([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229534) to GitLab core in 13.3).)
+([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229534) to GitLab core in 13.3.)
To see if a column is sortable, point your mouse at the header. Sortable columns
display an arrow next to the column name.
@@ -97,7 +102,7 @@ If you have at least Developer [permissions](../../user/permissions.md), to crea
- Navigate to **Issues > List** and click **Create Issue**.
- Create a new issue using the `type` drop-down and select `Incident`.
-- The page will refresh and you will notice there are now only fields relevant to Incidents.
+- The page refreshes and the page only displays fields relevant to Incidents.
![Incident List Create](./img/new_incident_create_v13_4.png)
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 23091f40430..c4046b36c55 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -10,10 +10,6 @@ DANGER: **Danger:**
Do not run this within 12 hours of a GitLab upgrade. This is to ensure that all background migrations
have finished, which otherwise may lead to data loss.
-CAUTION: **WARNING:**
-Removing LFS files from a project with forks is currently unsafe. The Rake task
-will refuse to run on projects with forks.
-
When you remove LFS files from a repository's history, they become orphaned and continue to consume
disk space. With this Rake task, you can remove invalid references from the database, which
will allow garbage collection of LFS files.
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index 4ece58f533d..feea038b7d2 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -671,7 +671,7 @@ X-Gitlab-Event: System Hook
"homepage":"http://example.com/jsmith/example",
"url":"git@example.com:jsmith/example.git",
"ssh_url":"git@example.com:jsmith/example.git",
- "http_url":"http://example.com/jsmith/example.git",
+ "http_url":"http://example.com/jsmith/example.git"
},
"changes": [
{
diff --git a/doc/topics/git/how_to_install_git/index.md b/doc/topics/git/how_to_install_git/index.md
index a90ccbf9eaf..1eea49d8ffe 100644
--- a/doc/topics/git/how_to_install_git/index.md
+++ b/doc/topics/git/how_to_install_git/index.md
@@ -18,14 +18,14 @@ is also available at the official Git website.
## Install Git on macOS using the Homebrew package manager
-Although it is easy to use the version of Git shipped with macOS
-or install the latest version of Git on macOS by downloading it from the project website,
-we recommend installing it via Homebrew to get access to
-an extensive selection of dependency managed libraries and applications.
-
-If you are sure you don't need access to any additional development libraries
-or don't have approximately 15gb of available disk space for Xcode and Homebrew,
-use one of the aforementioned methods.
+Although you can use the version of Git shipped with macOS or install the latest
+version of Git on macOS by downloading it from the project website, we recommend
+installing Git with Homebrew to get access to an extensive selection of
+dependency-managed libraries and applications.
+
+If you don't need access to any additional development libraries or don't have
+approximately 15 GB of available disk space for Xcode and Homebrew, use one of
+the previously mentioned methods.
### Installing Xcode
diff --git a/lib/gitlab/alert_management/alert_params.rb b/lib/gitlab/alert_management/alert_params.rb
index 0edc77efa10..3bb839c1114 100644
--- a/lib/gitlab/alert_management/alert_params.rb
+++ b/lib/gitlab/alert_management/alert_params.rb
@@ -20,6 +20,7 @@ module Gitlab
hosts: Array(annotations[:hosts]),
payload: payload,
started_at: parsed_payload['startsAt'],
+ ended_at: parsed_payload['endsAt'],
severity: annotations[:severity],
fingerprint: annotations[:fingerprint],
environment: annotations[:environment]
diff --git a/lib/gitlab/alerting/notification_payload_parser.rb b/lib/gitlab/alerting/notification_payload_parser.rb
index ce04205a1ba..348f851f551 100644
--- a/lib/gitlab/alerting/notification_payload_parser.rb
+++ b/lib/gitlab/alerting/notification_payload_parser.rb
@@ -20,7 +20,8 @@ module Gitlab
def call
{
'annotations' => annotations,
- 'startsAt' => starts_at
+ 'startsAt' => starts_at,
+ 'endsAt' => ends_at
}.compact
end
@@ -74,6 +75,12 @@ module Gitlab
current_time
end
+ def ends_at
+ Time.parse(payload[:end_time].to_s).rfc3339
+ rescue ArgumentError
+ nil
+ end
+
def environment
environment_name = payload[:gitlab_environment_name]
@@ -85,7 +92,7 @@ module Gitlab
end
def secondary_params
- payload.except(:start_time)
+ payload.except(:start_time, :end_time)
end
def flatten_secondary_params
diff --git a/lib/gitlab/checks/lfs_integrity.rb b/lib/gitlab/checks/lfs_integrity.rb
index e18cf6ff8f2..78952db7a3e 100644
--- a/lib/gitlab/checks/lfs_integrity.rb
+++ b/lib/gitlab/checks/lfs_integrity.rb
@@ -17,7 +17,7 @@ module Gitlab
return false unless new_lfs_pointers.present?
- existing_count = @project.all_lfs_objects
+ existing_count = @project.lfs_objects
.for_oids(new_lfs_pointers.map(&:lfs_oid))
.count
diff --git a/lib/gitlab/cleanup/orphan_lfs_file_references.rb b/lib/gitlab/cleanup/orphan_lfs_file_references.rb
index 10b227f3a2a..14eac474e27 100644
--- a/lib/gitlab/cleanup/orphan_lfs_file_references.rb
+++ b/lib/gitlab/cleanup/orphan_lfs_file_references.rb
@@ -17,14 +17,6 @@ module Gitlab
end
def run!
- # If this project is an LFS storage project (e.g. is the root of a fork
- # network), what it is safe to remove depends on the sum of its forks.
- # For now, skip cleaning up LFS for this complicated case
- if project.forks_count > 0 && project.lfs_storage_project == project
- log_info("Skipping orphan LFS check for #{project.name_with_namespace} as it is a fork root")
- return
- end
-
log_info("Looking for orphan LFS files for project #{project.name_with_namespace}")
remove_orphan_references
diff --git a/lib/gitlab/import_export/lfs_saver.rb b/lib/gitlab/import_export/lfs_saver.rb
index 18c590e1ca9..515fd98630c 100644
--- a/lib/gitlab/import_export/lfs_saver.rb
+++ b/lib/gitlab/import_export/lfs_saver.rb
@@ -16,7 +16,7 @@ module Gitlab
end
def save
- project.all_lfs_objects.find_in_batches(batch_size: BATCH_SIZE) do |batch|
+ project.lfs_objects.find_in_batches(batch_size: BATCH_SIZE) do |batch|
batch.each do |lfs_object|
save_lfs_object(lfs_object)
end
diff --git a/lib/gitlab/pages/settings.rb b/lib/gitlab/pages/settings.rb
index 47f56072b37..8650a80a85e 100644
--- a/lib/gitlab/pages/settings.rb
+++ b/lib/gitlab/pages/settings.rb
@@ -6,7 +6,7 @@ module Gitlab
DiskAccessDenied = Class.new(StandardError)
def path
- if ::Gitlab::Runtime.web_server? && ENV['GITLAB_PAGES_DENY_DISK_ACCESS'] == '1'
+ if ::Gitlab::Runtime.web_server? && !::Gitlab::Runtime.test_suite?
raise DiskAccessDenied
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 668e833072b..b88e224314c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2214,9 +2214,6 @@ msgstr ""
msgid "AlertManagement|Events"
msgstr ""
-msgid "AlertManagement|Full Alert Payload"
-msgstr ""
-
msgid "AlertManagement|High"
msgstr ""
@@ -2226,6 +2223,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -13415,6 +13415,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
diff --git a/package.json b/package.json
index d421ecc2836..d7b8514d9f2 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,7 @@
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.164.0",
- "@gitlab/ui": "21.0.0",
+ "@gitlab/ui": "21.2.1",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-1",
"@sentry/browser": "^5.22.3",
diff --git a/qa/qa/page/component/select2.rb b/qa/qa/page/component/select2.rb
index b8beb64b6bd..761bbb17168 100644
--- a/qa/qa/page/component/select2.rb
+++ b/qa/qa/page/component/select2.rb
@@ -8,6 +8,10 @@ module QA
find('.select2-result-label', text: item_text, match: :prefer_exact).click
end
+ def has_item?(item_text)
+ has_css?('.select2-result-label', text: item_text, match: :prefer_exact)
+ end
+
def current_selection
find('.select2-chosen').text
end
@@ -25,8 +29,12 @@ module QA
end
def search_and_select(item_text)
+ QA::Runtime::Logger.info "Searching and selecting: #{item_text}"
+
search_item(item_text)
+ raise QA::Page::Base::ElementNotFound, %Q(Couldn't find option named "#{item_text}") unless has_item?(item_text)
+
select_item(item_text)
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 8431e47831e..0b80ba84fa4 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -53,10 +53,6 @@ module QA
element :diffs_tab
end
- view 'app/assets/javascripts/diffs/components/diff_table_cell.vue' do
- element :diff_comment
- end
-
view 'app/assets/javascripts/diffs/components/inline_diff_table_row.vue' do
element :new_diff_line
end
diff --git a/qa/qa/page/project/settings/advanced.rb b/qa/qa/page/project/settings/advanced.rb
index 960d6c221b5..97519c3906c 100644
--- a/qa/qa/page/project/settings/advanced.rb
+++ b/qa/qa/page/project/settings/advanced.rb
@@ -38,20 +38,16 @@ module QA
click_element :change_path_button
end
- def select_transfer_option(namespace)
- search_and_select(namespace)
- end
-
def transfer_project!(project_name, namespace)
- # Retry added here due to seldom seen inconsistent UI state issue:
- # https://gitlab.com/gitlab-org/gitlab/-/issues/231242
- retry_on_exception do
- click_element_coordinates(:archive_project_content)
- expand_select_list
- # Workaround for a failure to search when there are no spaces around the /
- # https://gitlab.com/gitlab-org/gitlab/-/issues/218965
- select_transfer_option(namespace.gsub(/([^\s])\/([^\s])/, '\1 / \2'))
- end
+ QA::Runtime::Logger.info "Transferring project: #{project_name} to namespace: #{namespace}"
+
+ click_element_coordinates(:archive_project_content)
+
+ expand_select_list
+
+ # Workaround for a failure to search when there are no spaces around the /
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/218965
+ search_and_select(namespace.gsub(/([^\s])\/([^\s])/, '\1 / \2'))
click_element(:transfer_button)
fill_confirmation_text(project_name)
diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
index 2334a5313b3..b9e1ee53246 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
@@ -11,14 +11,14 @@ module QA
let(:target_group) do
Resource::Group.fabricate_via_api! do |group|
- group.path = 'target-group'
+ group.path = "target-group-for-transfer_#{SecureRandom.hex(8)}"
end
end
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.group = source_group
- project.name = 'transfer-project'
+ project.name = 'transfer-project'
project.initialize_with_readme = true
end
end
@@ -44,12 +44,15 @@ module QA
end
it 'user transfers a project between groups', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/406' do
- Page::File::Show.perform(&:go_to_general_settings)
+ # Retry is needed here as the target group is not avaliable for transfer right away.
+ QA::Support::Retrier.retry_on_exception(reload_page: page) do
+ Page::File::Show.perform(&:go_to_general_settings)
- Page::Project::Settings::Main.perform(&:expand_advanced_settings)
+ Page::Project::Settings::Main.perform(&:expand_advanced_settings)
- Page::Project::Settings::Advanced.perform do |advanced|
- advanced.transfer_project!(project.name, target_group.full_path)
+ Page::Project::Settings::Advanced.perform do |advanced|
+ advanced.transfer_project!(project.name, target_group.full_path)
+ end
end
Page::Project::Settings::Main.perform(&:click_project)
diff --git a/rubocop/cop/avoid_route_redirect_leading_slash.rb b/rubocop/cop/avoid_route_redirect_leading_slash.rb
index 591c003a166..0b0dc7d3d33 100644
--- a/rubocop/cop/avoid_route_redirect_leading_slash.rb
+++ b/rubocop/cop/avoid_route_redirect_leading_slash.rb
@@ -7,10 +7,10 @@ module RuboCop
#
# @example
# # bad
- # root to: redirect('/-/instance_statistics/dev_ops_report')
+ # root to: redirect('/-/autocomplete/users')
#
# # good
- # root to: redirect('-/instance_statistics/dev_ops_report')
+ # root to: redirect('-/autocomplete/users')
#
class AvoidRouteRedirectLeadingSlash < RuboCop::Cop::Cop
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index a84970eb736..5776332c499 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -125,8 +125,8 @@ export const rawIssue = {
timeEstimate: 0,
weight: null,
confidential: false,
- referencePath: 'gitlab-org/gitlab-test#27',
- path: '/gitlab-org/gitlab-test/-/issues/27',
+ referencePath: 'gitlab-org/test-subgroup/gitlab-test#27',
+ path: '/gitlab-org/test-subgroup/gitlab-test/-/issues/27',
labels: {
nodes: [
{
@@ -153,8 +153,8 @@ export const mockIssue = {
timeEstimate: 0,
weight: null,
confidential: false,
- referencePath: 'gitlab-org/gitlab-test#27',
- path: '/gitlab-org/gitlab-test/-/issues/27',
+ referencePath: 'gitlab-org/test-subgroup/gitlab-test#27',
+ path: '/gitlab-org/test-subgroup/gitlab-test/-/issues/27',
assignees,
labels: [
{
@@ -179,8 +179,8 @@ export const mockIssue2 = {
timeEstimate: 0,
weight: null,
confidential: false,
- referencePath: 'gitlab-org/gitlab-test#2',
- path: '/gitlab-org/gitlab-test/-/issues/28',
+ referencePath: 'gitlab-org/test-subgroup/gitlab-test#28',
+ path: '/gitlab-org/test-subgroup/gitlab-test/-/issues/28',
assignees,
labels,
epic: {
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index 8efad4d3ac7..bdbcd435708 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -10,6 +10,8 @@ import {
import actions, { gqlClient } from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types';
import { inactiveId, ListType } from '~/boards/constants';
+import issueMoveListMutation from '~/boards/queries/issue_move_list.mutation.graphql';
+import { fullBoardId } from '~/boards/boards_util';
const expectNotImplemented = action => {
it('is not implemented', () => {
@@ -17,6 +19,10 @@ const expectNotImplemented = action => {
});
};
+// We need this helper to make sure projectPath is including
+// subgroups when the movIssue action is called.
+const getProjectPath = path => path.split('#')[0];
+
describe('setInitialBoardData', () => {
it('sets data object', () => {
const mockData = {
@@ -290,6 +296,42 @@ describe('moveIssue', () => {
);
});
+ it('calls mutate with the correct variables', () => {
+ const mutationVariables = {
+ mutation: issueMoveListMutation,
+ variables: {
+ projectPath: getProjectPath(mockIssue.referencePath),
+ boardId: fullBoardId(state.endpoints.boardId),
+ iid: mockIssue.iid,
+ fromListId: 1,
+ toListId: 2,
+ moveBeforeId: undefined,
+ moveAfterId: undefined,
+ },
+ };
+ jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
+ data: {
+ issueMoveList: {
+ issue: rawIssue,
+ errors: [],
+ },
+ },
+ });
+
+ actions.moveIssue(
+ { state, commit: () => {} },
+ {
+ issueId: mockIssue.id,
+ issueIid: mockIssue.iid,
+ issuePath: mockIssue.referencePath,
+ fromListId: 'gid://gitlab/List/1',
+ toListId: 'gid://gitlab/List/2',
+ },
+ );
+
+ expect(gqlClient.mutate).toHaveBeenCalledWith(mutationVariables);
+ });
+
it('should commit MOVE_ISSUE mutation and MOVE_ISSUE_FAILURE mutation when unsuccessful', done => {
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: {
diff --git a/spec/frontend/diffs/components/parallel_diff_table_row_spec.js b/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
index 339352943a9..874c1cb74d5 100644
--- a/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
+++ b/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
@@ -1,9 +1,12 @@
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { TEST_HOST } from 'helpers/test_constants';
import { createStore } from '~/mr_notes/stores';
import ParallelDiffTableRow from '~/diffs/components/parallel_diff_table_row.vue';
import diffFileMockData from '../mock_data/diff_file';
+import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue';
+import discussionsMockData from '../mock_data/diff_discussions';
describe('ParallelDiffTableRow', () => {
describe('when one side is empty', () => {
@@ -158,4 +161,259 @@ describe('ParallelDiffTableRow', () => {
});
});
});
+
+ describe('Table Cells', () => {
+ let wrapper;
+ let store;
+ let thisLine;
+ const TEST_USER_ID = 'abc123';
+ const TEST_USER = { id: TEST_USER_ID };
+
+ const createComponent = (props = {}, propsStore = store, data = {}) => {
+ wrapper = shallowMount(ParallelDiffTableRow, {
+ store: propsStore,
+ propsData: {
+ line: thisLine,
+ fileHash: diffFileMockData.file_hash,
+ filePath: diffFileMockData.file_path,
+ contextLinesPath: 'contextLinesPath',
+ isHighlighted: false,
+ ...props,
+ },
+ data() {
+ return data;
+ },
+ });
+ };
+
+ const setWindowLocation = value => {
+ Object.defineProperty(window, 'location', {
+ writable: true,
+ value,
+ });
+ };
+
+ beforeEach(() => {
+ // eslint-disable-next-line prefer-destructuring
+ thisLine = diffFileMockData.parallel_diff_lines[2];
+ store = createStore();
+ store.state.notes.userData = TEST_USER;
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findNewTd = () => wrapper.find({ ref: 'newTd' });
+ const findOldTd = () => wrapper.find({ ref: 'oldTd' });
+
+ describe('td', () => {
+ it('highlights when isHighlighted true', () => {
+ store.state.diffs.highlightedRow = thisLine.left.line_code;
+ createComponent({}, store);
+
+ expect(findNewTd().classes()).toContain('hll');
+ expect(findOldTd().classes()).toContain('hll');
+ });
+
+ it('does not highlight when isHighlighted false', () => {
+ createComponent();
+
+ expect(findNewTd().classes()).not.toContain('hll');
+ expect(findOldTd().classes()).not.toContain('hll');
+ });
+ });
+
+ describe('comment button', () => {
+ const findNoteButton = () => wrapper.find({ ref: 'addDiffNoteButtonLeft' });
+
+ it.each`
+ hover | userData | query | mergeRefHeadComments | expectation
+ ${true} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${true}
+ ${true} | ${TEST_USER} | ${'diff_head=true'} | ${true} | ${true}
+ ${true} | ${TEST_USER} | ${'diff_head=true'} | ${false} | ${false}
+ ${true} | ${null} | ${''} | ${true} | ${false}
+ ${false} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${false}
+ `(
+ 'exists is $expectation - with userData ($userData) query ($query)',
+ async ({ hover, userData, query, mergeRefHeadComments, expectation }) => {
+ store.state.notes.userData = userData;
+ gon.features = { mergeRefHeadComments };
+ setWindowLocation({ href: `${TEST_HOST}?${query}` });
+ createComponent({}, store);
+ if (hover) await wrapper.find('.line_holder').trigger('mouseover');
+
+ expect(findNoteButton().exists()).toBe(expectation);
+ },
+ );
+
+ it.each`
+ line | expectation
+ ${{ ...thisLine, left: { discussions: [] } }} | ${true}
+ ${{ ...thisLine, left: { type: 'context', discussions: [] } }} | ${false}
+ ${{ ...thisLine, left: { type: 'old-nonewline', discussions: [] } }} | ${false}
+ ${{ ...thisLine, left: { discussions: [{}] } }} | ${false}
+ `('visible is $expectation - line ($line)', async ({ line, expectation }) => {
+ createComponent({ line }, store, { isLeftHover: true, isCommentButtonRendered: true });
+
+ expect(findNoteButton().isVisible()).toBe(expectation);
+ });
+
+ it.each`
+ disabled | commentsDisabled
+ ${'disabled'} | ${true}
+ ${undefined} | ${false}
+ `(
+ 'has attribute disabled=$disabled when the outer component has prop commentsDisabled=$commentsDisabled',
+ ({ disabled, commentsDisabled }) => {
+ thisLine.left.commentsDisabled = commentsDisabled;
+ createComponent({ line: { ...thisLine } }, store, {
+ isLeftHover: true,
+ isCommentButtonRendered: true,
+ });
+
+ expect(findNoteButton().attributes('disabled')).toBe(disabled);
+ },
+ );
+
+ const symlinkishFileTooltip =
+ 'Commenting on symbolic links that replace or are replaced by files is currently not supported.';
+ const realishFileTooltip =
+ 'Commenting on files that replace or are replaced by symbolic links is currently not supported.';
+ const otherFileTooltip = 'Add a comment to this line';
+ const findTooltip = () => wrapper.find({ ref: 'addNoteTooltipLeft' });
+
+ it.each`
+ tooltip | commentsDisabled
+ ${symlinkishFileTooltip} | ${{ wasSymbolic: true }}
+ ${symlinkishFileTooltip} | ${{ isSymbolic: true }}
+ ${realishFileTooltip} | ${{ wasReal: true }}
+ ${realishFileTooltip} | ${{ isReal: true }}
+ ${otherFileTooltip} | ${false}
+ `(
+ 'has the correct tooltip when commentsDisabled=$commentsDisabled',
+ ({ tooltip, commentsDisabled }) => {
+ thisLine.left.commentsDisabled = commentsDisabled;
+ createComponent({ line: { ...thisLine } }, store, {
+ isLeftHover: true,
+ isCommentButtonRendered: true,
+ });
+
+ expect(findTooltip().attributes('title')).toBe(tooltip);
+ },
+ );
+ });
+
+ describe('line number', () => {
+ const findLineNumberOld = () => wrapper.find({ ref: 'lineNumberRefOld' });
+ const findLineNumberNew = () => wrapper.find({ ref: 'lineNumberRefNew' });
+
+ it('renders line numbers in correct cells', () => {
+ createComponent();
+
+ expect(findLineNumberOld().exists()).toBe(true);
+ expect(findLineNumberNew().exists()).toBe(true);
+ });
+
+ describe('with lineNumber prop', () => {
+ const TEST_LINE_CODE = 'LC_42';
+ const TEST_LINE_NUMBER = 1;
+
+ describe.each`
+ lineProps | findLineNumber | expectedHref | expectedClickArg
+ ${{ line_code: TEST_LINE_CODE, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${`#${TEST_LINE_CODE}`} | ${TEST_LINE_CODE}
+ ${{ line_code: undefined, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${undefined}
+ `(
+ 'with line ($lineProps)',
+ ({ lineProps, findLineNumber, expectedHref, expectedClickArg }) => {
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ Object.assign(thisLine.left, lineProps);
+ Object.assign(thisLine.right, lineProps);
+ createComponent({
+ line: { ...thisLine },
+ });
+ });
+
+ it('renders', () => {
+ expect(findLineNumber().exists()).toBe(true);
+ expect(findLineNumber().attributes()).toEqual({
+ href: expectedHref,
+ 'data-linenumber': TEST_LINE_NUMBER.toString(),
+ });
+ });
+
+ it('on click, dispatches setHighlightedRow', () => {
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+
+ findLineNumber().trigger('click');
+
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'diffs/setHighlightedRow',
+ expectedClickArg,
+ );
+ expect(store.dispatch).toHaveBeenCalledTimes(2);
+ });
+ },
+ );
+ });
+ });
+
+ describe('diff-gutter-avatars', () => {
+ const TEST_LINE_CODE = 'LC_42';
+ const TEST_FILE_HASH = diffFileMockData.file_hash;
+ const findAvatars = () => wrapper.find(DiffGutterAvatars);
+ let line;
+
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+
+ line = {
+ left: {
+ line_code: TEST_LINE_CODE,
+ type: 'new',
+ old_line: null,
+ new_line: 1,
+ discussions: [{ ...discussionsMockData }],
+ discussionsExpanded: true,
+ text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ rich_text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ meta_data: null,
+ },
+ };
+ });
+
+ describe('with showCommentButton', () => {
+ it('renders if line has discussions', () => {
+ createComponent({ line });
+
+ expect(findAvatars().props()).toEqual({
+ discussions: line.left.discussions,
+ discussionsExpanded: line.left.discussionsExpanded,
+ });
+ });
+
+ it('does notrender if line has no discussions', () => {
+ line.left.discussions = [];
+ createComponent({ line });
+
+ expect(findAvatars().exists()).toEqual(false);
+ });
+
+ it('toggles line discussion', () => {
+ createComponent({ line });
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+
+ findAvatars().vm.$emit('toggleLineDiscussions');
+
+ expect(store.dispatch).toHaveBeenCalledWith('diffs/toggleLineDiscussions', {
+ lineCode: TEST_LINE_CODE,
+ fileHash: TEST_FILE_HASH,
+ expanded: !line.left.discussionsExpanded,
+ });
+ });
+ });
+ });
+ });
});
diff --git a/spec/frontend/issue_show/components/app_spec.js b/spec/frontend/issue_show/components/app_spec.js
index c5e94aa3376..1eabd3083ab 100644
--- a/spec/frontend/issue_show/components/app_spec.js
+++ b/spec/frontend/issue_show/components/app_spec.js
@@ -36,7 +36,7 @@ describe('Issuable output', () => {
const findStickyHeader = () => wrapper.find('[data-testid="issue-sticky-header"]');
- const mountComponent = (props = {}) => {
+ const mountComponent = (props = {}, options = {}) => {
wrapper = mount(IssuableApp, {
propsData: { ...appProps, ...props },
provide: {
@@ -45,7 +45,9 @@ describe('Issuable output', () => {
},
stubs: {
HighlightBar: true,
+ IncidentTabs: true,
},
+ ...options,
});
};
@@ -582,10 +584,23 @@ describe('Issuable output', () => {
describe('when using incident tabs description wrapper', () => {
beforeEach(() => {
- mountComponent({
- descriptionComponent: IncidentTabs,
- showTitleBorder: false,
- });
+ mountComponent(
+ {
+ descriptionComponent: IncidentTabs,
+ showTitleBorder: false,
+ },
+ {
+ mocks: {
+ $apollo: {
+ queries: {
+ alert: {
+ loading: false,
+ },
+ },
+ },
+ },
+ },
+ );
});
it('renders the description component', () => {
diff --git a/spec/frontend/issue_show/components/incident_tabs_spec.js b/spec/frontend/issue_show/components/incident_tabs_spec.js
deleted file mode 100644
index 0186b01b093..00000000000
--- a/spec/frontend/issue_show/components/incident_tabs_spec.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlTab } from '@gitlab/ui';
-import IncidentTabs from '~/issue_show/components/incidents/incident_tabs.vue';
-import { descriptionProps } from '../mock_data';
-import DescriptionComponent from '~/issue_show/components/description.vue';
-import HighlightBar from '~/issue_show/components/incidents/highlight_bar/higlight_bar.vue';
-
-describe('Incident Tabs component', () => {
- let wrapper;
-
- const mountComponent = () => {
- wrapper = shallowMount(IncidentTabs, {
- propsData: {
- ...descriptionProps,
- },
- stubs: {
- DescriptionComponent: true,
- },
- });
- };
-
- beforeEach(() => {
- mountComponent();
- });
-
- const findTabs = () => wrapper.findAll(GlTab);
- const findSummaryTab = () => findTabs().at(0);
- const findDescriptionComponent = () => wrapper.find(DescriptionComponent);
- const findHighlightBarComponent = () => wrapper.find(HighlightBar);
-
- describe('default state', () => {
- it('renders the summary tab', async () => {
- expect(findTabs()).toHaveLength(1);
- expect(findSummaryTab().exists()).toBe(true);
- expect(findSummaryTab().attributes('title')).toBe('Summary');
- });
-
- it('renders the description component with highlight bar', () => {
- expect(findDescriptionComponent().exists()).toBe(true);
- expect(findHighlightBarComponent().exists()).toBe(true);
- });
-
- it('passes all props to the description component', () => {
- expect(findDescriptionComponent().props()).toMatchObject(descriptionProps);
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/highlight_bar_spec.js b/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js
index 8a0b3a997e1..8d50df5e406 100644
--- a/spec/frontend/issue_show/components/highlight_bar_spec.js
+++ b/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
-import HighlightBar from '~/issue_show/components/incidents/highlight_bar/higlight_bar.vue';
+import HighlightBar from '~/issue_show/components/incidents/highlight_bar.vue';
import { formatDate } from '~/lib/utils/datetime_utility';
jest.mock('~/lib/utils/datetime_utility');
@@ -9,7 +9,7 @@ describe('Highlight Bar', () => {
let wrapper;
const alert = {
- createdAt: '2020-05-29T10:39:22Z',
+ startedAt: '2020-05-29T10:39:22Z',
detailsUrl: 'http://127.0.0.1:3000/root/unique-alerts/-/alert_management/1/details',
eventCount: 1,
title: 'Alert 1',
@@ -17,12 +17,8 @@ describe('Highlight Bar', () => {
const mountComponent = () => {
wrapper = shallowMount(HighlightBar, {
- provide: {
- fullPath: 'project/id',
- iid: '1',
- },
- data() {
- return { alert };
+ propsData: {
+ alert,
},
});
};
@@ -50,7 +46,7 @@ describe('Highlight Bar', () => {
const formattedDate = '2020-05-29 UTC';
formatDate.mockReturnValueOnce(formattedDate);
mountComponent();
- expect(formatDate).toHaveBeenCalledWith(alert.createdAt, 'yyyy-mm-dd Z');
+ expect(formatDate).toHaveBeenCalledWith(alert.startedAt, 'yyyy-mm-dd Z');
expect(wrapper.text()).toContain(formattedDate);
});
diff --git a/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js b/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js
new file mode 100644
index 00000000000..a51b497cd79
--- /dev/null
+++ b/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js
@@ -0,0 +1,101 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlTab } from '@gitlab/ui';
+import INVALID_URL from '~/lib/utils/invalid_url';
+import IncidentTabs from '~/issue_show/components/incidents/incident_tabs.vue';
+import { descriptionProps } from '../../mock_data';
+import DescriptionComponent from '~/issue_show/components/description.vue';
+import HighlightBar from '~/issue_show/components/incidents/highlight_bar.vue';
+import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
+
+const mockAlert = {
+ __typename: 'AlertManagementAlert',
+ detailsUrl: INVALID_URL,
+ iid: '1',
+};
+
+describe('Incident Tabs component', () => {
+ let wrapper;
+
+ const mountComponent = (data = {}) => {
+ wrapper = shallowMount(IncidentTabs, {
+ propsData: {
+ ...descriptionProps,
+ },
+ stubs: {
+ DescriptionComponent: true,
+ },
+ provide: {
+ fullPath: '',
+ iid: '',
+ },
+ data() {
+ return { alert: mockAlert, ...data };
+ },
+ mocks: {
+ $apollo: {
+ queries: {
+ alert: {
+ loading: true,
+ },
+ },
+ },
+ },
+ });
+ };
+
+ const findTabs = () => wrapper.findAll(GlTab);
+ const findSummaryTab = () => findTabs().at(0);
+ const findAlertDetailsTab = () => findTabs().at(1);
+ const findAlertDetailsComponent = () => wrapper.find(AlertDetailsTable);
+ const findDescriptionComponent = () => wrapper.find(DescriptionComponent);
+ const findHighlightBarComponent = () => wrapper.find(HighlightBar);
+
+ describe('empty state', () => {
+ beforeEach(() => {
+ mountComponent({ alert: null });
+ });
+
+ it('does not show the alert details tab', () => {
+ expect(findAlertDetailsComponent().exists()).toBe(false);
+ expect(findHighlightBarComponent().exists()).toBe(false);
+ });
+ });
+
+ describe('with an alert present', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('renders the summary tab', () => {
+ expect(findSummaryTab().exists()).toBe(true);
+ expect(findSummaryTab().attributes('title')).toBe('Summary');
+ });
+
+ it('renders the alert details tab', () => {
+ expect(findAlertDetailsTab().exists()).toBe(true);
+ expect(findAlertDetailsTab().attributes('title')).toBe('Alert details');
+ });
+
+ it('renders the alert details table with the correct props', () => {
+ const alert = { iid: mockAlert.iid };
+
+ expect(findAlertDetailsComponent().props('alert')).toEqual(alert);
+ expect(findAlertDetailsComponent().props('loading')).toBe(true);
+ });
+
+ it('renders the description component with highlight bar', () => {
+ expect(findDescriptionComponent().exists()).toBe(true);
+ expect(findHighlightBarComponent().exists()).toBe(true);
+ });
+
+ it('renders the highlight bar component with the correct props', () => {
+ const alert = { detailsUrl: mockAlert.detailsUrl };
+
+ expect(findHighlightBarComponent().props('alert')).toMatchObject(alert);
+ });
+
+ it('passes all props to the description component', () => {
+ expect(findDescriptionComponent().props()).toMatchObject(descriptionProps);
+ });
+ });
+});
diff --git a/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap b/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap
index 36021cb8ece..4d9e0af1545 100644
--- a/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap
+++ b/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap
@@ -45,34 +45,24 @@ exports[`PackageTitle renders with tags 1`] = `
<div
class="gl-display-flex gl-align-items-center gl-mr-5"
>
- <gl-icon-stub
- class="gl-text-gray-500 gl-mr-3"
- name="package"
- size="16"
- />
-
- <span
- class="gl-font-weight-bold"
+ <metadata-item-stub
data-testid="package-type"
- >
- maven
- </span>
+ icon="package"
+ link=""
+ size="s"
+ text="maven"
+ />
</div>
<div
class="gl-display-flex gl-align-items-center gl-mr-5"
>
- <gl-icon-stub
- class="gl-text-gray-500 gl-mr-3"
- name="disk"
- size="16"
- />
-
- <span
- class="gl-font-weight-bold"
+ <metadata-item-stub
data-testid="package-size"
- >
- 300 bytes
- </span>
+ icon="disk"
+ link=""
+ size="s"
+ text="300 bytes"
+ />
</div>
<div
class="gl-display-flex gl-align-items-center gl-mr-5"
@@ -135,34 +125,24 @@ exports[`PackageTitle renders without tags 1`] = `
<div
class="gl-display-flex gl-align-items-center gl-mr-5"
>
- <gl-icon-stub
- class="gl-text-gray-500 gl-mr-3"
- name="package"
- size="16"
- />
-
- <span
- class="gl-font-weight-bold"
+ <metadata-item-stub
data-testid="package-type"
- >
- maven
- </span>
+ icon="package"
+ link=""
+ size="s"
+ text="maven"
+ />
</div>
<div
class="gl-display-flex gl-align-items-center gl-mr-5"
>
- <gl-icon-stub
- class="gl-text-gray-500 gl-mr-3"
- name="disk"
- size="16"
- />
-
- <span
- class="gl-font-weight-bold"
+ <metadata-item-stub
data-testid="package-size"
- >
- 300 bytes
- </span>
+ icon="disk"
+ link=""
+ size="s"
+ text="300 bytes"
+ />
</div>
</div>
</div>
diff --git a/spec/frontend/packages/details/components/package_title_spec.js b/spec/frontend/packages/details/components/package_title_spec.js
index a0fd68616fb..d0ed78418af 100644
--- a/spec/frontend/packages/details/components/package_title_spec.js
+++ b/spec/frontend/packages/details/components/package_title_spec.js
@@ -52,7 +52,6 @@ describe('PackageTitle', () => {
const packageSize = () => wrapper.find('[data-testid="package-size"]');
const pipelineProject = () => wrapper.find('[data-testid="pipeline-project"]');
const packageRef = () => wrapper.find('[data-testid="package-ref"]');
- const packageRefIcon = () => wrapper.find('[data-testid="package-ref-icon"]');
const packageTags = () => wrapper.find(PackageTags);
afterEach(() => {
@@ -98,16 +97,16 @@ describe('PackageTitle', () => {
});
describe.each`
- packageEntity | expectedResult
+ packageEntity | text
${conanPackage} | ${'conan'}
${mavenPackage} | ${'maven'}
${npmPackage} | ${'npm'}
${nugetPackage} | ${'nuget'}
- `(`package type`, ({ packageEntity, expectedResult }) => {
+ `(`package type`, ({ packageEntity, text }) => {
beforeEach(() => createComponent({ packageEntity }));
- it(`${packageEntity.package_type} should render from Vuex getters ${expectedResult}`, () => {
- expect(packageType().text()).toBe(expectedResult);
+ it(`${packageEntity.package_type} should render from Vuex getters ${text}`, () => {
+ expect(packageType().props()).toEqual(expect.objectContaining({ text, icon: 'package' }));
});
});
@@ -115,13 +114,13 @@ describe('PackageTitle', () => {
it('correctly calculates when there is only 1 file', async () => {
await createComponent({ packageEntity: npmPackage, packageFiles: npmFiles });
- expect(packageSize().text()).toBe('200 bytes');
+ expect(packageSize().props()).toMatchObject({ text: '200 bytes', icon: 'disk' });
});
it('correctly calulates when there are multiple files', async () => {
await createComponent();
- expect(packageSize().text()).toBe('300 bytes');
+ expect(packageSize().props('text')).toBe('300 bytes');
});
});
@@ -153,8 +152,10 @@ describe('PackageTitle', () => {
it('correctly shows the package ref if there is one', async () => {
await createComponent({ packageEntity: npmPackage });
- expect(packageRefIcon().exists()).toBe(true);
- expect(packageRef().text()).toBe(npmPackage.pipeline.ref);
+ expect(packageRef().props()).toMatchObject({
+ text: npmPackage.pipeline.ref,
+ icon: 'branch',
+ });
});
});
@@ -168,8 +169,11 @@ describe('PackageTitle', () => {
it('correctly shows the pipeline project if there is one', async () => {
await createComponent({ packageEntity: npmPackage });
- expect(pipelineProject().text()).toBe(npmPackage.pipeline.project.name);
- expect(pipelineProject().attributes('href')).toBe(npmPackage.pipeline.project.web_url);
+ expect(pipelineProject().props()).toMatchObject({
+ text: npmPackage.pipeline.project.name,
+ icon: 'review-list',
+ link: npmPackage.pipeline.project.web_url,
+ });
});
});
});
diff --git a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
index 1ed269a3943..7a27f8fa431 100644
--- a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
@@ -7,7 +7,6 @@ import {
LIST_INTRO_TEXT,
EXPIRATION_POLICY_DISABLED_MESSAGE,
EXPIRATION_POLICY_DISABLED_TEXT,
- EXPIRATION_POLICY_WILL_RUN_IN,
} from '~/registry/explorer/constants';
jest.mock('~/lib/utils/datetime_utility', () => ({
@@ -68,13 +67,16 @@ describe('registry_header', () => {
it('when there is one image', async () => {
await mountComponent({ imagesCount: 1 });
- expect(findImagesCountSubHeader().text()).toMatchInterpolatedText('1 Image repository');
+ expect(findImagesCountSubHeader().props()).toMatchObject({
+ text: '1 Image repository',
+ icon: 'container-image',
+ });
});
it('when there is more than one image', async () => {
await mountComponent({ imagesCount: 3 });
- expect(findImagesCountSubHeader().text()).toMatchInterpolatedText('3 Image repositories');
+ expect(findImagesCountSubHeader().props('text')).toBe('3 Image repositories');
});
});
@@ -88,7 +90,11 @@ describe('registry_header', () => {
const text = findExpirationPolicySubHeader();
expect(text.exists()).toBe(true);
- expect(text.text()).toMatchInterpolatedText(EXPIRATION_POLICY_DISABLED_TEXT);
+ expect(text.props()).toMatchObject({
+ text: EXPIRATION_POLICY_DISABLED_TEXT,
+ icon: 'expire',
+ size: 'xl',
+ });
});
it('when is enabled', async () => {
@@ -100,7 +106,7 @@ describe('registry_header', () => {
const text = findExpirationPolicySubHeader();
expect(text.exists()).toBe(true);
- expect(text.text()).toMatchInterpolatedText(EXPIRATION_POLICY_WILL_RUN_IN);
+ expect(text.props('text')).toBe('Expiration policy will run in ');
});
it('when the expiration policy is completely disabled', async () => {
await mountComponent({
diff --git a/spec/frontend/vue_shared/components/registry/metadata_item_spec.js b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
new file mode 100644
index 00000000000..ff968ff1831
--- /dev/null
+++ b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
@@ -0,0 +1,101 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlLink } from '@gitlab/ui';
+import component from '~/vue_shared/components/registry/metadata_item.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+
+describe('Metadata Item', () => {
+ let wrapper;
+ const defaultProps = {
+ text: 'foo',
+ };
+
+ const mountComponent = (propsData = defaultProps) => {
+ wrapper = shallowMount(component, {
+ propsData,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findIcon = () => wrapper.find(GlIcon);
+ const findLink = (w = wrapper) => w.find(GlLink);
+ const findText = () => wrapper.find('[data-testid="metadata-item-text"]');
+ const findTooltipOnTruncate = (w = wrapper) => w.find(TooltipOnTruncate);
+
+ describe.each(['xs', 's', 'm', 'l', 'xl'])('size class', size => {
+ const className = `mw-${size}`;
+
+ it(`${size} is assigned correctly to text`, () => {
+ mountComponent({ ...defaultProps, size });
+
+ expect(findText().classes()).toContain(className);
+ });
+
+ it(`${size} is assigned correctly to link`, () => {
+ mountComponent({ ...defaultProps, link: 'foo', size });
+
+ expect(findTooltipOnTruncate().classes()).toContain(className);
+ });
+ });
+
+ describe('text', () => {
+ it('display a proper text', () => {
+ mountComponent();
+
+ expect(findText().text()).toBe(defaultProps.text);
+ });
+
+ it('uses tooltip_on_truncate', () => {
+ mountComponent();
+
+ const tooltip = findTooltipOnTruncate(findText());
+ expect(tooltip.exists()).toBe(true);
+ expect(tooltip.attributes('title')).toBe(defaultProps.text);
+ });
+ });
+
+ describe('link', () => {
+ it('if a link prop is passed shows a link and hides the text', () => {
+ mountComponent({ ...defaultProps, link: 'bar' });
+
+ expect(findLink().exists()).toBe(true);
+ expect(findText().exists()).toBe(false);
+
+ expect(findLink().attributes('href')).toBe('bar');
+ });
+
+ it('uses tooltip_on_truncate', () => {
+ mountComponent({ ...defaultProps, link: 'bar' });
+
+ const tooltip = findTooltipOnTruncate();
+ expect(tooltip.exists()).toBe(true);
+ expect(tooltip.attributes('title')).toBe(defaultProps.text);
+ expect(findLink(tooltip).exists()).toBe(true);
+ });
+
+ it('hides the link and shows the test if a link prop is not passed', () => {
+ mountComponent();
+
+ expect(findText().exists()).toBe(true);
+ expect(findLink().exists()).toBe(false);
+ });
+ });
+
+ describe('icon', () => {
+ it('if a icon prop is passed shows a icon', () => {
+ mountComponent({ ...defaultProps, icon: 'pencil' });
+
+ expect(findIcon().exists()).toBe(true);
+ expect(findIcon().props('name')).toBe('pencil');
+ });
+
+ it('if a icon prop is not passed hides the icon', () => {
+ mountComponent();
+
+ expect(findIcon().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/lib/gitlab/alert_management/alert_params_spec.rb b/spec/lib/gitlab/alert_management/alert_params_spec.rb
index 8bab79f5a6c..c3171be5e29 100644
--- a/spec/lib/gitlab/alert_management/alert_params_spec.rb
+++ b/spec/lib/gitlab/alert_management/alert_params_spec.rb
@@ -34,6 +34,7 @@ RSpec.describe Gitlab::AlertManagement::AlertParams do
hosts: ['gitlab.com'],
payload: payload,
started_at: started_at,
+ ended_at: nil,
fingerprint: nil,
environment: nil
)
diff --git a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb b/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
index c3d4fab221c..ff5ab1116fa 100644
--- a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
+++ b/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
@@ -7,10 +7,12 @@ RSpec.describe Gitlab::Alerting::NotificationPayloadParser do
describe '.call' do
let(:starts_at) { Time.current.change(usec: 0) }
+ let(:ends_at) { Time.current.change(usec: 0) }
let(:payload) do
{
'title' => 'alert title',
'start_time' => starts_at.rfc3339,
+ 'end_time' => ends_at.rfc3339,
'description' => 'Description',
'monitoring_tool' => 'Monitoring tool name',
'service' => 'Service',
@@ -32,7 +34,8 @@ RSpec.describe Gitlab::Alerting::NotificationPayloadParser do
'hosts' => ['gitlab.com'],
'severity' => 'low'
},
- 'startsAt' => starts_at.rfc3339
+ 'startsAt' => starts_at.rfc3339,
+ 'endsAt' => ends_at.rfc3339
}
)
end
@@ -141,6 +144,7 @@ RSpec.describe Gitlab::Alerting::NotificationPayloadParser do
{
'title' => '',
'start_time' => '',
+ 'end_time' => '',
'description' => '',
'monitoring_tool' => '',
'service' => '',
diff --git a/spec/lib/gitlab/checks/lfs_integrity_spec.rb b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
index 8fec702790c..4583cd72cfd 100644
--- a/spec/lib/gitlab/checks/lfs_integrity_spec.rb
+++ b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
@@ -57,25 +57,5 @@ RSpec.describe Gitlab::Checks::LfsIntegrity do
expect(subject.objects_missing?).to be_falsey
end
end
-
- context 'for forked project', :sidekiq_might_not_need_inline do
- let(:parent_project) { create(:project, :repository) }
- let(:project) { fork_project(parent_project, nil, repository: true) }
-
- before do
- allow(project).to receive(:lfs_enabled?).and_return(true)
- end
-
- it 'is true parent project is missing LFS objects' do
- expect(subject.objects_missing?).to be_truthy
- end
-
- it 'is false parent project already contains LFS objects for the fork' do
- lfs_object = create(:lfs_object, oid: blob_object.lfs_oid)
- create(:lfs_objects_project, project: parent_project, lfs_object: lfs_object)
-
- expect(subject.objects_missing?).to be_falsey
- end
- end
end
end
diff --git a/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb b/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb
index b120f77d5f6..efdfc0a980b 100644
--- a/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb
+++ b/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb
@@ -87,42 +87,4 @@ RSpec.describe Gitlab::Cleanup::OrphanLfsFileReferences do
.to receive(:get_all_lfs_pointers)
.and_return(oids.map { |oid| OpenStruct.new(lfs_oid: oid) })
end
-
- context 'LFS for forked projects' do
- let!(:fork_root) { create(:project, :repository, lfs_enabled: true) }
- let!(:fork_internal) { fork_project(fork_root, nil, repository: true) }
- let!(:fork_leaf) { fork_project(fork_internal, nil, repository: true) }
-
- let(:dry_run) { true }
-
- context 'root node' do
- let(:project) { fork_root }
-
- it 'skips cleanup' do
- expect(service).not_to receive(:remove_orphan_references)
-
- service.run!
- end
- end
-
- context 'internal node' do
- let(:project) { fork_internal }
-
- it 'runs cleanup' do
- expect(service).to receive(:remove_orphan_references)
-
- service.run!
- end
- end
-
- context 'leaf node' do
- let(:project) { fork_leaf }
-
- it 'runs cleanup' do
- expect(service).to receive(:remove_orphan_references)
-
- service.run!
- end
- end
- end
end
diff --git a/spec/lib/gitlab/pages/settings_spec.rb b/spec/lib/gitlab/pages/settings_spec.rb
index e495c004647..f5424a98153 100644
--- a/spec/lib/gitlab/pages/settings_spec.rb
+++ b/spec/lib/gitlab/pages/settings_spec.rb
@@ -10,21 +10,14 @@ RSpec.describe Gitlab::Pages::Settings do
it { is_expected.to eq('the path') }
- context 'when running under a web server' do
+ context 'when running under a web server outside of test mode' do
before do
+ allow(::Gitlab::Runtime).to receive(:test_suite?).and_return(false)
allow(::Gitlab::Runtime).to receive(:web_server?).and_return(true)
end
- it { is_expected.to eq('the path') }
-
- context 'with the env var' do
- before do
- stub_env('GITLAB_PAGES_DENY_DISK_ACCESS', '1')
- end
-
- it 'raises a DiskAccessDenied exception' do
- expect { subject }.to raise_error(described_class::DiskAccessDenied)
- end
+ it 'raises a DiskAccessDenied exception' do
+ expect { subject }.to raise_error(described_class::DiskAccessDenied)
end
end
end
diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb
index 71211b38418..eb9dcca842d 100644
--- a/spec/models/alert_management/alert_spec.rb
+++ b/spec/models/alert_management/alert_spec.rb
@@ -453,22 +453,4 @@ RSpec.describe AlertManagement::Alert do
expect { subject }.to change { alert.events }.by(1)
end
end
-
- describe '#present' do
- context 'when alert is generic' do
- let(:alert) { triggered_alert }
-
- it 'uses generic alert presenter' do
- expect(alert.present).to be_kind_of(AlertManagement::AlertPresenter)
- end
- end
-
- context 'when alert is Prometheus specific' do
- let(:alert) { build(:alert_management_alert, :prometheus, project: project) }
-
- it 'uses Prometheus Alert presenter' do
- expect(alert.present).to be_kind_of(AlertManagement::PrometheusAlertPresenter)
- end
- end
- end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 77b8b22e3f3..90bcc617101 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2976,68 +2976,6 @@ RSpec.describe Project do
expect(project.forks).to contain_exactly(forked_project)
end
end
-
- describe '#lfs_storage_project' do
- it 'returns self for non-forks' do
- expect(project.lfs_storage_project).to eq project
- end
-
- it 'returns the fork network root for forks' do
- second_fork = fork_project(forked_project)
-
- expect(second_fork.lfs_storage_project).to eq project
- end
-
- it 'returns self when fork_source is nil' do
- expect(forked_project).to receive(:fork_source).and_return(nil)
-
- expect(forked_project.lfs_storage_project).to eq forked_project
- end
- end
-
- describe '#all_lfs_objects' do
- let(:lfs_object) { create(:lfs_object) }
-
- context 'when LFS object is only associated to the source' do
- before do
- project.lfs_objects << lfs_object
- end
-
- it 'returns the lfs object for a project' do
- expect(project.all_lfs_objects).to contain_exactly(lfs_object)
- end
-
- it 'returns the lfs object for a fork' do
- expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
- end
- end
-
- context 'when LFS object is only associated to the fork' do
- before do
- forked_project.lfs_objects << lfs_object
- end
-
- it 'returns nothing' do
- expect(project.all_lfs_objects).to be_empty
- end
-
- it 'returns the lfs object for a fork' do
- expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
- end
- end
-
- context 'when LFS object is associated to both source and fork' do
- before do
- project.lfs_objects << lfs_object
- forked_project.lfs_objects << lfs_object
- end
-
- it 'returns the lfs object for the source and fork' do
- expect(project.all_lfs_objects).to contain_exactly(lfs_object)
- expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
- end
- end
- end
end
describe '#set_repository_read_only!' do
@@ -6150,53 +6088,6 @@ RSpec.describe Project do
end
end
- describe '#all_lfs_objects_oids' do
- let(:project) { create(:project) }
- let(:lfs_object) { create(:lfs_object) }
- let(:another_lfs_object) { create(:lfs_object) }
-
- subject { project.all_lfs_objects_oids }
-
- context 'when project has associated LFS objects' do
- before do
- create(:lfs_objects_project, lfs_object: lfs_object, project: project)
- create(:lfs_objects_project, lfs_object: another_lfs_object, project: project)
- end
-
- it 'returns OIDs of LFS objects' do
- expect(subject).to match_array([lfs_object.oid, another_lfs_object.oid])
- end
-
- context 'and there are specified oids' do
- subject { project.all_lfs_objects_oids(oids: [lfs_object.oid]) }
-
- it 'returns OIDs of LFS objects that match specified oids' do
- expect(subject).to eq([lfs_object.oid])
- end
- end
- end
-
- context 'when fork has associated LFS objects to itself and source' do
- let(:source) { create(:project) }
- let(:project) { fork_project(source) }
-
- before do
- create(:lfs_objects_project, lfs_object: lfs_object, project: source)
- create(:lfs_objects_project, lfs_object: another_lfs_object, project: project)
- end
-
- it 'returns OIDs of LFS objects' do
- expect(subject).to match_array([lfs_object.oid, another_lfs_object.oid])
- end
- end
-
- context 'when project has no associated LFS objects' do
- it 'returns empty array' do
- expect(subject).to be_empty
- end
- end
- end
-
describe '#lfs_objects_oids' do
let(:project) { create(:project) }
let(:lfs_object) { create(:lfs_object) }
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index 65bd335dd7e..6cd1c201c62 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -370,24 +370,6 @@ RSpec.describe GlobalPolicy do
end
end
- describe 'read instance statistics' do
- context 'regular user' do
- it { is_expected.to be_disallowed(:read_instance_statistics) }
- end
-
- context 'admin', :enable_admin_mode do
- let(:current_user) { create(:admin) }
-
- it { is_expected.to be_allowed(:read_instance_statistics) }
- end
-
- context 'anonymous' do
- let(:current_user) { nil }
-
- it { is_expected.not_to be_allowed(:read_instance_statistics) }
- end
- end
-
describe 'slash commands' do
context 'regular user' do
it { is_expected.to be_allowed(:use_slash_commands) }
diff --git a/spec/presenters/alert_management/alert_presenter_spec.rb b/spec/presenters/alert_management/alert_presenter_spec.rb
index 3b7920dfd5e..7d0dbead7a0 100644
--- a/spec/presenters/alert_management/alert_presenter_spec.rb
+++ b/spec/presenters/alert_management/alert_presenter_spec.rb
@@ -4,8 +4,7 @@ require 'spec_helper'
RSpec.describe AlertManagement::AlertPresenter do
let_it_be(:project) { create(:project) }
-
- let_it_be(:generic_payload) do
+ let_it_be(:payload) do
{
'title' => 'Alert title',
'start_time' => '2020-04-27T10:10:22.265949279Z',
@@ -20,42 +19,108 @@ RSpec.describe AlertManagement::AlertPresenter do
}
end
- let_it_be(:alert) do
- create(:alert_management_alert, :with_description, :with_host, :with_service, :with_monitoring_tool, project: project, payload: generic_payload)
- end
-
+ let_it_be(:alert) { create(:alert_management_alert, project: project, payload: payload) }
let(:alert_url) { "http://localhost/#{project.full_path}/-/alert_management/#{alert.iid}/details" }
subject(:presenter) { described_class.new(alert) }
describe '#issue_description' do
+ let_it_be(:alert) { create(:alert_management_alert, project: project, payload: {}) }
+
let(:markdown_line_break) { ' ' }
- it 'returns an alert issue description' do
- expect(presenter.issue_description).to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}#{markdown_line_break}
- **Severity:** #{presenter.severity}#{markdown_line_break}
- **Service:** #{alert.service}#{markdown_line_break}
- **Monitoring tool:** #{alert.monitoring_tool}#{markdown_line_break}
- **Hosts:** #{alert.hosts.join(' ')}#{markdown_line_break}
- **Description:** #{alert.description}#{markdown_line_break}
- **GitLab alert:** #{alert_url}
-
- #### Alert Details
-
- **title:** Alert title#{markdown_line_break}
- **start_time:** 2020-04-27T10:10:22.265949279Z#{markdown_line_break}
- **custom.alert.fields:** ["one", "two"]#{markdown_line_break}
- **yet.another:** 73
- MARKDOWN
- )
+ subject { presenter.issue_description }
+
+ context 'with an empty payload' do
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
+ **Severity:** #{presenter.severity}#{markdown_line_break}
+ **GitLab alert:** #{alert_url}
+
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'with optional alert attributes' do
+ let_it_be(:alert) do
+ create(:alert_management_alert, :with_description, :with_host, :with_service, :with_monitoring_tool, project: project, payload: payload)
+ end
+
+ before do
+ allow(alert.parsed_payload).to receive(:full_query).and_return('metric > 1')
+ end
+
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
+ **Severity:** #{presenter.severity}#{markdown_line_break}
+ **full_query:** `metric > 1`#{markdown_line_break}
+ **Service:** #{alert.service}#{markdown_line_break}
+ **Monitoring tool:** #{alert.monitoring_tool}#{markdown_line_break}
+ **Hosts:** #{alert.hosts.join(' ')}#{markdown_line_break}
+ **Description:** #{alert.description}#{markdown_line_break}
+ **GitLab alert:** #{alert_url}
+
+ #### Alert Details
+
+ **title:** Alert title#{markdown_line_break}
+ **start_time:** 2020-04-27T10:10:22.265949279Z#{markdown_line_break}
+ **custom.alert.fields:** ["one", "two"]#{markdown_line_break}
+ **yet.another:** 73
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'with incident markdown' do
+ before do
+ allow(alert.parsed_payload).to receive(:alert_markdown).and_return('**`markdown example`**')
+ end
+
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
+ **Severity:** #{presenter.severity}#{markdown_line_break}
+ **GitLab alert:** #{alert_url}
+
+
+ ---
+
+ **`markdown example`**
+ MARKDOWN
+ )
+ end
+ end
+
+ context 'with metrics_dashboard_url' do
+ before do
+ allow(alert.parsed_payload).to receive(:metrics_dashboard_url).and_return('https://gitlab.com/metrics')
+ end
+
+ it do
+ is_expected.to eq(
+ <<~MARKDOWN.chomp
+ **Start time:** #{presenter.start_time}#{markdown_line_break}
+ **Severity:** #{presenter.severity}#{markdown_line_break}
+ **GitLab alert:** #{alert_url}
+
+ [](https://gitlab.com/metrics)
+ MARKDOWN
+ )
+ end
end
end
- describe '#metrics_dashboard_url' do
- it 'is not defined' do
- expect(presenter.metrics_dashboard_url).to be_nil
+ describe '#start_time' do
+ it 'formats the start time of the alert' do
+ alert.started_at = Time.utc(2019, 5, 5)
+
+ expect(presenter.start_time). to eq('05 May 2019, 12:00AM (UTC)')
end
end
diff --git a/spec/presenters/alert_management/prometheus_alert_presenter_spec.rb b/spec/presenters/alert_management/prometheus_alert_presenter_spec.rb
deleted file mode 100644
index 74c77b70e5a..00000000000
--- a/spec/presenters/alert_management/prometheus_alert_presenter_spec.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe AlertManagement::PrometheusAlertPresenter do
- let_it_be(:project) { create(:project) }
- let(:payload) do
- {
- 'annotations' => {
- 'title' => 'Alert title',
- 'gitlab_incident_markdown' => '**`markdown example`**',
- 'custom annotation' => 'custom annotation value'
- },
- 'startsAt' => '2020-04-27T10:10:22.265949279Z',
- 'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
- }
- end
-
- let!(:alert) do
- create(:alert_management_alert, :prometheus, project: project, payload: payload)
- end
-
- let(:alert_url) { "http://localhost/#{project.full_path}/-/alert_management/#{alert.iid}/details" }
-
- subject(:presenter) { described_class.new(alert) }
-
- describe '#issue_description' do
- let(:markdown_line_break) { ' ' }
-
- it 'returns an alert issue description' do
- expect(presenter.issue_description).to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}#{markdown_line_break}
- **Severity:** #{presenter.severity}#{markdown_line_break}
- **full_query:** `vector(1)`#{markdown_line_break}
- **Monitoring tool:** Prometheus#{markdown_line_break}
- **GitLab alert:** #{alert_url}
-
- #### Alert Details
-
- **annotations.custom annotation:** custom annotation value#{markdown_line_break}
- **annotations.gitlab_incident_markdown:** **`markdown example`**#{markdown_line_break}
- **annotations.title:** Alert title#{markdown_line_break}
- **startsAt:** 2020-04-27T10:10:22.265949279Z#{markdown_line_break}
- **generatorURL:** http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1
-
- ---
-
- **`markdown example`**
- MARKDOWN
- )
- end
- end
-
- describe '#metrics_dashboard_url' do
- subject { presenter.metrics_dashboard_url }
-
- context 'for a non-prometheus alert' do
- it { is_expected.to be_nil }
- end
-
- context 'for a self-managed prometheus alert' do
- include_context 'self-managed prometheus alert attributes'
-
- it { is_expected.to eq(dashboard_url_for_alert) }
- end
-
- context 'for a gitlab-managed prometheus alert' do
- include_context 'gitlab-managed prometheus alert attributes'
-
- it { is_expected.to eq(dashboard_url_for_alert) }
- end
- end
-end
diff --git a/spec/services/alert_management/create_alert_issue_service_spec.rb b/spec/services/alert_management/create_alert_issue_service_spec.rb
index ce0da28b13f..f2be317a13d 100644
--- a/spec/services/alert_management/create_alert_issue_service_spec.rb
+++ b/spec/services/alert_management/create_alert_issue_service_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
end
it 'sets the issue description' do
- expect(created_issue.description).to include(alert_presenter.issue_summary_markdown.strip)
+ expect(created_issue.description).to include(alert_presenter.send(:issue_summary_markdown).strip)
end
end
diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb
index fafe152912b..098e524286f 100644
--- a/spec/services/projects/alerting/notify_service_spec.rb
+++ b/spec/services/projects/alerting/notify_service_spec.rb
@@ -15,10 +15,12 @@ RSpec.describe Projects::Alerting::NotifyService do
let(:fingerprint) { 'testing' }
let(:service) { described_class.new(project, nil, payload) }
let(:environment) { create(:environment, project: project) }
+ let(:ended_at) { nil }
let(:payload_raw) do
{
title: 'alert title',
start_time: starts_at.rfc3339,
+ end_time: ended_at&.rfc3339,
severity: 'low',
monitoring_tool: 'GitLab RSpec',
service: 'GitLab Test Suite',
@@ -38,9 +40,10 @@ RSpec.describe Projects::Alerting::NotifyService do
context 'with valid token' do
let(:token) { alerts_service.token }
- let(:incident_management_setting) { double(send_email?: email_enabled, create_issue?: issue_enabled) }
+ let(:incident_management_setting) { double(send_email?: email_enabled, create_issue?: issue_enabled, auto_close_incident?: auto_close_enabled) }
let(:email_enabled) { false }
let(:issue_enabled) { false }
+ let(:auto_close_enabled) { false }
before do
allow(service)
@@ -93,6 +96,57 @@ RSpec.describe Projects::Alerting::NotifyService do
it_behaves_like 'adds an alert management alert event'
+ context 'end time given' do
+ let(:ended_at) { Time.current.change(nsec: 0) }
+
+ it 'does not resolve the alert' do
+ expect { subject }.not_to change { alert.reload.status }
+ end
+
+ it 'does not set the ended at' do
+ subject
+
+ expect(alert.reload.ended_at).to be_nil
+ end
+
+ it_behaves_like 'does not an create alert management alert'
+
+ context 'auto_close_enabled setting enabled' do
+ let(:auto_close_enabled) { true }
+
+ it 'resolves the alert and sets the end time', :aggregate_failures do
+ subject
+ alert.reload
+
+ expect(alert.resolved?).to eq(true)
+ expect(alert.ended_at).to eql(ended_at)
+ end
+
+ context 'related issue exists' do
+ let(:alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint_sha) }
+ let(:issue) { alert.issue }
+
+ context 'state_tracking is enabled' do
+ before do
+ stub_feature_flags(track_resource_state_change_events: true)
+ end
+
+ it { expect { subject }.to change { issue.reload.state }.from('opened').to('closed') }
+ it { expect { subject }.to change(ResourceStateEvent, :count).by(1) }
+ end
+
+ context 'state_tracking is disabled' do
+ before do
+ stub_feature_flags(track_resource_state_change_events: false)
+ end
+
+ it { expect { subject }.to change { issue.reload.state }.from('opened').to('closed') }
+ it { expect { subject }.to change(Note, :count).by(1) }
+ end
+ end
+ end
+ end
+
context 'existing alert is resolved' do
let!(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: fingerprint_sha) }
@@ -114,6 +168,13 @@ RSpec.describe Projects::Alerting::NotifyService do
end
end
+ context 'end time given' do
+ let(:ended_at) { Time.current }
+
+ it_behaves_like 'creates an alert management alert'
+ it_behaves_like 'assigns the alert properties'
+ end
+
context 'with a minimal payload' do
let(:payload_raw) do
{
diff --git a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
index a606371099d..cfe8e863223 100644
--- a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
@@ -4,7 +4,8 @@ require 'spec_helper'
RSpec.describe Projects::LfsPointers::LfsDownloadService do
include StubRequests
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
+
let(:lfs_content) { SecureRandom.random_bytes(10) }
let(:oid) { Digest::SHA256.hexdigest(lfs_content) }
let(:download_link) { "http://gitlab.com/#{oid}" }
@@ -14,9 +15,11 @@ RSpec.describe Projects::LfsPointers::LfsDownloadService do
subject { described_class.new(project, lfs_object) }
- before do
+ before_all do
ApplicationSetting.create_from_defaults
+ end
+ before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: local_request_setting)
allow(project).to receive(:lfs_enabled?).and_return(true)
end
@@ -226,5 +229,55 @@ RSpec.describe Projects::LfsPointers::LfsDownloadService do
subject.execute
end
end
+
+ context 'when a large lfs object with the same oid already exists' do
+ let!(:existing_lfs_object) { create(:lfs_object, :with_file, :correct_oid) }
+
+ before do
+ stub_const("#{described_class}::LARGE_FILE_SIZE", 500)
+ stub_full_request(download_link).to_return(body: lfs_content)
+ end
+
+ context 'and first fragments are the same' do
+ let(:lfs_content) { existing_lfs_object.file.read }
+
+ context 'when lfs_link_existing_object feature flag disabled' do
+ before do
+ stub_feature_flags(lfs_link_existing_object: false)
+ end
+
+ it 'does not call link_existing_lfs_object!' do
+ expect(subject).not_to receive(:link_existing_lfs_object!)
+
+ subject.execute
+ end
+ end
+
+ it 'returns success' do
+ expect(subject.execute).to eq({ status: :success })
+ end
+
+ it 'links existing lfs object to the project' do
+ expect { subject.execute }
+ .to change { project.lfs_objects.include?(existing_lfs_object) }.from(false).to(true)
+ end
+ end
+
+ context 'and first fragments diverges' do
+ let(:lfs_content) { SecureRandom.random_bytes(1000) }
+ let(:oid) { existing_lfs_object.oid }
+
+ it 'raises oid mismatch error' do
+ expect(subject.execute).to eq({
+ status: :error,
+ message: "LFS file with oid #{oid} cannot be linked with an existing LFS object"
+ })
+ end
+
+ it 'does not change lfs objects' do
+ expect { subject.execute }.not_to change { project.lfs_objects }
+ end
+ end
+ end
end
end
diff --git a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
index d59f5dbae19..0e7d16f18e8 100644
--- a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb
@@ -24,11 +24,11 @@ RSpec.describe Projects::LfsPointers::LfsLinkService do
end
it 'links existing lfs objects to the project' do
- expect(project.all_lfs_objects.count).to eq 2
+ expect(project.lfs_objects.count).to eq 2
linked = subject.execute(new_oid_list.keys)
- expect(project.all_lfs_objects.count).to eq 3
+ expect(project.lfs_objects.count).to eq 3
expect(linked.size).to eq 3
end
@@ -52,7 +52,7 @@ RSpec.describe Projects::LfsPointers::LfsLinkService do
lfs_objects = create_list(:lfs_object, 7)
linked = subject.execute(lfs_objects.pluck(:oid))
- expect(project.all_lfs_objects.count).to eq 9
+ expect(project.lfs_objects.count).to eq 9
expect(linked.size).to eq 7
end
diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb
index 6a2c55a5e55..073e2e09397 100644
--- a/spec/services/projects/unlink_fork_service_spec.rb
+++ b/spec/services/projects/unlink_fork_service_spec.rb
@@ -58,26 +58,6 @@ RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_cachin
expect(source.forks_count).to be_zero
end
- context 'when the source has LFS objects' do
- let(:lfs_object) { create(:lfs_object) }
-
- before do
- lfs_object.projects << project
- end
-
- it 'links the fork to the lfs object before unlinking' do
- subject.execute
-
- expect(lfs_object.projects).to include(forked_project)
- end
-
- it 'does not fail if the lfs objects were already linked' do
- lfs_object.projects << forked_project
-
- expect { subject.execute }.not_to raise_error
- end
- end
-
context 'when the original project was deleted' do
it 'does not fail when the original project is deleted' do
source = forked_project.forked_from_project
@@ -152,24 +132,6 @@ RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_cachin
expect(project.forks_count).to be_zero
end
- context 'when given project is a fork of an unlinked parent' do
- let!(:fork_of_fork) { fork_project(forked_project, user) }
- let(:lfs_object) { create(:lfs_object) }
-
- before do
- lfs_object.projects << project
- end
-
- it 'saves lfs objects to the root project' do
- # Remove parent from network
- described_class.new(forked_project, user).execute
-
- described_class.new(fork_of_fork, user).execute
-
- expect(lfs_object.projects).to include(fork_of_fork)
- end
- end
-
context 'and is node with a parent' do
subject { described_class.new(forked_project, user) }
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 0f2d4eb4b65..9c46b1e2a87 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -87,7 +87,7 @@ RSpec.describe RepositoryForkWorker do
it 'calls Projects::LfsPointers::LfsLinkService#execute with OIDs of source project LFS objects' do
expect_fork_repository(success: true)
expect_next_instance_of(Projects::LfsPointers::LfsLinkService) do |service|
- expect(service).to receive(:execute).with(project.all_lfs_objects_oids)
+ expect(service).to receive(:execute).with(project.lfs_objects_oids)
end
perform!
diff --git a/vendor/Dockerfile/Binary.Dockerfile b/vendor/Dockerfile/Binary.Dockerfile
index e7d560da9ac..850b487e18f 100644
--- a/vendor/Dockerfile/Binary.Dockerfile
+++ b/vendor/Dockerfile/Binary.Dockerfile
@@ -2,7 +2,7 @@
# You must either commit your compiled binary into source control (not recommended)
# or build the binary first as part of a CI/CD pipeline.
-FROM buildpack-deps:jessie
+FROM buildpack-deps:buster
WORKDIR /usr/local/bin
diff --git a/vendor/Dockerfile/Golang.Dockerfile b/vendor/Dockerfile/Golang.Dockerfile
index ec94914be19..f9699dff665 100644
--- a/vendor/Dockerfile/Golang.Dockerfile
+++ b/vendor/Dockerfile/Golang.Dockerfile
@@ -6,7 +6,7 @@ COPY . .
RUN go-wrapper download
RUN go build -v
-FROM buildpack-deps:jessie
+FROM buildpack-deps:buster
WORKDIR /usr/local/bin
diff --git a/yarn.lock b/yarn.lock
index 9dce1852fe8..4782fed4382 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -848,10 +848,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.164.0.tgz#6cefad871c45f945ef92b99015d0f510b1d2de4a"
integrity sha512-a9e/cYUc1QQk7azjH4x/m6/p3icavwGEi5F9ipNlDqiJtUor5tqojxvMxPOhuVbN/mTwnC6lGsSZg4tqTsdJAQ==
-"@gitlab/ui@21.0.0":
- version "21.0.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-21.0.0.tgz#3e3b725fbce21dd9d2dc290c19111b49014d4700"
- integrity sha512-3uiqhRXZurbZsGZ3YpuTGnEfZPNcatG13ynJNuHKTH6CjwlYsjxlxKnTcSHPFnrbfy+bmSfcFYs0nDQsA1xcTA==
+"@gitlab/ui@21.2.1":
+ version "21.2.1"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-21.2.1.tgz#260e308e82374224095aea59a891f8a458eace3e"
+ integrity sha512-9ne5kPMGCVHSSeWmMzcnXgB4JPKhbVQ520FvM+z3MkvTaQrxhh4H/wKD4durBusTokbrRXsOhqtuV/NI1WJjDQ==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"