Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-07-01 21:08:51 +00:00
parent cc7885bc21
commit fe25c98fa8
85 changed files with 1129 additions and 328 deletions

View File

@ -471,6 +471,8 @@ Rails/TimeZone:
# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040
Rails/SaveBang:
Enabled: true
AllowImplicitReturn: false
AllowedReceivers: ['ActionDispatch::TestRequest']
Include:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'

View File

@ -745,25 +745,35 @@ Style/StringLiteralsInInterpolation:
Style/SymbolProc:
Enabled: false
# Offense count: 1478
# Offense count: 2362
# Cop supports --auto-correct.
# Configuration parameters: AllowImplicitReturn, AllowedReceivers.
Rails/SaveBang:
Exclude:
- 'ee/spec/controllers/boards/issues_controller_spec.rb'
- 'ee/spec/controllers/boards/lists_controller_spec.rb'
- 'ee/spec/controllers/ee/sent_notifications_controller_spec.rb'
- 'ee/spec/controllers/groups/epic_issues_controller_spec.rb'
- 'ee/spec/controllers/groups/epic_links_controller_spec.rb'
- 'ee/spec/controllers/groups/epics_controller_spec.rb'
- 'ee/spec/controllers/groups/roadmap_controller_spec.rb'
- 'ee/spec/controllers/groups/sso_controller_spec.rb'
- 'ee/spec/controllers/projects/environments_controller_spec.rb'
- 'ee/spec/controllers/projects/issues_controller_spec.rb'
- 'ee/spec/controllers/projects/merge_requests/creations_controller_spec.rb'
- 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
- 'ee/spec/controllers/projects/project_members_controller_spec.rb'
- 'ee/spec/controllers/projects/service_desk_controller_spec.rb'
- 'ee/spec/controllers/projects/subscriptions_controller_spec.rb'
- 'ee/spec/controllers/projects/vulnerability_feedback_controller_spec.rb'
- 'ee/spec/controllers/subscriptions_controller_spec.rb'
- 'ee/spec/factories/ci/job_artifacts.rb'
- 'ee/spec/factories/epics.rb'
- 'ee/spec/factories/licenses.rb'
- 'ee/spec/factories/merge_requests.rb'
- 'ee/spec/features/admin/admin_users_spec.rb'
- 'ee/spec/features/admin/geo/admin_geo_nodes_spec.rb'
- 'ee/spec/features/admin/licenses/admin_views_license_spec.rb'
- 'ee/spec/features/boards/scoped_issue_board_spec.rb'
- 'ee/spec/features/ci_shared_runner_warnings_spec.rb'
- 'ee/spec/features/dashboards/operations_spec.rb'
@ -772,13 +782,19 @@ Rails/SaveBang:
- 'ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb'
- 'ee/spec/features/projects/members/invite_group_and_members_spec.rb'
- 'ee/spec/features/projects/merge_requests/user_approves_merge_request_spec.rb'
- 'ee/spec/features/projects/mirror_spec.rb'
- 'ee/spec/features/projects/new_project_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_approval_settings_spec.rb'
- 'ee/spec/features/projects/settings/user_manages_members_spec.rb'
- 'ee/spec/features/search/elastic/global_search_spec.rb'
- 'ee/spec/features/security/project/internal_access_spec.rb'
- 'ee/spec/features/security/project/public_access_spec.rb'
- 'ee/spec/finders/epics_finder_spec.rb'
- 'ee/spec/finders/security/vulnerabilities_finder_spec.rb'
- 'ee/spec/frontend/fixtures/analytics.rb'
- 'ee/spec/graphql/resolvers/vulnerabilities_resolver_spec.rb'
- 'ee/spec/helpers/application_helper_spec.rb'
- 'ee/spec/helpers/ee/dashboard_helper_spec.rb'
- 'ee/spec/helpers/ee/issues_helper_spec.rb'
- 'ee/spec/initializers/fog_google_https_private_urls_spec.rb'
- 'ee/spec/lib/analytics/merge_request_metrics_calculator_spec.rb'
@ -787,66 +803,93 @@ Rails/SaveBang:
- 'ee/spec/lib/ee/gitlab/background_migration/move_epic_issues_after_epics_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/populate_any_approval_rule_for_merge_requests_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/populate_any_approval_rule_for_projects_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/prune_orphaned_geo_events_spec.rb'
- 'ee/spec/lib/ee/gitlab/checks/push_rules/commit_check_spec.rb'
- 'ee/spec/lib/ee/gitlab/ci/pipeline/quota/activity_spec.rb'
- 'ee/spec/lib/gitlab/auth/ldap/access_spec.rb'
- 'ee/spec/lib/gitlab/auth/o_auth/user_spec.rb'
- 'ee/spec/lib/gitlab/auth/saml/user_spec.rb'
- 'ee/spec/lib/gitlab/background_migration/fix_orphan_promoted_issues_spec.rb'
- 'ee/spec/lib/gitlab/elastic/search_results_spec.rb'
- 'ee/spec/lib/gitlab/email/handler/ee/service_desk_handler_spec.rb'
- 'ee/spec/lib/gitlab/geo/cron_manager_spec.rb'
- 'ee/spec/lib/gitlab/geo/jwt_request_decoder_spec.rb'
- 'ee/spec/lib/gitlab/geo/oauth/session_spec.rb'
- 'ee/spec/lib/gitlab/geo_spec.rb'
- 'ee/spec/lib/gitlab/git_access_spec.rb'
- 'ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb'
- 'ee/spec/lib/gitlab/mirror_spec.rb'
- 'ee/spec/mailers/notify_spec.rb'
- 'ee/spec/migrations/fix_any_approver_rule_for_projects_spec.rb'
- 'ee/spec/migrations/geo/migrate_ci_job_artifacts_to_separate_registry_spec.rb'
- 'ee/spec/migrations/geo/migrate_lfs_objects_to_separate_registry_spec.rb'
- 'ee/spec/migrations/schedule_merge_request_any_approval_rule_migration_spec.rb'
- 'ee/spec/migrations/schedule_project_any_approval_rule_migration_spec.rb'
- 'ee/spec/models/application_setting_spec.rb'
- 'ee/spec/models/approval_merge_request_rule_spec.rb'
- 'ee/spec/models/approval_project_rule_spec.rb'
- 'ee/spec/models/approval_state_spec.rb'
- 'ee/spec/models/burndown_spec.rb'
- 'ee/spec/models/ci/build_spec.rb'
- 'ee/spec/models/ci/pipeline_spec.rb'
- 'ee/spec/models/ci/subscriptions/project_spec.rb'
- 'ee/spec/models/concerns/approver_migrate_hook_spec.rb'
- 'ee/spec/models/concerns/deprecated_approvals_before_merge_spec.rb'
- 'ee/spec/models/concerns/elastic/note_spec.rb'
- 'ee/spec/models/ee/appearance_spec.rb'
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
- 'ee/spec/models/ee/protected_branch_spec.rb'
- 'ee/spec/models/ee/protected_ref_access_spec.rb'
- 'ee/spec/models/ee/protected_ref_spec.rb'
- 'ee/spec/models/elasticsearch_indexed_namespace_spec.rb'
- 'ee/spec/models/environment_spec.rb'
- 'ee/spec/models/epic_spec.rb'
- 'ee/spec/models/geo/project_registry_spec.rb'
- 'ee/spec/models/geo_node_spec.rb'
- 'ee/spec/models/geo_node_status_spec.rb'
- 'ee/spec/models/gitlab_subscription_spec.rb'
- 'ee/spec/models/group_spec.rb'
- 'ee/spec/models/issue_spec.rb'
- 'ee/spec/models/label_note_spec.rb'
- 'ee/spec/models/lfs_object_spec.rb'
- 'ee/spec/models/license_spec.rb'
- 'ee/spec/models/merge_request_spec.rb'
- 'ee/spec/models/merge_train_spec.rb'
- 'ee/spec/models/operations/feature_flag_scope_spec.rb'
- 'ee/spec/models/operations/feature_flag_spec.rb'
- 'ee/spec/models/operations/feature_flags/strategy_spec.rb'
- 'ee/spec/models/operations/feature_flags/user_list_spec.rb'
- 'ee/spec/models/packages/package_spec.rb'
- 'ee/spec/models/project_ci_cd_setting_spec.rb'
- 'ee/spec/models/project_services/github_service_spec.rb'
- 'ee/spec/models/project_services/jenkins_service_spec.rb'
- 'ee/spec/models/project_spec.rb'
- 'ee/spec/models/protected_environment_spec.rb'
- 'ee/spec/models/repository_spec.rb'
- 'ee/spec/models/scim_identity_spec.rb'
- 'ee/spec/models/scim_oauth_access_token_spec.rb'
- 'ee/spec/models/upload_spec.rb'
- 'ee/spec/models/user_preference_spec.rb'
- 'ee/spec/models/user_spec.rb'
- 'ee/spec/models/visible_approvable_spec.rb'
- 'ee/spec/models/vulnerabilities/feedback_spec.rb'
- 'ee/spec/models/vulnerabilities/issue_link_spec.rb'
- 'ee/spec/policies/group_policy_spec.rb'
- 'ee/spec/policies/note_policy_spec.rb'
- 'ee/spec/policies/project_policy_spec.rb'
- 'ee/spec/policies/protected_branch_policy_spec.rb'
- 'ee/spec/policies/vulnerabilities/feedback_policy_spec.rb'
- 'ee/spec/presenters/audit_event_presenter_spec.rb'
- 'ee/spec/presenters/epic_presenter_spec.rb'
- 'ee/spec/presenters/packages/conan/package_presenter_spec.rb'
- 'ee/spec/requests/api/boards_spec.rb'
- 'ee/spec/requests/api/conan_packages_spec.rb'
- 'ee/spec/requests/api/epic_issues_spec.rb'
- 'ee/spec/requests/api/epic_links_spec.rb'
- 'ee/spec/requests/api/epics_spec.rb'
- 'ee/spec/requests/api/geo_nodes_spec.rb'
- 'ee/spec/requests/api/geo_spec.rb'
- 'ee/spec/requests/api/go_proxy_spec.rb'
- 'ee/spec/requests/api/graphql/group/epics_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/epic_tree/reorder_spec.rb'
- 'ee/spec/requests/api/groups_spec.rb'
@ -861,9 +904,15 @@ Rails/SaveBang:
- 'ee/spec/requests/api/protected_branches_spec.rb'
- 'ee/spec/requests/api/scim_spec.rb'
- 'ee/spec/requests/api/todos_spec.rb'
- 'ee/spec/requests/lfs_http_spec.rb'
- 'ee/spec/services/approval_rules/finalize_service_spec.rb'
- 'ee/spec/services/approval_rules/update_service_spec.rb'
- 'ee/spec/services/ci/minutes/email_notification_service_spec.rb'
- 'ee/spec/services/ci/process_build_service_spec.rb'
- 'ee/spec/services/ci/register_job_service_spec.rb'
- 'ee/spec/services/ee/boards/issues/create_service_spec.rb'
- 'ee/spec/services/ee/boards/issues/list_service_spec.rb'
- 'ee/spec/services/ee/boards/lists/list_service_spec.rb'
- 'ee/spec/services/ee/issuable/clone/attributes_rewriter_spec.rb'
- 'ee/spec/services/ee/issuable/common_system_notes_service_spec.rb'
- 'ee/spec/services/ee/issues/update_service_spec.rb'
@ -872,13 +921,15 @@ Rails/SaveBang:
- 'ee/spec/services/ee/notes/quick_actions_service_spec.rb'
- 'ee/spec/services/ee/notification_service_spec.rb'
- 'ee/spec/services/ee/resource_events/change_weight_service_spec.rb'
- 'ee/spec/services/elastic/index_record_service_spec.rb'
- 'ee/spec/services/epic_links/create_service_spec.rb'
- 'ee/spec/services/epics/close_service_spec.rb'
- 'ee/spec/services/epics/issue_promote_service_spec.rb'
- 'ee/spec/services/epics/reopen_service_spec.rb'
- 'ee/spec/services/epics/tree_reorder_service_spec.rb'
- 'ee/spec/services/epics/update_dates_service_spec.rb'
- 'ee/spec/services/epics/update_service_spec.rb'
- 'ee/spec/services/geo/blob_verification_secondary_service_spec.rb'
- 'ee/spec/services/geo/files_expire_service_spec.rb'
- 'ee/spec/services/geo/metrics_update_service_spec.rb'
- 'ee/spec/services/geo/registry_consistency_service_spec.rb'
- 'ee/spec/services/geo/repository_verification_secondary_service_spec.rb'
@ -887,8 +938,12 @@ Rails/SaveBang:
- 'ee/spec/services/lfs/unlock_file_service_spec.rb'
- 'ee/spec/services/merge_requests/approval_service_spec.rb'
- 'ee/spec/services/merge_requests/remove_approval_service_spec.rb'
- 'ee/spec/services/merge_requests/update_blocks_service_spec.rb'
- 'ee/spec/services/merge_trains/refresh_merge_request_service_spec.rb'
- 'ee/spec/services/packages/conan/create_package_file_service_spec.rb'
- 'ee/spec/services/projects/after_rename_service_spec.rb'
- 'ee/spec/services/projects/import_export/export_service_spec.rb'
- 'ee/spec/services/projects/update_mirror_service_spec.rb'
- 'ee/spec/services/projects/update_service_spec.rb'
- 'ee/spec/services/quick_actions/interpret_service_spec.rb'
- 'ee/spec/services/slash_commands/global_slack_handler_spec.rb'
@ -896,50 +951,94 @@ Rails/SaveBang:
- 'ee/spec/services/status_page/trigger_publish_service_spec.rb'
- 'ee/spec/services/todo_service_spec.rb'
- 'ee/spec/services/update_build_minutes_service_spec.rb'
- 'ee/spec/services/vulnerability_feedback/create_service_spec.rb'
- 'ee/spec/support/helpers/ee/geo_helpers.rb'
- 'ee/spec/support/protected_tags/access_control_shared_examples.rb'
- 'ee/spec/support/shared_examples/features/protected_branches_access_control_shared_examples.rb'
- 'ee/spec/support/shared_examples/finders/geo/framework_registry_finder_shared_examples.rb'
- 'ee/spec/support/shared_examples/graphql/geo/geo_registries_resolver_shared_examples.rb'
- 'ee/spec/support/shared_examples/lib/analytics/common_merge_request_metrics_refresh_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/concerns/replicator_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/elasticsearch_indexed_container_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/geo_framework_registry_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/member_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/mentionable_shared_examples.rb'
- 'ee/spec/support/shared_examples/policies/protected_environments_shared_examples.rb'
- 'ee/spec/support/shared_examples/requests/api/graphql/geo/registries_shared_examples.rb'
- 'ee/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb'
- 'ee/spec/support/shared_examples/requests/api/project_approval_rules_api_shared_examples.rb'
- 'ee/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/build_execute_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/issue_epic_shared_examples.rb'
- 'ee/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb'
- 'ee/spec/workers/adjourned_project_deletion_worker_spec.rb'
- 'ee/spec/workers/clear_shared_runners_minutes_worker_spec.rb'
- 'ee/spec/workers/create_github_webhook_worker_spec.rb'
- 'ee/spec/workers/elastic_indexer_worker_spec.rb'
- 'ee/spec/workers/elastic_namespace_rollout_worker_spec.rb'
- 'ee/spec/workers/geo/container_repository_sync_dispatch_worker_spec.rb'
- 'ee/spec/workers/geo/file_download_dispatch_worker_spec.rb'
- 'ee/spec/workers/geo/prune_event_log_worker_spec.rb'
- 'ee/spec/workers/geo/registry_sync_worker_spec.rb'
- 'ee/spec/workers/geo/repository_shard_sync_worker_spec.rb'
- 'ee/spec/workers/repository_import_worker_spec.rb'
- 'ee/spec/workers/update_all_mirrors_worker_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_http_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_ssh_with_key_spec.rb'
- 'spec/controllers/abuse_reports_controller_spec.rb'
- 'spec/controllers/admin/impersonations_controller_spec.rb'
- 'spec/controllers/admin/runners_controller_spec.rb'
- 'spec/controllers/admin/services_controller_spec.rb'
- 'spec/controllers/boards/issues_controller_spec.rb'
- 'spec/controllers/groups/milestones_controller_spec.rb'
- 'spec/controllers/groups/runners_controller_spec.rb'
- 'spec/controllers/groups/uploads_controller_spec.rb'
- 'spec/controllers/groups_controller_spec.rb'
- 'spec/controllers/oauth/authorizations_controller_spec.rb'
- 'spec/controllers/omniauth_callbacks_controller_spec.rb'
- 'spec/controllers/profiles/emails_controller_spec.rb'
- 'spec/controllers/profiles/notifications_controller_spec.rb'
- 'spec/controllers/projects/artifacts_controller_spec.rb'
- 'spec/controllers/projects/cycle_analytics/events_controller_spec.rb'
- 'spec/controllers/projects/cycle_analytics_controller_spec.rb'
- 'spec/controllers/projects/discussions_controller_spec.rb'
- 'spec/controllers/projects/forks_controller_spec.rb'
- 'spec/controllers/projects/group_links_controller_spec.rb'
- 'spec/controllers/projects/imports_controller_spec.rb'
- 'spec/controllers/projects/issues_controller_spec.rb'
- 'spec/controllers/projects/labels_controller_spec.rb'
- 'spec/controllers/projects/merge_requests_controller_spec.rb'
- 'spec/controllers/projects/milestones_controller_spec.rb'
- 'spec/controllers/projects/notes_controller_spec.rb'
- 'spec/controllers/projects/pipelines_controller_spec.rb'
- 'spec/controllers/projects/releases/evidences_controller_spec.rb'
- 'spec/controllers/projects/runners_controller_spec.rb'
- 'spec/controllers/projects/starrers_controller_spec.rb'
- 'spec/controllers/projects/uploads_controller_spec.rb'
- 'spec/controllers/projects_controller_spec.rb'
- 'spec/controllers/sent_notifications_controller_spec.rb'
- 'spec/controllers/sessions_controller_spec.rb'
- 'spec/controllers/users_controller_spec.rb'
- 'spec/factories/alert_management/alerts.rb'
- 'spec/factories/boards.rb'
- 'spec/factories/ci/pipelines.rb'
- 'spec/factories/design_management/designs.rb'
- 'spec/factories/design_management/versions.rb'
- 'spec/factories/emails.rb'
- 'spec/factories/issues.rb'
- 'spec/factories/labels.rb'
- 'spec/factories/merge_requests.rb'
- 'spec/factories/plans.rb'
- 'spec/factories/projects.rb'
- 'spec/factories/services.rb'
- 'spec/factories/wiki_pages.rb'
- 'spec/factories_spec.rb'
- 'spec/features/admin/admin_appearance_spec.rb'
- 'spec/features/admin/admin_labels_spec.rb'
- 'spec/features/admin/admin_mode/login_spec.rb'
- 'spec/features/admin/admin_runners_spec.rb'
- 'spec/features/admin/admin_sees_project_statistics_spec.rb'
- 'spec/features/admin/admin_sees_projects_statistics_spec.rb'
- 'spec/features/admin/admin_users_impersonation_tokens_spec.rb'
- 'spec/features/admin/admin_users_spec.rb'
- 'spec/features/boards/sidebar_spec.rb'
@ -951,6 +1050,7 @@ Rails/SaveBang:
- 'spec/features/dashboard/projects_spec.rb'
- 'spec/features/error_tracking/user_sees_error_index_spec.rb'
- 'spec/features/groups/members/request_access_spec.rb'
- 'spec/features/issuables/close_reopen_report_toggle_spec.rb'
- 'spec/features/issues/bulk_assignment_labels_spec.rb'
- 'spec/features/issues/gfm_autocomplete_spec.rb'
- 'spec/features/issues/issue_sidebar_spec.rb'
@ -965,30 +1065,45 @@ Rails/SaveBang:
- 'spec/features/merge_request/user_posts_diff_notes_spec.rb'
- 'spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb'
- 'spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb'
- 'spec/features/merge_request/user_sees_discussions_spec.rb'
- 'spec/features/merge_request/user_sees_merge_widget_spec.rb'
- 'spec/features/merge_request/user_sees_versions_spec.rb'
- 'spec/features/merge_requests/user_mass_updates_spec.rb'
- 'spec/features/profiles/emails_spec.rb'
- 'spec/features/profiles/password_spec.rb'
- 'spec/features/profiles/personal_access_tokens_spec.rb'
- 'spec/features/projects/features_visibility_spec.rb'
- 'spec/features/projects/fork_spec.rb'
- 'spec/features/projects/jobs/permissions_spec.rb'
- 'spec/features/projects/jobs_spec.rb'
- 'spec/features/projects/members/user_requests_access_spec.rb'
- 'spec/features/projects/pages_lets_encrypt_spec.rb'
- 'spec/features/projects/pages_spec.rb'
- 'spec/features/projects/pipelines/pipeline_spec.rb'
- 'spec/features/projects/pipelines/pipelines_spec.rb'
- 'spec/features/projects/remote_mirror_spec.rb'
- 'spec/features/projects/services/user_activates_slack_notifications_spec.rb'
- 'spec/features/projects/settings/access_tokens_spec.rb'
- 'spec/features/projects/show/user_sees_deletion_failure_message_spec.rb'
- 'spec/features/projects/user_sees_sidebar_spec.rb'
- 'spec/features/projects/wiki/user_updates_wiki_page_spec.rb'
- 'spec/features/projects/wiki/user_views_wiki_page_spec.rb'
- 'spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb'
- 'spec/features/runners_spec.rb'
- 'spec/features/security/project/internal_access_spec.rb'
- 'spec/features/security/project/private_access_spec.rb'
- 'spec/features/security/project/public_access_spec.rb'
- 'spec/features/users/login_spec.rb'
- 'spec/features/users/show_spec.rb'
- 'spec/finders/admin/projects_finder_spec.rb'
- 'spec/finders/autocomplete/move_to_project_finder_spec.rb'
- 'spec/finders/ci/pipelines_for_merge_request_finder_spec.rb'
- 'spec/finders/group_descendants_finder_spec.rb'
- 'spec/finders/group_projects_finder_spec.rb'
- 'spec/finders/issues_finder_spec.rb'
- 'spec/finders/joined_groups_finder_spec.rb'
- 'spec/finders/merge_requests_finder_spec.rb'
- 'spec/finders/personal_projects_finder_spec.rb'
- 'spec/finders/projects_finder_spec.rb'
- 'spec/finders/uploader_finder_spec.rb'
- 'spec/frontend/fixtures/issues.rb'
@ -997,6 +1112,11 @@ Rails/SaveBang:
- 'spec/graphql/mutations/merge_requests/set_wip_spec.rb'
- 'spec/graphql/resolvers/boards_resolver_spec.rb'
- 'spec/helpers/appearances_helper_spec.rb'
- 'spec/helpers/auto_devops_helper_spec.rb'
- 'spec/helpers/issuables_helper_spec.rb'
- 'spec/helpers/issues_helper_spec.rb'
- 'spec/helpers/members_helper_spec.rb'
- 'spec/helpers/notes_helper_spec.rb'
- 'spec/helpers/profiles_helper_spec.rb'
- 'spec/helpers/projects/alert_management_helper_spec.rb'
- 'spec/helpers/projects_helper_spec.rb'
@ -1006,18 +1126,23 @@ Rails/SaveBang:
- 'spec/lib/after_commit_queue_spec.rb'
- 'spec/lib/backup/manager_spec.rb'
- 'spec/lib/banzai/reference_parser/external_issue_parser_spec.rb'
- 'spec/lib/banzai/reference_redactor_spec.rb'
- 'spec/lib/gitlab/alerting/alert_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb'
- 'spec/lib/gitlab/auth/ldap/user_spec.rb'
- 'spec/lib/gitlab/auth/o_auth/user_spec.rb'
- 'spec/lib/gitlab/auth/saml/user_spec.rb'
- 'spec/lib/gitlab/auth_spec.rb'
- 'spec/lib/gitlab/authorized_keys_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb'
- 'spec/lib/gitlab/background_migration/digest_column_spec.rb'
- 'spec/lib/gitlab/background_migration/encrypt_columns_spec.rb'
- 'spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb'
- 'spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb'
- 'spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb'
- 'spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb'
- 'spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb'
@ -1032,82 +1157,130 @@ Rails/SaveBang:
- 'spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb'
- 'spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb'
- 'spec/lib/gitlab/background_migration/remove_restricted_todos_spec.rb'
- 'spec/lib/gitlab/background_migration/reset_merge_status_spec.rb'
- 'spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb'
- 'spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb'
- 'spec/lib/gitlab/bitbucket_server_import/importer_spec.rb'
- 'spec/lib/gitlab/ci/ansi2json/style_spec.rb'
- 'spec/lib/gitlab/ci/status/build/common_spec.rb'
- 'spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb'
- 'spec/lib/gitlab/cycle_analytics/events_spec.rb'
- 'spec/lib/gitlab/database/custom_structure_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
- 'spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb'
- 'spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
- 'spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb'
- 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb'
- 'spec/lib/gitlab/git/object_pool_spec.rb'
- 'spec/lib/gitlab/git/remote_mirror_spec.rb'
- 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/git_access_spec.rb'
- 'spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb'
- 'spec/lib/gitlab/gitaly_client/repository_service_spec.rb'
- 'spec/lib/gitlab/import_export/avatar_saver_spec.rb'
- 'spec/lib/gitlab/import_export/base/relation_factory_spec.rb'
- 'spec/lib/gitlab/import_export/design_repo_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb'
- 'spec/lib/gitlab/import_export/fork_spec.rb'
- 'spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb'
- 'spec/lib/gitlab/import_export/group/relation_factory_spec.rb'
- 'spec/lib/gitlab/import_export/group/tree_saver_spec.rb'
- 'spec/lib/gitlab/import_export/importer_spec.rb'
- 'spec/lib/gitlab/import_export/lfs_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/lfs_saver_spec.rb'
- 'spec/lib/gitlab/import_export/members_mapper_spec.rb'
- 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/project/tree_saver_spec.rb'
- 'spec/lib/gitlab/import_export/repo_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/saver_spec.rb'
- 'spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb'
- 'spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb'
- 'spec/lib/gitlab/import_export/uploads_manager_spec.rb'
- 'spec/lib/gitlab/import_export/uploads_saver_spec.rb'
- 'spec/lib/gitlab/import_export/wiki_restorer_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb'
- 'spec/lib/gitlab/lets_encrypt/client_spec.rb'
- 'spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb'
- 'spec/lib/gitlab/markdown_cache/redis/store_spec.rb'
- 'spec/lib/gitlab/middleware/go_spec.rb'
- 'spec/lib/gitlab/shard_health_cache_spec.rb'
- 'spec/lib/mattermost/command_spec.rb'
- 'spec/lib/mattermost/session_spec.rb'
- 'spec/lib/mattermost/team_spec.rb'
- 'spec/mailers/notify_spec.rb'
- 'spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb'
- 'spec/migrations/20200122123016_backfill_project_settings_spec.rb'
- 'spec/migrations/20200123155929_remove_invalid_jira_data_spec.rb'
- 'spec/migrations/20200127090233_remove_invalid_issue_tracker_data_spec.rb'
- 'spec/migrations/20200130145430_reschedule_migrate_issue_trackers_data_spec.rb'
- 'spec/migrations/20200313203550_remove_orphaned_chat_names_spec.rb'
- 'spec/migrations/20200406102120_backfill_deployment_clusters_from_deployments_spec.rb'
- 'spec/migrations/20200526115436_dedup_mr_metrics_spec.rb'
- 'spec/migrations/add_deploy_token_type_to_deploy_tokens_spec.rb'
- 'spec/migrations/add_incident_settings_to_all_existing_projects_spec.rb'
- 'spec/migrations/add_unique_constraint_to_approvals_user_id_and_merge_request_id_spec.rb'
- 'spec/migrations/backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table_spec.rb'
- 'spec/migrations/backfill_imported_snippet_repositories_spec.rb'
- 'spec/migrations/backfill_releases_table_updated_at_and_add_not_null_constraints_to_timestamps_spec.rb'
- 'spec/migrations/backfill_snippet_repositories_spec.rb'
- 'spec/migrations/encrypt_plaintext_attributes_on_application_settings_spec.rb'
- 'spec/migrations/enqueue_reset_merge_status_second_run_spec.rb'
- 'spec/migrations/enqueue_reset_merge_status_spec.rb'
- 'spec/migrations/fill_file_store_lfs_objects_spec.rb'
- 'spec/migrations/fill_store_uploads_spec.rb'
- 'spec/migrations/fix_null_type_labels_spec.rb'
- 'spec/migrations/fix_pool_repository_source_project_id_spec.rb'
- 'spec/migrations/fix_projects_without_project_feature_spec.rb'
- 'spec/migrations/fix_projects_without_prometheus_services_spec.rb'
- 'spec/migrations/fix_wrong_pages_access_level_spec.rb'
- 'spec/migrations/insert_project_hooks_plan_limits_spec.rb'
- 'spec/migrations/migrate_auto_dev_ops_domain_to_cluster_domain_spec.rb'
- 'spec/migrations/move_limits_from_plans_spec.rb'
- 'spec/migrations/populate_project_statistics_packages_size_spec.rb'
- 'spec/migrations/schedule_link_lfs_objects_projects_spec.rb'
- 'spec/migrations/schedule_populate_merge_request_assignees_table_spec.rb'
- 'spec/migrations/seed_repository_storages_weighted_spec.rb'
- 'spec/models/appearance_spec.rb'
- 'spec/models/application_record_spec.rb'
- 'spec/models/application_setting_spec.rb'
- 'spec/models/ci/build_metadata_spec.rb'
- 'spec/models/ci/build_spec.rb'
- 'spec/models/ci/build_trace_chunk_spec.rb'
- 'spec/models/ci/instance_variable_spec.rb'
- 'spec/models/ci/legacy_stage_spec.rb'
- 'spec/models/ci/persistent_ref_spec.rb'
- 'spec/models/ci/pipeline_spec.rb'
- 'spec/models/ci/runner_spec.rb'
- 'spec/models/clusters/applications/helm_spec.rb'
- 'spec/models/commit_spec.rb'
- 'spec/models/commit_status_spec.rb'
- 'spec/models/concerns/avatarable_spec.rb'
- 'spec/models/concerns/bulk_insertable_associations_spec.rb'
- 'spec/models/concerns/cache_markdown_field_spec.rb'
- 'spec/models/concerns/case_sensitivity_spec.rb'
- 'spec/models/concerns/featurable_spec.rb'
- 'spec/models/concerns/issuable_spec.rb'
- 'spec/models/concerns/mentionable_spec.rb'
- 'spec/models/concerns/milestoneable_spec.rb'
- 'spec/models/concerns/milestoneish_spec.rb'
- 'spec/models/concerns/routable_spec.rb'
- 'spec/models/concerns/subscribable_spec.rb'
- 'spec/models/concerns/token_authenticatable_spec.rb'
- 'spec/models/container_repository_spec.rb'
- 'spec/models/cycle_analytics/issue_spec.rb'
- 'spec/models/cycle_analytics/plan_spec.rb'
- 'spec/models/cycle_analytics/production_spec.rb'
- 'spec/models/deploy_keys_project_spec.rb'
- 'spec/models/deploy_token_spec.rb'
- 'spec/models/deployment_spec.rb'
- 'spec/models/design_management/version_spec.rb'
- 'spec/models/diff_discussion_spec.rb'
- 'spec/models/diff_note_spec.rb'
- 'spec/models/email_spec.rb'
- 'spec/models/environment_spec.rb'
@ -1119,7 +1292,9 @@ Rails/SaveBang:
- 'spec/models/hooks/system_hook_spec.rb'
- 'spec/models/hooks/web_hook_spec.rb'
- 'spec/models/identity_spec.rb'
- 'spec/models/issue/metrics_spec.rb'
- 'spec/models/issue_spec.rb'
- 'spec/models/jira_import_state_spec.rb'
- 'spec/models/key_spec.rb'
- 'spec/models/lfs_objects_project_spec.rb'
- 'spec/models/member_spec.rb'
@ -1131,12 +1306,18 @@ Rails/SaveBang:
- 'spec/models/note_spec.rb'
- 'spec/models/notification_setting_spec.rb'
- 'spec/models/pages_domain_spec.rb'
- 'spec/models/project_auto_devops_spec.rb'
- 'spec/models/project_feature_spec.rb'
- 'spec/models/project_services/bamboo_service_spec.rb'
- 'spec/models/project_services/buildkite_service_spec.rb'
- 'spec/models/project_services/jira_service_spec.rb'
- 'spec/models/project_services/packagist_service_spec.rb'
- 'spec/models/project_services/pipelines_email_service_spec.rb'
- 'spec/models/project_services/teamcity_service_spec.rb'
- 'spec/models/project_spec.rb'
- 'spec/models/project_team_spec.rb'
- 'spec/models/protectable_dropdown_spec.rb'
- 'spec/models/redirect_route_spec.rb'
- 'spec/models/release_spec.rb'
- 'spec/models/remote_mirror_spec.rb'
- 'spec/models/resource_milestone_event_spec.rb'
@ -1147,47 +1328,73 @@ Rails/SaveBang:
- 'spec/models/upload_spec.rb'
- 'spec/models/user_preference_spec.rb'
- 'spec/models/user_spec.rb'
- 'spec/models/user_status_spec.rb'
- 'spec/models/wiki_page/meta_spec.rb'
- 'spec/models/wiki_page_spec.rb'
- 'spec/policies/ci/build_policy_spec.rb'
- 'spec/policies/ci/pipeline_policy_spec.rb'
- 'spec/policies/ci/pipeline_schedule_policy_spec.rb'
- 'spec/policies/group_policy_spec.rb'
- 'spec/policies/issue_policy_spec.rb'
- 'spec/policies/merge_request_policy_spec.rb'
- 'spec/policies/project_policy_spec.rb'
- 'spec/presenters/ci/build_runner_presenter_spec.rb'
- 'spec/presenters/ci/trigger_presenter_spec.rb'
- 'spec/requests/api/access_requests_spec.rb'
- 'spec/requests/api/boards_spec.rb'
- 'spec/requests/api/branches_spec.rb'
- 'spec/requests/api/ci/runner_spec.rb'
- 'spec/requests/api/commit_statuses_spec.rb'
- 'spec/requests/api/deployments_spec.rb'
- 'spec/requests/api/environments_spec.rb'
- 'spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb'
- 'spec/requests/api/graphql/user_query_spec.rb'
- 'spec/requests/api/graphql_spec.rb'
- 'spec/requests/api/group_import_spec.rb'
- 'spec/requests/api/group_milestones_spec.rb'
- 'spec/requests/api/internal/base_spec.rb'
- 'spec/requests/api/issues/get_group_issues_spec.rb'
- 'spec/requests/api/issues/post_projects_issues_spec.rb'
- 'spec/requests/api/jobs_spec.rb'
- 'spec/requests/api/labels_spec.rb'
- 'spec/requests/api/members_spec.rb'
- 'spec/requests/api/merge_request_diffs_spec.rb'
- 'spec/requests/api/merge_requests_spec.rb'
- 'spec/requests/api/notes_spec.rb'
- 'spec/requests/api/pages/internal_access_spec.rb'
- 'spec/requests/api/pages/private_access_spec.rb'
- 'spec/requests/api/pages/public_access_spec.rb'
- 'spec/requests/api/pipeline_schedules_spec.rb'
- 'spec/requests/api/project_import_spec.rb'
- 'spec/requests/api/project_milestones_spec.rb'
- 'spec/requests/api/projects_spec.rb'
- 'spec/requests/api/runners_spec.rb'
- 'spec/requests/api/snippets_spec.rb'
- 'spec/requests/git_http_spec.rb'
- 'spec/requests/lfs_http_spec.rb'
- 'spec/requests/profiles/notifications_controller_spec.rb'
- 'spec/requests/projects/cycle_analytics_events_spec.rb'
- 'spec/serializers/environment_status_entity_spec.rb'
- 'spec/serializers/issue_entity_spec.rb'
- 'spec/serializers/job_entity_spec.rb'
- 'spec/serializers/merge_request_poll_widget_entity_spec.rb'
- 'spec/serializers/merge_request_widget_entity_spec.rb'
- 'spec/services/auth/container_registry_authentication_service_spec.rb'
- 'spec/services/auto_merge/base_service_spec.rb'
- 'spec/services/auto_merge_service_spec.rb'
- 'spec/services/ci/create_cross_project_pipeline_service_spec.rb'
- 'spec/services/ci/create_pipeline_service_spec.rb'
- 'spec/services/ci/register_job_service_spec.rb'
- 'spec/services/ci/retry_build_service_spec.rb'
- 'spec/services/ci/update_runner_service_spec.rb'
- 'spec/services/clusters/update_service_spec.rb'
- 'spec/services/deployments/after_create_service_spec.rb'
- 'spec/services/design_management/generate_image_versions_service_spec.rb'
- 'spec/services/discussions/resolve_service_spec.rb'
- 'spec/services/draft_notes/destroy_service_spec.rb'
- 'spec/services/emails/confirm_service_spec.rb'
- 'spec/services/groups/destroy_service_spec.rb'
- 'spec/services/groups/import_export/import_service_spec.rb'
- 'spec/services/issuable/bulk_update_service_spec.rb'
- 'spec/services/issuable/clone/attributes_rewriter_spec.rb'
- 'spec/services/issuable/common_system_notes_service_spec.rb'
- 'spec/services/issues/close_service_spec.rb'
@ -1197,6 +1404,7 @@ Rails/SaveBang:
- 'spec/services/issues/update_service_spec.rb'
- 'spec/services/labels/promote_service_spec.rb'
- 'spec/services/members/destroy_service_spec.rb'
- 'spec/services/merge_requests/build_service_spec.rb'
- 'spec/services/merge_requests/conflicts/list_service_spec.rb'
- 'spec/services/merge_requests/create_service_spec.rb'
- 'spec/services/merge_requests/merge_service_spec.rb'
@ -1206,11 +1414,15 @@ Rails/SaveBang:
- 'spec/services/milestones/destroy_service_spec.rb'
- 'spec/services/milestones/promote_service_spec.rb'
- 'spec/services/milestones/transfer_service_spec.rb'
- 'spec/services/notes/create_service_spec.rb'
- 'spec/services/notification_recipients/build_service_spec.rb'
- 'spec/services/notification_service_spec.rb'
- 'spec/services/projects/after_rename_service_spec.rb'
- 'spec/services/projects/autocomplete_service_spec.rb'
- 'spec/services/projects/create_service_spec.rb'
- 'spec/services/projects/destroy_service_spec.rb'
- 'spec/services/projects/fork_service_spec.rb'
- 'spec/services/projects/hashed_storage/base_attachment_service_spec.rb'
- 'spec/services/projects/move_access_service_spec.rb'
- 'spec/services/projects/move_project_group_links_service_spec.rb'
- 'spec/services/projects/overwrite_project_service_spec.rb'
@ -1219,6 +1431,8 @@ Rails/SaveBang:
- 'spec/services/projects/update_pages_service_spec.rb'
- 'spec/services/projects/update_service_spec.rb'
- 'spec/services/quick_actions/interpret_service_spec.rb'
- 'spec/services/reset_project_cache_service_spec.rb'
- 'spec/services/resource_events/change_milestone_service_spec.rb'
- 'spec/services/system_hooks_service_spec.rb'
- 'spec/services/system_note_service_spec.rb'
- 'spec/services/system_notes/issuables_service_spec.rb'
@ -1226,42 +1440,69 @@ Rails/SaveBang:
- 'spec/services/todos/destroy/confidential_issue_service_spec.rb'
- 'spec/services/users/destroy_service_spec.rb'
- 'spec/services/users/repair_ldap_blocked_service_spec.rb'
- 'spec/services/verify_pages_domain_service_spec.rb'
- 'spec/sidekiq/cron/job_gem_dependency_spec.rb'
- 'spec/support/helpers/cycle_analytics_helpers.rb'
- 'spec/support/helpers/design_management_test_helpers.rb'
- 'spec/support/helpers/jira_service_helper.rb'
- 'spec/support/helpers/login_helpers.rb'
- 'spec/support/helpers/notification_helpers.rb'
- 'spec/support/helpers/stub_action_cable_connection.rb'
- 'spec/support/helpers/stub_object_storage.rb'
- 'spec/support/migrations_helpers/cluster_helpers.rb'
- 'spec/support/migrations_helpers/namespaces_helper.rb'
- 'spec/support/migrations_helpers/track_untracked_uploads_helpers.rb'
- 'spec/support/shared_contexts/email_shared_context.rb'
- 'spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb'
- 'spec/support/shared_contexts/mailers/notify_shared_context.rb'
- 'spec/support/shared_examples/controllers/cache_control_shared_examples.rb'
- 'spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb'
- 'spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb'
- 'spec/support/shared_examples/features/editable_merge_request_shared_examples.rb'
- 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb'
- 'spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb'
- 'spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb'
- 'spec/support/shared_examples/models/concerns/limitable_shared_examples.rb'
- 'spec/support/shared_examples/models/concerns/timebox_shared_examples.rb'
- 'spec/support/shared_examples/models/diff_note_after_commit_shared_examples.rb'
- 'spec/support/shared_examples/models/member_shared_examples.rb'
- 'spec/support/shared_examples/models/members_notifications_shared_example.rb'
- 'spec/support/shared_examples/models/mentionable_shared_examples.rb'
- 'spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb'
- 'spec/support/shared_examples/models/relative_positioning_shared_examples.rb'
- 'spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb'
- 'spec/support/shared_examples/models/update_project_statistics_shared_examples.rb'
- 'spec/support/shared_examples/models/with_uploads_shared_examples.rb'
- 'spec/support/shared_examples/policies/project_policy_shared_examples.rb'
- 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
- 'spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb'
- 'spec/support/shared_examples/requests/api/award_emoji_todo_shared_examples.rb'
- 'spec/support/shared_examples/requests/api/boards_shared_examples.rb'
- 'spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb'
- 'spec/support/shared_examples/serializers/note_entity_shared_examples.rb'
- 'spec/support/shared_examples/services/common_system_notes_shared_examples.rb'
- 'spec/support/shared_examples/services/issuable_shared_examples.rb'
- 'spec/support/shared_examples/services/wiki_pages/destroy_service_shared_examples.rb'
- 'spec/tasks/gitlab/web_hook_rake_spec.rb'
- 'spec/uploaders/file_uploader_spec.rb'
- 'spec/uploaders/object_storage_spec.rb'
- 'spec/views/notify/changed_milestone_email.html.haml_spec.rb'
- 'spec/views/projects/imports/new.html.haml_spec.rb'
- 'spec/views/projects/merge_requests/show.html.haml_spec.rb'
- 'spec/views/shared/_label_row.html.haml_spec.rb'
- 'spec/workers/concerns/project_export_options_spec.rb'
- 'spec/workers/gitlab/import/stuck_project_import_jobs_worker_spec.rb'
- 'spec/workers/gitlab/jira_import/stuck_jira_import_jobs_worker_spec.rb'
- 'spec/workers/migrate_external_diffs_worker_spec.rb'
- 'spec/workers/namespaceless_project_destroy_worker_spec.rb'
- 'spec/workers/namespaces/root_statistics_worker_spec.rb'
- 'spec/workers/pages_domain_verification_worker_spec.rb'
- 'spec/workers/process_commit_worker_spec.rb'
- 'spec/workers/propagate_integration_worker_spec.rb'
- 'spec/workers/propagate_service_template_worker_spec.rb'
- 'spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb'
- 'spec/workers/repository_check/single_repository_worker_spec.rb'
- 'spec/workers/repository_cleanup_worker_spec.rb'
- 'spec/workers/repository_import_worker_spec.rb'
- 'spec/workers/repository_update_remote_mirror_worker_spec.rb'
- 'spec/workers/stuck_ci_jobs_worker_spec.rb'
- 'spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb'

