diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-09 21:08:21 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-09 21:08:21 +0000 |
commit | 64786982930713d095ccd3aebd812182a1879fed (patch) | |
tree | 542e79df02f79049d8a63b31388c7d1e3e3b9166 | |
parent | 3d0474695407d24d49bb94f29a182739ee35e1f8 (diff) | |
download | gitlab-ce-64786982930713d095ccd3aebd812182a1879fed.tar.gz |
Add latest changes from gitlab-org/gitlab@master
48 files changed, 1216 insertions, 597 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index f9e92340afa..3b4a7a9369d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -447,3 +447,12 @@ Rails/TimeZone: - 'spec/models/**/*' - 'ee/app/models/**/*' - 'ee/spec/models/**/*' + +# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040 +Rails/SaveBang: + Enabled: true + Include: + - 'spec/**/*.rb' + - 'ee/spec/**/*.rb' + - 'qa/spec/**/*.rb' + - 'qa/qa/specs/**/*.rb' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a4c56feda27..9e3a54fa7e9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -768,3 +768,524 @@ Style/StringLiteralsInInterpolation: # IgnoredMethods: respond_to, define_method Style/SymbolProc: Enabled: false + +# Offense count: 1478 +# Cop supports --auto-correct. +# Configuration parameters: AllowImplicitReturn, AllowedReceivers. +Rails/SaveBang: + Exclude: + - '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/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/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/merge_requests.rb' + - 'ee/spec/features/admin/geo/admin_geo_nodes_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' + - 'ee/spec/features/issues/gfm_autocomplete_ee_spec.rb' + - 'ee/spec/features/merge_request/user_approves_spec.rb' + - '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/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/finders/epics_finder_spec.rb' + - 'ee/spec/frontend/fixtures/analytics.rb' + - 'ee/spec/helpers/application_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' + - 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules_spec.rb' + - '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/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/elastic/search_results_spec.rb' + - 'ee/spec/lib/gitlab/email/handler/ee/service_desk_handler_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/mailers/notify_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_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_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/deprecated_approvals_before_merge_spec.rb' + - 'ee/spec/models/concerns/elastic/note_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/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/group_spec.rb' + - 'ee/spec/models/issue_spec.rb' + - 'ee/spec/models/label_note_spec.rb' + - 'ee/spec/models/license_spec.rb' + - 'ee/spec/models/merge_request_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/project_services/github_service_spec.rb' + - 'ee/spec/models/project_services/jenkins_service_spec.rb' + - 'ee/spec/models/project_spec.rb' + - 'ee/spec/models/scim_identity_spec.rb' + - 'ee/spec/models/scim_oauth_access_token_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/protected_branch_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/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/graphql/group/epics_spec.rb' + - 'ee/spec/requests/api/graphql/mutations/epic_tree/reorder_spec.rb' + - 'ee/spec/requests/api/groups_spec.rb' + - 'ee/spec/requests/api/issues_spec.rb' + - 'ee/spec/requests/api/ldap_group_links_spec.rb' + - 'ee/spec/requests/api/maven_packages_spec.rb' + - 'ee/spec/requests/api/merge_request_approval_rules_spec.rb' + - 'ee/spec/requests/api/merge_request_approvals_spec.rb' + - 'ee/spec/requests/api/merge_requests_spec.rb' + - 'ee/spec/requests/api/project_approvals_spec.rb' + - 'ee/spec/requests/api/projects_spec.rb' + - 'ee/spec/requests/api/protected_branches_spec.rb' + - 'ee/spec/requests/api/scim_spec.rb' + - 'ee/spec/requests/api/todos_spec.rb' + - 'ee/spec/services/approval_rules/finalize_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/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' + - 'ee/spec/services/ee/merge_requests/refresh_service_spec.rb' + - 'ee/spec/services/ee/merge_requests/update_service_spec.rb' + - '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/issue_promote_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/metrics_update_service_spec.rb' + - 'ee/spec/services/geo/registry_consistency_service_spec.rb' + - 'ee/spec/services/geo/repository_verification_secondary_service_spec.rb' + - 'ee/spec/services/groups/autocomplete_service_spec.rb' + - 'ee/spec/services/ldap_group_reset_service_spec.rb' + - '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_trains/refresh_merge_request_service_spec.rb' + - 'ee/spec/services/projects/after_rename_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' + - 'ee/spec/services/start_pull_mirroring_service_spec.rb' + - '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/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/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/project_approval_rules_api_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/create_github_webhook_worker_spec.rb' + - 'ee/spec/workers/elastic_indexer_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/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' + - 'spec/controllers/abuse_reports_controller_spec.rb' + - 'spec/controllers/admin/impersonations_controller_spec.rb' + - 'spec/controllers/admin/runners_controller_spec.rb' + - 'spec/controllers/boards/issues_controller_spec.rb' + - 'spec/controllers/groups/runners_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_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/runners_controller_spec.rb' + - 'spec/controllers/projects_controller_spec.rb' + - 'spec/factories/ci/pipelines.rb' + - 'spec/factories/design_management/designs.rb' + - 'spec/factories/design_management/versions.rb' + - 'spec/factories/labels.rb' + - 'spec/factories/projects.rb' + - 'spec/features/admin/admin_mode/login_spec.rb' + - 'spec/features/admin/admin_runners_spec.rb' + - 'spec/features/admin/admin_users_impersonation_tokens_spec.rb' + - 'spec/features/admin/admin_users_spec.rb' + - 'spec/features/boards/sidebar_spec.rb' + - 'spec/features/calendar_spec.rb' + - 'spec/features/commits_spec.rb' + - 'spec/features/dashboard/datetime_on_tooltips_spec.rb' + - 'spec/features/dashboard/issuables_counter_spec.rb' + - 'spec/features/dashboard/project_member_activity_index_spec.rb' + - '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/issues/bulk_assignment_labels_spec.rb' + - 'spec/features/issues/gfm_autocomplete_spec.rb' + - 'spec/features/issues/issue_sidebar_spec.rb' + - 'spec/features/issues/note_polling_spec.rb' + - 'spec/features/issues/user_creates_branch_and_merge_request_spec.rb' + - 'spec/features/issues/user_creates_confidential_merge_request_spec.rb' + - 'spec/features/issues/user_edits_issue_spec.rb' + - 'spec/features/issues/user_filters_issues_spec.rb' + - 'spec/features/issues/user_sees_live_update_spec.rb' + - 'spec/features/issues/user_sorts_issues_spec.rb' + - 'spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb' + - '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_merge_widget_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/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/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/users_views_asciidoc_page_with_includes_spec.rb' + - 'spec/features/security/project/private_access_spec.rb' + - 'spec/features/users/login_spec.rb' + - 'spec/features/users/show_spec.rb' + - 'spec/finders/autocomplete/move_to_project_finder_spec.rb' + - 'spec/finders/group_descendants_finder_spec.rb' + - 'spec/finders/issues_finder_spec.rb' + - 'spec/finders/merge_requests_finder_spec.rb' + - 'spec/finders/projects_finder_spec.rb' + - 'spec/finders/uploader_finder_spec.rb' + - 'spec/frontend/fixtures/issues.rb' + - 'spec/frontend/fixtures/merge_requests.rb' + - 'spec/graphql/mutations/merge_requests/set_locked_spec.rb' + - 'spec/graphql/mutations/merge_requests/set_wip_spec.rb' + - 'spec/graphql/resolvers/boards_resolver_spec.rb' + - 'spec/helpers/appearances_helper_spec.rb' + - 'spec/helpers/profiles_helper_spec.rb' + - 'spec/helpers/projects/alert_management_helper_spec.rb' + - 'spec/helpers/projects_helper_spec.rb' + - 'spec/helpers/visibility_level_helper_spec.rb' + - 'spec/initializers/active_record_locking_spec.rb' + - 'spec/initializers/fog_google_https_private_urls_spec.rb' + - '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/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/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/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_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' + - 'spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb' + - 'spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb' + - 'spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb' + - 'spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb' + - 'spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb' + - 'spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb' + - 'spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb' + - 'spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb' + - '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/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/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/git/remote_mirror_spec.rb' + - 'spec/lib/gitlab/git_access_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/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/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/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_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/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/shard_health_cache_spec.rb' + - 'spec/mailers/notify_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/20200406102120_backfill_deployment_clusters_from_deployments_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_releases_table_updated_at_and_add_not_null_constraints_to_timestamps_spec.rb' + - 'spec/migrations/encrypt_plaintext_attributes_on_application_settings_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_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/schedule_link_lfs_objects_projects_spec.rb' + - 'spec/models/appearance_spec.rb' + - 'spec/models/application_setting_spec.rb' + - 'spec/models/ci/build_spec.rb' + - 'spec/models/ci/instance_variable_spec.rb' + - 'spec/models/ci/pipeline_spec.rb' + - 'spec/models/ci/runner_spec.rb' + - 'spec/models/clusters/applications/helm_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/featurable_spec.rb' + - 'spec/models/concerns/issuable_spec.rb' + - 'spec/models/concerns/mentionable_spec.rb' + - 'spec/models/concerns/milestoneable_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/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_note_spec.rb' + - 'spec/models/email_spec.rb' + - 'spec/models/environment_spec.rb' + - 'spec/models/event_spec.rb' + - 'spec/models/fork_network_spec.rb' + - 'spec/models/generic_commit_status_spec.rb' + - 'spec/models/grafana_integration_spec.rb' + - 'spec/models/group_spec.rb' + - 'spec/models/hooks/system_hook_spec.rb' + - 'spec/models/hooks/web_hook_spec.rb' + - 'spec/models/identity_spec.rb' + - 'spec/models/issue_spec.rb' + - 'spec/models/key_spec.rb' + - 'spec/models/lfs_objects_project_spec.rb' + - 'spec/models/member_spec.rb' + - 'spec/models/members/group_member_spec.rb' + - 'spec/models/members/project_member_spec.rb' + - 'spec/models/merge_request_spec.rb' + - 'spec/models/milestone_spec.rb' + - 'spec/models/namespace_spec.rb' + - 'spec/models/note_spec.rb' + - 'spec/models/notification_setting_spec.rb' + - 'spec/models/pages_domain_spec.rb' + - 'spec/models/project_services/bamboo_service_spec.rb' + - 'spec/models/project_services/jira_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/release_spec.rb' + - 'spec/models/remote_mirror_spec.rb' + - 'spec/models/resource_milestone_event_spec.rb' + - 'spec/models/route_spec.rb' + - 'spec/models/sentry_issue_spec.rb' + - 'spec/models/service_spec.rb' + - 'spec/models/snippet_spec.rb' + - 'spec/models/upload_spec.rb' + - 'spec/models/user_preference_spec.rb' + - 'spec/models/user_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/merge_request_policy_spec.rb' + - 'spec/policies/project_policy_spec.rb' + - 'spec/requests/api/boards_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_milestones_spec.rb' + - 'spec/requests/api/internal/base_spec.rb' + - 'spec/requests/api/issues/get_group_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/pipeline_schedules_spec.rb' + - 'spec/requests/api/project_import_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/profiles/notifications_controller_spec.rb' + - 'spec/requests/projects/cycle_analytics_events_spec.rb' + - 'spec/serializers/environment_status_entity_spec.rb' + - 'spec/serializers/merge_request_poll_widget_entity_spec.rb' + - 'spec/serializers/merge_request_widget_entity_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/deployments/after_create_service_spec.rb' + - 'spec/services/design_management/generate_image_versions_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/clone/attributes_rewriter_spec.rb' + - 'spec/services/issuable/common_system_notes_service_spec.rb' + - 'spec/services/issues/close_service_spec.rb' + - 'spec/services/issues/create_service_spec.rb' + - 'spec/services/issues/export_csv_service_spec.rb' + - 'spec/services/issues/reopen_service_spec.rb' + - '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/conflicts/list_service_spec.rb' + - 'spec/services/merge_requests/create_service_spec.rb' + - 'spec/services/merge_requests/merge_service_spec.rb' + - 'spec/services/merge_requests/post_merge_service_spec.rb' + - 'spec/services/merge_requests/refresh_service_spec.rb' + - 'spec/services/merge_requests/update_service_spec.rb' + - 'spec/services/milestones/destroy_service_spec.rb' + - 'spec/services/milestones/promote_service_spec.rb' + - 'spec/services/milestones/transfer_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/create_service_spec.rb' + - 'spec/services/projects/fork_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' + - 'spec/services/projects/propagate_service_template_spec.rb' + - 'spec/services/projects/unlink_fork_service_spec.rb' + - '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/system_hooks_service_spec.rb' + - 'spec/services/system_note_service_spec.rb' + - 'spec/services/system_notes/issuables_service_spec.rb' + - 'spec/services/todo_service_spec.rb' + - '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/support/helpers/cycle_analytics_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/track_untracked_uploads_helpers.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/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/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/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/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/boards_shared_examples.rb' + - 'spec/support/shared_examples/services/common_system_notes_shared_examples.rb' + - 'spec/support/shared_examples/services/issuable_shared_examples.rb' + - 'spec/tasks/gitlab/web_hook_rake_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/migrate_external_diffs_worker_spec.rb' + - 'spec/workers/namespaceless_project_destroy_worker_spec.rb' + - 'spec/workers/pages_domain_verification_worker_spec.rb' + - 'spec/workers/propagate_service_template_worker_spec.rb' + - 'spec/workers/remove_unreferenced_lfs_objects_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' diff --git a/app/assets/javascripts/alert_management/components/alert_management_list.vue b/app/assets/javascripts/alert_management/components/alert_management_list.vue index d7972de62d9..e2098c851d1 100644 --- a/app/assets/javascripts/alert_management/components/alert_management_list.vue +++ b/app/assets/javascripts/alert_management/components/alert_management_list.vue @@ -282,9 +282,7 @@ export default { }, getAssignees(assignees) { // TODO: Update to show list of assignee(s) after https://gitlab.com/gitlab-org/gitlab/-/issues/218405 - return assignees.nodes?.length > 0 - ? assignees.nodes[0]?.username - : s__('AlertManagement|Unassigned'); + return assignees?.length > 0 ? assignees[0]?.username : s__('AlertManagement|Unassigned'); }, handlePageChange(page) { const { startCursor, endCursor } = this.alerts.pageInfo; diff --git a/app/assets/javascripts/alert_management/graphql/fragments/list_item.fragment.graphql b/app/assets/javascripts/alert_management/graphql/fragments/list_item.fragment.graphql index 746c4435f38..003aa9ac0f0 100644 --- a/app/assets/javascripts/alert_management/graphql/fragments/list_item.fragment.graphql +++ b/app/assets/javascripts/alert_management/graphql/fragments/list_item.fragment.graphql @@ -6,10 +6,8 @@ fragment AlertListItem on AlertManagementAlert { startedAt endedAt eventCount - issueIid + issueIid, assignees { - nodes { - username - } - } + username + }, } diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue index 0404c8cdfed..58b16f35347 100644 --- a/app/assets/javascripts/clusters_list/components/clusters.vue +++ b/app/assets/javascripts/clusters_list/components/clusters.vue @@ -1,10 +1,12 @@ <script> +import * as Sentry from '@sentry/browser'; import { mapState, mapActions } from 'vuex'; import { GlDeprecatedBadge as GlBadge, GlLink, GlLoadingIcon, GlPagination, + GlSprintf, GlTable, } from '@gitlab/ui'; import tooltip from '~/vue_shared/directives/tooltip'; @@ -12,11 +14,14 @@ import { CLUSTER_TYPES, STATUSES } from '../constants'; import { __, sprintf } from '~/locale'; export default { + nodeMemoryText: __('%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)'), + nodeCpuText: __('%{totalCpu} (%{freeSpacePercentage}%{percentSymbol} free)'), components: { GlBadge, GlLink, GlLoadingIcon, GlPagination, + GlSprintf, GlTable, }, directives: { @@ -47,15 +52,14 @@ export default { key: 'node_size', label: __('Nodes'), }, - // Fields are missing calculation methods and not ready to display - // { - // key: 'node_cpu', - // label: __('Total cores (vCPUs)'), - // }, - // { - // key: 'node_memory', - // label: __('Total memory (GB)'), - // }, + { + key: 'total_cpu', + label: __('Total cores (CPUs)'), + }, + { + key: 'total_memory', + label: __('Total memory (GB)'), + }, { key: 'cluster_type', label: __('Cluster level'), @@ -72,11 +76,102 @@ export default { }, methods: { ...mapActions(['fetchClusters', 'setPage']), + k8sQuantityToGb(quantity) { + if (!quantity) { + return 0; + } else if (quantity.endsWith(__('Ki'))) { + return parseInt(quantity.substr(0, quantity.length - 2), 10) * 0.000001024; + } else if (quantity.endsWith(__('Mi'))) { + return parseInt(quantity.substr(0, quantity.length - 2), 10) * 0.001048576; + } + // We are trying to track quantity types coming from Kubernetes. + // Sentry will notify us if we are missing types. + throw new Error(`UnknownK8sMemoryQuantity:${quantity}`); + }, + k8sQuantityToCpu(quantity) { + if (!quantity) { + return 0; + } else if (quantity.endsWith('m')) { + return parseInt(quantity.substr(0, quantity.length - 1), 10) / 1000.0; + } else if (quantity.endsWith('n')) { + return parseInt(quantity.substr(0, quantity.length - 1), 10) / 1000000000.0; + } + + // We are trying to track quantity types coming from Kubernetes. + // Sentry will notify us if we are missing types. + throw new Error(`UnknownK8sCpuQuantity:${quantity}`); + }, statusTitle(status) { const iconTitle = STATUSES[status] || STATUSES.default; return sprintf(__('Status: %{title}'), { title: iconTitle.title }, false); }, + totalMemoryAndUsage(nodes) { + try { + // For EKS node.usage will not be present unless the user manually + // install the metrics server + if (nodes && nodes[0].usage) { + let totalAllocatableMemory = 0; + let totalUsedMemory = 0; + + nodes.reduce((total, node) => { + const allocatableMemoryQuantity = node.status.allocatable.memory; + const allocatableMemoryGb = this.k8sQuantityToGb(allocatableMemoryQuantity); + totalAllocatableMemory += allocatableMemoryGb; + + const usedMemoryQuantity = node.usage.memory; + const usedMemoryGb = this.k8sQuantityToGb(usedMemoryQuantity); + totalUsedMemory += usedMemoryGb; + + return null; + }, 0); + + const freeSpacePercentage = (1 - totalUsedMemory / totalAllocatableMemory) * 100; + + return { + totalMemory: totalAllocatableMemory.toFixed(2), + freeSpacePercentage: Math.round(freeSpacePercentage), + }; + } + } catch (error) { + Sentry.captureException(error); + } + + return { totalMemory: null, freeSpacePercentage: null }; + }, + totalCpuAndUsage(nodes) { + try { + // For EKS node.usage will not be present unless the user manually + // install the metrics server + if (nodes && nodes[0].usage) { + let totalAllocatableCpu = 0; + let totalUsedCpu = 0; + + nodes.reduce((total, node) => { + const allocatableCpuQuantity = node.status.allocatable.cpu; + const allocatableCpu = this.k8sQuantityToCpu(allocatableCpuQuantity); + totalAllocatableCpu += allocatableCpu; + + const usedCpuQuantity = node.usage.cpu; + const usedCpuGb = this.k8sQuantityToCpu(usedCpuQuantity); + totalUsedCpu += usedCpuGb; + + return null; + }, 0); + + const freeSpacePercentage = (1 - totalUsedCpu / totalAllocatableCpu) * 100; + + return { + totalCpu: totalAllocatableCpu.toFixed(2), + freeSpacePercentage: Math.round(freeSpacePercentage), + }; + } + } catch (error) { + Sentry.captureException(error); + } + + return { totalCpu: null, freeSpacePercentage: null }; + }, }, }; </script> @@ -109,6 +204,34 @@ export default { }}</small> </template> + <template #cell(total_cpu)="{ item }"> + <span v-if="item.nodes"> + <gl-sprintf :message="$options.nodeCpuText"> + <template #totalCpu>{{ totalCpuAndUsage(item.nodes).totalCpu }}</template> + <template #freeSpacePercentage>{{ + totalCpuAndUsage(item.nodes).freeSpacePercentage + }}</template> + <template #percentSymbol + >%</template + > + </gl-sprintf> + </span> + </template> + + <template #cell(total_memory)="{ item }"> + <span v-if="item.nodes"> + <gl-sprintf :message="$options.nodeMemoryText"> + <template #totalMemory>{{ totalMemoryAndUsage(item.nodes).totalMemory }}</template> + <template #freeSpacePercentage>{{ + totalMemoryAndUsage(item.nodes).freeSpacePercentage + }}</template> + <template #percentSymbol + >%</template + > + </gl-sprintf> + </span> + </template> + <template #cell(cluster_type)="{value}"> <gl-badge variant="light"> {{ value }} diff --git a/app/controllers/repositories/git_http_controller.rb b/app/controllers/repositories/git_http_controller.rb index e3dbe6fcbdf..6a27d63625e 100644 --- a/app/controllers/repositories/git_http_controller.rb +++ b/app/controllers/repositories/git_http_controller.rb @@ -9,7 +9,7 @@ module Repositories rescue_from Gitlab::GitAccess::ForbiddenError, with: :render_403_with_exception rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404_with_exception - rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422_with_exception + rescue_from Gitlab::GitAccessProject::CreationError, with: :render_422_with_exception rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception # GET /foo/bar.git/info/refs?service=git-upload-pack (git pull) diff --git a/app/graphql/resolvers/alert_management/alerts/assignees_resolver.rb b/app/graphql/resolvers/alert_management/alerts/assignees_resolver.rb deleted file mode 100644 index 208b30b7f01..00000000000 --- a/app/graphql/resolvers/alert_management/alerts/assignees_resolver.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module Resolvers - module AlertManagement - module Alerts - class AssigneesResolver < BaseResolver - type Types::UserType, null: true - - # With lazy-loaded assignees, authorizations should be avoided - # in earlier phases to take advantage of batching. See - # AssigneeLoader for authorization steps. - # https://gitlab.com/gitlab-org/gitlab/-/issues/217767 - def self.skip_authorizations? - true - end - - def resolve(**args) - return [] unless Feature.enabled?(:alert_assignee) - - ::Gitlab::Graphql::Loaders::AlertManagement::Alerts::AssigneesLoader - .new(object.id, user_authorization_filter) - .find - end - - private - - def user_authorization_filter - proc do |users| - users.select { |user| Ability.allowed?(context[:current_user], :read_user, user) } - end - end - end - end - end -end diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb index ae5fc7c28e8..1630bf4491d 100644 --- a/app/graphql/types/alert_management/alert_type.rb +++ b/app/graphql/types/alert_management/alert_type.rb @@ -85,10 +85,15 @@ module Types description: 'Timestamp the alert was last updated' field :assignees, - Types::UserType.connection_type, + [Types::UserType], null: true, - description: 'Assignees of the alert', - resolver: ::Resolvers::AlertManagement::Alerts::AssigneesResolver + description: 'Assignees of the alert' + + def assignees + return User.none unless Feature.enabled?(:alert_assignee, object.project) + + object.assignees + end end end end diff --git a/app/models/alert_management/alert_assignee.rb b/app/models/alert_management/alert_assignee.rb index 91a52bf8f74..c74b2699182 100644 --- a/app/models/alert_management/alert_assignee.rb +++ b/app/models/alert_management/alert_assignee.rb @@ -7,7 +7,5 @@ module AlertManagement validates :alert, presence: true validates :assignee, presence: true, uniqueness: { scope: :alert_id } - - scope :for_alert_ids, -> (ids) { includes(:assignee).where(alert_id: ids) } end end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index c919f57a8fc..755e704aeaa 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -800,13 +800,17 @@ module Ci @latest_builds_with_artifacts ||= builds.latest.with_artifacts_not_expired.to_a end + def latest_report_builds(reports_scope = ::Ci::JobArtifact.with_reports) + builds.latest.with_reports(reports_scope) + end + def has_reports?(reports_scope) - complete? && builds.latest.with_reports(reports_scope).exists? + complete? && latest_report_builds(reports_scope).exists? end def test_reports Gitlab::Ci::Reports::TestReports.new.tap do |test_reports| - builds.latest.with_reports(Ci::JobArtifact.test_reports).preload(:project).find_each do |build| + latest_report_builds(Ci::JobArtifact.test_reports).preload(:project).find_each do |build| build.collect_test_reports!(test_reports) end end @@ -828,7 +832,7 @@ module Ci def coverage_reports Gitlab::Ci::Reports::CoverageReports.new.tap do |coverage_reports| - builds.latest.with_reports(Ci::JobArtifact.coverage_reports).each do |build| + latest_report_builds(Ci::JobArtifact.coverage_reports).each do |build| build.collect_coverage_reports!(coverage_reports) end end @@ -836,7 +840,7 @@ module Ci def terraform_reports ::Gitlab::Ci::Reports::TerraformReports.new.tap do |terraform_reports| - builds.latest.with_reports(::Ci::JobArtifact.terraform_reports).each do |build| + latest_report_builds(::Ci::JobArtifact.terraform_reports).each do |build| build.collect_terraform_reports!(terraform_reports) end end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 73eb0ee22c0..81107bb00e3 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -373,7 +373,10 @@ module Clusters def retrieve_nodes result = ::Gitlab::Kubernetes::KubeClient.graceful_request(id) { kubeclient.get_nodes } - cluster_nodes = result[:response].to_a + + return unless result[:response] + + cluster_nodes = result[:response] result = ::Gitlab::Kubernetes::KubeClient.graceful_request(id) { kubeclient.metrics_client.get_nodes } nodes_metrics = result[:response].to_a diff --git a/changelogs/unreleased/215668-settings-auto-fix.yml b/changelogs/unreleased/215668-settings-auto-fix.yml new file mode 100644 index 00000000000..b0ac2c15fcf --- /dev/null +++ b/changelogs/unreleased/215668-settings-auto-fix.yml @@ -0,0 +1,5 @@ +--- +title: Add model for project level security auto-fix settings +merge_request: 32577 +author: +type: added diff --git a/changelogs/unreleased/feature-show-memory-cpu-on-cluster-list.yml b/changelogs/unreleased/feature-show-memory-cpu-on-cluster-list.yml new file mode 100644 index 00000000000..e3375d85821 --- /dev/null +++ b/changelogs/unreleased/feature-show-memory-cpu-on-cluster-list.yml @@ -0,0 +1,5 @@ +--- +title: Adds cluster CPU and Memory to cluster index +merge_request: 32601 +author: +type: changed diff --git a/config/webpack.config.js b/config/webpack.config.js index c17734ed3dc..557db58b1b9 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -19,10 +19,11 @@ const IS_EE = require('./helpers/is_ee_env'); const DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost'; const DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808; const DEV_SERVER_LIVERELOAD = IS_DEV_SERVER && process.env.DEV_SERVER_LIVERELOAD !== 'false'; -const WEBPACK_REPORT = process.env.WEBPACK_REPORT; -const WEBPACK_MEMORY_TEST = process.env.WEBPACK_MEMORY_TEST; -const NO_COMPRESSION = process.env.NO_COMPRESSION; -const NO_SOURCEMAPS = process.env.NO_SOURCEMAPS; +const WEBPACK_REPORT = process.env.WEBPACK_REPORT && process.env.WEBPACK_REPORT !== 'false'; +const WEBPACK_MEMORY_TEST = + process.env.WEBPACK_MEMORY_TEST && process.env.WEBPACK_MEMORY_TEST !== 'false'; +const NO_COMPRESSION = process.env.NO_COMPRESSION && process.env.NO_COMPRESSION !== 'false'; +const NO_SOURCEMAPS = process.env.NO_SOURCEMAPS && process.env.NO_SOURCEMAPS !== 'false'; const VUE_VERSION = require('vue/package.json').version; const VUE_LOADER_VERSION = require('vue-loader/package.json').version; diff --git a/db/migrate/20200604143628_create_project_security_settings.rb b/db/migrate/20200604143628_create_project_security_settings.rb new file mode 100644 index 00000000000..f972cb509a7 --- /dev/null +++ b/db/migrate/20200604143628_create_project_security_settings.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class CreateProjectSecuritySettings < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def up + with_lock_retries do + create_table :project_security_settings, id: false do |t| + t.references :project, primary_key: true, index: false, foreign_key: { on_delete: :cascade } + t.timestamps_with_timezone + + t.boolean :auto_fix_container_scanning, default: true, null: false + t.boolean :auto_fix_dast, default: true, null: false + t.boolean :auto_fix_dependency_scanning, default: true, null: false + t.boolean :auto_fix_sast, default: true, null: false + end + end + end + + def down + with_lock_retries do + drop_table :project_security_settings + end + end +end diff --git a/db/structure.sql b/db/structure.sql index f5006c09830..861544f2550 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -5316,6 +5316,25 @@ CREATE SEQUENCE public.project_repository_storage_moves_id_seq ALTER SEQUENCE public.project_repository_storage_moves_id_seq OWNED BY public.project_repository_storage_moves.id; +CREATE TABLE public.project_security_settings ( + project_id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + auto_fix_container_scanning boolean DEFAULT true NOT NULL, + auto_fix_dast boolean DEFAULT true NOT NULL, + auto_fix_dependency_scanning boolean DEFAULT true NOT NULL, + auto_fix_sast boolean DEFAULT true NOT NULL +); + +CREATE SEQUENCE public.project_security_settings_project_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE public.project_security_settings_project_id_seq OWNED BY public.project_security_settings.project_id; + CREATE TABLE public.project_settings ( project_id integer NOT NULL, created_at timestamp with time zone NOT NULL, @@ -7822,6 +7841,8 @@ ALTER TABLE ONLY public.project_repository_states ALTER COLUMN id SET DEFAULT ne ALTER TABLE ONLY public.project_repository_storage_moves ALTER COLUMN id SET DEFAULT nextval('public.project_repository_storage_moves_id_seq'::regclass); +ALTER TABLE ONLY public.project_security_settings ALTER COLUMN project_id SET DEFAULT nextval('public.project_security_settings_project_id_seq'::regclass); + ALTER TABLE ONLY public.project_statistics ALTER COLUMN id SET DEFAULT nextval('public.project_statistics_id_seq'::regclass); ALTER TABLE ONLY public.project_tracing_settings ALTER COLUMN id SET DEFAULT nextval('public.project_tracing_settings_id_seq'::regclass); @@ -8748,6 +8769,9 @@ ALTER TABLE ONLY public.project_repository_states ALTER TABLE ONLY public.project_repository_storage_moves ADD CONSTRAINT project_repository_storage_moves_pkey PRIMARY KEY (id); +ALTER TABLE ONLY public.project_security_settings + ADD CONSTRAINT project_security_settings_pkey PRIMARY KEY (project_id); + ALTER TABLE ONLY public.project_settings ADD CONSTRAINT project_settings_pkey PRIMARY KEY (project_id); @@ -12711,6 +12735,9 @@ ALTER TABLE ONLY public.ci_daily_report_results ALTER TABLE ONLY public.cluster_providers_aws ADD CONSTRAINT fk_rails_ed1fdfaeb2 FOREIGN KEY (created_by_user_id) REFERENCES public.users(id) ON DELETE SET NULL; +ALTER TABLE ONLY public.project_security_settings + ADD CONSTRAINT fk_rails_ed4abe1338 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE; + ALTER TABLE ONLY public.ci_daily_build_group_report_results ADD CONSTRAINT fk_rails_ee072d13b3 FOREIGN KEY (last_pipeline_id) REFERENCES public.ci_pipelines(id) ON DELETE CASCADE; @@ -13806,5 +13833,6 @@ COPY "schema_migrations" (version) FROM STDIN; 20200528171933 20200601210148 20200603073101 +20200604143628 \. diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index ce338ef875a..b0cc72965aa 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -172,27 +172,7 @@ type AlertManagementAlert { """ Assignees of the alert """ - assignees( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection + assignees: [User!] """ Timestamp the alert was created diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 9ac10a14575..10b34f6af91 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -486,51 +486,20 @@ "name": "assignees", "description": "Assignees of the alert", "args": [ - { - "name": "after", - "description": "Returns the elements in the list that come after the specified cursor.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "Returns the elements in the list that come before the specified cursor.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "Returns the first _n_ elements from the list.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "Returns the last _n_ elements from the list.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } + ], "type": { - "kind": "OBJECT", - "name": "UserConnection", - "ofType": null + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "User", + "ofType": null + } + } }, "isDeprecated": false, "deprecationReason": null diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 802b118b170..96bac1d3549 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -61,6 +61,7 @@ Describes an alert from the project's Alert Management | Name | Type | Description | | --- | ---- | ---------- | +| `assignees` | User! => Array | Assignees of the alert | | `createdAt` | Time | Timestamp the alert was created | | `description` | String | Description of the alert | | `details` | JSON | Alert details | diff --git a/doc/ci/environments/incremental_rollouts.md b/doc/ci/environments/incremental_rollouts.md index c35e7cac0e5..5da5c8e0a87 100644 --- a/doc/ci/environments/incremental_rollouts.md +++ b/doc/ci/environments/incremental_rollouts.md @@ -117,7 +117,7 @@ available, [demonstrating configuration of timed rollouts](https://gitlab.com/gl ## Blue-Green Deployment -Also sometimes known as canary or red-black deployment, this technique is used to reduce +Also sometimes known as A/B deployment or red-black deployment, this technique is used to reduce downtime and risk during a deployment. When combined with incremental rollouts, you can minimize the impact of a deployment causing an issue. diff --git a/doc/development/telemetry/usage_ping.md b/doc/development/telemetry/usage_ping.md index d8fa50ac47a..975268bcd4a 100644 --- a/doc/development/telemetry/usage_ping.md +++ b/doc/development/telemetry/usage_ping.md @@ -289,7 +289,11 @@ Examples of query optimization work: - [Example 1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26445) - [Example 2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26871) -### 4. Ask for a Telemetry Review +### 4. Add the metric definition + +When adding, changing, or updating metrics, please update the [Usage Statistics definition table](#usage-statistics-definitions). + +### 5. Ask for a Telemetry Review On GitLab.com, we have DangerBot setup to monitor Telemetry related files and DangerBot will recommend a Telemetry review. Mention `@gitlab-org/growth/telemetry/engineers` in your MR for a review. diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 7fffbbde5cd..6eb1cde7bbb 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -56,20 +56,24 @@ Beginning with GitLab 13.0, Docker privileged mode is necessary only if you've [ GitLab relies on [`rules`](../../../ci/yaml/README.md#rules) to start relevant analyzers depending on the languages detected in the repository. The current detection logic limits the maximum search depth to two levels. For example, the `gemnasium-dependency_scanning` job is enabled if a repository contains either a `Gemfile`Â or `api/Gemfile` file, but not if the only supported dependency file is `api/client/Gemfile`. -The following languages and dependency managers are supported. - -| Language (package managers) | Supported | Scan tool(s) | -|----------------------------- | --------- | ------------ | -| Java ([Gradle](https://gradle.org/)) | yes | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | -| Java ([Maven](https://maven.apache.org/)) | yes | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | -| JavaScript ([npm](https://www.npmjs.com/), [yarn](https://classic.yarnpkg.com/en/)) | yes | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [Retire.js](https://retirejs.github.io/retire.js/) | -| PHP ([Composer](https://getcomposer.org/)) | yes | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | -| Python ([pip](https://pip.pypa.io/en/stable/)) | yes | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | -| Python ([Pipfile](https://pipenv.kennethreitz.org/en/latest/basics/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/-/issues/11756 "Pipfile.lock support for Dependency Scanning"))| not available | -| Python ([poetry](https://python-poetry.org/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/-/issues/7006 "Support Poetry in Dependency Scanning")) | not available | -| Ruby ([gem](https://rubygems.org/)) | yes | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) | -| Scala ([sbt](https://www.scala-sbt.org/)) | yes | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | -| Go ([Go Modules](https://github.com/golang/go/wiki/Modules)) | yes ([alpha](https://gitlab.com/gitlab-org/gitlab/-/issues/7132)) | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | +The following languages and dependency managers are supported: + +| Language (package managers) | Supported files | Scan tool(s) | +|----------------------------- | --------------- | ------------ | +| Java ([Gradle](https://gradle.org/), [Maven](https://maven.apache.org/)) | `build.gradle`, `build.gradle.kts`, `pom.xml` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | +| JavaScript ([npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/en/)) | `package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [Retire.js](https://retirejs.github.io/retire.js) | +| Go ([Golang](https://golang.org/)) | `go.sum` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | +| PHP ([Composer](https://getcomposer.org/)) | `composer.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | +| Python ([setuptools](https://setuptools.readthedocs.io/en/latest/), [pip](https://pip.pypa.io/en/stable/), [Pipenv](https://pipenv.pypa.io/en/latest/)) | `setup.py`, `requirements.txt`, `requirements.pip`, `requires.txt`, `Pipfile` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | +| Ruby ([Bundler](https://bundler.io/)) | `Gemfile.lock`, `gems.locked` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) | +| Scala ([sbt](https://www.scala-sbt.org/)) | `build.sbt` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | + +Plans are underway for supporting the following languages, dependency managers, and dependency files. For details, see the issue link for each. + +| Language (package managers) | Supported files | Scan tool(s) | Issue | +|----------------------------- | --------------- | ------------ | ----- | +| Python ([Poetry](https://poetry.eustace.io/)) | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/issues/7006) | +| Python ([Pipenv](https://pipenv.pypa.io/en/latest/)) | `Pipfile.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#11756](https://gitlab.com/gitlab-org/gitlab/-/issues/11756) | ## Contribute your scanner diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md index 8779b3ea9bd..c5638a8a3cd 100644 --- a/doc/user/packages/container_registry/index.md +++ b/doc/user/packages/container_registry/index.md @@ -496,8 +496,9 @@ older tags and images are regularly removed from the Container Registry. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15398) in GitLab 12.8. NOTE: **Note:** -Expiration policies for projects created before GitLab 12.8 may be enabled by an -admin in the [CI/CD Package Registry settings](./../../admin_area/settings/index.md#cicd). +For GitLab.com, expiration policies are not available for projects created before GitLab 12.8. +For self-managed instances, expiration policies may be enabled by an admin in the +[CI/CD Package Registry settings](./../../admin_area/settings/index.md#cicd). Note the inherent [risks involved](./index.md#use-with-external-container-registries). It is possible to create a per-project expiration policy, so that you can make sure that diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md index 6033d02df73..bf9b58acf14 100644 --- a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md +++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md @@ -287,6 +287,9 @@ To enable this setting: 1. Navigate to your project's **Settings > Pages**. 1. Tick the checkbox **Force HTTPS (requires valid certificates)**. +NOTE: **Note** +If you use CloudFlare CDN in front of GitLab Pages, make sure to set the SSL connection setting to `full` instead of `flexible`. For more details, see the [CloudFlare CDN directions](https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef). + <!-- ## Troubleshooting Include any troubleshooting steps that you can foresee. If you know beforehand what issues diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 6702c053fc7..37e3da984d6 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -8,7 +8,6 @@ module Gitlab ForbiddenError = Class.new(StandardError) NotFoundError = Class.new(StandardError) - ProjectCreationError = Class.new(StandardError) TimeoutError = Class.new(StandardError) ProjectMovedError = Class.new(NotFoundError) @@ -75,7 +74,7 @@ module Gitlab check_db_accessibility!(cmd) check_namespace! - check_project!(changes, cmd) + check_project!(cmd) check_repository_existence! case cmd @@ -112,8 +111,7 @@ module Gitlab private - def check_project!(changes, cmd) - ensure_project_on_push!(cmd, changes) + def check_project!(_cmd) check_project_accessibility! add_project_moved_message! end @@ -230,32 +228,6 @@ module Gitlab end end - def ensure_project_on_push!(cmd, changes) - return if project || deploy_key? - return unless receive_pack?(cmd) && changes == ANY && authentication_abilities.include?(:push_code) - - namespace = Namespace.find_by_full_path(namespace_path) - - return unless user&.can?(:create_projects, namespace) - - project_params = { - path: repository_path, - namespace_id: namespace.id, - visibility_level: Gitlab::VisibilityLevel::PRIVATE - } - - project = Projects::CreateService.new(user, project_params).execute - - unless project.saved? - raise ProjectCreationError, "Could not create project: #{project.errors.full_messages.join(', ')}" - end - - @project = project - user_access.project = @project - - Checks::ProjectCreated.new(repository, user, protocol).add_message - end - def check_repository_existence! unless repository.exists? raise NotFoundError, ERROR_MESSAGES[:no_repo] diff --git a/lib/gitlab/git_access_project.rb b/lib/gitlab/git_access_project.rb new file mode 100644 index 00000000000..c79a61c263e --- /dev/null +++ b/lib/gitlab/git_access_project.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Gitlab + class GitAccessProject < GitAccess + extend ::Gitlab::Utils::Override + + CreationError = Class.new(StandardError) + + private + + override :check_project! + def check_project!(cmd) + ensure_project_on_push!(cmd) + + super + end + + def ensure_project_on_push!(cmd) + return if project || deploy_key? + return unless receive_pack?(cmd) && changes == ANY && authentication_abilities.include?(:push_code) + + namespace = Namespace.find_by_full_path(namespace_path) + + return unless user&.can?(:create_projects, namespace) + + project_params = { + path: repository_path, + namespace_id: namespace.id, + visibility_level: Gitlab::VisibilityLevel::PRIVATE + } + + project = Projects::CreateService.new(user, project_params).execute + + unless project.saved? + raise CreationError, "Could not create project: #{project.errors.full_messages.join(', ')}" + end + + @project = project + user_access.project = @project + + Checks::ProjectCreated.new(repository, user, protocol).add_message + end + end +end diff --git a/lib/gitlab/git_access_snippet.rb b/lib/gitlab/git_access_snippet.rb index ba9920caf6f..3de6c9ee30a 100644 --- a/lib/gitlab/git_access_snippet.rb +++ b/lib/gitlab/git_access_snippet.rb @@ -47,11 +47,10 @@ module Gitlab end override :check_project! - def check_project!(cmd, changes) + def check_project!(cmd) return unless snippet.is_a?(ProjectSnippet) - check_project_accessibility! - add_project_moved_message! + super end override :check_push_access! diff --git a/lib/gitlab/gl_repository.rb b/lib/gitlab/gl_repository.rb index b75b4be9a4e..abd4e847a50 100644 --- a/lib/gitlab/gl_repository.rb +++ b/lib/gitlab/gl_repository.rb @@ -6,7 +6,7 @@ module Gitlab PROJECT = RepoType.new( name: :project, - access_checker_class: Gitlab::GitAccess, + access_checker_class: Gitlab::GitAccessProject, repository_resolver: -> (project) { project&.repository } ).freeze WIKI = RepoType.new( diff --git a/lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader.rb b/lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader.rb deleted file mode 100644 index 7671dbb58ee..00000000000 --- a/lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Graphql - module Loaders - module AlertManagement - module Alerts - # Batches requests for AlertManagement::Alert#assignees - # to avoid N+1 queries - class AssigneesLoader - # @param alert_id [Integer] - # @param authorization_filter [Proc] Filter to be applied - # to output assignees - def initialize(alert_id, authorization_filter) - @alert_id = alert_id - @authorization_filter = authorization_filter - end - - # Returns BatchLoader::GraphQL which evaluates - # to a Gitlab::Graphql::FilterableArray of User objects - def find - BatchLoader::GraphQL.for(alert_id).batch(default_value: default_value) do |alert_ids, loader| - load_assignees(loader, alert_ids) - end - end - - private - - attr_reader :alert_id, :authorization_filter - - def default_value - Gitlab::Graphql::FilterableArray.new(authorization_filter) - end - - def load_assignees(loader, alert_ids) - ::AlertManagement::AlertAssignee - .for_alert_ids(alert_ids) - .each { |alert_assignee| add_assignee_for_alert(loader, alert_assignee) } - end - - def add_assignee_for_alert(loader, alert_assignee) - # loader optionally accepts a block, allowing - # access to the current expected output, allowing - # us to collect assignees - loader.call(alert_assignee.alert_id) { |assignees| assignees << alert_assignee.assignee } - end - end - end - end - end - end -end diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml index 8851b106ad5..a2213b67ee1 100644 --- a/lib/gitlab/import_export/project/import_export.yml +++ b/lib/gitlab/import_export/project/import_export.yml @@ -397,3 +397,4 @@ ee: - protected_environments: - :deploy_access_levels - :service_desk_setting + - :security_setting diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a28588496ba..e36decd3c00 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -622,6 +622,12 @@ msgstr "" msgid "%{token}..." msgstr "" +msgid "%{totalCpu} (%{freeSpacePercentage}%{percentSymbol} free)" +msgstr "" + +msgid "%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)" +msgstr "" + msgid "%{totalWeight} total weight" msgstr "" @@ -12641,6 +12647,9 @@ msgstr "" msgid "Keyboard shortcuts" msgstr "" +msgid "Ki" +msgstr "" + msgid "Kubernetes" msgstr "" @@ -14098,6 +14107,9 @@ msgstr "" msgid "Metrics|e.g. req/sec" msgstr "" +msgid "Mi" +msgstr "" + msgid "Microsoft Azure" msgstr "" @@ -23489,9 +23501,15 @@ msgstr "" msgid "Total artifacts size: %{total_size}" msgstr "" +msgid "Total cores (CPUs)" +msgstr "" + msgid "Total issues" msgstr "" +msgid "Total memory (GB)" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "" diff --git a/spec/frontend/alert_management/components/alert_management_list_spec.js b/spec/frontend/alert_management/components/alert_management_list_spec.js index 39099f25150..b917d78dd95 100644 --- a/spec/frontend/alert_management/components/alert_management_list_spec.js +++ b/spec/frontend/alert_management/components/alert_management_list_spec.js @@ -262,7 +262,7 @@ describe('AlertManagementList', () => { findAssignees() .at(1) .text(), - ).toBe(mockAlerts[1].assignees.nodes[0].username); + ).toBe(mockAlerts[1].assignees[0].username); }); it('navigates to the detail page when alert row is clicked', () => { @@ -291,7 +291,6 @@ describe('AlertManagementList', () => { startedAt: '2020-03-17T23:18:14.996Z', endedAt: '2020-04-17T23:18:14.996Z', severity: 'high', - assignees: { nodes: [] }, }, ], }, diff --git a/spec/frontend/alert_management/mocks/alerts.json b/spec/frontend/alert_management/mocks/alerts.json index 60bf075016c..402adc4675b 100644 --- a/spec/frontend/alert_management/mocks/alerts.json +++ b/spec/frontend/alert_management/mocks/alerts.json @@ -1,33 +1,33 @@ [ - { - "iid": "1527542", - "title": "SyntaxError: Invalid or unexpected token", - "severity": "CRITICAL", - "eventCount": 7, - "createdAt": "2020-04-17T23:18:14.996Z", - "startedAt": "2020-04-17T23:18:14.996Z", - "endedAt": "2020-04-17T23:18:14.996Z", - "status": "TRIGGERED", - "assignees": { "nodes": [] } - }, - { - "iid": "1527543", - "title": "Some other alert Some other alert Some other alert Some other alert Some other alert Some other alert", - "severity": "MEDIUM", - "eventCount": 1, - "startedAt": "2020-04-17T23:18:14.996Z", - "endedAt": "2020-04-17T23:18:14.996Z", - "status": "ACKNOWLEDGED", - "assignees": { "nodes": [{ "username": "root" }] } - }, - { - "iid": "1527544", - "title": "SyntaxError: Invalid or unexpected token", - "severity": "LOW", - "eventCount": 4, - "startedAt": "2020-04-17T23:18:14.996Z", - "endedAt": "2020-04-17T23:18:14.996Z", - "status": "RESOLVED", - "assignees": { "nodes": [{ "username": "root" }] } - } -] + { + "iid": "1527542", + "title": "SyntaxError: Invalid or unexpected token", + "severity": "CRITICAL", + "eventCount": 7, + "createdAt": "2020-04-17T23:18:14.996Z", + "startedAt": "2020-04-17T23:18:14.996Z", + "endedAt": "2020-04-17T23:18:14.996Z", + "status": "TRIGGERED", + "assignees": [] + }, + { + "iid": "1527543", + "title": "Some other alert Some other alert Some other alert Some other alert Some other alert Some other alert", + "severity": "MEDIUM", + "eventCount": 1, + "startedAt": "2020-04-17T23:18:14.996Z", + "endedAt": "2020-04-17T23:18:14.996Z", + "status": "ACKNOWLEDGED", + "assignees": [{"username": "root"}] + }, + { + "iid": "1527544", + "title": "SyntaxError: Invalid or unexpected token", + "severity": "LOW", + "eventCount": 4, + "startedAt": "2020-04-17T23:18:14.996Z", + "endedAt": "2020-04-17T23:18:14.996Z", + "status": "RESOLVED", + "assignees": [{"username": "root"}] + } + ] diff --git a/spec/frontend/clusters_list/components/clusters_spec.js b/spec/frontend/clusters_list/components/clusters_spec.js index 9f76078a69a..3a5c4c4c008 100644 --- a/spec/frontend/clusters_list/components/clusters_spec.js +++ b/spec/frontend/clusters_list/components/clusters_spec.js @@ -5,6 +5,7 @@ import MockAdapter from 'axios-mock-adapter'; import { apiData } from '../mock_data'; import { mount } from '@vue/test-utils'; import { GlLoadingIcon, GlTable, GlPagination } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; describe('Clusters', () => { let mock; @@ -36,7 +37,11 @@ describe('Clusters', () => { }; }; + let captureException; + beforeEach(() => { + captureException = jest.spyOn(Sentry, 'captureException'); + mock = new MockAdapter(axios); mockPollingApi(200, apiData, paginationHeader()); @@ -46,6 +51,7 @@ describe('Clusters', () => { afterEach(() => { wrapper.destroy(); mock.restore(); + captureException.mockRestore(); }); describe('clusters table', () => { @@ -106,8 +112,8 @@ describe('Clusters', () => { ${'Unknown'} | ${0} ${'1'} | ${1} ${'2'} | ${2} - ${'Unknown'} | ${3} - ${'Unknown'} | ${4} + ${'1'} | ${3} + ${'1'} | ${4} ${'Unknown'} | ${5} `('renders node size for each cluster', ({ nodeSize, lineNumber }) => { const sizes = findTable().findAll('td:nth-child(3)'); @@ -115,6 +121,58 @@ describe('Clusters', () => { expect(size.text()).toBe(nodeSize); }); + + describe('nodes with unknown quantity', () => { + it('notifies Sentry about all missing quantity types', () => { + expect(captureException).toHaveBeenCalledTimes(8); + }); + + it('notifies Sentry about CPU missing quantity types', () => { + const missingCpuTypeError = new Error('UnknownK8sCpuQuantity:1missingCpuUnit'); + + expect(captureException).toHaveBeenCalledWith(missingCpuTypeError); + }); + + it('notifies Sentry about Memory missing quantity types', () => { + const missingMemoryTypeError = new Error('UnknownK8sMemoryQuantity:1missingMemoryUnit'); + + expect(captureException).toHaveBeenCalledWith(missingMemoryTypeError); + }); + }); + }); + + describe('cluster CPU', () => { + it.each` + clusterCpu | lineNumber + ${''} | ${0} + ${'1.93 (87% free)'} | ${1} + ${'3.87 (86% free)'} | ${2} + ${'(% free)'} | ${3} + ${'(% free)'} | ${4} + ${''} | ${5} + `('renders total cpu for each cluster', ({ clusterCpu, lineNumber }) => { + const clusterCpus = findTable().findAll('td:nth-child(4)'); + const cpuData = clusterCpus.at(lineNumber); + + expect(cpuData.text()).toBe(clusterCpu); + }); + }); + + describe('cluster Memory', () => { + it.each` + clusterMemory | lineNumber + ${''} | ${0} + ${'5.92 (78% free)'} | ${1} + ${'12.86 (79% free)'} | ${2} + ${'(% free)'} | ${3} + ${'(% free)'} | ${4} + ${''} | ${5} + `('renders total memory for each cluster', ({ clusterMemory, lineNumber }) => { + const clusterMemories = findTable().findAll('td:nth-child(5)'); + const memoryData = clusterMemories.at(lineNumber); + + expect(memoryData.text()).toBe(clusterMemory); + }); }); describe('pagination', () => { diff --git a/spec/frontend/clusters_list/mock_data.js b/spec/frontend/clusters_list/mock_data.js index 6ce0aa90f10..eb8582796f7 100644 --- a/spec/frontend/clusters_list/mock_data.js +++ b/spec/frontend/clusters_list/mock_data.js @@ -11,7 +11,12 @@ export const clusterList = [ environment_scope: 'development', cluster_type: 'project_type', status: 'unreachable', - nodes: [{ usage: { cpu: '246155922n', memory: '1255212Ki' } }], + nodes: [ + { + status: { allocatable: { cpu: '1930m', memory: '5777156Ki' } }, + usage: { cpu: '246155922n', memory: '1255212Ki' }, + }, + ], }, { name: 'My Cluster 3', @@ -19,8 +24,14 @@ export const clusterList = [ cluster_type: 'project_type', status: 'authentication_failure', nodes: [ - { usage: { cpu: '246155922n', memory: '1255212Ki' } }, - { usage: { cpu: '307051934n', memory: '1379136Ki' } }, + { + status: { allocatable: { cpu: '1930m', memory: '5777156Ki' } }, + usage: { cpu: '246155922n', memory: '1255212Ki' }, + }, + { + status: { allocatable: { cpu: '1940m', memory: '6777156Ki' } }, + usage: { cpu: '307051934n', memory: '1379136Ki' }, + }, ], }, { @@ -28,12 +39,23 @@ export const clusterList = [ environment_scope: 'production', cluster_type: 'project_type', status: 'deleting', + nodes: [ + { + status: { allocatable: { cpu: '1missingCpuUnit', memory: '1missingMemoryUnit' } }, + usage: { cpu: '1missingCpuUnit', memory: '1missingMemoryUnit' }, + }, + ], }, { name: 'My Cluster 5', environment_scope: 'development', cluster_type: 'project_type', status: 'created', + nodes: [ + { + status: { allocatable: { cpu: '1missingCpuUnit', memory: '1missingMemoryUnit' } }, + }, + ], }, { name: 'My Cluster 6', diff --git a/spec/graphql/resolvers/alert_management/alerts/assignees_resolver_spec.rb b/spec/graphql/resolvers/alert_management/alerts/assignees_resolver_spec.rb deleted file mode 100644 index d18c828b191..00000000000 --- a/spec/graphql/resolvers/alert_management/alerts/assignees_resolver_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Resolvers::AlertManagement::Alerts::AssigneesResolver do - include GraphqlHelpers - - describe '#resolve' do - let_it_be(:current_user) { create(:user) } - let_it_be(:project) { create(:project) } - let_it_be(:alert) { create(:alert_management_alert, :all_fields, project: project) } - let_it_be(:another_alert) { create(:alert_management_alert, :all_fields, project: project) } - - it 'resolves for a single alert' do - result = batch_sync(max_queries: 2) { resolve_assignees(alert) } - - expect(result).to match_array(alert.assignees) - end - - it 'resolves for multiple alerts' do - result = batch_sync(max_queries: 2) { [resolve_assignees(alert), resolve_assignees(another_alert)] } - - expect(result).to match_array([alert.assignees, another_alert.assignees]) - end - - private - - def resolve_assignees(alert, args = {}, context = { current_user: current_user }) - resolve(described_class, obj: alert, args: args, ctx: context) - end - end -end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index c93bb901981..1668149d8f5 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -1388,7 +1388,7 @@ module Gitlab let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } let(:config) do { - stages: ["build", "test", "release"], # rubocop:disable Style/WordArray + stages: %w[build test release], release: { stage: "release", only: ["tags"], diff --git a/spec/lib/gitlab/git_access_project_spec.rb b/spec/lib/gitlab/git_access_project_spec.rb new file mode 100644 index 00000000000..f7f7976ccb8 --- /dev/null +++ b/spec/lib/gitlab/git_access_project_spec.rb @@ -0,0 +1,166 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::GitAccessProject do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository) } + let(:actor) { user } + let(:project_path) { project.path } + let(:namespace_path) { project&.namespace&.path } + let(:protocol) { 'ssh' } + let(:authentication_abilities) { %i[read_project download_code push_code] } + let(:changes) { Gitlab::GitAccess::ANY } + let(:push_access_check) { access.check('git-receive-pack', changes) } + let(:pull_access_check) { access.check('git-upload-pack', changes) } + + describe '#check_project_accessibility!' do + context 'when the project is nil' do + let(:project) { nil } + let(:project_path) { "new-project" } + + context 'when user is allowed to create project in namespace' do + let(:namespace_path) { user.namespace.path } + let(:access) do + described_class.new(actor, nil, + protocol, authentication_abilities: authentication_abilities, + repository_path: project_path, namespace_path: namespace_path) + end + + it 'blocks pull access with "not found"' do + expect { pull_access_check }.to raise_not_found + end + + it 'allows push access' do + expect { push_access_check }.not_to raise_error + end + end + + context 'when user is not allowed to create project in namespace' do + let(:user2) { create(:user) } + let(:namespace_path) { user2.namespace.path } + let(:access) do + described_class.new(actor, nil, + protocol, authentication_abilities: authentication_abilities, + repository_path: project_path, namespace_path: namespace_path) + end + + it 'blocks push and pull with "not found"' do + aggregate_failures do + expect { pull_access_check }.to raise_not_found + expect { push_access_check }.to raise_not_found + end + end + end + end + end + + describe '#ensure_project_on_push!' do + let(:access) do + described_class.new(actor, project, + protocol, authentication_abilities: authentication_abilities, + repository_path: project_path, namespace_path: namespace_path) + end + + before do + allow(access).to receive(:changes).and_return(changes) + end + + context 'when push' do + let(:cmd) { 'git-receive-pack' } + + context 'when project does not exist' do + let(:project_path) { "nonexistent" } + let(:project) { nil } + + context 'when changes is _any' do + let(:changes) { Gitlab::GitAccess::ANY } + + context 'when authentication abilities include push code' do + let(:authentication_abilities) { [:push_code] } + + context 'when user can create project in namespace' do + let(:namespace_path) { user.namespace.path } + + it 'creates a new project' do + expect { access.send(:ensure_project_on_push!, cmd) } + .to change { Project.count }.by(1) + .and change { Project.where(namespace: user.namespace, name: project_path).count }.by(1) + end + end + + context 'when user cannot create project in namespace' do + let(:user2) { create(:user) } + let(:namespace_path) { user2.namespace.path } + + it 'does not create a new project' do + expect { access.send(:ensure_project_on_push!, cmd) }.not_to change { Project.count } + end + end + end + + context 'when authentication abilities do not include push code' do + let(:authentication_abilities) { [] } + + context 'when user can create project in namespace' do + let(:namespace_path) { user.namespace.path } + + it 'does not create a new project' do + expect { access.send(:ensure_project_on_push!, cmd) }.not_to change { Project.count } + end + end + end + end + + context 'when check contains actual changes' do + let(:changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" } + + it 'does not create a new project' do + expect { access.send(:ensure_project_on_push!, cmd) }.not_to change { Project.count } + end + end + end + + context 'when project exists' do + let(:changes) { Gitlab::GitAccess::ANY } + let!(:project) { create(:project) } + + it 'does not create a new project' do + expect { access.send(:ensure_project_on_push!, cmd) }.not_to change { Project.count } + end + end + + context 'when deploy key is used' do + let(:key) { create(:deploy_key, user: user) } + let(:actor) { key } + let(:project_path) { "nonexistent" } + let(:project) { nil } + let(:namespace_path) { user.namespace.path } + let(:changes) { Gitlab::GitAccess::ANY } + + it 'does not create a new project' do + expect { access.send(:ensure_project_on_push!, cmd) }.not_to change { Project.count } + end + end + end + + context 'when pull' do + let(:cmd) { 'git-upload-pack' } + let(:changes) { Gitlab::GitAccess::ANY } + + context 'when project does not exist' do + let(:project_path) { "new-project" } + let(:namespace_path) { user.namespace.path } + let(:project) { nil } + + it 'does not create a new project' do + expect { access.send(:ensure_project_on_push!, cmd) }.not_to change { Project.count } + end + end + end + end + + def raise_not_found + raise_error(Gitlab::GitAccess::NotFoundError, Gitlab::GitAccess::ERROR_MESSAGES[:project_not_found]) + end +end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 55526241673..7c09fc5cc79 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -228,40 +228,12 @@ describe Gitlab::GitAccess do context 'when the project is nil' do let(:project) { nil } let(:project_path) { "new-project" } + let(:namespace_path) { user.namespace.path } - context 'when user is allowed to create project in namespace' do - let(:namespace_path) { user.namespace.path } - let(:access) do - described_class.new(actor, nil, - protocol, authentication_abilities: authentication_abilities, - repository_path: project_path, namespace_path: namespace_path, - redirected_path: redirected_path) - end - - it 'blocks pull access with "not found"' do + it 'blocks push and pull with "not found"' do + aggregate_failures do expect { pull_access_check }.to raise_not_found - end - - it 'allows push access' do - expect { push_access_check }.not_to raise_error - end - end - - context 'when user is not allowed to create project in namespace' do - let(:user2) { create(:user) } - let(:namespace_path) { user2.namespace.path } - let(:access) do - described_class.new(actor, nil, - protocol, authentication_abilities: authentication_abilities, - repository_path: project_path, namespace_path: namespace_path, - redirected_path: redirected_path) - end - - it 'blocks push and pull with "not found"' do - aggregate_failures do - expect { pull_access_check }.to raise_not_found - expect { push_access_check }.to raise_not_found - end + expect { push_access_check }.to raise_not_found end end end @@ -443,106 +415,6 @@ describe Gitlab::GitAccess do end end - describe '#ensure_project_on_push!' do - let(:access) do - described_class.new(actor, project, - protocol, authentication_abilities: authentication_abilities, - repository_path: project_path, namespace_path: namespace_path, - redirected_path: redirected_path) - end - - context 'when push' do - let(:cmd) { 'git-receive-pack' } - - context 'when project does not exist' do - let(:project_path) { "nonexistent" } - let(:project) { nil } - - context 'when changes is _any' do - let(:changes) { Gitlab::GitAccess::ANY } - - context 'when authentication abilities include push code' do - let(:authentication_abilities) { [:push_code] } - - context 'when user can create project in namespace' do - let(:namespace_path) { user.namespace.path } - - it 'creates a new project' do - expect { access.send(:ensure_project_on_push!, cmd, changes) }.to change { Project.count }.by(1) - end - end - - context 'when user cannot create project in namespace' do - let(:user2) { create(:user) } - let(:namespace_path) { user2.namespace.path } - - it 'does not create a new project' do - expect { access.send(:ensure_project_on_push!, cmd, changes) }.not_to change { Project.count } - end - end - end - - context 'when authentication abilities do not include push code' do - let(:authentication_abilities) { [] } - - context 'when user can create project in namespace' do - let(:namespace_path) { user.namespace.path } - - it 'does not create a new project' do - expect { access.send(:ensure_project_on_push!, cmd, changes) }.not_to change { Project.count } - end - end - end - end - - context 'when check contains actual changes' do - let(:changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" } - - it 'does not create a new project' do - expect { access.send(:ensure_project_on_push!, cmd, changes) }.not_to change { Project.count } - end - end - end - - context 'when project exists' do - let(:changes) { Gitlab::GitAccess::ANY } - let!(:project) { create(:project) } - - it 'does not create a new project' do - expect { access.send(:ensure_project_on_push!, cmd, changes) }.not_to change { Project.count } - end - end - - context 'when deploy key is used' do - let(:key) { create(:deploy_key, user: user) } - let(:actor) { key } - let(:project_path) { "nonexistent" } - let(:project) { nil } - let(:namespace_path) { user.namespace.path } - let(:changes) { Gitlab::GitAccess::ANY } - - it 'does not create a new project' do - expect { access.send(:ensure_project_on_push!, cmd, changes) }.not_to change { Project.count } - end - end - end - - context 'when pull' do - let(:cmd) { 'git-upload-pack' } - let(:changes) { Gitlab::GitAccess::ANY } - - context 'when project does not exist' do - let(:project_path) { "new-project" } - let(:namespace_path) { user.namespace.path } - let(:project) { nil } - - it 'does not create a new project' do - expect { access.send(:ensure_project_on_push!, cmd, changes) }.not_to change { Project.count } - end - end - end - end - describe '#check_download_access!' do it 'allows maintainers to pull' do project.add_maintainer(user) diff --git a/spec/lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader_spec.rb deleted file mode 100644 index e4f5ad324ba..00000000000 --- a/spec/lib/gitlab/graphql/loaders/alert_management/alerts/assignees_loader_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Gitlab::Graphql::Loaders::AlertManagement::Alerts::AssigneesLoader do - describe '#find' do - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } - let_it_be(:alert1) { create(:alert_management_alert, project: project, assignees: [user]) } - let_it_be(:alert2) { create(:alert_management_alert, :all_fields, project: project) } - let_it_be(:alert3) { create(:alert_management_alert, project: project) } - let(:filter) { proc {} } - - subject do - [ - described_class.new(alert1.id, filter).find, - described_class.new(alert2.id, filter).find, - described_class.new(alert3.id, filter).find - ].map(&:sync) - end - - it 'only queries once for alert assignees' do - # One query for alert_assignees, one query for users - expect { subject }.not_to exceed_query_limit(2) - end - - it 'returns appropriate assignees for alerts' do - expect(subject).to eq [alert1.assignees.to_a, alert2.assignees.to_a, alert3.assignees.to_a] - end - - context 'with a filter' do - let(:filter) { proc { |users| users.select { |u| u == user } } } - - it 'limits assignees by the filter' do - expect(subject).to eq [alert1.assignees.to_a, alert2.assignees.to_a, alert3.assignees.to_a] - expect(subject.all?(Gitlab::Graphql::FilterableArray)).to be_truthy - - filtered_result = subject.map { |assignees| assignees.filter_callback.call(assignees) } - - expect(filtered_result).to eq [[user], [], []] - end - end - end -end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 432190b4318..88d5a01072f 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -481,6 +481,7 @@ project: - upstream_project_subscriptions - downstream_project_subscriptions - service_desk_setting +- security_setting - import_failures - container_expiration_policy - resource_groups diff --git a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb index 4913984e5dc..c5a7327332e 100644 --- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb +++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb @@ -51,6 +51,7 @@ describe 'Test coverage of the Project Import' do project.metrics_setting project.boards.lists.label.priorities project.service_desk_setting + project.security_setting ].freeze end diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index aa2dfe26caa..97fd30837d4 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -864,3 +864,11 @@ SystemNoteMetadata: - action - created_at - updated_at +ProjectSecuritySetting: + - project_id + - auto_fix_container_scanning + - auto_fix_dast + - auto_fix_dependency_scanning + - auto_fix_sast + - created_at + - updated_at diff --git a/spec/models/alert_management/alert_assignee_spec.rb b/spec/models/alert_management/alert_assignee_spec.rb index 367469c7d47..c51a5d543ab 100644 --- a/spec/models/alert_management/alert_assignee_spec.rb +++ b/spec/models/alert_management/alert_assignee_spec.rb @@ -3,37 +3,19 @@ require 'spec_helper' describe AlertManagement::AlertAssignee do - let_it_be(:user1) { create(:user) } - let_it_be(:user2) { create(:user) } - let_it_be(:alert1) { create(:alert_management_alert, assignees: [user1, user2]) } - let_it_be(:alert2) { create(:alert_management_alert, assignees: [user2]) } - describe 'associations' do it { is_expected.to belong_to(:alert) } it { is_expected.to belong_to(:assignee) } end describe 'validations' do - subject { alert1.alert_assignees.build(assignee: user1) } + let(:alert) { create(:alert_management_alert) } + let(:user) { create(:user) } + + subject { alert.alert_assignees.build(assignee: user) } it { is_expected.to validate_presence_of(:alert) } it { is_expected.to validate_presence_of(:assignee) } it { is_expected.to validate_uniqueness_of(:assignee).scoped_to(:alert_id) } end - - describe 'scopes' do - describe '.for_alert_ids' do - let(:alert_ids) { alert1.id } - - subject { described_class.for_alert_ids(alert_ids) } - - it { is_expected.to contain_exactly(*alert1.reload.alert_assignees) } - - context 'with multiple ids' do - let(:alert_ids) { [alert1.id, alert2.id] } - - it { is_expected.to contain_exactly(*alert1.reload.alert_assignees, *alert2.reload.alert_assignees) } - end - end - end end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 59c536d6831..b5cf832b898 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2749,6 +2749,30 @@ describe Ci::Pipeline, :mailer do end end + describe '#latest_report_builds' do + it 'returns build with test artifacts' do + test_build = create(:ci_build, :test_reports, pipeline: pipeline, project: project) + coverage_build = create(:ci_build, :coverage_reports, pipeline: pipeline, project: project) + create(:ci_build, :artifacts, pipeline: pipeline, project: project) + + expect(pipeline.latest_report_builds).to contain_exactly(test_build, coverage_build) + end + + it 'filters builds by scope' do + test_build = create(:ci_build, :test_reports, pipeline: pipeline, project: project) + create(:ci_build, :coverage_reports, pipeline: pipeline, project: project) + + expect(pipeline.latest_report_builds(Ci::JobArtifact.test_reports)).to contain_exactly(test_build) + end + + it 'only returns not retried builds' do + test_build = create(:ci_build, :test_reports, pipeline: pipeline, project: project) + create(:ci_build, :test_reports, :retried, pipeline: pipeline, project: project) + + expect(pipeline.latest_report_builds).to contain_exactly(test_build) + end + end + describe '#has_reports?' do subject { pipeline.has_reports?(Ci::JobArtifact.test_reports) } diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 1b9f697a071..8dbbe42a29f 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -1057,7 +1057,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do .and_raise(SocketError) end - it { is_expected.to eq(connection_status: :unreachable, nodes: []) } + it { is_expected.to eq(connection_status: :unreachable, nodes: nil) } end context 'cluster cannot be authenticated to' do @@ -1066,7 +1066,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do .and_raise(OpenSSL::X509::CertificateError.new("Certificate error")) end - it { is_expected.to eq(connection_status: :authentication_failure, nodes: []) } + it { is_expected.to eq(connection_status: :authentication_failure, nodes: nil) } end describe 'Kubeclient::HttpError' do @@ -1078,18 +1078,18 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do .and_raise(Kubeclient::HttpError.new(error_code, error_message, nil)) end - it { is_expected.to eq(connection_status: :authentication_failure, nodes: []) } + it { is_expected.to eq(connection_status: :authentication_failure, nodes: nil) } context 'generic timeout' do let(:error_message) { 'Timed out connecting to server'} - it { is_expected.to eq(connection_status: :unreachable, nodes: []) } + it { is_expected.to eq(connection_status: :unreachable, nodes: nil) } end context 'gateway timeout' do let(:error_message) { '504 Gateway Timeout for GET https://kubernetes.example.com/api/v1'} - it { is_expected.to eq(connection_status: :unreachable, nodes: []) } + it { is_expected.to eq(connection_status: :unreachable, nodes: nil) } end end @@ -1099,7 +1099,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do .and_raise(StandardError) end - it { is_expected.to eq(connection_status: :unknown_failure, nodes: []) } + it { is_expected.to eq(connection_status: :unknown_failure, nodes: nil) } it 'notifies Sentry' do expect(Gitlab::ErrorTracking).to receive(:track_exception) diff --git a/spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb deleted file mode 100644 index 86b56e42a24..00000000000 --- a/spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true -require 'spec_helper' - -describe 'getting Alert Management Alert Assignees' do - include GraphqlHelpers - - let_it_be(:project) { create(:project) } - let_it_be(:current_user) { create(:user) } - let_it_be(:first_alert) { create(:alert_management_alert, project: project, assignees: [current_user]) } - let_it_be(:second_alert) { create(:alert_management_alert, project: project) } - - let(:params) { {} } - - let(:fields) do - <<~QUERY - nodes { - #{all_graphql_fields_for('AlertManagementAlert')} - } - QUERY - end - - let(:query) do - graphql_query_for( - 'project', - { 'fullPath' => project.full_path }, - query_graphql_field('alertManagementAlerts', params, fields) - ) - end - - let(:alerts) { graphql_data.dig('project', 'alertManagementAlerts', 'nodes') } - let(:assignees) { alerts.map { |alert| [alert['iid'], alert['assignees']['nodes']] }.to_h } - let(:first_assignees) { assignees[first_alert.iid.to_s] } - let(:second_assignees) { assignees[second_alert.iid.to_s] } - - before do - project.add_developer(current_user) - end - - it 'returns the correct assignees' do - post_graphql(query, current_user: current_user) - - expect(first_assignees.length).to eq(1) - expect(first_assignees.first).to include('username' => current_user.username) - expect(second_assignees).to be_empty - end - - it 'applies appropriate filters for non-visible users' do - allow(Ability).to receive(:allowed?).and_call_original - allow(Ability).to receive(:allowed?).with(current_user, :read_user, current_user).and_return(false) - - post_graphql(query, current_user: current_user) - - expect(first_assignees).to be_empty - expect(second_assignees).to be_empty - end - - it 'avoids N+1 queries' do - base_count = ActiveRecord::QueryRecorder.new do - post_graphql(query, current_user: current_user) - end - - # An N+1 would mean a new alert would increase the query count - third_alert = create(:alert_management_alert, project: project, assignees: [current_user]) - - expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(base_count) - - third_assignees = assignees[third_alert.iid.to_s] - - expect(third_assignees.length).to eq(1) - expect(third_assignees.first).to include('username' => current_user.username) - end - - context 'with alert_assignee flag disabled' do - before do - stub_feature_flags(alert_assignee: false) - end - - it 'excludes assignees' do - post_graphql(query, current_user: current_user) - - expect(first_assignees).to be_empty - expect(second_assignees).to be_empty - end - end -end diff --git a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb index 05c1eb732ef..ae819f93ee7 100644 --- a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb +++ b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb @@ -75,7 +75,7 @@ describe 'getting Alert Management Alerts' do 'updatedAt' => triggered_alert.updated_at.strftime('%Y-%m-%dT%H:%M:%SZ') ) - expect(first_alert['assignees']['nodes'].first).to include('username' => triggered_alert.assignees.first.username) + expect(first_alert['assignees'].first).to include('username' => triggered_alert.assignees.first.username) expect(second_alert).to include( 'iid' => resolved_alert.iid.to_s, @@ -137,5 +137,18 @@ describe 'getting Alert Management Alerts' do end end end + + context 'with alert_assignee flag disabled' do + before do + stub_feature_flags(alert_assignee: false) + project.add_developer(current_user) + + post_graphql(query, current_user: current_user) + end + + it 'excludes assignees' do + expect(alerts.first['assignees']).to be_empty + end + end end end |