View File

@ -574,18 +574,18 @@ GEM
json-schema (2.8.0)
addressable (>= 2.4)
jwt (2.1.0)
kaminari (1.0.1)
kaminari (1.2.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.0.1)
kaminari-activerecord (= 1.0.1)
kaminari-core (= 1.0.1)
kaminari-actionview (1.0.1)
kaminari-actionview (= 1.2.1)
kaminari-activerecord (= 1.2.1)
kaminari-core (= 1.2.1)
kaminari-actionview (1.2.1)
actionview
kaminari-core (= 1.0.1)
kaminari-activerecord (1.0.1)
kaminari-core (= 1.2.1)
kaminari-activerecord (1.2.1)
activerecord
kaminari-core (= 1.0.1)
kaminari-core (1.0.1)
kaminari-core (= 1.2.1)
kaminari-core (1.2.1)
kgio (2.11.3)
knapsack (1.17.0)
rake

View File

@ -1,7 +1,5 @@
<script>
import { escape } from 'lodash';
import { GlTooltip } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import { GlTooltip, GlSprintf } from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
@ -11,6 +9,7 @@ export default {
ClipboardButton,
FileIcon,
Icon,
GlSprintf,
},
directives: {
GlTooltip,
@ -57,36 +56,6 @@ export default {
collapseIcon() {
return this.isExpanded ? 'chevron-down' : 'chevron-right';
},
errorFnText() {
return this.errorFn
? sprintf(
__(`%{spanStart}in%{spanEnd} %{errorFn}`),
{
errorFn: `<strong>${escape(this.errorFn)}</strong>`,
spanStart: `<span class="text-tertiary">`,
spanEnd: `</span>`,
},
false,
)
: '';
},
errorPositionText() {
return this.errorLine
? sprintf(
__(`%{spanStart}at line%{spanEnd} %{errorLine}%{errorColumn}`),
{
errorLine: `<strong>${this.errorLine}</strong>`,
errorColumn: this.errorColumn ? `:<strong>${this.errorColumn}</strong>` : ``,
spanStart: `<span class="text-tertiary">`,
spanEnd: `</span>`,
},
false,
)
: '';
},
errorInfo() {
return `${this.errorFnText} ${this.errorPositionText}`;
},
},
methods: {
isHighlighted(lineNum) {
@ -132,7 +101,27 @@ export default {
:text="filePath"
css-class="btn-default btn-transparent btn-clipboard position-static"
/>
<span v-html="errorInfo"></span>
<gl-sprintf v-if="errorFn" :message="__('%{spanStart}in%{spanEnd} %{errorFn}')">
<template #span="{content}">
<span class="gl-text-gray-400">{{ content }}&nbsp;</span>
</template>
<template #errorFn>
<strong>{{ errorFn }}&nbsp;</strong>
</template>
</gl-sprintf>
<gl-sprintf :message="__('%{spanStart}at line%{spanEnd} %{errorLine}%{errorColumn}')">
<template #span="{content}">
<span class="gl-text-gray-400">{{ content }}&nbsp;</span>
</template>
<template #errorLine>
<strong>{{ errorLine }}</strong>
</template>
<template #errorColumn>
<strong v-if="errorColumn">:{{ errorColumn }}</strong>
</template>
</gl-sprintf>
</div>
</div>

View File

@ -6,7 +6,7 @@
// TODO: need to move this component to graphql - https://gitlab.com/gitlab-org/gitlab/-/issues/221246
import { escape, isNumber } from 'lodash';
import { GlLink, GlTooltipDirective as GlTooltip, GlLabel } from '@gitlab/ui';
import { GlLink, GlTooltipDirective as GlTooltip, GlSprintf, GlLabel } from '@gitlab/ui';
import {
dateInWords,
formatDate,
@ -24,12 +24,15 @@ import { isScopedLabel } from '~/lib/utils/common_utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
isScopedLabel,
i18n: {
openedAgo: __('opened %{timeAgoString} by %{user}'),
},
components: {
Icon,
IssueAssignees,
GlLink,
GlLabel,
GlSprintf,
},
directives: {
GlTooltip,
@ -105,23 +108,21 @@ export default {
}
return __('Milestone');
},
openedAgoByString() {
const { author, created_at } = this.issuable;
issuableAuthor() {
return this.issuable.author;
},
issuableCreatedAt() {
return getTimeago().format(this.issuable.created_at);
},
popoverDataAttrs() {
const { id, username, name, avatar_url } = this.issuableAuthor;
return sprintf(
__('opened %{timeAgoString} by %{user}'),
{
timeAgoString: escape(getTimeago().format(created_at)),
user: `<a href="${escape(author.web_url)}"
data-user-id=${escape(author.id)}
data-username=${escape(author.username)}
data-name=${escape(author.name)}
data-avatar-url="${escape(author.avatar_url)}">
${escape(author.name)}
</a>`,
},
false,
);
return {
'data-user-id': id,
'data-username': username,
'data-name': name,
'data-avatar-url': avatar_url,
};
},
referencePath() {
return this.issuable.references.relative;
@ -167,7 +168,7 @@ export default {
mounted() {
// TODO: Refactor user popover to use its own component instead of
// spawning event listeners on Vue-rendered elements.
initUserPopovers([this.$refs.openedAgoByContainer.querySelector('a')]);
initUserPopovers([this.$refs.openedAgoByContainer.$el]);
},
methods: {
issuableLink(params) {
@ -233,9 +234,22 @@ export default {
<div class="issuable-info">
<span class="js-ref-path">{{ referencePath }}</span>
<span class="d-none d-sm-inline-block mr-1">
<span data-testid="openedByMessage" class="d-none d-sm-inline-block mr-1">
&middot;
<span ref="openedAgoByContainer" v-html="openedAgoByString"></span>
<gl-sprintf :message="$options.i18n.openedAgo">
<template #timeAgoString>
<span>{{ issuableCreatedAt }}</span>
</template>
<template #user>
<gl-link
ref="openedAgoByContainer"
v-bind="popoverDataAttrs"
:href="issuableAuthor.web_url"
>
{{ issuableAuthor.name }}
</gl-link>
</template>
</gl-sprintf>
</span>
<gl-link

View File

@ -98,6 +98,7 @@ export default {
input: {
projectPath: this.projectPath,
jiraProjectKey: project,
usersMapping: [],
},
},
update: (store, { data }) =>

View File

@ -227,6 +227,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:raw_blob_request_limit,
:namespace_storage_size_limit,
:issues_create_limit,
:default_branch_name,
disabled_oauth_sign_in_sources: [],
import_sources: [],
repository_storages: [],

View File

@ -62,7 +62,7 @@ module WikiActions
render 'shared/wikis/show'
elsif file_blob
send_blob(wiki.repository, file_blob, allow_caching: container.public?)
send_blob(wiki.repository, file_blob)
elsif show_create_form?
# Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
title = params[:id] unless params[:random_title].present?

View File

@ -34,6 +34,18 @@ class Groups::ApplicationController < ApplicationController
end
end
def authorize_create_deploy_token!
unless can?(current_user, :create_deploy_token, group)
return render_404
end
end
def authorize_destroy_deploy_token!
unless can?(current_user, :destroy_deploy_token, group)
return render_404
end
end
def authorize_admin_group_member!
unless can?(current_user, :admin_group_member, group)
return render_403

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class Groups::DeployTokensController < Groups::ApplicationController
before_action :authorize_admin_group!
before_action :authorize_destroy_deploy_token!
def revoke
@token = @group.deploy_tokens.find(params[:id])

View File

@ -4,7 +4,7 @@ module Groups
module Settings
class RepositoryController < Groups::ApplicationController
skip_cross_project_access_check :show
before_action :authorize_admin_group!
before_action :authorize_create_deploy_token!
before_action :define_deploy_token_variables
before_action do
push_frontend_feature_flag(:ajax_new_deploy_token, @group)

View File

@ -33,6 +33,8 @@ class EventsFinder
end
def execute
return Event.none if cannot_access_private_profile?
events = get_events
events = by_current_user_access(events)
@ -103,6 +105,10 @@ class EventsFinder
end
# rubocop: enable CodeReuse/ActiveRecord
def cannot_access_private_profile?
source.is_a?(User) && !Ability.allowed?(current_user, :read_user_profile, source)
end
def sort(events)
return events unless params[:sort]

View File

@ -190,6 +190,7 @@ module ApplicationSettingsHelper
:container_expiration_policies_enable_historic_entries,
:container_registry_token_expire_delay,
:default_artifacts_expire_in,
:default_branch_name,
:default_branch_protection,
:default_ci_config_path,
:default_group_visibility,

View File

@ -12,8 +12,8 @@ module EnvironmentsHelper
def environments_folder_list_view_data
{
"endpoint" => folder_project_environments_path(@project, @folder, format: :json),
"folder_name" => @folder,
"can_read_environment" => can?(current_user, :read_environment, @project).to_s
"folder-name" => @folder,
"can-read-environment" => can?(current_user, :read_environment, @project).to_s
}
end
@ -33,10 +33,10 @@ module EnvironmentsHelper
def environment_logs_data(project, environment)
{
"environment_name": environment.name,
"environments_path": project_environments_path(project, format: :json),
"environment_id": environment.id,
"cluster_applications_documentation_path" => help_page_path('user/clusters/applications.md', anchor: 'elastic-stack')
"environment-name": environment.name,
"environments-path": project_environments_path(project, format: :json),
"environment-id": environment.id,
"cluster-applications-documentation-path" => help_page_path('user/clusters/applications.md', anchor: 'elastic-stack')
}
end
@ -50,18 +50,18 @@ module EnvironmentsHelper
return {} unless project
{
'settings_path' => edit_project_service_path(project, 'prometheus'),
'clusters_path' => project_clusters_path(project),
'dashboards_endpoint' => project_performance_monitoring_dashboards_path(project, format: :json),
'default_branch' => project.default_branch,
'project_path' => project_path(project),
'tags_path' => project_tags_path(project),
'external_dashboard_url' => project.metrics_setting_external_dashboard_url,
'custom_metrics_path' => project_prometheus_metrics_path(project),
'validate_query_path' => validate_query_project_prometheus_metrics_path(project),
'custom_metrics_available' => "#{custom_metrics_available?(project)}",
'prometheus_alerts_available' => "#{can?(current_user, :read_prometheus_alerts, project)}",
'dashboard_timezone' => project.metrics_setting_dashboard_timezone.to_s.upcase
'settings-path' => edit_project_service_path(project, 'prometheus'),
'clusters-path' => project_clusters_path(project),
'dashboards-endpoint' => project_performance_monitoring_dashboards_path(project, format: :json),
'default-branch' => project.default_branch,
'project-path' => project_path(project),
'tags-path' => project_tags_path(project),
'external-dashboard-url' => project.metrics_setting_external_dashboard_url,
'custom-metrics-path' => project_prometheus_metrics_path(project),
'validate-query-path' => validate_query_project_prometheus_metrics_path(project),
'custom-metrics-available' => "#{custom_metrics_available?(project)}",
'prometheus-alerts-available' => "#{can?(current_user, :read_prometheus_alerts, project)}",
'dashboard-timezone' => project.metrics_setting_dashboard_timezone.to_s.upcase
}
end
@ -69,11 +69,11 @@ module EnvironmentsHelper
return {} unless environment
{
'metrics_dashboard_base_path' => environment_metrics_path(environment),
'current_environment_name' => environment.name,
'has_metrics' => "#{environment.has_metrics?}",
'prometheus_status' => "#{environment.prometheus_status}",
'environment_state' => "#{environment.state}"
'metrics-dashboard-base-path' => environment_metrics_path(environment),
'current-environment-name' => environment.name,
'has-metrics' => "#{environment.has_metrics?}",
'prometheus-status' => "#{environment.prometheus_status}",
'environment-state' => "#{environment.state}"
}
end
@ -81,22 +81,23 @@ module EnvironmentsHelper
return {} unless project && environment
{
'metrics_endpoint' => additional_metrics_project_environment_path(project, environment, format: :json),
'dashboard_endpoint' => metrics_dashboard_project_environment_path(project, environment, format: :json),
'deployments_endpoint' => project_environment_deployments_path(project, environment, format: :json),
'alerts_endpoint' => project_prometheus_alerts_path(project, environment_id: environment.id, format: :json)
'metrics-endpoint' => additional_metrics_project_environment_path(project, environment, format: :json),
'dashboard-endpoint' => metrics_dashboard_project_environment_path(project, environment, format: :json),
'deployments-endpoint' => project_environment_deployments_path(project, environment, format: :json),
'alerts-endpoint' => project_prometheus_alerts_path(project, environment_id: environment.id, format: :json)
}
end
def static_metrics_data
{
'documentation_path' => help_page_path('administration/monitoring/prometheus/index.md'),
'empty_getting_started_svg_path' => image_path('illustrations/monitoring/getting_started.svg'),
'empty_loading_svg_path' => image_path('illustrations/monitoring/loading.svg'),
'empty_no_data_svg_path' => image_path('illustrations/monitoring/no_data.svg'),
'empty_no_data_small_svg_path' => image_path('illustrations/chart-empty-state-small.svg'),
'empty_unable_to_connect_svg_path' => image_path('illustrations/monitoring/unable_to_connect.svg'),
'custom_dashboard_base_path' => Metrics::Dashboard::CustomDashboardService::DASHBOARD_ROOT
'documentation-path' => help_page_path('administration/monitoring/prometheus/index.md'),
'empty-getting-started-svg-path' => image_path('illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path' => image_path('illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path' => image_path('illustrations/monitoring/no_data.svg'),
'empty-no-data-small-svg-path' => image_path('illustrations/chart-empty-state-small.svg'),
'empty-unable-to-connect-svg-path' => image_path('illustrations/monitoring/unable_to_connect.svg'),
'custom-dashboard-base-path' => Metrics::Dashboard::CustomDashboardService::DASHBOARD_ROOT
}
end
end

View File

@ -50,6 +50,7 @@ module ApplicationSettingImplementation
default_artifacts_expire_in: '30 days',
default_branch_protection: Settings.gitlab['default_branch_protection'],
default_ci_config_path: nil,
default_branch_name: nil,
default_group_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_project_creation: Settings.gitlab['default_project_creation'],
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],

11
app/models/approval.rb Normal file
View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class Approval < ApplicationRecord
belongs_to :user
belongs_to :merge_request
validates :merge_request_id, presence: true
validates :user_id, presence: true, uniqueness: { scope: [:merge_request_id] }
scope :with_user, -> { joins(:user) }
end

View File

@ -73,9 +73,12 @@ class Group < Namespace
validates :variables, variable_duplicates: true
validates :two_factor_grace_period, presence: true, numericality: { greater_than_or_equal_to: 0 }
validates :name,
format: { with: Gitlab::Regex.group_name_regex,
message: Gitlab::Regex.group_name_regex_message }, if: :name_changed?
html_safety: true,
format: { with: Gitlab::Regex.group_name_regex,
message: Gitlab::Regex.group_name_regex_message },
if: :name_changed?
add_authentication_token_field :runners_token, encrypted: -> { Feature.enabled?(:groups_tokens_optional_encryption, default_enabled: true) ? :optional : :required }

View File

@ -92,6 +92,9 @@ class MergeRequest < ApplicationRecord
has_many :draft_notes
has_many :reviews, inverse_of: :merge_request
has_many :approvals, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :approved_by_users, through: :approvals, source: :user
KNOWN_MERGE_PARAMS = [
:auto_merge_strategy,
:should_remove_source_branch,
@ -519,7 +522,7 @@ class MergeRequest < ApplicationRecord
participants << merge_user
end
participants
participants.select { |participant| Ability.allowed?(participant, :read_merge_request, self) }
end
def first_commit

View File

@ -114,9 +114,7 @@ class GroupPolicy < BasePolicy
enable :create_cluster
enable :update_cluster
enable :admin_cluster
enable :destroy_deploy_token
enable :read_deploy_token
enable :create_deploy_token
end
rule { owner }.policy do
@ -128,6 +126,8 @@ class GroupPolicy < BasePolicy
enable :set_note_created_at
enable :set_emails_disabled
enable :update_default_branch_protection
enable :create_deploy_token
enable :destroy_deploy_token
end
rule { can?(:read_nested_project_resources) }.policy do

View File

@ -0,0 +1,72 @@
# frozen_string_literal: true
module Snippets
class RepositoryValidationService
attr_reader :current_user, :snippet, :repository
RepositoryValidationError = Class.new(StandardError)
def initialize(user, snippet)
@current_user = user
@snippet = snippet
@repository = snippet.repository
end
def execute
if snippet.nil?
return service_response_error('No snippet found.', 404)
end
check_branch_count!
check_branch_name_default!
check_tag_count!
check_file_count!
check_size!
ServiceResponse.success(message: 'Valid snippet repository.')
rescue RepositoryValidationError => e
ServiceResponse.error(message: "Error: #{e.message}", http_status: 400)
end
private
def check_branch_count!
return if repository.branch_count == 1
raise RepositoryValidationError, _('Repository has more than one branch.')
end
def check_branch_name_default!
branches = repository.branch_names
return if branches.first == Gitlab::Checks::SnippetCheck::DEFAULT_BRANCH
raise RepositoryValidationError, _('Repository has an invalid default branch name.')
end
def check_tag_count!
return if repository.tag_count == 0
raise RepositoryValidationError, _('Repository has tags.')
end
def check_file_count!
file_count = repository.ls_files(nil).size
limit = Snippet.max_file_limit(current_user)
if file_count > limit
raise RepositoryValidationError, _('Repository files count over the limit')
end
if file_count == 0
raise RepositoryValidationError, _('Repository must contain at least 1 file.')
end
end
def check_size!
return unless snippet.repository_size_checker.above_size_limit?
raise RepositoryValidationError, _('Repository size is above the limit.')
end
end
end

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
# HtmlSafetyValidator
#
# Validates that a value does not contain HTML
# or other unsafe content that could lead to XSS.
# Relies on Rails HTML Sanitizer:
# https://github.com/rails/rails-html-sanitizer
#
# Example:
#
# class Group < ActiveRecord::Base
# validates :name, presence: true, html_safety: true
# end
#
class HtmlSafetyValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.blank? || safe_value?(value)
record.errors.add(attribute, self.class.error_message)
end
def self.error_message
_("cannot contain HTML/XML tags, including any word between angle brackets (<,>).")
end
private
# The `FullSanitizer` encodes ampersands as the HTML entity name.
# This isn't particularly necessary for preventing XSS so the ampersand
# is pre-encoded to avoid it being flagged in the comparison.
def safe_value?(text)
pre_encoded_text = text.gsub('&', '&amp;')
Rails::Html::FullSanitizer.new.sanitize(pre_encoded_text) == pre_encoded_text
end
end

View File

@ -57,7 +57,7 @@
- @repos.each do |repo|
%tr{ id: "repo_#{repo.project_key}___#{repo.slug}", data: { project: repo.project_key, repository: repo.slug } }
%td
= link_to repo.browse_url, repo.browse_url, target: '_blank', rel: 'noopener noreferrer'
= sanitize(link_to(repo.browse_url, repo.browse_url, target: '_blank', rel: 'noopener noreferrer'), attributes: %w(href target rel))
%td.import-target
%fieldset.row
.input-group
@ -78,7 +78,7 @@
- @incompatible_repos.each do |repo|
%tr{ id: "repo_#{repo.project_key}___#{repo.slug}" }
%td
= link_to repo.browse_url, repo.browse_url, target: '_blank', rel: 'noopener noreferrer'
= sanitize(link_to(repo.browse_url, repo.browse_url, target: '_blank', rel: 'noopener noreferrer'), attributes: %w(href target rel))
%td.import-target
%td.import-actions-job-status
= label_tag 'Incompatible Project', nil, class: 'label badge-danger'

View File

@ -47,7 +47,7 @@
.issuable-meta
%ul.controls
- if issue.moved?
- if issue.closed? && issue.moved?
%li.issuable-status
= _('CLOSED (MOVED)')
- elsif issue.closed?

View File

@ -32,7 +32,7 @@
.note-header-info
%a{ href: user_path(note.author) }
%span.note-header-author-name.bold
= sanitize(note.author.name)
= note.author.name
= user_status(note.author)
%span.note-headline-light
= note.author.to_reference

View File

@ -12,7 +12,7 @@
- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description
- cache_key = project_list_cache_key(project, pipeline_status: pipeline_status)
- updated_tooltip = time_ago_with_tooltip(project.last_activity_date)
- show_pipeline_status_icon = pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project)
- show_pipeline_status_icon = pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project) && project.last_pipeline.present?
- css_controls_class = compact_mode ? [] : ["flex-lg-row", "justify-content-lg-between"]
- css_controls_class << "with-pipeline-status" if show_pipeline_status_icon
- avatar_container_class = project.creator && use_creator_avatar ? '' : 'rect-avatar'

View File

@ -0,0 +1,5 @@
---
title: Issue list page shows correct status for moved re-opened issues
merge_request: 33238
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add default_branch_name to ApplicationSettings visible attrs
merge_request: 35681
author:
type: other

View File

@ -8,6 +8,7 @@
#
---
- accessibility_testing
- advanced_deployments
- alert_management
- analysis
- api
@ -28,7 +29,7 @@
- code_testing
- collection
- compliance_management
- container_behavior_analytics
- container_host_security
- container_network_security
- container_registry
- container_scanning
@ -39,6 +40,7 @@
- dependency_proxy
- dependency_scanning
- design_management
- design_system
- devops_reports
- digital_experience_management
- disaster_recovery
@ -60,7 +62,6 @@
- helm_chart_registry
- importers
- incident_management
- incremental_rollout
- infrastructure_as_code
- integrations
- interactive_application_security_testing
@ -79,17 +80,18 @@
- malware_scanning
- merge_trains
- metrics
- navigation
- omnibus_package
- package_registry
- pages
- pki_management
- planning_analytics
- product_analytics
- projects
- quality_management
- release_evidence
- release_orchestration
- requirements_management
- responsible_disclosure
- review_apps
- roadmaps
- runbooks

View File

@ -1,4 +1,5 @@
# Be sure to restart your server when you modify this file.
Rails.application.config.action_dispatch.use_cookies_with_metadata = true
Rails.application.config.action_dispatch.cookies_serializer = :hybrid
Rails.application.config.action_dispatch.cookies_serializer =
Gitlab::Utils.to_boolean(ENV['USE_UNSAFE_HYBRID_COOKIES']) ? :hybrid : :json

View File

@ -0,0 +1,21 @@
---
# Warning: gitlab.OutdatedVersions
#
# Checks for references to versions of GitLab that are no longer supported.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence
message: 'Can this reference to "%s" be refactored?'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#importance-of-referencing-gitlab-versions-and-tiers
level: warning
nonword: true
ignorecase: true
tokens:
- "GitLab 2."
- "GitLab 3."
- "GitLab 4."
- "GitLab 5."
- "GitLab 6."
- "GitLab 7."
- "GitLab 8."
- "GitLab 9."

View File

@ -136,7 +136,8 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
## Group deploy tokens
These endpoints require group maintainer access or higher.
Group maintainers and owners can list group deploy
tokens. Only group owners can create and delete group deploy tokens.
### List group deploy tokens

View File

@ -328,6 +328,9 @@ tenses, words, and phrases:
- Don't use profanity or obscenities. Doing so may negatively affect other
users and contributors, which is contrary to GitLab's value of
[diversity and inclusion](https://about.gitlab.com/handbook/values/#diversity-inclusion).
- Avoid the use of [racially-insensitive terminology or phrases](https://www.marketplace.org/2020/06/17/tech-companies-update-language-to-avoid-offensive-terms/). For example:
- Use *primary* and *secondary* for database and server relationships.
- Use *allowlist* and *denylist* to describe access control lists.
### Word usage clarifications
@ -848,19 +851,42 @@ To indicate the steps of navigation through the UI:
## Images
Images, including screenshots, can help a reader better understand a concept.
However, they can be hard to maintain, and should be used sparingly.
Before including an image in the documentation, ensure it provides value to the reader.
### Capture the image
Use images to help the reader understand where they are in a process, or how they need to
interact with the application.
When you take screenshots:
- *Capture the most relevant area of the page.* Don't include unnecessary white
space or areas of the page that don't help illustrate your point. Also, don't
include the entire page if you don't have to, but also ensure the image
contains enough information to allow the user to determine where things are.
- *Be consistent.* Find a browser window size that works for you that also
displays all areas of the product, including the left navigation (usually >
1200px wide). For consistency, use this browser window size for your
screenshots by installing a browser extension for setting a window to a
specific size (for example,
[Window Resizer](https://chrome.google.com/webstore/detail/window-resizer/kkelicaakdanhinjdeammmilcgefonfh/related?hl=en)
for Google Chrome).
### Save the image
- Save the image with a lowercase file name that is descriptive of the feature
or concept in the image. If the image is of the GitLab interface, append the
GitLab version to the file name, based on the following format:
`image_name_vX_Y.png`. For example, for a screenshot taken from the pipelines
page of GitLab 11.1, a valid name is `pipelines_v11_1.png`. If you're adding an
illustration that doesn't include parts of the user interface, add the release
number corresponding to the release the image was added to; for an MR added to
11.1's milestone, a valid name for an illustration is `devops_diagram_v11_1.png`.
- Place images in a separate directory named `img/` in the same directory where
the `.md` document that you're working on is located.
- Images should have a specific, non-generic name that will
differentiate and describe them properly.
- For screenshots of GitLab software, append the GitLab version the screenshot was taken from to the
file name. Use the following format: `image_name_vX_Y.png`.
- For example, for a screenshot taken from the pipelines page of
GitLab 11.1, a valid name is `pipelines_v11_1.png`. If you're
adding an illustration that does not include parts of the UI,
add the release number corresponding to the release the image
was added to. Example, for an MR added to 11.1's milestone,
a valid name for an illustration is `devops_diagram_v11_1.png`.
- Keep all file names in lower case.
- Consider using PNG images instead of JPEG.
- [Compress all PNG images](#compress-images).
- Compress gifs with <https://ezgif.com/optimize> or similar tool.
@ -869,13 +895,20 @@ To indicate the steps of navigation through the UI:
- Max image size: 100KB (gifs included).
- See also how to link and embed [videos](#videos) to illustrate the docs.
Inside the document:
### Add the image link to content
- The Markdown way of using an image inside a document is:
`![Proper description what the image is about](img/document_image_title_vX_Y.png)`
- Always use a proper description for what the image is about. That way, when a
browser fails to show the image, this text will be used as an alternative
description.
The Markdown code for including an image in a document is:
`![Image description which will be the alt tag](img/document_image_title_vX_Y.png)`
The image description is the alt text for the rendered image on the docs site.
For accessibility and SEO, use [descriptions](https://webaim.org/techniques/alttext/)
that:
- Are accurate, succinct, and unique.
- Don't use *image of …* or *graphic of…* to describe the image.
Also, if a heading immediately follows an image, be sure to add three dashes
(`---`) between the image and the heading.
### Remove image shadow

View File

@ -56,6 +56,8 @@ GitLab can be integrated with the following enhancements:
- Configure [PlantUML](../administration/integration/plantuml.md) to use diagrams in AsciiDoc documents.
- Attach merge requests to [Trello](trello_power_up.md) cards.
- Enable integrated code intelligence powered by [Sourcegraph](sourcegraph.md).
- Add [Elasticsearch](elasticsearch.md) for [Advanced Global Search](../user/search/advanced_global_search.md),
[Advanced System Search](../user/search/advanced_search_syntax.md), and faster searching.
## Integrations

View File

@ -433,6 +433,7 @@ The following are some available Rake tasks:
| [`sudo gitlab-rake gitlab:elastic:recreate_index[<TARGET_NAME>]`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Wrapper task for `gitlab:elastic:delete_index[<TARGET_NAME>]` and `gitlab:elastic:create_empty_index[<TARGET_NAME>]`. |
| [`sudo gitlab-rake gitlab:elastic:index_snippets`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Performs an Elasticsearch import that indexes the snippets data. |
| [`sudo gitlab-rake gitlab:elastic:projects_not_indexed`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Displays which projects are not indexed. |
| [`sudo gitlab-rake gitlab:elastic:reindex_cluster`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Schedules a zero-downtime cluster reindexing task. This feature should be used with an index that was created after GitLab 13.0. |
NOTE: **Note:**
The `TARGET_NAME` parameter is optional and will use the default index/alias name from the current `RAILS_ENV` if not set.

View File

@ -147,8 +147,35 @@ puts Sidekiq::Queue.new("background_migration").size
Sidekiq::ScheduledSet.new.select { |r| r.klass == 'BackgroundMigrationWorker' }.size
```
There is also a [Rake task](../administration/raketasks/maintenance.md#display-status-of-database-migrations)
for displaying the status of each database migration.
### What do I do if my background migrations are stuck?
CAUTION: **Warning:** The following operations can disrupt your GitLab performance.
NOTE: **Note:** It is safe to re-execute these commands, especially if you have 1000+ pending jobs which would likely overflow your runtime memory.
**For Omnibus installations**
```shell
# Start the rails console
sudo gitlab-rails c
# Execute the following in the rails console
scheduled_queue = Sidekiq::ScheduledSet.new
pending_job_classes = scheduled_queue.select { |job| job["class"] == "BackgroundMigrationWorker" }.map { |job| job["args"].first }.uniq
pending_job_classes.each { |job_class| Gitlab::BackgroundMigration.steal(job_class) }
```
**For installations from source**
```shell
# Start the rails console
sudo -u git -H bundle exec rails RAILS_ENV=production
# Execute the following in the rails console
scheduled_queue = Sidekiq::ScheduledSet.new
pending_job_classes = scheduled_queue.select { |job| job["class"] == "BackgroundMigrationWorker" }.map { |job| job["args"].first }.uniq
pending_job_classes.each { |job_class| Gitlab::BackgroundMigration.steal(job_class) }
```
## Upgrading to a new major version

View File

@ -256,6 +256,8 @@ group.
| Edit epic comments (posted by any user) **(ULTIMATE)** | | | | ✓ (2) | ✓ (2) |
| Edit group settings | | | | | ✓ |
| Manage group level CI/CD variables | | | | | ✓ |
| List group deploy tokens | | | | ✓ | ✓ |
| Create/Delete group deploy tokens | | | | | ✓ |
| Manage group members | | | | | ✓ |
| Delete group | | | | | ✓ |
| Delete group epic **(ULTIMATE)** | | | | | ✓ |

View File

@ -4,6 +4,10 @@ module API
class ImportGithub < Grape::API::Instance
rescue_from Octokit::Unauthorized, with: :provider_unauthorized
before do
forbidden! unless Gitlab::CurrentSettings.import_sources&.include?('github')
end
helpers do
def client
@client ||= Gitlab::LegacyGithubImport::Client.new(params[:personal_access_token], client_options)

View File

@ -14,8 +14,8 @@ module API
"#{issuable_name}_iid".to_sym
end
def update_issuable_key
"update_#{issuable_name}".to_sym
def admin_issuable_key
"admin_#{issuable_name}".to_sym
end
def read_issuable_key
@ -60,7 +60,7 @@ module API
requires :duration, type: String, desc: 'The duration to be parsed'
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/time_estimate" do
authorize! update_issuable_key, load_issuable
authorize! admin_issuable_key, load_issuable
status :ok
update_issuable(time_estimate: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)))
@ -71,7 +71,7 @@ module API
requires issuable_key, type: Integer, desc: "The ID of a project #{issuable_name}"
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/reset_time_estimate" do
authorize! update_issuable_key, load_issuable
authorize! admin_issuable_key, load_issuable
status :ok
update_issuable(time_estimate: 0)
@ -83,7 +83,7 @@ module API
requires :duration, type: String, desc: 'The duration to be parsed'
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/add_spent_time" do
authorize! update_issuable_key, load_issuable
authorize! admin_issuable_key, load_issuable
update_issuable(spend_time: {
duration: Gitlab::TimeTrackingFormatter.parse(params.delete(:duration)),
@ -96,7 +96,7 @@ module API
requires issuable_key, type: Integer, desc: "The ID of a project #{issuable_name}"
end
post ":id/#{issuable_collection_name}/:#{issuable_key}/reset_spent_time" do
authorize! update_issuable_key, load_issuable
authorize! admin_issuable_key, load_issuable
status :ok
update_issuable(spend_time: { duration: :reset, user_id: current_user.id })

View File

@ -253,7 +253,7 @@ module Banzai
object_parent_type = parent.is_a?(Group) ? :group : :project
{
original: text,
original: escape_html_entities(text),
link: link_content,
link_reference: link_reference,
object_parent_type => parent.id,

View File

@ -38,7 +38,7 @@ module Banzai
private
def unescape_and_scrub_uri(uri)
Addressable::URI.unescape(uri).scrub
Addressable::URI.unescape(uri).scrub.delete("\0")
end
end
end

View File

@ -3,7 +3,7 @@
module Gitlab
module ImportExport
class SnippetRepoRestorer < RepoRestorer
attr_reader :snippet
attr_reader :snippet, :user
SnippetRepositoryError = Class.new(StandardError)
@ -33,6 +33,16 @@ module Gitlab
def create_repository_from_bundle
repository.create_from_bundle(path_to_bundle)
snippet.track_snippet_repository(repository.storage)
response = Snippets::RepositoryValidationService.new(user, snippet).execute
if response.error?
repository.remove
snippet.snippet_repository.delete
snippet.repository.expire_exists_cache
raise SnippetRepositoryError, _("Invalid repository bundle for snippet with id %{snippet_id}") % { snippet_id: snippet.id }
end
end
def create_repository_from_db

View File

@ -3,7 +3,7 @@
module Gitlab
module MarkdownCache
# Increment this number every time the renderer changes its output
CACHE_COMMONMARK_VERSION = 22
CACHE_COMMONMARK_VERSION = 23
CACHE_COMMONMARK_VERSION_START = 10
BaseError = Class.new(StandardError)

View File

@ -12434,6 +12434,9 @@ msgstr ""
msgid "Invalid query"
msgstr ""
msgid "Invalid repository bundle for snippet with id %{snippet_id}"
msgstr ""
msgid "Invalid repository path"
msgstr ""
@ -19225,15 +19228,33 @@ msgstr ""
msgid "Repository cleanup has started. You will receive an email once the cleanup operation is complete."
msgstr ""
msgid "Repository files count over the limit"
msgstr ""
msgid "Repository has an invalid default branch name."
msgstr ""
msgid "Repository has more than one branch."
msgstr ""
msgid "Repository has no locks."
msgstr ""
msgid "Repository has tags."
msgstr ""
msgid "Repository maintenance"
msgstr ""
msgid "Repository mirroring"
msgstr ""
msgid "Repository must contain at least 1 file."
msgstr ""
msgid "Repository size is above the limit."
msgstr ""
msgid "Repository static objects"
msgstr ""
@ -26684,6 +26705,9 @@ msgstr ""
msgid "cannot block others"
msgstr ""
msgid "cannot contain HTML/XML tags, including any word between angle brackets (<,>)."
msgstr ""
msgid "cannot include leading slash or directory traversal."
msgstr ""

View File

@ -125,7 +125,7 @@
"string-hash": "1.1.3",
"style-loader": "^1.1.3",
"svg4everybody": "2.1.9",
"swagger-ui-dist": "^3.24.3",
"swagger-ui-dist": "^3.26.2",
"three": "^0.84.0",
"three-orbit-controls": "^82.1.0",
"three-stl-loader": "^1.0.4",
@ -151,7 +151,7 @@
"webpack-cli": "^3.3.11",
"webpack-stats-plugin": "^0.3.1",
"worker-loader": "^2.0.0",
"xterm": "^3.5.0"
"xterm": "3.14.5"
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.10.1",

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Verify' do
RSpec.describe 'Verify' do
describe 'Add or Remove CI variable via UI', :smoke do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Verify', :docker, :runner do
RSpec.describe 'Verify', :docker, :runner do
describe 'Pipeline creation and processing' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:max_wait) { 30 }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Verify', :docker, :runner do
RSpec.describe 'Verify', :docker, :runner do
describe 'Runner registration' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let!(:runner) do

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Verify', :docker, :runner do
RSpec.describe 'Verify', :docker, :runner do
describe 'Code coverage statistics' do
let(:simplecov) { '\(\d+.\d+\%\) covered' }
let(:executor) { "qa-runner-#{Time.now.to_i}" }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Release' do
RSpec.describe 'Release' do
describe 'Deploy key creation' do
it 'user adds a deploy key' do
Flow::Login.sign_in

View File

@ -3,7 +3,7 @@
require 'digest/sha1'
module QA
context 'Release', :docker, :runner do
RSpec.describe 'Release', :docker, :runner do
describe 'Git clone using a deploy key' do
before do
Flow::Login.sign_in

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Release', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/213222', type: :flaky } do
RSpec.describe 'Release', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/213222', type: :flaky } do
describe 'Deploy token creation' do
it 'user adds a deploy token' do
Flow::Login.sign_in

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Release', :docker do
RSpec.describe 'Release', :docker do
describe 'Parent-child pipelines dependent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Release', :docker do
RSpec.describe 'Release', :docker do
describe 'Parent-child pipelines independent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Monitor' do
RSpec.describe 'Monitor' do
describe 'with Prometheus in a Gitlab-managed cluster', :orchestrated, :kubernetes do
before :all do
@cluster = Service::KubernetesCluster.new.create!

View File

@ -128,6 +128,13 @@ RSpec.describe Admin::ApplicationSettingsController do
expect(ApplicationSetting.current.repository_storages_weighted_default).to eq(75)
end
it "updates default_branch_name setting" do
put :update, params: { application_setting: { default_branch_name: "example_branch_name" } }
expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.default_branch_name).to eq("example_branch_name")
end
context 'external policy classification settings' do
let(:settings) do
{

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
# Read about factories at https://github.com/thoughtbot/factory_bot
FactoryBot.define do
factory :approval do
merge_request
user
end
end

View File

@ -205,6 +205,14 @@ RSpec.describe 'Dashboard Projects' do
it_behaves_like 'hidden pipeline status'
end
context "when last_pipeline is missing" do
before do
project.last_pipeline.delete
end
it_behaves_like 'hidden pipeline status'
end
end
context 'last push widget', :use_clean_rails_memory_store_caching do

View File

@ -6,6 +6,7 @@ RSpec.describe "User views issues" do
let!(:closed_issue) { create(:closed_issue, project: project) }
let!(:open_issue1) { create(:issue, project: project) }
let!(:open_issue2) { create(:issue, project: project) }
let!(:moved_open_issue) { create(:issue, project: project, moved_to: create(:issue)) }
let_it_be(:user) { create(:user) }
@ -36,6 +37,7 @@ RSpec.describe "User views issues" do
.and have_content(open_issue1.title)
.and have_content(open_issue2.title)
.and have_no_content(closed_issue.title)
.and have_content(moved_open_issue.title)
.and have_no_selector(".js-new-board-list")
end
@ -66,6 +68,7 @@ RSpec.describe "User views issues" do
.and have_content(closed_issue.title)
.and have_no_content(open_issue1.title)
.and have_no_content(open_issue2.title)
.and have_no_content(moved_open_issue.title)
.and have_no_selector(".js-new-board-list")
end
@ -86,6 +89,8 @@ RSpec.describe "User views issues" do
.and have_content(closed_issue.title)
.and have_content(open_issue1.title)
.and have_content(open_issue2.title)
.and have_content(moved_open_issue.title)
.and have_no_content('CLOSED (MOVED)')
.and have_no_selector(".js-new-board-list")
end

View File

@ -5,15 +5,17 @@ require 'spec_helper'
RSpec.describe 'Comments on personal snippets', :js do
include NoteInteractionHelpers
let!(:user) { create(:user) }
let!(:snippet) { create(:personal_snippet, :public) }
let_it_be(:snippet) { create(:personal_snippet, :public) }
let_it_be(:other_note) { create(:note_on_personal_snippet) }
let(:user_name) { 'Test User' }
let!(:user) { create(:user, name: user_name) }
let!(:snippet_notes) do
[
create(:note_on_personal_snippet, noteable: snippet, author: user),
create(:note_on_personal_snippet, noteable: snippet)
]
end
let!(:other_note) { create(:note_on_personal_snippet) }
before do
stub_feature_flags(snippets_vue: false)
@ -56,6 +58,26 @@ RSpec.describe 'Comments on personal snippets', :js do
expect(page).to show_user_status(status)
end
end
it 'shows the author name' do
visit snippet_path(snippet)
within("#note_#{snippet_notes[0].id}") do
expect(page).to have_content(user_name)
end
end
context 'when the author name contains HTML' do
let(:user_name) { '<h1><a href="https://bad.link/malicious.exe" class="evil">Fake Content<img class="fake-icon" src="image.png"></a></h1>' }
it 'renders the name as plain text' do
visit snippet_path(snippet)
content = find("#note_#{snippet_notes[0].id} .note-header-author-name").text
expect(content).to eq user_name
end
end
end
context 'when submitting a note' do

View File

@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe EventsFinder do
let_it_be(:user) { create(:user) }
let(:private_user) { create(:user, private_profile: true) }
let(:other_user) { create(:user) }
let(:project1) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
@ -57,6 +58,12 @@ RSpec.describe EventsFinder do
expect(events).to be_empty
end
it 'returns nothing when the target profile is private' do
events = described_class.new(source: private_user, current_user: other_user).execute
expect(events).to be_empty
end
end
describe 'wiki events feature flag' do

View File

@ -1,8 +1,10 @@
import { shallowMount } from '@vue/test-utils';
import { GlSprintf } from '@gitlab/ui';
import StackTraceEntry from '~/error_tracking/components/stacktrace_entry.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
import { trimText } from 'helpers/text_helper';
describe('Stacktrace Entry', () => {
let wrapper;
@ -21,6 +23,9 @@ describe('Stacktrace Entry', () => {
errorLine: 24,
...props,
},
stubs: {
GlSprintf,
},
});
}
@ -53,7 +58,7 @@ describe('Stacktrace Entry', () => {
const extraInfo = { errorLine: 34, errorFn: 'errorFn', errorColumn: 77 };
mountComponent({ expanded: false, lines: [], ...extraInfo });
expect(wrapper.find(Icon).exists()).toBe(false);
expect(findFileHeaderContent()).toContain(
expect(trimText(findFileHeaderContent())).toContain(
`in ${extraInfo.errorFn} at line ${extraInfo.errorLine}:${extraInfo.errorColumn}`,
);
});
@ -61,17 +66,17 @@ describe('Stacktrace Entry', () => {
it('should render only lineNo:columnNO when there is no errorFn ', () => {
const extraInfo = { errorLine: 34, errorFn: null, errorColumn: 77 };
mountComponent({ expanded: false, lines: [], ...extraInfo });
expect(findFileHeaderContent()).not.toContain(`in ${extraInfo.errorFn}`);
expect(findFileHeaderContent()).toContain(`${extraInfo.errorLine}:${extraInfo.errorColumn}`);
const fileHeaderContent = trimText(findFileHeaderContent());
expect(fileHeaderContent).not.toContain(`in ${extraInfo.errorFn}`);
expect(fileHeaderContent).toContain(`${extraInfo.errorLine}:${extraInfo.errorColumn}`);
});
it('should render only lineNo when there is no errorColumn ', () => {
const extraInfo = { errorLine: 34, errorFn: 'errorFn', errorColumn: null };
mountComponent({ expanded: false, lines: [], ...extraInfo });
expect(findFileHeaderContent()).toContain(
`in ${extraInfo.errorFn} at line ${extraInfo.errorLine}`,
);
expect(findFileHeaderContent()).not.toContain(`:${extraInfo.errorColumn}`);
const fileHeaderContent = trimText(findFileHeaderContent());
expect(fileHeaderContent).toContain(`in ${extraInfo.errorFn} at line ${extraInfo.errorLine}`);
expect(fileHeaderContent).not.toContain(`:${extraInfo.errorColumn}`);
});
});
});

View File

@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import { GlLabel } from '@gitlab/ui';
import { GlSprintf, GlLabel } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import { trimText } from 'helpers/text_helper';
import initUserPopovers from '~/user_popovers';
@ -50,6 +50,10 @@ describe('Issuable component', () => {
scopedLabels,
},
},
stubs: {
'gl-sprintf': GlSprintf,
'gl-link': '<a><slot></slot></a>',
},
});
};
@ -73,7 +77,7 @@ describe('Issuable component', () => {
const findConfidentialIcon = () => wrapper.find('.fa-eye-slash');
const findTaskStatus = () => wrapper.find('.task-status');
const findOpenedAgoContainer = () => wrapper.find({ ref: 'openedAgoByContainer' });
const findOpenedAgoContainer = () => wrapper.find('[data-testid="openedByMessage"]');
const findMilestone = () => wrapper.find('.js-milestone');
const findMilestoneTooltip = () => findMilestone().attributes('title');
const findDueDate = () => wrapper.find('.js-due-date');
@ -94,7 +98,7 @@ describe('Issuable component', () => {
factory();
expect(initUserPopovers).toHaveBeenCalledWith([findOpenedAgoContainer().find('a').element]);
expect(initUserPopovers).toHaveBeenCalledWith([wrapper.vm.$refs.openedAgoByContainer.$el]);
});
});
@ -191,7 +195,7 @@ describe('Issuable component', () => {
});
it('renders fuzzy opened date and author', () => {
expect(trimText(findOpenedAgoContainer().text())).toEqual(
expect(trimText(findOpenedAgoContainer().text())).toContain(
`opened 1 month ago by ${TEST_USER_NAME}`,
);
});

View File

@ -258,6 +258,7 @@ describe('JiraImportApp', () => {
input: {
jiraProjectKey: 'MTG',
projectPath: 'gitlab-org/gitlab-test',
usersMapping: [],
},
},
};

View File

@ -1,40 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`monitoring/utils stateAndPropsFromDataset initial monitoring data from fixture should match snapshot 1`] = `
Object {
"dataProps": Object {
"alertsEndpoint": "/monitoring/monitor-project/prometheus/alerts.json?environment_id=1",
"clustersPath": "/monitoring/monitor-project/-/clusters",
"customMetricsAvailable": true,
"customMetricsPath": "/monitoring/monitor-project/prometheus/metrics",
"defaultBranch": "master",
"documentationPath": "/help/administration/monitoring/prometheus/index.md",
"emptyGettingStartedSvgPath": "/images/illustrations/monitoring/getting_started.svg",
"emptyLoadingSvgPath": "/images/illustrations/monitoring/loading.svg",
"emptyNoDataSmallSvgPath": "/images/illustrations/chart-empty-state-small.svg",
"emptyNoDataSvgPath": "/images/illustrations/monitoring/no_data.svg",
"emptyUnableToConnectSvgPath": "/images/illustrations/monitoring/unable_to_connect.svg",
"environmentState": "available",
"externalDashboardUrl": null,
"hasMetrics": false,
"metricsDashboardBasePath": "/monitoring/monitor-project/-/environments/1/metrics",
"metricsEndpoint": "/monitoring/monitor-project/-/environments/1/additional_metrics.json",
"prometheusAlertsAvailable": true,
"prometheusStatus": "",
"settingsPath": "/monitoring/monitor-project/-/services/prometheus/edit",
"tagsPath": "/monitoring/monitor-project/-/tags",
"validateQueryPath": "/monitoring/monitor-project/prometheus/metrics/validate_query",
},
"initState": Object {
"currentDashboard": undefined,
"currentEnvironmentName": "environment1",
"customDashboardBasePath": ".gitlab/dashboards",
"dashboardEndpoint": "/monitoring/monitor-project/-/environments/1/metrics_dashboard.json",
"dashboardTimezone": "LOCAL",
"dashboardsEndpoint": "/monitoring/monitor-project/-/performance_monitoring/dashboards.json",
"deploymentsEndpoint": "/monitoring/monitor-project/-/environments/1/deployments.json",
"logsPath": "/monitoring/monitor-project/-/logs?environment_name=environment1",
"projectPath": "/monitoring/monitor-project",
},
}
`;

View File

@ -1,7 +1,8 @@
import { stateAndPropsFromDataset } from '~/monitoring/utils';
import { mapToDashboardViewModel } from '~/monitoring/stores/utils';
import { metricStates } from '~/monitoring/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { convertObjectProps } from '~/lib/utils/common_utils';
import { convertToCamelCase } from '~/lib/utils/text_utility';
import { metricsResult } from './mock_data';
@ -11,8 +12,14 @@ export const metricsDashboardResponse = getJSONFixture(
);
export const metricsDashboardPayload = metricsDashboardResponse.dashboard;
export const datasetState = stateAndPropsFromDataset(
convertObjectPropsToCamelCase(metricsDashboardResponse.metrics_data),
const datasetState = stateAndPropsFromDataset(
// It's preferable to have props in snake_case, this will be addressed at:
// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33574
convertObjectProps(
// Some props use kebab-case, convert to snake_case first
key => convertToCamelCase(key.replace(/-/g, '_')),
metricsDashboardResponse.metrics_data,
),
);
export const dashboardProps = datasetState.dataProps;

View File

@ -1,5 +1,4 @@
import * as monitoringUtils from '~/monitoring/utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import { TEST_HOST } from 'jest/helpers/test_constants';
import {
@ -8,7 +7,7 @@ import {
anomalyMockGraphData,
barMockData,
} from './mock_data';
import { metricsDashboardResponse, metricsDashboardViewModel, graphData } from './fixture_data';
import { metricsDashboardViewModel, graphData } from './fixture_data';
const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`;
@ -26,15 +25,6 @@ const rollingRange = {
};
describe('monitoring/utils', () => {
describe('stateAndPropsFromDataset', () => {
it('initial monitoring data from fixture should match snapshot', () => {
const datasetState = monitoringUtils.stateAndPropsFromDataset(
convertObjectPropsToCamelCase(metricsDashboardResponse.metrics_data),
);
expect(datasetState).toMatchSnapshot();
});
});
describe('trackGenerateLinkToChartEventOptions', () => {
it('should return Cluster Monitoring options if located on Cluster Health Dashboard', () => {
document.body.dataset.page = 'groups:clusters:show';

View File

@ -18,30 +18,30 @@ RSpec.describe EnvironmentsHelper do
it 'returns data' do
expect(metrics_data).to include(
'settings_path' => edit_project_service_path(project, 'prometheus'),
'clusters_path' => project_clusters_path(project),
'metrics_dashboard_base_path' => environment_metrics_path(environment),
'current_environment_name' => environment.name,
'documentation_path' => help_page_path('administration/monitoring/prometheus/index.md'),
'empty_getting_started_svg_path' => match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty_loading_svg_path' => match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty_no_data_svg_path' => match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
'empty_unable_to_connect_svg_path' => match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
'metrics_endpoint' => additional_metrics_project_environment_path(project, environment, format: :json),
'deployments_endpoint' => project_environment_deployments_path(project, environment, format: :json),
'default_branch' => 'master',
'project_path' => project_path(project),
'tags_path' => project_tags_path(project),
'has_metrics' => "#{environment.has_metrics?}",
'prometheus_status' => "#{environment.prometheus_status}",
'external_dashboard_url' => nil,
'environment_state' => environment.state,
'custom_metrics_path' => project_prometheus_metrics_path(project),
'validate_query_path' => validate_query_project_prometheus_metrics_path(project),
'custom_metrics_available' => 'true',
'alerts_endpoint' => project_prometheus_alerts_path(project, environment_id: environment.id, format: :json),
'prometheus_alerts_available' => 'true',
'custom_dashboard_base_path' => Metrics::Dashboard::CustomDashboardService::DASHBOARD_ROOT
'settings-path' => edit_project_service_path(project, 'prometheus'),
'clusters-path' => project_clusters_path(project),
'metrics-dashboard-base-path' => environment_metrics_path(environment),
'current-environment-name' => environment.name,
'documentation-path' => help_page_path('administration/monitoring/prometheus/index.md'),
'empty-getting-started-svg-path' => match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path' => match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path' => match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
'empty-unable-to-connect-svg-path' => match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
'metrics-endpoint' => additional_metrics_project_environment_path(project, environment, format: :json),
'deployments-endpoint' => project_environment_deployments_path(project, environment, format: :json),
'default-branch' => 'master',
'project-path' => project_path(project),
'tags-path' => project_tags_path(project),
'has-metrics' => "#{environment.has_metrics?}",
'prometheus-status' => "#{environment.prometheus_status}",
'external-dashboard-url' => nil,
'environment-state' => environment.state,
'custom-metrics-path' => project_prometheus_metrics_path(project),
'validate-query-path' => validate_query_project_prometheus_metrics_path(project),
'custom-metrics-available' => 'true',
'alerts-endpoint' => project_prometheus_alerts_path(project, environment_id: environment.id, format: :json),
'prometheus-alerts-available' => 'true',
'custom-dashboard-base-path' => Metrics::Dashboard::CustomDashboardService::DASHBOARD_ROOT
)
end
@ -54,7 +54,7 @@ RSpec.describe EnvironmentsHelper do
it 'returns false' do
expect(metrics_data).to include(
'prometheus_alerts_available' => 'false'
'prometheus-alerts-available' => 'false'
)
end
end
@ -65,7 +65,7 @@ RSpec.describe EnvironmentsHelper do
end
it 'adds external_dashboard_url' do
expect(metrics_data['external_dashboard_url']).to eq('http://gitlab.com')
expect(metrics_data['external-dashboard-url']).to eq('http://gitlab.com')
end
end
@ -76,7 +76,7 @@ RSpec.describe EnvironmentsHelper do
subject { metrics_data }
it { is_expected.to include('environment_state' => 'stopped') }
it { is_expected.to include('environment-state' => 'stopped') }
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Cookies serializer initializer' do
def load_initializer
load Rails.root.join('config/initializers/cookies_serializer.rb')
end
subject { Rails.application.config.action_dispatch.cookies_serializer }
it 'uses JSON serializer by default' do
load_initializer
expect(subject).to eq(:json)
end
it 'uses the unsafe hybrid serializer when the environment variables is set' do
stub_env('USE_UNSAFE_HYBRID_COOKIES', 'true')
load_initializer
expect(subject).to eq(:hybrid)
end
end

View File

@ -20,6 +20,18 @@ RSpec.describe Banzai::Filter::AbstractReferenceFilter do
end
end
describe '#data_attributes_for' do
let_it_be(:issue) { create(:issue, project: project) }
it 'is not an XSS vector' do
allow(described_class).to receive(:object_class).and_return(Issue)
data_attributes = filter.data_attributes_for('xss &lt;img onerror=alert(1) src=x&gt;', project, issue, link_content: true)
expect(data_attributes[:original]).to eq('xss &amp;lt;img onerror=alert(1) src=x&amp;gt;')
end
end
describe '#parent_per_reference' do
it 'returns a Hash containing projects grouped per parent paths' do
expect(filter).to receive(:references_per_parent)

View File

@ -229,6 +229,7 @@ RSpec.describe Banzai::Filter::UploadLinkFilter do
'invalid UTF-8 byte sequences' | '%FF'
'garbled path' | 'open(/var/tmp/):%20/location%0Afrom:%20/test'
'whitespace' | "d18213acd3732630991986120e167e3d/Landscape_8.jpg\nand more"
'null byte' | "%00"
end
with_them do

View File

@ -24,7 +24,7 @@ RSpec.describe Banzai::Pipeline::FullPipeline do
it 'escapes the data-original attribute on a reference' do
markdown = %Q{[">bad things](#{issue.to_reference})}
result = described_class.to_html(markdown, project: project)
expect(result).to include(%{data-original='\"&gt;bad things'})
expect(result).to include(%{data-original='\"&amp;gt;bad things'})
end
end

View File

@ -4,9 +4,9 @@ require 'spec_helper'
RSpec.describe Gitlab::ImportExport::SnippetRepoRestorer do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
let(:snippet) { create(:project_snippet, project: project, author: user) }
let(:project) { create(:project, namespace: user.namespace) }
let(:snippet) { create(:project_snippet, project: project, author: user) }
let(:shared) { project.import_export_shared }
let(:exporter) { Gitlab::ImportExport::SnippetsRepoSaver.new(project: project, shared: shared, current_user: user) }
let(:restorer) do
@ -57,33 +57,63 @@ RSpec.describe Gitlab::ImportExport::SnippetRepoRestorer do
it_behaves_like 'no bundle file present'
end
context 'when the snippet bundle exists' do
let!(:snippet_with_repo) { create(:project_snippet, :repository, project: project) }
context 'when the snippet repository bundle exists' do
let!(:snippet_with_repo) { create(:project_snippet, :repository, project: project, author: user) }
let(:bundle_path) { ::Gitlab::ImportExport.snippets_repo_bundle_path(shared.export_path) }
let(:snippet_bundle_path) { File.join(bundle_path, "#{snippet_with_repo.hexdigest}.bundle") }
let(:result) { exporter.save }
let(:repository) { snippet.repository }
before do
expect(exporter.save).to be_truthy
end
it 'creates the repository from the bundle' do
expect(snippet.repository_exists?).to be_falsey
expect(snippet.snippet_repository).to be_nil
expect(snippet.repository).to receive(:create_from_bundle).and_call_original
context 'when it is valid' do
before do
allow(repository).to receive(:branch_count).and_return(1)
allow(repository).to receive(:tag_count).and_return(0)
allow(repository).to receive(:branch_names).and_return(['master'])
allow(repository).to receive(:ls_files).and_return(['foo'])
end
expect(restorer.restore).to be_truthy
expect(snippet.repository_exists?).to be_truthy
expect(snippet.snippet_repository).not_to be_nil
it 'creates the repository from the bundle' do
expect(snippet.repository_exists?).to be_falsey
expect(snippet.snippet_repository).to be_nil
expect(repository).to receive(:create_from_bundle).and_call_original
expect(restorer.restore).to be_truthy
expect(snippet.repository_exists?).to be_truthy
expect(snippet.snippet_repository).not_to be_nil
end
it 'sets same shard in snippet repository as in the repository storage' do
expect(repository).to receive(:storage).and_return('picked')
expect(repository).to receive(:create_from_bundle)
expect(restorer.restore).to be_truthy
expect(snippet.snippet_repository.shard_name).to eq 'picked'
end
end
it 'sets same shard in snippet repository as in the repository storage' do
expect(snippet).to receive(:repository_storage).and_return('picked')
expect(snippet.repository).to receive(:create_from_bundle)
context 'when it is invalid' do
it 'returns false and deletes the repository from disk and the database' do
gitlab_shell = Gitlab::Shell.new
shard_name = snippet.repository.shard
path = snippet.disk_path + '.git'
error_response = ServiceResponse.error(message: 'Foo', http_status: 400)
restorer.restore
allow_next_instance_of(Snippets::RepositoryValidationService) do |instance|
allow(instance).to receive(:execute).and_return(error_response)
end
expect(snippet.snippet_repository.shard_name).to eq 'picked'
aggregate_failures do
expect(restorer.restore).to be false
expect(shared.errors.first).to match(/Invalid repository bundle/)
expect(snippet.repository_exists?).to eq false
expect(snippet.reload.snippet_repository).to be_nil
expect(gitlab_shell.repository_exists?(shard_name, path)).to eq false
end
end
end
end
end

View File

@ -38,6 +38,7 @@ RSpec.describe Gitlab::ImportExport::SnippetsRepoRestorer do
expect(snippet1.repository_exists?).to be false
expect(snippet2.repository_exists?).to be false
allow_any_instance_of(Snippets::RepositoryValidationService).to receive(:execute).and_return(ServiceResponse.success)
expect(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet1, path_to_bundle: bundle_path(snippet1))).and_call_original
expect(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet2, path_to_bundle: bundle_path(snippet2))).and_call_original
expect(restorer.restore).to be_truthy

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Approval do
context 'presence validation' do
it { is_expected.to validate_presence_of(:merge_request_id) }
it { is_expected.to validate_presence_of(:user_id) }
end
context 'uniqueness validation' do
let!(:existing_record) { create(:approval) }
it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:merge_request_id]) }
end
end

View File

@ -3676,7 +3676,7 @@ RSpec.describe MergeRequest do
describe '#merge_participants' do
it 'contains author' do
expect(subject.merge_participants).to eq([subject.author])
expect(subject.merge_participants).to contain_exactly(subject.author)
end
describe 'when merge_when_pipeline_succeeds? is true' do
@ -3690,8 +3690,20 @@ RSpec.describe MergeRequest do
author: user)
end
it 'contains author only' do
expect(subject.merge_participants).to eq([subject.author])
context 'author is not a project member' do
it 'is empty' do
expect(subject.merge_participants).to be_empty
end
end
context 'author is a project member' do
before do
subject.project.team.add_reporter(user)
end
it 'contains author only' do
expect(subject.merge_participants).to contain_exactly(subject.author)
end
end
end
@ -3704,8 +3716,24 @@ RSpec.describe MergeRequest do
merge_user: merge_user)
end
it 'contains author and merge user' do
expect(subject.merge_participants).to eq([subject.author, merge_user])
before do
subject.project.team.add_reporter(subject.author)
end
context 'merge user is not a member' do
it 'contains author only' do
expect(subject.merge_participants).to contain_exactly(subject.author)
end
end
context 'both author and merge users are project members' do
before do
subject.project.team.add_reporter(merge_user)
end
it 'contains author and merge user' do
expect(subject.merge_participants).to contain_exactly(subject.author, merge_user)
end
end
end
end

View File

@ -204,7 +204,7 @@ RSpec.describe API::DeployTokens do
end
context 'deploy token creation' do
shared_examples 'creating a deploy token' do |entity, unauthenticated_response|
shared_examples 'creating a deploy token' do |entity, unauthenticated_response, authorized_role|
let(:expires_time) { 1.year.from_now }
let(:params) do
{
@ -231,9 +231,9 @@ RSpec.describe API::DeployTokens do
it { is_expected.to have_gitlab_http_status(:forbidden) }
end
context 'when authenticated as maintainer' do
context "when authenticated as #{authorized_role}" do
before do
send(entity).add_maintainer(user)
send(entity).send("add_#{authorized_role}", user)
end
it 'creates the deploy token' do
@ -282,7 +282,7 @@ RSpec.describe API::DeployTokens do
response
end
it_behaves_like 'creating a deploy token', :project, :not_found
it_behaves_like 'creating a deploy token', :project, :not_found, :maintainer
end
describe 'POST /groups/:id/deploy_tokens' do
@ -291,7 +291,17 @@ RSpec.describe API::DeployTokens do
response
end
it_behaves_like 'creating a deploy token', :group, :forbidden
it_behaves_like 'creating a deploy token', :group, :forbidden, :owner
context 'when authenticated as maintainer' do
before do
group.add_maintainer(user)
end
let(:params) { { name: 'test', scopes: ['read_repository'] } }
it { is_expected.to have_gitlab_http_status(:forbidden) }
end
end
end
@ -320,6 +330,14 @@ RSpec.describe API::DeployTokens do
group.add_maintainer(user)
end
it { is_expected.to have_gitlab_http_status(:forbidden) }
end
context 'when authenticated as owner' do
before do
group.add_owner(user)
end
it 'calls the deploy token destroy service' do
expect(::Groups::DeployTokens::DestroyService).to receive(:new)
.with(group, user, token_id: group_deploy_token.id)

View File

@ -192,6 +192,19 @@ RSpec.describe API::Events do
end
end
context 'when target users profile is private' do
it 'returns no events' do
user.update!(private_profile: true)
private_project.add_developer(non_member)
get api("/users/#{user.username}/events", non_member)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to eq([])
end
end
context 'when scope is passed' do
context 'when unauthenticated' do
it 'returns no user events' do

View File

@ -26,6 +26,18 @@ RSpec.describe API::ImportGithub do
end
end
it 'rejects requests when Github Importer is disabled' do
stub_application_setting(import_sources: nil)
post api("/import/github", user), params: {
target_namespace: user.namespace_path,
personal_access_token: token,
repo_id: non_existing_record_id
}
expect(response).to have_gitlab_http_status(:forbidden)
end
it 'returns 201 response when the project is imported successfully' do
allow(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)

View File

@ -0,0 +1,69 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Snippets::RepositoryValidationService do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:snippet) { create(:personal_snippet, :empty_repo, author: user) }
let(:repository) { snippet.repository }
let(:service) { described_class.new(user, snippet) }
subject { service.execute }
before do
allow(repository).to receive(:branch_count).and_return(1)
allow(repository).to receive(:ls_files).and_return(['foo'])
allow(repository).to receive(:branch_names).and_return(['master'])
end
it 'returns error when the repository has more than one branch' do
allow(repository).to receive(:branch_count).and_return(2)
expect(subject).to be_error
expect(subject.message).to match /Repository has more than one branch/
end
it 'returns error when existing branch name is not the default one' do
allow(repository).to receive(:branch_names).and_return(['foo'])
expect(subject).to be_error
expect(subject.message).to match /Repository has an invalid default branch name/
end
it 'returns error when the repository has tags' do
allow(repository).to receive(:tag_count).and_return(1)
expect(subject).to be_error
expect(subject.message).to match /Repository has tags/
end
it 'returns error when the repository has more file than the limit' do
limit = Snippet.max_file_limit(user) + 1
files = Array.new(limit) { FFaker::Filesystem.file_name }
allow(repository).to receive(:ls_files).and_return(files)
expect(subject).to be_error
expect(subject.message).to match /Repository files count over the limit/
end
it 'returns error when the repository has no files' do
allow(repository).to receive(:ls_files).and_return([])
expect(subject).to be_error
expect(subject.message).to match /Repository must contain at least 1 file/
end
it 'returns error when the repository size is over the limit' do
expect_any_instance_of(Gitlab::RepositorySizeChecker).to receive(:above_size_limit?).and_return(true)
expect(subject).to be_error
expect(subject.message).to match /Repository size is above the limit/
end
it 'returns success when no validation errors are raised' do
expect(subject).to be_success
end
end
end

View File

@ -158,46 +158,18 @@ RSpec.shared_examples 'wiki controller actions' do
context 'when page is a file' do
include WikiHelpers
let(:id) { upload_file_to_wiki(container, user, file_name) }
where(:file_name) { ['dk.png', 'unsanitized.svg', 'git-cheat-sheet.pdf'] }
context 'when file is an image' do
let(:file_name) { 'dk.png' }
with_them do
let(:id) { upload_file_to_wiki(container, user, file_name) }
it 'delivers the image' do
it 'delivers the file with the correct headers' do
subject
expect(response.headers['Content-Disposition']).to match(/^inline/)
expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
context 'when file is a svg' do
let(:file_name) { 'unsanitized.svg' }
it 'delivers the image' do
subject
expect(response.headers['Content-Disposition']).to match(/^inline/)
expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
it_behaves_like 'project cache control headers' do
let(:project) { container }
end
end
context 'when file is a pdf' do
let(:file_name) { 'git-cheat-sheet.pdf' }
it 'sets the content type to sets the content response headers' do
subject
expect(response.headers['Content-Disposition']).to match(/^inline/)
expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
it_behaves_like 'project cache control headers' do
let(:project) { container }
expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq('true')
expect(response.cache_control[:public]).to be(false)
expect(response.cache_control[:extras]).to include('no-store')
end
end
end

View File

@ -4,6 +4,16 @@ RSpec.shared_examples 'an unauthorized API user' do
it { is_expected.to eq(403) }
end
RSpec.shared_examples 'API user with insufficient permissions' do
context 'with non member that is the author' do
before do
issuable.update!(author: non_member) # an external author can't admin issuable
end
it_behaves_like 'an unauthorized API user'
end
end
RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
let(:non_member) { create(:user) }
@ -14,6 +24,7 @@ RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", non_member), params: { duration: '1w' }) }
it_behaves_like 'an unauthorized API user'
it_behaves_like 'API user with insufficient permissions'
end
it "sets the time estimate for #{issuable_name}" do
@ -53,6 +64,7 @@ RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/reset_time_estimate", non_member)) }
it_behaves_like 'an unauthorized API user'
it_behaves_like 'API user with insufficient permissions'
end
it "resets the time estimate for #{issuable_name}" do
@ -70,6 +82,7 @@ RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
end
it_behaves_like 'an unauthorized API user'
it_behaves_like 'API user with insufficient permissions'
end
it "add spent time for #{issuable_name}" do
@ -119,6 +132,7 @@ RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/reset_spent_time", non_member)) }
it_behaves_like 'an unauthorized API user'
it_behaves_like 'API user with insufficient permissions'
end
it "resets spent time for #{issuable_name}" do

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe HtmlSafetyValidator do
let(:validator) { described_class.new(attributes: [:name]) }
let(:group) { build(:group) }
def validate(value)
validator.validate_each(group, :name, value)
end
it 'adds an error when a script is included in the name' do
validate('My group <script>evil_script</script>')
expect(group.errors[:name]).to eq([HtmlSafetyValidator.error_message])
end
it 'does not add an error when an ampersand is included in the name' do
validate('Group with 1 & 2')
expect(group.errors).to be_empty
end
end

View File

@ -23,7 +23,7 @@ RSpec.describe 'projects/issues/show' do
project.add_developer(user)
end
it 'shows "Closed (moved)" if an issue has been moved' do
it 'shows "Closed (moved)" if an issue has been moved and closed' do
render
expect(rendered).to have_selector('.status-box-issue-closed:not(.hidden)', text: 'Closed (moved)')
@ -41,6 +41,14 @@ RSpec.describe 'projects/issues/show' do
expect(rendered).to have_selector("a[href=\"#{issue_path(new_issue)}\"]", text: 'moved')
end
it 'does not show "closed (moved)" if an issue has been moved and reopened (not closed)' do
allow(issue).to receive(:closed?).and_return(false)
render
expect(rendered).not_to have_selector('.status-box-issue-closed:not(.hidden)', text: 'Closed (moved)')
end
end
context 'when user cannot see moved issue' do

View File

@ -11222,10 +11222,10 @@ svg4everybody@2.1.9:
resolved "https://registry.yarnpkg.com/svg4everybody/-/svg4everybody-2.1.9.tgz#5bd9f6defc133859a044646d4743fabc28db7e2d"
integrity sha1-W9n23vwTOFmgRGRtR0P6vCjbfi0=
swagger-ui-dist@^3.24.3:
version "3.24.3"
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.24.3.tgz#99754d11b0ddd314a1a50db850acb415e4b0a0c6"
integrity sha512-kB8qobP42Xazaym7sD9g5mZuRL4416VIIYZMqPEIskkzKqbPLQGEiHA3ga31bdzyzFLgr6Z797+6X1Am6zYpbg==
swagger-ui-dist@^3.26.2:
version "3.26.2"
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.26.2.tgz#22c700906c8911b1c9956da6c3fca371dba6219f"
integrity sha512-cpR3A9uEs95gGQSaIXgiTpnetIifTF1u2a0fWrnVl+HyLpCdHVgOy7FGlVD1iVkts7AE5GOiGjA7VyDNiRaNgw==
symbol-observable@^1.0.2:
version "1.2.0"
@ -12647,10 +12647,10 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
xterm@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.5.0.tgz#ba3f464bc5730c9d259ebe62131862224db9ddcc"
integrity sha512-IpG3P3gkT0/xDPS0j3igpk92JYlUajaEHk3/EQSUeIRJmPiF2lyham3Xt/GD3o98uOrRluvowjNj0AFeYK+AXQ==
xterm@3.14.5:
version "3.14.5"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.14.5.tgz#c9d14e48be6873aa46fb429f22f2165557fd2dea"
integrity sha512-DVmQ8jlEtL+WbBKUZuMxHMBgK/yeIZwkXB81bH+MGaKKnJGYwA+770hzhXPfwEIokK9On9YIFPRleVp/5G7z9g==
y18n@^3.2.1:
version "3.2.1"