Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-01 12:12:10 +00:00
parent 46f35a6167
commit 9c5341dd08
93 changed files with 1570 additions and 1081 deletions

View File

@ -13,6 +13,8 @@ code_quality:
artifacts:
paths:
- gl-code-quality-report.json # GitLab-specific
# extends generated values cannot overwrite values from included files
# Use !reference as a workaround here
rules: !reference [".reports:rules:code_quality", rules]
allow_failure: true

View File

@ -72,6 +72,8 @@ danger-review-local:
reviewers-recommender:
extends:
- .default-retry
- .review:rules:reviewers-recommender
# extends generated values cannot overwrite values from included files
# Use !reference as a workaround here
rules: !reference [".review:rules:reviewers-recommender", rules]
stage: test
needs: []

View File

@ -1,9 +1,6 @@
---
# Cop supports --auto-correct.
RSpec/ExpectChange:
# Offense count: 1707
# Temporarily disabled due to too many offenses
Enabled: false
Exclude:
- 'ee/spec/controllers/admin/applications_controller_spec.rb'
- 'ee/spec/controllers/ee/groups_controller_spec.rb'
@ -28,8 +25,10 @@ RSpec/ExpectChange:
- 'ee/spec/controllers/registrations/groups_controller_spec.rb'
- 'ee/spec/controllers/registrations/groups_projects_controller_spec.rb'
- 'ee/spec/controllers/trials_controller_spec.rb'
- 'ee/spec/elastic/migrate/20220119120500_populate_commit_permissions_in_main_index_spec.rb'
- 'ee/spec/features/groups/group_settings_spec.rb'
- 'ee/spec/features/projects_spec.rb'
- 'ee/spec/features/signup_spec.rb'
- 'ee/spec/features/users/login_spec.rb'
- 'ee/spec/graphql/ee/mutations/ci/runner/update_spec.rb'
- 'ee/spec/graphql/mutations/boards/epics/create_spec.rb'
@ -38,9 +37,9 @@ RSpec/ExpectChange:
- 'ee/spec/graphql/mutations/dast_site_profiles/delete_spec.rb'
- 'ee/spec/graphql/mutations/dast_site_validations/revoke_spec.rb'
- 'ee/spec/helpers/paid_feature_callout_helper_spec.rb'
- 'ee/spec/lib/analytics/group_activity_calculator_spec.rb'
- 'ee/spec/lib/audit/changes_spec.rb'
- 'ee/spec/lib/audit/external_status_check_changes_auditor_spec.rb'
- 'ee/spec/lib/audit/group_merge_request_approval_setting_changes_auditor_spec.rb'
- 'ee/spec/lib/audit/group_push_rules_changes_auditor_spec.rb'
- 'ee/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb'
- 'ee/spec/lib/bulk_imports/projects/pipelines/push_rule_pipeline_spec.rb'
@ -52,14 +51,17 @@ RSpec/ExpectChange:
- 'ee/spec/lib/ee/audit/project_setting_changes_auditor_spec.rb'
- 'ee/spec/lib/ee/audit/protected_branches_changes_auditor_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/create_security_setting_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/delete_invalid_epic_issues_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/drop_invalid_remediations_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/populate_latest_pipeline_ids_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings_spec.rb'
- 'ee/spec/lib/ee/gitlab/elastic/helper_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/project/tree_restorer_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/repo_restorer_spec.rb'
- 'ee/spec/lib/ee/gitlab/issuable/clone/copy_resource_events_service_spec.rb'
- 'ee/spec/lib/ee/gitlab/scim/deprovision_service_spec.rb'
- 'ee/spec/lib/ee/gitlab/scim/provisioning_service_spec.rb'
- 'ee/spec/lib/gitlab/audit/auditor_spec.rb'
- 'ee/spec/lib/gitlab/auth/group_saml/identity_linker_spec.rb'
- 'ee/spec/lib/gitlab/auth/group_saml/user_spec.rb'
- 'ee/spec/lib/gitlab/auth/o_auth/user_spec.rb'
@ -75,6 +77,7 @@ RSpec/ExpectChange:
- 'ee/spec/models/concerns/geo/verification_state_spec.rb'
- 'ee/spec/models/dast/profile_schedule_spec.rb'
- 'ee/spec/models/dast_site_spec.rb'
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
- 'ee/spec/models/ee/event_spec.rb'
- 'ee/spec/models/ee/lfs_object_spec.rb'
- 'ee/spec/models/ee/merge_request_diff_spec.rb'
@ -96,6 +99,7 @@ RSpec/ExpectChange:
- 'ee/spec/requests/api/epic_issues_spec.rb'
- 'ee/spec/requests/api/epics_spec.rb'
- 'ee/spec/requests/api/geo_spec.rb'
- 'ee/spec/requests/api/graphql/audit_events/streaming/headers/update_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/audit_events/external_audit_event_destinations/create_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/audit_events/external_audit_event_destinations/destroy_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/audit_events/external_audit_event_destinations/update_spec.rb'
@ -108,6 +112,7 @@ RSpec/ExpectChange:
- 'ee/spec/requests/api/graphql/mutations/dast_site_validations/revoke_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/quality_management/test_cases/create_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/requirements_management/update_requirement_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/work_items/update_spec.rb'
- 'ee/spec/requests/api/group_push_rule_spec.rb'
- 'ee/spec/requests/api/groups_spec.rb'
- 'ee/spec/requests/api/invitations_spec.rb'
@ -121,6 +126,7 @@ RSpec/ExpectChange:
- 'ee/spec/requests/api/todos_spec.rb'
- 'ee/spec/requests/api/users_spec.rb'
- 'ee/spec/requests/ee/projects/deploy_tokens_controller_spec.rb'
- 'ee/spec/requests/groups/protected_environments_controller_spec.rb'
- 'ee/spec/requests/groups_controller_spec.rb'
- 'ee/spec/requests/smartcard_controller_spec.rb'
- 'ee/spec/services/app_sec/dast/scanner_profiles/destroy_service_spec.rb'
@ -135,6 +141,9 @@ RSpec/ExpectChange:
- 'ee/spec/services/approval_rules/project_rule_destroy_service_spec.rb'
- 'ee/spec/services/approval_rules/update_service_spec.rb'
- 'ee/spec/services/audit_event_service_spec.rb'
- 'ee/spec/services/audit_events/streaming/headers/create_service_spec.rb'
- 'ee/spec/services/audit_events/streaming/headers/destroy_service_spec.rb'
- 'ee/spec/services/audit_events/streaming/headers/update_service_spec.rb'
- 'ee/spec/services/audit_events/user_impersonation_group_audit_event_service_spec.rb'
- 'ee/spec/services/auto_merge/merge_train_service_spec.rb'
- 'ee/spec/services/boards/epics/create_service_spec.rb'
@ -146,14 +155,17 @@ RSpec/ExpectChange:
- 'ee/spec/services/compliance_management/frameworks/create_service_spec.rb'
- 'ee/spec/services/compliance_management/frameworks/destroy_service_spec.rb'
- 'ee/spec/services/compliance_management/frameworks/update_service_spec.rb'
- 'ee/spec/services/deploy_keys/create_service_spec.rb'
- 'ee/spec/services/deployments/approval_service_spec.rb'
- 'ee/spec/services/deployments/auto_rollback_service_spec.rb'
- 'ee/spec/services/ee/gpg_keys/destroy_service_spec.rb'
- 'ee/spec/services/ee/groups/deploy_tokens/create_service_spec.rb'
- 'ee/spec/services/ee/groups/deploy_tokens/destroy_service_spec.rb'
- 'ee/spec/services/ee/groups/deploy_tokens/revoke_service_spec.rb'
- 'ee/spec/services/ee/issuable/common_system_notes_service_spec.rb'
- 'ee/spec/services/ee/issues/create_service_spec.rb'
- 'ee/spec/services/ee/issues/update_service_spec.rb'
- 'ee/spec/services/ee/keys/destroy_service_spec.rb'
- 'ee/spec/services/ee/members/create_service_spec.rb'
- 'ee/spec/services/ee/members/destroy_service_spec.rb'
- 'ee/spec/services/ee/members/invite_service_spec.rb'
@ -163,6 +175,7 @@ RSpec/ExpectChange:
- 'ee/spec/services/ee/projects/deploy_tokens/create_service_spec.rb'
- 'ee/spec/services/ee/projects/deploy_tokens/destroy_service_spec.rb'
- 'ee/spec/services/ee/todos/destroy/entity_leave_service_spec.rb'
- 'ee/spec/services/ee/two_factor/destroy_service_spec.rb'
- 'ee/spec/services/ee/users/approve_service_spec.rb'
- 'ee/spec/services/ee/users/block_service_spec.rb'
- 'ee/spec/services/ee/users/reject_service_spec.rb'
@ -196,8 +209,12 @@ RSpec/ExpectChange:
- 'ee/spec/services/keys/create_service_spec.rb'
- 'ee/spec/services/lfs/lock_file_service_spec.rb'
- 'ee/spec/services/lfs/unlock_file_service_spec.rb'
- 'ee/spec/services/members/activate_service_spec.rb'
- 'ee/spec/services/merge_request_approval_settings/update_service_spec.rb'
- 'ee/spec/services/merge_requests/update_blocks_service_spec.rb'
- 'ee/spec/services/namespaces/free_user_cap/update_prevent_sharing_outside_hierarchy_service_spec.rb'
- 'ee/spec/services/projects/disable_deploy_key_service_spec.rb'
- 'ee/spec/services/projects/enable_deploy_key_service_spec.rb'
- 'ee/spec/services/projects/import_service_spec.rb'
- 'ee/spec/services/projects/mark_for_deletion_service_spec.rb'
- 'ee/spec/services/projects/restore_service_spec.rb'
@ -215,6 +232,7 @@ RSpec/ExpectChange:
- 'ee/spec/services/security/ingestion/tasks/ingest_vulnerabilities_spec.rb'
- 'ee/spec/services/security/orchestration/assign_service_spec.rb'
- 'ee/spec/services/security/override_uuids_service_spec.rb'
- 'ee/spec/services/security/security_orchestration_policies/sync_opened_merge_requests_service_spec.rb'
- 'ee/spec/services/security/store_scan_service_spec.rb'
- 'ee/spec/services/start_pull_mirroring_service_spec.rb'
- 'ee/spec/services/system_notes/epics_service_spec.rb'
@ -235,16 +253,15 @@ RSpec/ExpectChange:
- 'ee/spec/support/shared_examples/services/update_issuable_health_status_shared_examples.rb'
- 'ee/spec/tasks/geo/git_rake_spec.rb'
- 'ee/spec/tasks/gitlab/elastic_rake_spec.rb'
- 'ee/spec/workers/ee/projects/inactive_projects_deletion_cron_worker_spec.rb'
- 'ee/spec/workers/elastic_remove_expired_namespace_subscriptions_from_index_cron_worker_spec.rb'
- 'ee/spec/workers/geo/verification_state_backfill_service_spec.rb'
- 'ee/spec/workers/new_epic_worker_spec.rb'
- 'ee/spec/workers/store_security_reports_worker_spec.rb'
- 'spec/controllers/admin/clusters_controller_spec.rb'
- 'spec/controllers/admin/groups_controller_spec.rb'
- 'spec/controllers/admin/runners_controller_spec.rb'
- 'spec/controllers/admin/spam_logs_controller_spec.rb'
- 'spec/controllers/admin/users_controller_spec.rb'
- 'spec/controllers/groups/clusters_controller_spec.rb'
- 'spec/controllers/groups/runners_controller_spec.rb'
- 'spec/controllers/groups_controller_spec.rb'
- 'spec/controllers/import/bitbucket_controller_spec.rb'
@ -254,7 +271,6 @@ RSpec/ExpectChange:
- 'spec/controllers/omniauth_callbacks_controller_spec.rb'
- 'spec/controllers/profiles/gpg_keys_controller_spec.rb'
- 'spec/controllers/profiles/keys_controller_spec.rb'
- 'spec/controllers/projects/clusters_controller_spec.rb'
- 'spec/controllers/projects/deploy_keys_controller_spec.rb'
- 'spec/controllers/projects/issues_controller_spec.rb'
- 'spec/controllers/projects/merge_requests/creations_controller_spec.rb'
@ -277,7 +293,6 @@ RSpec/ExpectChange:
- 'spec/features/groups/import_export/import_file_spec.rb'
- 'spec/features/groups_spec.rb'
- 'spec/features/invites_spec.rb'
- 'spec/features/profiles/personal_access_tokens_spec.rb'
- 'spec/features/projects/import_export/import_file_spec.rb'
- 'spec/features/projects_spec.rb'
- 'spec/features/users/signup_spec.rb'
@ -294,11 +309,13 @@ RSpec/ExpectChange:
- 'spec/lib/gitlab/auth/saml/identity_linker_spec.rb'
- 'spec/lib/gitlab/background_migration/add_primary_email_to_emails_if_user_confirmed_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_group_features_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_imported_issue_search_data_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb'
- 'spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb'
- 'spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb'
- 'spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb'
- 'spec/lib/gitlab/background_migration/remove_vulnerability_finding_links_spec.rb'
- 'spec/lib/gitlab/background_task_spec.rb'
- 'spec/lib/gitlab/bitbucket_import/importer_spec.rb'
- 'spec/lib/gitlab/bitbucket_server_import/importer_spec.rb'
- 'spec/lib/gitlab/checks/matching_merge_request_spec.rb'
@ -314,6 +331,7 @@ RSpec/ExpectChange:
- 'spec/lib/gitlab/config/entry/validatable_spec.rb'
- 'spec/lib/gitlab/daemon_spec.rb'
- 'spec/lib/gitlab/database/async_indexes/index_creator_spec.rb'
- 'spec/lib/gitlab/database/async_indexes/index_destructor_spec.rb'
- 'spec/lib/gitlab/database/background_migration/batched_job_spec.rb'
- 'spec/lib/gitlab/database/background_migration/batched_migration_runner_spec.rb'
- 'spec/lib/gitlab/database/background_migration/batched_migration_spec.rb'
@ -325,6 +343,8 @@ RSpec/ExpectChange:
- 'spec/lib/gitlab/email/handler/service_desk_handler_spec.rb'
- 'spec/lib/gitlab/fogbugz_import/importer_spec.rb'
- 'spec/lib/gitlab/git_access_project_spec.rb'
- 'spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb'
- 'spec/lib/gitlab/github_import/importer/events/renamed_spec.rb'
- 'spec/lib/gitlab/github_import/importer/releases_importer_spec.rb'
- 'spec/lib/gitlab/hashed_storage/migrator_spec.rb'
- 'spec/lib/gitlab/import/merge_request_creator_spec.rb'
@ -353,7 +373,9 @@ RSpec/ExpectChange:
- 'spec/migrations/20220124130028_dedup_runner_projects_spec.rb'
- 'spec/migrations/20220202105733_delete_service_template_records_spec.rb'
- 'spec/migrations/20220222192525_remove_null_releases_spec.rb'
- 'spec/migrations/20220629184402_unset_escalation_policies_for_alert_incidents_spec.rb'
- 'spec/migrations/backfill_cycle_analytics_aggregations_spec.rb'
- 'spec/migrations/bulk_insert_cluster_enabled_grants_spec.rb'
- 'spec/migrations/cleanup_after_add_primary_email_to_emails_if_user_confirmed_spec.rb'
- 'spec/migrations/cleanup_after_fixing_issue_when_admin_changed_primary_email_spec.rb'
- 'spec/migrations/cleanup_after_fixing_regression_with_new_users_emails_spec.rb'
@ -363,6 +385,7 @@ RSpec/ExpectChange:
- 'spec/models/alert_management/alert_spec.rb'
- 'spec/models/analytics/cycle_analytics/aggregation_spec.rb'
- 'spec/models/analytics/cycle_analytics/stage_event_hash_spec.rb'
- 'spec/models/application_setting_spec.rb'
- 'spec/models/broadcast_message_spec.rb'
- 'spec/models/chat_name_spec.rb'
- 'spec/models/ci/bridge_spec.rb'
@ -375,8 +398,6 @@ RSpec/ExpectChange:
- 'spec/models/ci/ref_spec.rb'
- 'spec/models/ci/runner_spec.rb'
- 'spec/models/clusters/cluster_spec.rb'
- 'spec/models/commit_signatures/gpg_signature_spec.rb'
- 'spec/models/commit_signatures/x509_commit_signature_spec.rb'
- 'spec/models/commit_status_spec.rb'
- 'spec/models/concerns/atomic_internal_id_spec.rb'
- 'spec/models/concerns/bulk_insert_safe_spec.rb'
@ -384,6 +405,7 @@ RSpec/ExpectChange:
- 'spec/models/concerns/delete_with_limit_spec.rb'
- 'spec/models/concerns/ignorable_columns_spec.rb'
- 'spec/models/concerns/issuable_spec.rb'
- 'spec/models/concerns/require_email_verification_spec.rb'
- 'spec/models/concerns/resolvable_discussion_spec.rb'
- 'spec/models/concerns/resolvable_note_spec.rb'
- 'spec/models/concerns/routable_spec.rb'
@ -449,7 +471,6 @@ RSpec/ExpectChange:
- 'spec/requests/api/projects_spec.rb'
- 'spec/requests/api/releases_spec.rb'
- 'spec/requests/api/snippets_spec.rb'
- 'spec/requests/api/system_hooks_spec.rb'
- 'spec/requests/api/users_spec.rb'
- 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
- 'spec/requests/import/gitlab_groups_controller_spec.rb'
@ -504,6 +525,7 @@ RSpec/ExpectChange:
- '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/import_csv_service_spec.rb'
- 'spec/services/issues/move_service_spec.rb'
- 'spec/services/issues/reopen_service_spec.rb'
- 'spec/services/issues/update_service_spec.rb'
@ -526,6 +548,7 @@ RSpec/ExpectChange:
- 'spec/services/notes/create_service_spec.rb'
- 'spec/services/notes/destroy_service_spec.rb'
- 'spec/services/notes/quick_actions_service_spec.rb'
- 'spec/services/packages/cleanup/update_policy_service_spec.rb'
- 'spec/services/packages/helm/process_file_service_spec.rb'
- 'spec/services/packages/mark_package_for_destruction_service_spec.rb'
- 'spec/services/packages/update_package_file_service_spec.rb'
@ -534,7 +557,6 @@ RSpec/ExpectChange:
- 'spec/services/pages_domains/retry_acme_order_service_spec.rb'
- 'spec/services/personal_access_tokens/last_used_service_spec.rb'
- 'spec/services/projects/auto_devops/disable_service_spec.rb'
- 'spec/services/projects/destroy_service_spec.rb'
- 'spec/services/projects/fetch_statistics_increment_service_spec.rb'
- 'spec/services/projects/hashed_storage/migration_service_spec.rb'
- 'spec/services/projects/hashed_storage/rollback_repository_service_spec.rb'
@ -562,6 +584,7 @@ RSpec/ExpectChange:
- 'spec/services/todos/destroy/group_private_service_spec.rb'
- 'spec/services/todos/destroy/project_private_service_spec.rb'
- 'spec/services/todos/destroy/unauthorized_features_service_spec.rb'
- 'spec/services/uploads/destroy_service_spec.rb'
- 'spec/services/users/approve_service_spec.rb'
- 'spec/services/users/ban_service_spec.rb'
- 'spec/services/users/batch_status_cleaner_service_spec.rb'
@ -571,7 +594,7 @@ RSpec/ExpectChange:
- 'spec/services/users/update_highest_member_role_service_spec.rb'
- 'spec/services/users/update_service_spec.rb'
- 'spec/services/verify_pages_domain_service_spec.rb'
- 'spec/services/web_hooks/destroy_service_spec.rb'
- 'spec/services/work_items/parent_links/create_service_spec.rb'
- 'spec/support/services/deploy_token_shared_examples.rb'
- 'spec/support/services/issuable_import_csv_service_shared_examples.rb'
- 'spec/support/shared_contexts/email_shared_context.rb'
@ -581,6 +604,7 @@ RSpec/ExpectChange:
- 'spec/support/shared_examples/graphql/notes_creation_shared_examples.rb'
- 'spec/support/shared_examples/incident_management/issuable_escalation_statuses/build_examples.rb'
- 'spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb'
- 'spec/support/shared_examples/models/commit_signature_shared_examples.rb'
- 'spec/support/shared_examples/models/concerns/bulk_insert_safe_shared_examples.rb'
- 'spec/support/shared_examples/models/concerns/can_move_repository_storage_shared_examples.rb'
- 'spec/support/shared_examples/models/concerns/cron_schedulable_shared_examples.rb'
@ -613,6 +637,7 @@ RSpec/ExpectChange:
- 'spec/workers/destroy_pages_deployments_worker_spec.rb'
- 'spec/workers/environments/auto_delete_cron_worker_spec.rb'
- 'spec/workers/gitlab/phabricator_import/base_worker_spec.rb'
- 'spec/workers/gitlab_service_ping_worker_spec.rb'
- 'spec/workers/group_import_worker_spec.rb'
- 'spec/workers/incident_management/process_alert_worker_v2_spec.rb'
- 'spec/workers/new_issue_worker_spec.rb'
@ -627,3 +652,4 @@ RSpec/ExpectChange:
- 'spec/workers/update_highest_role_worker_spec.rb'
- 'spec/workers/user_status_cleanup/batch_worker_spec.rb'
- 'spec/workers/users/create_statistics_worker_spec.rb'
- 'spec/workers/web_hooks/log_destroy_worker_spec.rb'

View File

@ -1,9 +1,6 @@
---
# Cop supports --auto-correct.
RSpec/PredicateMatcher:
# Offense count: 2480
# Temporarily disabled due to too many offenses
Enabled: false
Exclude:
- 'ee/spec/controllers/admin/elasticsearch_controller_spec.rb'
- 'ee/spec/controllers/admin/geo/projects_controller_spec.rb'
@ -11,11 +8,16 @@ RSpec/PredicateMatcher:
- 'ee/spec/controllers/groups/group_members_controller_spec.rb'
- 'ee/spec/controllers/groups/ldaps_controller_spec.rb'
- 'ee/spec/controllers/projects_controller_spec.rb'
- 'ee/spec/elastic/migrate/20220118150500_delete_orphaned_commits_spec.rb'
- 'ee/spec/elastic/migrate/20220119120500_populate_commit_permissions_in_main_index_spec.rb'
- 'ee/spec/elastic/migrate/20220613120500_migrate_commits_to_separate_index_spec.rb'
- 'ee/spec/elastic/migrate/20220713103500_delete_commits_from_original_index_spec.rb'
- 'ee/spec/elastic/migrate/migration_shared_examples.rb'
- 'ee/spec/features/admin/admin_settings_spec.rb'
- 'ee/spec/features/projects/members/member_is_removed_from_project_spec.rb'
- 'ee/spec/features/projects/mirror_spec.rb'
- 'ee/spec/features/signup_spec.rb'
- 'ee/spec/finders/epics_finder_spec.rb'
- 'ee/spec/graphql/resolvers/path_locks_resolver_spec.rb'
- 'ee/spec/helpers/ee/groups_helper_spec.rb'
- 'ee/spec/helpers/ee/issues_helper_spec.rb'
@ -70,6 +72,7 @@ RSpec/PredicateMatcher:
- 'ee/spec/models/project_spec.rb'
- 'ee/spec/models/saml_provider_spec.rb'
- 'ee/spec/models/security/orchestration_policy_configuration_spec.rb'
- 'ee/spec/presenters/ci/minutes/usage_presenter_spec.rb'
- 'ee/spec/requests/api/boards_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/epics/set_subscription_spec.rb'
- 'ee/spec/requests/api/groups_spec.rb'
@ -96,6 +99,8 @@ RSpec/PredicateMatcher:
- 'ee/spec/services/jira/requests/issues/list_service_spec.rb'
- 'ee/spec/services/milestones/promote_service_spec.rb'
- 'ee/spec/services/protected_environments/create_service_spec.rb'
- 'ee/spec/services/vulnerabilities/create_from_security_finding_service_spec.rb'
- 'ee/spec/services/vulnerabilities/findings/create_from_security_finding_service_spec.rb'
- 'ee/spec/services/vulnerabilities/manually_create_service_spec.rb'
- 'ee/spec/services/vulnerability_exports/export_service_spec.rb'
- 'ee/spec/support/shared_examples/graphql/mutations/dast_on_demand_scans_shared_examples.rb'
@ -113,7 +118,6 @@ RSpec/PredicateMatcher:
- 'qa/qa/specs/features/ee/browser_ui/12_geo/database_delete_replication_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/2_plan/epic/roadmap_spec.rb'
- 'qa/spec/runtime/env_spec.rb'
- 'qa/spec/runtime/feature_spec.rb'
- 'qa/spec/specs/helpers/context_selector_spec.rb'
- 'spec/components/diffs/overflow_warning_component_spec.rb'
- 'spec/controllers/admin/dev_ops_report_controller_spec.rb'
@ -123,6 +127,7 @@ RSpec/PredicateMatcher:
- 'spec/controllers/concerns/checks_collaboration_spec.rb'
- 'spec/controllers/groups/avatars_controller_spec.rb'
- 'spec/controllers/groups/clusters_controller_spec.rb'
- 'spec/controllers/groups/group_links_controller_spec.rb'
- 'spec/controllers/groups/group_members_controller_spec.rb'
- 'spec/controllers/groups/settings/applications_controller_spec.rb'
- 'spec/controllers/omniauth_callbacks_controller_spec.rb'
@ -157,7 +162,6 @@ RSpec/PredicateMatcher:
- 'spec/features/unsubscribe_links_spec.rb'
- 'spec/features/users/signup_spec.rb'
- 'spec/finders/group_descendants_finder_spec.rb'
- 'spec/finders/issues_finder_spec.rb'
- 'spec/finders/merge_request_target_project_finder_spec.rb'
- 'spec/helpers/application_helper_spec.rb'
- 'spec/helpers/application_settings_helper_spec.rb'
@ -169,6 +173,7 @@ RSpec/PredicateMatcher:
- 'spec/helpers/projects_helper_spec.rb'
- 'spec/helpers/recaptcha_helper_spec.rb'
- 'spec/helpers/sessions_helper_spec.rb'
- 'spec/helpers/sorting_helper_spec.rb'
- 'spec/lib/backup/files_spec.rb'
- 'spec/lib/bitbucket/connection_spec.rb'
- 'spec/lib/bitbucket/page_spec.rb'
@ -260,7 +265,6 @@ RSpec/PredicateMatcher:
- 'spec/lib/gitlab/fake_application_settings_spec.rb'
- 'spec/lib/gitlab/git/blob_spec.rb'
- 'spec/lib/gitlab/git/branch_spec.rb'
- 'spec/lib/gitlab/git/commit_spec.rb'
- 'spec/lib/gitlab/git/keep_around_spec.rb'
- 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb'
@ -273,6 +277,7 @@ RSpec/PredicateMatcher:
- 'spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb'
- 'spec/lib/gitlab/gl_repository/repo_type_spec.rb'
- 'spec/lib/gitlab/gpg/commit_spec.rb'
- 'spec/lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer_spec.rb'
- 'spec/lib/gitlab/hashed_storage/migrator_spec.rb'
- 'spec/lib/gitlab/i18n/translation_entry_spec.rb'
- 'spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb'
@ -308,6 +313,7 @@ RSpec/PredicateMatcher:
- 'spec/lib/gitlab/user_access_snippet_spec.rb'
- 'spec/lib/gitlab/user_access_spec.rb'
- 'spec/lib/gitlab/utils/sanitize_node_link_spec.rb'
- 'spec/lib/gitlab/version_info_spec.rb'
- 'spec/lib/gitlab/view/presenter/base_spec.rb'
- 'spec/lib/gitlab/visibility_level_spec.rb'
- 'spec/lib/object_storage/direct_upload_spec.rb'
@ -400,7 +406,6 @@ RSpec/PredicateMatcher:
- 'spec/requests/api/merge_requests_spec.rb'
- 'spec/requests/api/project_clusters_spec.rb'
- 'spec/requests/api/project_export_spec.rb'
- 'spec/requests/api/project_hooks_spec.rb'
- 'spec/requests/api/project_snippets_spec.rb'
- 'spec/requests/api/projects_spec.rb'
- 'spec/requests/api/resource_access_tokens_spec.rb'
@ -425,11 +430,13 @@ RSpec/PredicateMatcher:
- 'spec/services/container_expiration_policies/update_service_spec.rb'
- 'spec/services/customer_relations/contacts/update_service_spec.rb'
- 'spec/services/customer_relations/organizations/update_service_spec.rb'
- 'spec/services/deployments/create_for_build_service_spec.rb'
- 'spec/services/deployments/older_deployments_drop_service_spec.rb'
- 'spec/services/draft_notes/publish_service_spec.rb'
- 'spec/services/environments/schedule_to_delete_review_apps_service_spec.rb'
- 'spec/services/groups/destroy_service_spec.rb'
- 'spec/services/groups/group_links/create_service_spec.rb'
- 'spec/services/groups/group_links/destroy_service_spec.rb'
- 'spec/services/groups/transfer_service_spec.rb'
- 'spec/services/groups/update_service_spec.rb'
- 'spec/services/issuable/bulk_update_service_spec.rb'
@ -449,6 +456,7 @@ RSpec/PredicateMatcher:
- 'spec/services/note_summary_spec.rb'
- 'spec/services/notes/build_service_spec.rb'
- 'spec/services/notes/quick_actions_service_spec.rb'
- 'spec/services/packages/cleanup/update_policy_service_spec.rb'
- 'spec/services/packages/debian/find_or_create_incoming_service_spec.rb'
- 'spec/services/packages/nuget/update_package_from_metadata_service_spec.rb'
- 'spec/services/projects/after_rename_service_spec.rb'
@ -478,6 +486,7 @@ RSpec/PredicateMatcher:
- 'spec/services/users/destroy_service_spec.rb'
- 'spec/support/shared_contexts/email_shared_context.rb'
- 'spec/support/shared_examples/ci/auto_merge_merge_requests_shared_examples.rb'
- 'spec/support/shared_examples/finders/issues_finder_shared_examples.rb'
- 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb'
- 'spec/support/shared_examples/models/application_setting_shared_examples.rb'
- 'spec/support/shared_examples/models/cluster_application_core_shared_examples.rb'
@ -486,6 +495,7 @@ RSpec/PredicateMatcher:
- 'spec/support/shared_examples/models/member_shared_examples.rb'
- 'spec/support/shared_examples/models/note_access_check_shared_examples.rb'
- 'spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb'
- 'spec/support/shared_examples/requests/api/hooks_shared_examples.rb'
- 'spec/support/shared_examples/uploaders/object_storage_shared_examples.rb'
- 'spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb'
- 'spec/tasks/gitlab/backup_rake_spec.rb'
@ -497,12 +507,13 @@ RSpec/PredicateMatcher:
- 'spec/validators/namespace_path_validator_spec.rb'
- 'spec/validators/project_path_validator_spec.rb'
- 'spec/workers/bulk_imports/entity_worker_spec.rb'
- 'spec/workers/bulk_imports/pipeline_worker_spec.rb'
- 'spec/workers/ci/delete_objects_worker_spec.rb'
- 'spec/workers/concerns/worker_attributes_spec.rb'
- 'spec/workers/container_expiration_policies/cleanup_container_repository_worker_spec.rb'
- 'spec/workers/group_destroy_worker_spec.rb'
- 'spec/workers/hashed_storage/migrator_worker_spec.rb'
- 'spec/workers/hashed_storage/rollbacker_worker_spec.rb'
- 'spec/workers/project_destroy_worker_spec.rb'
- 'spec/workers/remote_mirror_notification_worker_spec.rb'
- 'spec/workers/remove_expired_group_links_worker_spec.rb'
- 'spec/workers/x509_issuer_crl_check_worker_spec.rb'

View File

@ -1 +1 @@
31ea786fbf0a7874b44efcb1f8b43bc4536d9b7e
2720ae51a9acae55951c54268649a5cd0e2fa5ba

View File

@ -350,6 +350,7 @@ group :development do
gem 'solargraph', '~> 0.45.0', require: false
gem 'letter_opener_web', '~> 2.0.0'
gem 'lookbook'
# Better errors handler
gem 'better_errors', '~> 2.9.0'
@ -486,7 +487,7 @@ gem 'ssh_data', '~> 1.3'
gem 'spamcheck', '~> 0.1.0'
# Gitaly GRPC protocol definitions
gem 'gitaly', '~> 15.1.0-rc1'
gem 'gitaly', '~> 15.2.0-rc1'
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.0.2'

View File

@ -501,7 +501,7 @@ GEM
rails (>= 3.2.0)
git (1.11.0)
rchardet (~> 1.8)
gitaly (15.1.0.pre.rc1)
gitaly (15.2.0.pre.rc1)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab (4.16.1)
@ -676,6 +676,7 @@ GEM
nokogiri (>= 1.4)
html2text (0.2.0)
nokogiri (~> 1.6)
htmlbeautifier (1.4.2)
htmlentities (4.3.4)
http (4.4.1)
addressable (~> 2.3)
@ -770,7 +771,7 @@ GEM
reverse_markdown (~> 1.0)
rugged (>= 0.24, < 2.0)
thor (>= 0.19, < 2.0)
listen (3.6.0)
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
locale (2.1.3)
@ -783,6 +784,15 @@ GEM
loofah (2.18.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lookbook (0.9.3)
actioncable
htmlbeautifier (~> 1.3)
listen (~> 3.0)
railties (>= 5.0)
redcarpet (~> 3.5)
rouge (~> 3.26)
view_component (~> 2.0)
yard (~> 0.9.25)
lru_redux (1.1.0)
lumberjack (1.2.7)
mail (2.7.1)
@ -1053,7 +1063,7 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.4.2)
rails-html-sanitizer (1.4.3)
loofah (~> 2.3)
rails-i18n (7.0.3)
i18n (>= 0.7, < 2)
@ -1069,7 +1079,7 @@ GEM
randexp (0.1.7)
rash_alt (0.4.12)
hashie (>= 3.4)
rb-fsevent (0.10.4)
rb-fsevent (0.11.1)
rb-inotify (0.10.1)
ffi (~> 1.0)
rbtrace (0.4.14)
@ -1083,6 +1093,7 @@ GEM
recaptcha (4.13.1)
json
recursive-open-struct (1.1.3)
redcarpet (3.5.1)
redis (4.4.0)
redis-actionpack (5.2.0)
actionpack (>= 5, < 7)
@ -1395,7 +1406,7 @@ GEM
tty-screen (0.8.1)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.4)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
u2f (0.2.1)
uber (0.1.0)
@ -1561,7 +1572,7 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly (~> 15.1.0.pre.rc1)
gitaly (~> 15.2.0.pre.rc1)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
gitlab-dangerfiles (~> 3.5.0)
@ -1622,6 +1633,7 @@ DEPENDENCIES
lockbox (~> 0.6.2)
lograge (~> 0.5)
loofah (~> 2.18.0)
lookbook
lru_redux
mail (= 2.7.1)
mail-smtp_pool (~> 0.1.0)!

View File

@ -501,19 +501,13 @@ const linkType = (sourceMarkdown) => {
const normalizeUrl = (url) => decodeURIComponent(removeLastSlashInUrlPath(removeUrlProtocol(url)));
/**
* Validates that the provided URL is well-formed
* Validates that the provided URL is a valid GFM autolink
*
* @param {String} url
* @returns Returns true when the browsers URL constructor
* can successfully parse the URL string
* @returns Returns true when the URL is a valid GFM autolink
*/
const isValidUrl = (url) => {
try {
return new URL(url) && true;
} catch {
return false;
}
};
const isValidAutolinkURL = (url) =>
/(https?:\/\/)?([\w-])+\.{1}([a-zA-Z]{2,63})([/\w-]*)*\/?\??([^#\n\r]*)?#?([^\n\r]*)/.test(url);
const findChildWithMark = (mark, parent) => {
let child;
@ -550,7 +544,7 @@ const isAutoLink = (linkMark, parent) => {
if (
!child ||
!child.isText ||
!isValidUrl(href) ||
!isValidAutolinkURL(href) ||
normalizeUrl(child.text) !== normalizeUrl(href)
) {
return false;

View File

@ -1,10 +1,11 @@
<script>
import { GlAvatar, GlLink } from '@gitlab/ui';
import { GlAvatar, GlBadge, GlLink } from '@gitlab/ui';
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
export default {
components: {
GlAvatar,
GlBadge,
GlLink,
},
props: {
@ -25,6 +26,16 @@ export default {
required: false,
default: null,
},
description: {
type: String,
required: false,
default: null,
},
isOwner: {
type: Boolean,
required: false,
default: false,
},
},
AVATAR_SHAPE_OPTION_RECT,
};
@ -41,7 +52,12 @@ export default {
:size="48"
/>
</gl-link>
<gl-link :href="href" class="gl-font-weight-bold gl-text-gray-900!">{{ fullName }}</gl-link>
<div>
<div class="gl-mb-1">
<gl-link :href="href" class="gl-font-weight-bold gl-text-gray-900!">{{ fullName }}</gl-link>
<gl-badge v-if="isOwner" variant="info">{{ s__('Runner|Owner') }}</gl-badge>
</div>
<div v-if="description">{{ description }}</div>
</div>
</div>
</template>

View File

@ -30,6 +30,7 @@ export default {
data() {
return {
projects: {
ownerProjectId: null,
items: [],
pageInfo: {},
count: 0,
@ -48,6 +49,7 @@ export default {
update(data) {
const { runner } = data;
return {
ownerProjectId: runner?.ownerProject?.id,
count: runner?.projectCount || 0,
items: runner?.projects?.nodes || [],
pageInfo: runner?.projects?.pageInfo || {},
@ -76,6 +78,11 @@ export default {
});
},
},
methods: {
isOwner(projectId) {
return projectId === this.projects.ownerProjectId;
},
},
I18N_NONE,
};
</script>
@ -98,6 +105,8 @@ export default {
:name="project.name"
:full-name="project.nameWithNamespace"
:avatar-url="project.avatarUrl"
:description="project.description"
:is-owner="isOwner(project.id)"
/>
</template>
<span v-else class="gl-text-gray-500">{{ $options.I18N_NONE }}</span>

View File

@ -9,11 +9,15 @@ query getRunnerProjects(
) {
runner(id: $id) {
id
ownerProject {
id
}
projectCount
projects(first: $first, last: $last, before: $before, after: $after) {
nodes {
id
avatarUrl
description
name
nameWithNamespace
webUrl

View File

@ -456,6 +456,8 @@ class Member < ApplicationRecord
# transaction has been committed, resulting in the job either throwing an
# error or not doing any meaningful work.
# rubocop: disable CodeReuse/ServiceClass
# This method is overridden in the test environment, see stubbed_member.rb
def refresh_member_authorized_projects(blocking:)
UserProjectAccessChangedService.new(user_id).execute(blocking: blocking)
end

View File

@ -111,7 +111,7 @@ class ProjectMember < Member
# rubocop:disable CodeReuse/ServiceClass
if blocking
AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker.bulk_perform_and_wait([[project.id, user.id]])
blocking_project_authorizations_refresh
else
AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker.perform_async(project.id, user.id)
end
@ -124,6 +124,11 @@ class ProjectMember < Member
# rubocop:enable CodeReuse/ServiceClass
end
# This method is overridden in the test environment, see stubbed_member.rb
def blocking_project_authorizations_refresh
AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker.bulk_perform_and_wait([[project.id, user.id]])
end
# TODO: https://gitlab.com/groups/gitlab-org/-/epics/7054
# temporary until we can we properly remove the source columns
override :set_member_namespace_id

View File

@ -180,7 +180,6 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :read_deploy_token
enable :create_jira_connect_subscription
enable :maintainer_access
enable :maintain_namespace
enable :read_upload
enable :destroy_upload
end

View File

@ -11,7 +11,6 @@ module Namespaces
enable :owner_access
enable :create_projects
enable :admin_namespace
enable :maintain_namespace
enable :read_namespace
enable :read_statistics
enable :create_jira_connect_subscription

View File

@ -0,0 +1,5 @@
%head
= stylesheet_link_tag "application"
= stylesheet_link_tag "application_utilities"
%body{ style: "background-color: #{params.dig(:lookbook, :display, :bg_color) || 'white'}" }
.container.gl-mt-6= yield

View File

@ -44,7 +44,7 @@
- if Feature.enabled?(:moved_mr_sidebar, @project)
.gl-ml-auto.gl-align-items-center.gl-display-none.gl-md-display-flex.js-expand-sidebar{ class: "gl-lg-display-none!" }
= render Pajamas::ButtonComponent.new(size: 'small',
icon: 'angle-double-left',
icon: 'chevron-double-lg-left',
button_options: { class: 'js-sidebar-toggle' }) do
= _('Expand')
.d-flex.flex-wrap.align-items-center.justify-content-lg-end

View File

@ -7,7 +7,7 @@ module WaitableWorker
# Schedules multiple jobs and waits for them to be completed.
def bulk_perform_and_wait(args_list)
# Short-circuit: it's more efficient to do small numbers of jobs inline
if args_list.size == 1
if args_list.size == 1 && !always_async_project_authorizations_refresh?
return bulk_perform_inline(args_list)
end
@ -29,6 +29,10 @@ module WaitableWorker
bulk_perform_async(failed) if failed.present?
end
def always_async_project_authorizations_refresh?
Feature.enabled?(:always_async_project_authorizations_refresh)
end
end
def perform(*args)

View File

@ -18,8 +18,6 @@ module Gitlab
class Application < Rails::Application
config.load_defaults 6.1
config.view_component.preview_route = "/-/view_component/previews"
config.active_support.hash_digest_class = ::OpenSSL::Digest::SHA256
# This section contains configuration from Rails upgrades to override the new defaults so that we

View File

@ -43,6 +43,13 @@ Rails.application.configure do
# Annotate rendered view with template file names as HTML comments
config.action_view.annotate_rendered_view_with_filenames = true
# ViewComponent previews
config.view_component.default_preview_layout = "component_preview"
config.view_component.preview_route = "/-/view_component/previews"
config.view_component.preview_paths << "#{config.root}/spec/components/previews"
# Push preview path now to prevent FrozenError during view_component's initialzer
config.autoload_paths.push("#{config.root}/spec/components/previews")
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.

View File

@ -21,6 +21,8 @@ Rails.application.configure do
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = Gitlab::Utils.to_boolean(ENV['CACHE_CLASSES'], default: false)
config.view_component.preview_route = "/-/view_component/previews"
# Configure static asset server for tests with Cache-Control for performance
config.assets.compile = false if ENV['CI']
# There is no need to check if assets are precompiled locally

View File

@ -0,0 +1,8 @@
---
name: always_async_project_authorizations_refresh
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92333
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367683
milestone: '15.3'
type: development
group: group::workspace
default_enabled: false

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
if Rails.env.development?
# :nocov: Lookbook is only available in development
Lookbook::ApplicationController.class_eval do
content_security_policy false
end
Rails.application.configure do
config.lookbook.experimental_features = [:pages]
config.lookbook.page_paths = ["#{config.root}/spec/components/docs"]
end
# :nocov:
end

View File

@ -3,7 +3,7 @@ data_category: optional
key_path: counts.keys
description: Number of keys.
product_section: dev
product_stage: managed
product_stage: manage
product_group: authentication_and_authorization
product_category: authentication_and_authorization
value_type: number

View File

@ -12,4 +12,5 @@ if Rails.env.development?
get '/rails/info' => 'rails/info#index'
mount LetterOpenerWeb::Engine, at: '/rails/letter_opener'
mount Lookbook::Engine, at: '/rails/lookbook'
end

View File

@ -0,0 +1,3 @@
# frozen_string_literal: true
markdown(customer_success.build_message)

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
require_relative '../../tooling/danger/customer_success'
module Danger
class CustomerSuccess < ::Danger::Plugin
include Tooling::Danger::CustomerSuccess
end
end

View File

@ -173,17 +173,18 @@ module.exports = (path, options = {}) => {
'^.+\\.(gql|graphql)$': 'jest-transform-graphql',
'^.+_worker\\.js$': './spec/frontend/__helpers__/web_worker_transformer.js',
'^.+\\.js$': 'babel-jest',
'^.+\\.vue$': 'vue-jest',
'^.+\\.vue$': '@vue/vue2-jest',
'spec/frontend/editor/schema/ci/yaml_tests/.+\\.(yml|yaml)$':
'./spec/frontend/__helpers__/yaml_transformer.js',
'^.+\\.(md|zip|png|yml|yaml)$': 'jest-raw-loader',
},
transformIgnorePatterns: [`node_modules/(?!(${transformIgnoreNodeModules.join('|')}))`],
timers: 'fake',
timers: 'legacy',
testEnvironment: '<rootDir>/spec/frontend/environment.js',
testEnvironmentOptions: {
IS_EE,
IS_JH,
},
testRunner: 'jest-jasmine2',
};
};

View File

@ -48,6 +48,12 @@ module API
before do
header['X-Frame-Options'] = 'SAMEORIGIN'
header['X-Content-Type-Options'] = 'nosniff'
if Rails.application.config.content_security_policy && !Rails.application.config.content_security_policy_report_only
policy = ActionDispatch::ContentSecurityPolicy.new { |p| p.default_src :none }
end
request.env[ActionDispatch::ContentSecurityPolicy::Request::POLICY] = policy
end
before do

View File

@ -930,6 +930,12 @@ module Gitlab
gitaly_repository_client.set_full_path(full_path)
end
def full_path
wrapped_gitaly_errors do
gitaly_repository_client.full_path
end
end
def disconnect_alternates
wrapped_gitaly_errors do
gitaly_repository_client.disconnect_alternates

View File

@ -271,6 +271,18 @@ module Gitlab
nil
end
def full_path
response = GitalyClient.call(
@storage,
:repository_service,
:full_path,
Gitaly::FullPathRequest.new(repository: @gitaly_repo),
timeout: GitalyClient.fast_timeout
)
response.path.presence
end
def license_short_name
request = Gitaly::FindLicenseRequest.new(repository: @gitaly_repo)

View File

@ -34061,6 +34061,9 @@ msgstr ""
msgid "Runners|upgrade recommended"
msgstr ""
msgid "Runner|Owner"
msgstr ""
msgid "Running"
msgstr ""

View File

@ -200,13 +200,13 @@
"@gitlab/stylelint-config": "4.1.0",
"@graphql-eslint/eslint-plugin": "3.10.6",
"@testing-library/dom": "^7.16.2",
"@types/jest": "^26.0.24",
"@vue/test-utils": "1.3.0",
"@vue/vue2-jest": "^27.0.0",
"acorn": "^6.3.0",
"ajv": "^8.10.0",
"ajv-formats": "^2.1.1",
"axios-mock-adapter": "^1.15.0",
"babel-jest": "^26.5.2",
"babel-jest": "^27.5.1",
"chalk": "^2.4.1",
"cheerio": "^1.0.0-rc.9",
"commander": "^2.20.3",
@ -221,14 +221,16 @@
"istanbul-lib-coverage": "^3.0.0",
"istanbul-lib-report": "^3.0.0",
"istanbul-reports": "^3.0.0",
"jest": "^26.5.2",
"jest": "^27.5.1",
"jest-canvas-mock": "^2.1.2",
"jest-diff": "^27.4.6",
"jest-environment-jsdom": "^26.5.2",
"jest-diff": "^27.5.1",
"jest-environment-jsdom": "^27.5.1",
"jest-jasmine2": "^27.5.1",
"jest-junit": "^12.0.0",
"jest-raw-loader": "^1.0.1",
"jest-transform-graphql": "^2.1.0",
"jest-util": "^26.5.2",
"jest-util": "^27.5.1",
"markdownlint-cli": "0.31.0",
"miragejs": "^0.1.40",
"mock-apollo-client": "1.2.0",
@ -242,7 +244,6 @@
"sass": "^1.49.9",
"stylelint": "^14.9.1",
"timezone-mock": "^1.0.8",
"vue-jest": "4.0.1",
"webpack-dev-server": "4.9.3",
"xhr-mock": "^2.5.1",
"yarn-check-webpack-plugin": "^1.2.0",

View File

@ -183,8 +183,7 @@ module QA
switch_to_sign_in_tab if has_sign_in_tab?
switch_to_standard_tab if has_standard_tab?
fill_element :login_field, user.username
fill_element :password_field, user.password
fill_in_credential(user)
if Runtime::Env.running_on_dot_com?
click_accept_all_cookies if has_accept_all_cookies_button?
@ -211,6 +210,11 @@ module QA
Page::Main::Menu.validate_elements_present! unless skip_page_validation
end
def fill_in_credential(user)
fill_element :login_field, user.username
fill_element :password_field, user.password
end
# Handle request for password change
# Happens on clean GDK installations when seeded root admin password is expired
#
@ -236,3 +240,5 @@ module QA
end
end
end
QA::Page::Main::Login.prepend_mod_with('Page::Main::Login', namespace: QA)

View File

@ -0,0 +1,20 @@
---
title: Welcome to our Lookbook 👋
---
<p>With Lookbook we can navigate, inspect and interact with our ViewComponent previews.</p>
<h2>Usage</h2>
<ul>
<li>Use the sidebar on the left to navigate our component previews.</li>
<li>Many previews can be interacted with by making changes in the <em>Params</em> tab.</li>
<li>Some previews have additional usage instructions in their <em>Notes</em> tab.</li>
</ul>
<h2>Learn more</h2>
<ul>
<li>Learn all about <a href="https://viewcomponent.org/">ViewComponent</a> and <a href="https://github.com/allmarkedup/lookbook">Lookbook</a>.</li>
<li>Have a look at our ViewComponent page in the <a href="https://docs.gitlab.com/ee/development/fe_guide/view_component.html">Frontend development docs</a>.</li>
</ul>

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Pajamas
class AlertComponentPreview < ViewComponent::Preview
# @param body text
# @param dismissible toggle
# @param variant select [info, warning, success, danger, tip]
def default(body: nil, dismissible: true, variant: :info)
render(Pajamas::AlertComponent.new(
title: "Title",
dismissible: dismissible,
variant: variant.to_sym
)) do |c|
if body
c.with_body { body }
end
end
end
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Pajamas
class AvatarComponentPreview < ViewComponent::Preview
# Avatar
# ----
# See its design reference [here](https://design.gitlab.com/components/avatar).
def default
user
end
# We show user avatars in a circle.
# @param size select [16, 24, 32, 48, 64, 96]
def user(size: 64)
render(Pajamas::AvatarComponent.new(User.first, size: size))
end
# @param size select [16, 24, 32, 48, 64, 96]
def project(size: 64)
render(Pajamas::AvatarComponent.new(Project.first, size: size))
end
# @param size select [16, 24, 32, 48, 64, 96]
def group(size: 64)
render(Pajamas::AvatarComponent.new(Group.first, size: size))
end
end
end

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
module Pajamas
class BannerComponentPreview < ViewComponent::Preview
# Banner
# ----
# See its design reference [here](https://design.gitlab.com/components/banner).
#
# @param button_text text
# @param button_link text
# @param content textarea
# @param embedded toggle
# @param variant select [introduction, promotion]
def default(
button_text: "Learn more",
button_link: "https://about.gitlab.com/",
content: "Add your message here.",
embedded: false,
variant: :promotion
)
render(Pajamas::BannerComponent.new(
button_text: button_text,
button_link: button_link,
embedded: embedded,
svg_path: "illustrations/autodevops.svg",
variant: variant
)) do |c|
content_tag :p, content
end
end
# Use the `primary_action` slot instead of `button_text` and `button_link` if you need something more special,
# like rendering a partial that holds your button.
def with_primary_action_slot
render(Pajamas::BannerComponent.new) do |c|
c.primary_action do
# You could also `render` another partial here.
tag.button "I'm special", class: "btn btn-md btn-confirm gl-button"
end
content_tag :p, "This banner uses the primary_action slot."
end
end
# Use the `illustration` slot instead of `svg_path` if your illustration is not part or the asset pipeline,
# but for example, an inline SVG via `custom_icon`.
def with_illustration_slot
render(Pajamas::BannerComponent.new) do |c|
c.illustration do
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="white" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-thumbs-up"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"></path></svg>'.html_safe # rubocop:disable Layout/LineLength
end
content_tag :p, "This banner uses the illustration slot."
end
end
end
end

View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
module Pajamas
class ButtonComponentPreview < ViewComponent::Preview
# Button
# ----
# See its design reference [here](https://design.gitlab.com/components/banner).
#
# @param category select [primary, secondary, tertiary]
# @param variant select [default, confirm, danger, dashed, link, reset]
# @param size select [small, medium]
# @param type select [button, reset, submit]
# @param disabled toggle
# @param loading toggle
# @param block toggle
# @param selected toggle
# @param icon text
# @param text text
def default( # rubocop:disable Metrics/ParameterLists
category: :primary,
variant: :default,
size: :medium,
type: :button,
disabled: false,
loading: false,
block: false,
selected: false,
icon: "pencil",
text: "Edit"
)
render(Pajamas::ButtonComponent.new(
category: category,
variant: variant,
size: size,
type: type,
disabled: disabled,
loading: loading,
block: block,
selected: selected,
icon: icon
)) do
text.presence
end
end
# The component can also be used to create links that look and feel like buttons.
# Just provide a `href` and optionally a `target` to create an `<a>` tag.
def link
render(Pajamas::ButtonComponent.new(
href: "https://gitlab.com",
target: "_blank"
)) do
"This is a link"
end
end
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Pajamas
class CardComponentPreview < ViewComponent::Preview
# Card
# ----
# See its design reference [here](https://design.gitlab.com/components/card).
#
# @param header text
# @param body textarea
# @param footer text
def default(header: nil, body: "Every card has a body.", footer: nil)
render(Pajamas::CardComponent.new) do |c|
if header
c.with_header { header }
end
c.with_body do
content_tag(:p, body)
end
if footer
c.with_footer { footer }
end
end
end
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Pajamas
class SpinnerComponentPreview < ViewComponent::Preview
# Spinner
# ----
# See its design reference [here](https://design.gitlab.com/components/spinner).
#
# @param inline toggle
# @param label text
# @param size select [[small, sm], [medium, md], [large, lg], [extra large, xl]]
def default(inline: false, label: "Loading", size: :md)
render(Pajamas::SpinnerComponent.new(inline: inline, label: label, size: size))
end
# Use a light spinner on dark backgrounds
#
# @display bg_color "#222"
def light
render(Pajamas::SpinnerComponent.new(color: :light))
end
end
end

View File

@ -1,4 +1,6 @@
import EventEmitter from 'events';
// eslint-disable-next-line no-restricted-syntax
import { setImmediate } from 'timers';
const axios = jest.requireActual('~/lib/utils/axios_utils').default;

View File

@ -1,5 +1,7 @@
/**
* Helper for testing action with expected mutations inspired in
// eslint-disable-next-line no-restricted-syntax
import { setImmediate } from 'timers';
/** Helper for testing action with expected mutations inspired in
* https://vuex.vuejs.org/en/testing.html
*
* @param {(Function|Object)} action to be tested, or object of named parameters

View File

@ -1,4 +1,2 @@
export default () =>
new Promise((resolve) => {
requestAnimationFrame(resolve);
});
// eslint-disable-next-line no-restricted-syntax
export default () => new Promise(jest.requireActual('timers').setImmediate);

View File

@ -6,7 +6,7 @@ const babelJestTransformer = require('babel-jest');
// [1]: https://webpack.js.org/loaders/worker-loader/
module.exports = {
process: (contentArg, filename, ...args) => {
const { code: content } = babelJestTransformer.process(contentArg, filename, ...args);
const { code: content } = babelJestTransformer.default.process(contentArg, filename, ...args);
return `const { FakeWebWorker } = require("helpers/web_worker_fake");
module.exports = class JestTransformedWorker extends FakeWebWorker {

View File

@ -10,7 +10,6 @@ import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import ProjectSelect from '~/boards/components/project_select.vue';
import defaultState from '~/boards/stores/state';
import waitForPromises from 'helpers/wait_for_promises';
import { mockList, mockActiveGroupProjects } from './mock_data';
@ -133,7 +132,7 @@ describe('ProjectSelect component', () => {
const dropdownToggle = findGlDropdown().find('.dropdown-toggle');
await dropdownToggle.trigger('click');
await waitForPromises();
jest.runOnlyPendingTimers();
await nextTick();
const searchInput = findGlDropdown().findComponent(GlFormInput).element;

View File

@ -1,3 +1,4 @@
import { nextTick } from 'vue';
import CaptchaModal from '~/captcha/captcha_modal.vue';
import { waitForCaptchaToBeSolved } from '~/captcha/wait_for_captcha_to_be_solved';
@ -15,7 +16,7 @@ describe('waitForCaptchaToBeSolved', () => {
it('opens a modal, resolves with captcha response on success', async () => {
CaptchaModal.mounted.mockImplementationOnce(function mounted() {
requestAnimationFrame(() => {
return nextTick().then(() => {
this.$emit('receivedCaptchaResponse', response);
this.$emit('hidden');
});
@ -36,7 +37,7 @@ describe('waitForCaptchaToBeSolved', () => {
it("opens a modal, rejects with error in case the captcha isn't solved", async () => {
CaptchaModal.mounted.mockImplementationOnce(function mounted() {
requestAnimationFrame(() => {
return nextTick().then(() => {
this.$emit('receivedCaptchaResponse', null);
this.$emit('hidden');
});

View File

@ -150,7 +150,6 @@ describe('InstallAgentModal', () => {
});
it("doesn't render agent installation instructions", () => {
expect(findModal().text()).not.toContain(i18n.basicInstallTitle);
expect(findModal().findComponent(GlFormInputGroup).exists()).toBe(false);
expect(findModal().findComponent(GlAlert).exists()).toBe(false);
});

View File

@ -85,30 +85,6 @@ describe('AppComponent', () => {
await nextTick();
});
describe('computed', () => {
describe('groups', () => {
it('should return list of groups from store', () => {
jest.spyOn(vm.store, 'getGroups').mockImplementation(() => {});
const { groups } = vm;
expect(vm.store.getGroups).toHaveBeenCalled();
expect(groups).not.toBeDefined();
});
});
describe('pageInfo', () => {
it('should return pagination info from store', () => {
jest.spyOn(vm.store, 'getPaginationInfo').mockImplementation(() => {});
const { pageInfo } = vm;
expect(vm.store.getPaginationInfo).toHaveBeenCalled();
expect(pageInfo).not.toBeDefined();
});
});
});
describe('methods', () => {
describe('fetchGroups', () => {
it('should call `getGroups` with all the params provided', () => {

View File

@ -8,12 +8,12 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
const TEST_TABS = [
{
title: 'Lorem',
icon: 'angle-up',
icon: 'chevron-lg-up',
views: [{ name: 'lorem-1' }, { name: 'lorem-2' }],
},
{
title: 'Ipsum',
icon: 'angle-down',
icon: 'chevron-lg-down',
views: [{ name: 'ipsum-1' }, { name: 'ipsum-2' }],
},
];

View File

@ -292,16 +292,11 @@ describe('common_utils', () => {
const spy = jest.fn();
const debouncedSpy = commonUtils.debounceByAnimationFrame(spy);
return new Promise((resolve) => {
window.requestAnimationFrame(() => {
debouncedSpy();
debouncedSpy();
window.requestAnimationFrame(() => {
expect(spy).toHaveBeenCalledTimes(1);
resolve();
});
});
});
debouncedSpy();
debouncedSpy();
jest.runOnlyPendingTimers();
expect(spy).toHaveBeenCalledTimes(1);
});
});

View File

@ -18,14 +18,12 @@ function mockXHRResponse({ responseText, responseContentType } = {}) {
.mockReturnValue(responseContentType);
jest.spyOn(global.XMLHttpRequest.prototype, 'send').mockImplementation(function send() {
requestAnimationFrame(() => {
Object.defineProperties(this, {
readyState: { value: XMLHttpRequest.DONE },
status: { value: 200 },
response: { value: responseText },
});
this.onreadystatechange();
Object.defineProperties(this, {
readyState: { value: XMLHttpRequest.DONE },
status: { value: 200 },
response: { value: responseText },
});
this.onreadystatechange();
});
}

View File

@ -4,6 +4,7 @@ import VueApollo from 'vue-apollo';
import Vue, { nextTick } from 'vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue';
import CiLint from '~/pipeline_editor/components/lint/ci_lint.vue';
import CiValidate from '~/pipeline_editor/components/validate/ci_validate.vue';
@ -22,6 +23,7 @@ import {
} from '~/pipeline_editor/constants';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql';
import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
import {
mockBlobContentQueryResponse,
mockCiLintPath,
@ -81,6 +83,15 @@ describe('Pipeline editor tabs component', () => {
const createComponentWithApollo = ({ props, provide = {}, mountFn = shallowMount } = {}) => {
const handlers = [[getBlobContent, mockBlobContentData]];
mockApollo = createMockApollo(handlers);
mockApollo.clients.defaultClient.cache.writeQuery({
query: getAppStatus,
data: {
app: {
__typename: 'PipelineEditorApp',
status: EDITOR_APP_STATUS_VALID,
},
},
});
createComponent({
props,
@ -203,7 +214,7 @@ describe('Pipeline editor tabs component', () => {
});
describe('if badge has been dismissed before', () => {
beforeEach(() => {
it('does not render badge if it has been dismissed before', async () => {
localStorage.setItem(VALIDATE_TAB_BADGE_DISMISSED_KEY, 'true');
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponse);
createComponentWithApollo({
@ -217,9 +228,9 @@ describe('Pipeline editor tabs component', () => {
validateTabIllustrationPath: 'path/to/svg',
},
});
});
it('does not render badge if it has been dismissed before', () => {
await waitForPromises();
expect(findBadge().exists()).toBe(false);
});
});

View File

@ -1,4 +1,5 @@
import { GlDropdown } from '@gitlab/ui';
import { nextTick } from 'vue';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
@ -61,11 +62,10 @@ describe('Pipelines stage component', () => {
const findMergeTrainWarning = () => wrapper.find('[data-testid="warning-message-merge-trains"]');
const findLoadingState = () => wrapper.find('[data-testid="pipeline-stage-loading-state"]');
const openStageDropdown = () => {
findDropdownToggle().trigger('click');
return new Promise((resolve) => {
wrapper.vm.$root.$on('bv::dropdown::show', resolve);
});
const openStageDropdown = async () => {
await findDropdownToggle().trigger('click');
await waitForPromises();
await nextTick();
};
describe('loading state', () => {
@ -77,7 +77,10 @@ describe('Pipelines stage component', () => {
await openStageDropdown();
});
it('displays loading state while jobs are being fetched', () => {
it('displays loading state while jobs are being fetched', async () => {
jest.runOnlyPendingTimers();
await nextTick();
expect(findLoadingState().exists()).toBe(true);
expect(findLoadingState().text()).toBe(PipelineStage.i18n.loadingText);
});
@ -98,46 +101,41 @@ describe('Pipelines stage component', () => {
expect(glTooltipDirectiveMock.mock.calls[0][1].modifiers.ds0).toBe(true);
});
it('should render a dropdown with the status icon', () => {
it('renders a dropdown with the status icon', () => {
expect(findDropdown().exists()).toBe(true);
expect(findDropdownToggle().exists()).toBe(true);
expect(findCiIcon().exists()).toBe(true);
});
it('should render a borderless ci-icon', () => {
it('renders a borderless ci-icon', () => {
expect(findCiIcon().exists()).toBe(true);
expect(findCiIcon().props('isBorderless')).toBe(true);
expect(findCiIcon().classes('borderless')).toBe(true);
});
it('should render a ci-icon with a custom border class', () => {
it('renders a ci-icon with a custom border class', () => {
expect(findCiIcon().exists()).toBe(true);
expect(findCiIcon().classes('gl-border')).toBe(true);
});
});
describe('when update dropdown is changed', () => {
beforeEach(() => {
createComponent();
});
});
describe('when user opens dropdown and stage request is successful', () => {
beforeEach(async () => {
mock.onGet(dropdownPath).reply(200, stageReply);
createComponent();
await openStageDropdown();
await jest.runAllTimers();
await axios.waitForAll();
});
it('should render the received data and emit `clickedDropdown` event', async () => {
it('renders the received data and emit `clickedDropdown` event', async () => {
expect(findDropdownMenu().text()).toContain(stageReply.latest_statuses[0].name);
expect(findDropdownMenuTitle().text()).toContain(stageReply.name);
expect(eventHub.$emit).toHaveBeenCalledWith('clickedDropdown');
});
it('should refresh when updateDropdown is set to true', async () => {
it('refreshes when updateDropdown is set to true', async () => {
expect(mock.history.get).toHaveLength(1);
wrapper.setProps({ updateDropdown: true });
@ -148,15 +146,14 @@ describe('Pipelines stage component', () => {
});
describe('when user opens dropdown and stage request fails', () => {
beforeEach(async () => {
it('should close the dropdown', async () => {
mock.onGet(dropdownPath).reply(500);
createComponent();
await openStageDropdown();
await axios.waitForAll();
});
await waitForPromises();
it('should close the dropdown', () => {
expect(findDropdown().classes('show')).toBe(false);
});
});
@ -181,26 +178,29 @@ describe('Pipelines stage component', () => {
it('should update the stage to request the new endpoint provided', async () => {
await openStageDropdown();
await axios.waitForAll();
jest.runOnlyPendingTimers();
await waitForPromises();
expect(findDropdownMenu().text()).toContain('this is the updated content');
});
});
describe('pipelineActionRequestComplete', () => {
beforeEach(() => {
beforeEach(async () => {
mock.onGet(dropdownPath).reply(200, stageReply);
mock.onPost(`${stageReply.latest_statuses[0].status.action.path}.json`).reply(200);
createComponent();
await waitForPromises();
await nextTick();
});
const clickCiAction = async () => {
await openStageDropdown();
await axios.waitForAll();
jest.runOnlyPendingTimers();
await waitForPromises();
findCiActionBtn().trigger('click');
await axios.waitForAll();
await findCiActionBtn().trigger('click');
};
it('closes dropdown when job item action is clicked', async () => {
@ -211,29 +211,30 @@ describe('Pipelines stage component', () => {
expect(hidden).toHaveBeenCalledTimes(0);
await clickCiAction();
await waitForPromises();
expect(hidden).toHaveBeenCalledTimes(1);
});
it('emits `pipelineActionRequestComplete` when job item action is clicked', async () => {
await clickCiAction();
await waitForPromises();
expect(wrapper.emitted('pipelineActionRequestComplete')).toHaveLength(1);
});
});
describe('With merge trains enabled', () => {
beforeEach(async () => {
it('shows a warning on the dropdown', async () => {
mock.onGet(dropdownPath).reply(200, stageReply);
createComponent({
isMergeTrain: true,
});
await openStageDropdown();
await axios.waitForAll();
});
jest.runOnlyPendingTimers();
await waitForPromises();
it('shows a warning on the dropdown', () => {
const warning = findMergeTrainWarning();
expect(warning.text()).toBe('Merge train pipeline jobs can not be retried');

View File

@ -45,6 +45,7 @@ describe('Pipelines', () => {
ciLintPath: '/ci/lint',
resetCachePath: `${mockProjectPath}/settings/ci_cd/reset_cache`,
newPipelinePath: `${mockProjectPath}/pipelines/new`,
ciRunnerSettingsPath: `${mockProjectPath}/-/settings/ci_cd#js-runners-settings`,
};
@ -654,7 +655,12 @@ describe('Pipelines', () => {
// Mock init a polling cycle
wrapper.vm.poll.options.notificationCallback(true);
findStagesDropdownToggle().trigger('click');
await findStagesDropdownToggle().trigger('click');
jest.runOnlyPendingTimers();
// cancelMock is getting overwritten in pipelines_service.js#L29
// so we have to spy on it again here
cancelMock = jest.spyOn(wrapper.vm.service.cancelationSource, 'cancel');
await waitForPromises();
@ -664,7 +670,8 @@ describe('Pipelines', () => {
});
it('stops polling & restarts polling', async () => {
findStagesDropdownToggle().trigger('click');
await findStagesDropdownToggle().trigger('click');
jest.runOnlyPendingTimers();
await waitForPromises();
expect(cancelMock).not.toHaveBeenCalled();

View File

@ -14,6 +14,7 @@ import RunnerPauseButton from '~/runner/components/runner_pause_button.vue';
import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue';
import RunnerEditButton from '~/runner/components/runner_edit_button.vue';
import RunnersJobs from '~/runner/components/runner_jobs.vue';
import runnerQuery from '~/runner/graphql/show/runner.query.graphql';
import AdminRunnerShowApp from '~/runner/admin_runner_show/admin_runner_show_app.vue';
import { captureException } from '~/runner/sentry_utils';
@ -182,17 +183,19 @@ describe('AdminRunnerShowApp', () => {
});
describe('When loading', () => {
beforeEach(() => {
it('does not show runner details', () => {
mockRunnerQueryResult();
createComponent();
});
it('does not show runner details', () => {
expect(findRunnerDetails().exists()).toBe(false);
});
it('does not show runner jobs', () => {
mockRunnerQueryResult();
createComponent();
expect(findRunnersJobs().exists()).toBe(false);
});
});

View File

@ -50,6 +50,7 @@ import {
allRunnersDataPaginated,
onlineContactTimeoutSecs,
staleTimeoutSecs,
emptyPageInfo,
emptyStateSvgPath,
emptyStateFilteredSvgPath,
} from '../mock_data';
@ -380,13 +381,20 @@ describe('AdminRunnersApp', () => {
beforeEach(async () => {
mockRunnersHandler.mockResolvedValue({
data: {
runners: { nodes: [] },
runners: {
nodes: [],
pageInfo: emptyPageInfo,
},
},
});
await createComponent();
});
it('shows no errors', () => {
expect(createAlert).not.toHaveBeenCalled();
});
it('shows an empty state', () => {
expect(findRunnerListEmptyState().props('isSearchFiltered')).toBe(false);
});

View File

@ -1,10 +1,12 @@
import { GlAvatar } from '@gitlab/ui';
import { GlAvatar, GlBadge } from '@gitlab/ui';
import { s__ } from '~/locale';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import RunnerAssignedItem from '~/runner/components/runner_assigned_item.vue';
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
const mockHref = '/group/project';
const mockName = 'Project';
const mockDescription = 'Project description';
const mockFullName = 'Group / Project';
const mockAvatarUrl = '/avatar.png';
@ -12,6 +14,7 @@ describe('RunnerAssignedItem', () => {
let wrapper;
const findAvatar = () => wrapper.findByTestId('item-avatar');
const findBadge = () => wrapper.findComponent(GlBadge);
const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMountExtended(RunnerAssignedItem, {
@ -20,6 +23,7 @@ describe('RunnerAssignedItem', () => {
name: mockName,
fullName: mockFullName,
avatarUrl: mockAvatarUrl,
description: mockDescription,
...props,
},
});
@ -51,4 +55,14 @@ describe('RunnerAssignedItem', () => {
expect(groupFullName.attributes('href')).toBe(mockHref);
});
it('Shows description', () => {
expect(wrapper.text()).toContain(mockDescription);
});
it('Shows owner badge', () => {
createComponent({ props: { isOwner: true } });
expect(findBadge().text()).toBe(s__('Runner|Owner'));
});
});

View File

@ -95,6 +95,7 @@ describe('RunnerProjects', () => {
name,
fullName: nameWithNamespace,
avatarUrl,
isOwner: true, // first project is always owner
});
});

View File

@ -178,13 +178,10 @@ describe('GroupRunnerShowApp', () => {
});
describe('When loading', () => {
beforeEach(() => {
it('does not show runner details', () => {
mockRunnerQueryResult();
createComponent();
});
it('does not show runner details', () => {
expect(findRunnerDetails().exists()).toBe(false);
});
});

View File

@ -47,6 +47,7 @@ import {
groupRunnersCountData,
onlineContactTimeoutSecs,
staleTimeoutSecs,
emptyPageInfo,
emptyStateSvgPath,
emptyStateFilteredSvgPath,
} from '../mock_data';
@ -331,13 +332,20 @@ describe('GroupRunnersApp', () => {
data: {
group: {
id: '1',
runners: { nodes: [] },
runners: {
edges: [],
pageInfo: emptyPageInfo,
},
},
},
});
await createComponent();
});
it('shows no errors', () => {
expect(createAlert).not.toHaveBeenCalled();
});
it('shows an empty state', async () => {
expect(findRunnerListEmptyState().exists()).toBe(true);
});

View File

@ -19,6 +19,14 @@ import groupRunnersCountData from 'test_fixtures/graphql/runner/list/group_runne
import { RUNNER_PAGE_SIZE } from '~/runner/constants';
const emptyPageInfo = {
__typename: 'PageInfo',
hasNextPage: false,
hasPreviousPage: false,
startCursor: '',
endCursor: '',
};
// Other mock data
// Mock searches and their corresponding urls
@ -233,6 +241,7 @@ export {
groupRunnersData,
groupRunnersDataPaginated,
groupRunnersCountData,
emptyPageInfo,
runnerData,
runnerWithGroupData,
runnerProjectsData,

View File

@ -1,4 +1,5 @@
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import EscalationStatus from '~/sidebar/components/incidents/escalation_status.vue';
@ -61,6 +62,8 @@ describe('EscalationStatus', () => {
createComponent();
// Open dropdown
await toggleDropdown();
jest.runOnlyPendingTimers();
await nextTick();
expect(findDropdownMenu().classes('show')).toBe(true);
@ -74,6 +77,8 @@ describe('EscalationStatus', () => {
createComponent({ preventDropdownClose: true });
// Open dropdown
await toggleDropdown();
jest.runOnlyPendingTimers();
await nextTick();
expect(findDropdownMenu().classes('show')).toBe(true);

View File

@ -1,4 +1,6 @@
/* Setup for unit test environment */
// eslint-disable-next-line no-restricted-syntax
import { setImmediate } from 'timers';
import 'helpers/shared_test_setup';
import { initializeTestTimeout } from 'helpers/timeout';

View File

@ -204,7 +204,7 @@ describe('WorkItemAssignees component', () => {
expect(findTokenSelector().props('dropdownItems')).toHaveLength(2);
});
it('should search for users with correct key after text input', async () => {
it('searches for users with correct key after text input', async () => {
const searchKey = 'Hello';
findTokenSelector().vm.$emit('focus');

View File

@ -54,16 +54,16 @@ RSpec.describe ::Gitlab::BareRepositoryImport::Repository do
end
context 'hashed storage' do
let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
let(:hashed_path) { "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" }
let(:root_path) { TestEnv.repos_path }
let(:repo_path) { File.join(root_path, "#{hashed_path}.git") }
let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") }
let(:raw_repository) { Gitlab::Git::Repository.new('default', "#{hashed_path}.git", nil, nil) }
let(:full_path) { 'to/repo' }
before do
raw_repository.create_repository
raw_repository.set_full_path(full_path: 'to/repo')
raw_repository.set_full_path(full_path: full_path) if full_path
end
after do
@ -95,16 +95,17 @@ RSpec.describe ::Gitlab::BareRepositoryImport::Repository do
expect(subject).not_to be_processable
end
it 'returns false when group and project name are missing' do
repository = Rugged::Repository.new(repo_path)
repository.config.delete('gitlab.fullpath')
expect(subject).not_to be_processable
end
it 'returns true when group path and project name are present' do
expect(subject).to be_processable
end
context 'group and project name are missing' do
let(:full_path) { nil }
it 'returns false' do
expect(subject).not_to be_processable
end
end
end
describe '#project_full_path' do

View File

@ -2017,17 +2017,14 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
describe '#set_full_path' do
before do
repository_rugged.config["gitlab.fullpath"] = repository_path
repository.set_full_path(full_path: repository_path)
end
context 'is given a path' do
it 'writes it to disk' do
repository.set_full_path(full_path: "not-the/real-path.git")
config = File.read(File.join(repository_path, "config"))
expect(config).to include("[gitlab]")
expect(config).to include("fullpath = not-the/real-path.git")
expect(repository.full_path).to eq('not-the/real-path.git')
end
end
@ -2035,15 +2032,12 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
it 'does not write it to disk' do
repository.set_full_path(full_path: "")
config = File.read(File.join(repository_path, "config"))
expect(config).to include("[gitlab]")
expect(config).to include("fullpath = #{repository_path}")
expect(repository.full_path).to eq(repository_path)
end
end
context 'repository does not exist' do
it 'raises NoRepository and does not call Gitaly WriteConfig' do
it 'raises NoRepository and does not call SetFullPath' do
repository = Gitlab::Git::Repository.new('default', 'does/not/exist.git', '', 'group/project')
expect(repository.gitaly_repository_client).not_to receive(:set_full_path)
@ -2055,6 +2049,18 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
end
end
describe '#full_path' do
let(:full_path) { 'some/path' }
before do
repository.set_full_path(full_path: full_path)
end
it 'returns the full path' do
expect(repository.full_path).to eq(full_path)
end
end
describe '#merge_to_ref' do
let(:repository) { mutable_repository }
let(:branch_head) { '6d394385cf567f80a8fd85055db1ab4c5295806f' }

View File

@ -153,11 +153,6 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures do
end
it 'logs' do
allow(Gitlab::AppJsonLogger).to receive(:info).with(
hash_including(
"class" => "AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker"
)
)
expect(Gitlab::AppJsonLogger).to receive(:info).with(
message: 'Actor was :ci',
project_id: project.id
@ -750,11 +745,6 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures do
it { expect { pull_access_check }.not_to raise_error }
it 'logs' do
expect(Gitlab::AppJsonLogger).to receive(:info).with(
hash_including(
"class" => "AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker"
)
).once
expect(Gitlab::AppJsonLogger).to receive(:info).with(
message: 'Actor was :ci',
project_id: project.id

View File

@ -351,4 +351,16 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
client.set_full_path(path)
end
end
describe '#full_path' do
let(:path) { 'repo/path' }
it 'sends a full_path message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:full_path)
.and_return(double(path: path))
expect(client.full_path).to eq(path)
end
end
end

View File

@ -166,11 +166,12 @@ RSpec.describe GroupMember do
let_it_be(:project_c) { create(:project, group: group) }
let_it_be(:user) { create(:user) }
shared_examples_for 'calls UserProjectAccessChangedService to recalculate authorizations' do
it 'calls UserProjectAccessChangedService to recalculate authorizations' do
expect_next_instance_of(UserProjectAccessChangedService, user.id) do |service|
expect(service).to receive(:execute).with(blocking: blocking)
end
shared_examples_for 'calls AuthorizedProjectsWorker inline to recalculate authorizations' do
# this is inline with the overridden behaviour in stubbed_member.rb
it 'calls AuthorizedProjectsWorker inline to recalculate authorizations' do
worker_instance = AuthorizedProjectsWorker.new
expect(AuthorizedProjectsWorker).to receive(:new).and_return(worker_instance)
expect(worker_instance).to receive(:perform).with(user.id)
action
end
@ -178,15 +179,14 @@ RSpec.describe GroupMember do
context 'on create' do
let(:action) { group.add_member(user, Gitlab::Access::GUEST) }
let(:blocking) { true }
it 'changes access level', :sidekiq_inline do
it 'changes access level' do
expect { action }.to change { user.can?(:guest_access, project_a) }.from(false).to(true)
.and change { user.can?(:guest_access, project_b) }.from(false).to(true)
.and change { user.can?(:guest_access, project_c) }.from(false).to(true)
end
it_behaves_like 'calls UserProjectAccessChangedService to recalculate authorizations'
it_behaves_like 'calls AuthorizedProjectsWorker inline to recalculate authorizations'
end
context 'on update' do
@ -195,15 +195,14 @@ RSpec.describe GroupMember do
end
let(:action) { group.members.find_by(user: user).update!(access_level: Gitlab::Access::DEVELOPER) }
let(:blocking) { true }
it 'changes access level', :sidekiq_inline do
it 'changes access level' do
expect { action }.to change { user.can?(:developer_access, project_a) }.from(false).to(true)
.and change { user.can?(:developer_access, project_b) }.from(false).to(true)
.and change { user.can?(:developer_access, project_c) }.from(false).to(true)
end
it_behaves_like 'calls UserProjectAccessChangedService to recalculate authorizations'
it_behaves_like 'calls AuthorizedProjectsWorker inline to recalculate authorizations'
end
context 'on destroy' do
@ -212,7 +211,6 @@ RSpec.describe GroupMember do
end
let(:action) { group.members.find_by(user: user).destroy! }
let(:blocking) { false }
it 'changes access level', :sidekiq_inline do
expect { action }.to change { user.can?(:guest_access, project_a) }.from(true).to(false)
@ -220,7 +218,11 @@ RSpec.describe GroupMember do
.and change { user.can?(:guest_access, project_c) }.from(true).to(false)
end
it_behaves_like 'calls UserProjectAccessChangedService to recalculate authorizations'
it 'schedules an AuthorizedProjectsWorker job to recalculate authorizations' do
expect(AuthorizedProjectsWorker).to receive(:bulk_perform_async).with([[user.id]])
action
end
end
end
end

View File

@ -213,10 +213,11 @@ RSpec.describe ProjectMember do
let_it_be(:user) { create(:user) }
shared_examples_for 'calls AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker inline to recalculate authorizations' do
it 'calls AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker' do
expect(AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker).to receive(:bulk_perform_and_wait).with(
[[project.id, user.id]]
)
# this is inline with the overridden behaviour in stubbed_member.rb
it 'calls AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker inline' do
worker_instance = AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker.new
expect(AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker).to receive(:new).and_return(worker_instance)
expect(worker_instance).to receive(:perform).with(project.id, user.id)
action
end

View File

@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe Namespace do
include ProjectForksHelper
include GitHelpers
include ReloadHelpers
let_it_be(:group_sti_name) { Group.sti_name }
@ -1076,9 +1075,9 @@ RSpec.describe Namespace do
it 'updates project full path in .git/config' do
parent.update!(path: 'mygroup_new')
expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}"
expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}"
expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}"
expect(project_in_parent_group.reload.repository.full_path).to eq "mygroup_new/#{project_in_parent_group.path}"
expect(hashed_project_in_subgroup.reload.repository.full_path).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}"
expect(legacy_project_in_subgroup.reload.repository.full_path).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}"
end
it 'updates the project storage location' do
@ -1092,14 +1091,6 @@ RSpec.describe Namespace do
expect(repository_hashed_project_in_subgroup.reload.disk_path).to eq hashed_project_in_subgroup.disk_path
expect(repository_legacy_project_in_subgroup.reload.disk_path).to eq "mygroup_moved/mysubgroup/#{legacy_project_in_subgroup.path}"
end
def project_rugged(project)
# Routes are loaded when creating the projects, so we need to manually
# reload them for the below code to be aware of the above UPDATE.
project.route.reload
rugged_repo(project.repository)
end
end
end

View File

@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe Project, factory_default: :keep do
include ProjectForksHelper
include GitHelpers
include ExternalAuthorizationServiceHelpers
include ReloadHelpers
include StubGitlabCalls
@ -5741,16 +5740,18 @@ RSpec.describe Project, factory_default: :keep do
describe '#set_full_path' do
let_it_be(:project) { create(:project, :repository) }
let(:repository) { project.repository.raw }
it 'writes full path in .git/config when key is missing' do
project.set_full_path
expect(rugged_config['gitlab.fullpath']).to eq project.full_path
expect(repository.full_path).to eq project.full_path
end
it 'updates full path in .git/config when key is present' do
project.set_full_path(gl_full_path: 'old/path')
expect { project.set_full_path }.to change { rugged_config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
expect { project.set_full_path }.to change { repository.full_path }.from('old/path').to(project.full_path)
end
it 'does not raise an error with an empty repository' do
@ -8436,10 +8437,6 @@ RSpec.describe Project, factory_default: :keep do
export_job.finish
end
def rugged_config
rugged_repo(project.repository).config
end
def create_pipeline(project, status = 'success')
create(:ci_pipeline, project: project,
sha: project.commit.sha,

View File

@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe RemoteMirror, :mailer do
include GitHelpers
before do
stub_feature_flags(remote_mirror_no_delay: false)
end
@ -96,16 +94,6 @@ RSpec.describe RemoteMirror, :mailer do
expect(mirror.url).to eq('http://foo:bar@test.com')
expect(mirror.credentials).to eq({ user: 'foo', password: 'bar' })
end
it 'does not update the repository config if credentials changed' do
mirror = create_mirror(url: 'http://foo:bar@test.com')
repo = mirror.project.repository
old_config = rugged_repo(repo).config
mirror.update_attribute(:url, 'http://foo:baz@test.com')
expect(rugged_repo(repo).config.to_hash).to eq(old_config.to_hash)
end
end
end

View File

@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe GroupPolicy do
include_context 'GroupPolicy context'
using RSpec::Parameterized::TableSyntax
context 'public group with no user' do
let(:group) { create(:group, :public, :crm_enabled) }
@ -1230,30 +1229,4 @@ RSpec.describe GroupPolicy do
it { is_expected.to be_disallowed(:admin_crm_contact) }
it { is_expected.to be_disallowed(:admin_crm_organization) }
end
describe 'maintain_namespace' do
context 'with non-admin roles' do
where(:role, :allowed) do
:guest | false
:reporter | false
:developer | false
:maintainer | true
:owner | true
end
with_them do
let(:current_user) { public_send(role) }
it do
expect(subject.allowed?(:maintain_namespace)).to eq allowed
end
end
end
context 'as an admin', :enable_admin_mode do
let(:current_user) { admin }
it { is_expected.to be_allowed(:maintain_namespace) }
end
end
end

View File

@ -8,7 +8,7 @@ RSpec.describe Namespaces::UserNamespacePolicy do
let_it_be(:admin) { create(:admin) }
let_it_be(:namespace) { create(:user_namespace, owner: owner) }
let(:owner_permissions) { [:owner_access, :create_projects, :admin_namespace, :read_namespace, :read_statistics, :transfer_projects, :admin_package, :maintain_namespace] }
let(:owner_permissions) { [:owner_access, :create_projects, :admin_namespace, :read_namespace, :read_statistics, :transfer_projects, :admin_package] }
subject { described_class.new(current_user, namespace) }

View File

@ -262,4 +262,54 @@ RSpec.describe API::API do
end
end
end
describe 'content security policy header' do
let_it_be(:user) { create(:user) }
let(:csp) { nil }
let(:report_only) { false }
subject { get api("/users/#{user.id}", user) }
before do
allow(Rails.application.config).to receive(:content_security_policy).and_return(csp)
allow(Rails.application.config).to receive(:content_security_policy_report_only).and_return(report_only)
end
context 'when CSP is not configured globally' do
it 'does not set the CSP header' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Security-Policy']).to be_nil
end
end
context 'when CSP is configured globally' do
let(:csp) do
ActionDispatch::ContentSecurityPolicy.new do |p|
p.default_src :self
end
end
it 'sets a stricter CSP header' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Security-Policy']).to eq("default-src 'none'")
end
context 'when report_only is true' do
let(:report_only) { true }
it 'does not set any CSP header' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Security-Policy']).to be_nil
expect(response.headers['Content-Security-Policy-Report-Only']).to be_nil
end
end
end
end
end

View File

@ -447,7 +447,7 @@ RSpec.describe API::Invitations do
emails = 'email3@example.com,email4@example.com,email5@example.com,email6@example.com,email7@example.com'
unresolved_n_plus_ones = 32 # currently there are 8 queries added per email
unresolved_n_plus_ones = 36 # currently there are 9 queries added per email
expect do
post invitations_url(group, maintainer), params: { email: emails, access_level: Member::DEVELOPER }

View File

@ -27,7 +27,10 @@ RSpec.describe Members::Groups::CreatorService do
context 'authorized projects update' do
it 'schedules a single project authorization update job when called multiple times' do
expect(AuthorizedProjectsWorker).to receive(:bulk_perform_and_wait).once
# this is inline with the overridden behaviour in stubbed_member.rb
worker_instance = AuthorizedProjectsWorker.new
expect(AuthorizedProjectsWorker).to receive(:new).once.and_return(worker_instance)
expect(worker_instance).to receive(:perform).with(user.id)
1.upto(3) do
described_class.add_member(source, user, :maintainer)

View File

@ -3,7 +3,6 @@
require 'spec_helper'
RSpec.describe Projects::AfterRenameService do
let(:rugged_config) { rugged_repo(project.repository).config }
let(:legacy_storage) { Storage::LegacyProject.new(project) }
let(:hashed_storage) { Storage::Hashed.new(project) }
let!(:path_before_rename) { project.path }
@ -71,10 +70,10 @@ RSpec.describe Projects::AfterRenameService do
end
end
it 'updates project full path in .git/config' do
it 'updates project full path in gitaly' do
service_execute
expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
expect(project.repository.full_path).to eq(project.full_path)
end
it 'updates storage location' do
@ -173,10 +172,10 @@ RSpec.describe Projects::AfterRenameService do
end
end
it 'updates project full path in .git/config' do
it 'updates project full path in gitaly' do
service_execute
expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
expect(project.repository.full_path).to eq(project.full_path)
end
it 'updates storage location' do

View File

@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe Projects::CreateService, '#execute' do
include ExternalAuthorizationServiceHelpers
include GitHelpers
let(:user) { create :user }
let(:project_name) { 'GitLab' }
@ -769,11 +768,10 @@ RSpec.describe Projects::CreateService, '#execute' do
create_project(user, opts)
end
it 'writes project full path to .git/config' do
it 'writes project full path to gitaly' do
project = create_project(user, opts)
rugged = rugged_repo(project.repository)
expect(rugged.config['gitlab.fullpath']).to eq project.full_path
expect(project.repository.full_path).to eq project.full_path
end
it 'triggers PostCreationWorker' do

View File

@ -68,12 +68,10 @@ RSpec.describe Projects::HashedStorage::MigrateRepositoryService do
service.execute
end
it 'writes project full path to .git/config' do
it 'writes project full path to gitaly' do
service.execute
rugged_config = rugged_repo(project.repository).config['gitlab.fullpath']
expect(rugged_config).to eq project.full_path
expect(project.repository.full_path).to eq project.full_path
end
end

View File

@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab_redis_shared_state do
include GitHelpers
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project) { create(:project, :repository, :wiki_repo, :design_repo, storage_version: ::Project::HASHED_STORAGE_FEATURES[:repository]) }
let(:legacy_storage) { Storage::LegacyProject.new(project) }
@ -68,12 +66,10 @@ RSpec.describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab
service.execute
end
it 'writes project full path to .git/config' do
it 'writes project full path to gitaly' do
service.execute
rugged_config = rugged_repo(project.repository).config['gitlab.fullpath']
expect(rugged_config).to eq project.full_path
expect(project.repository.full_path).to eq project.full_path
end
end

View File

@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Projects::TransferService do
include GitHelpers
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:group_integration) { create(:integrations_slack, :group, group: group, webhook: 'http://group.slack.com') }
@ -202,10 +200,10 @@ RSpec.describe Projects::TransferService do
expect(project.disk_path).to start_with(group.path)
end
it 'updates project full path in .git/config' do
it 'updates project full path in gitaly' do
execute_transfer
expect(rugged_config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}"
expect(project.repository.full_path).to eq "#{group.full_path}/#{project.path}"
end
it 'updates storage location' do
@ -296,10 +294,10 @@ RSpec.describe Projects::TransferService do
expect(original_path).to eq current_path
end
it 'rolls back project full path in .git/config' do
it 'rolls back project full path in gitaly' do
attempt_project_transfer
expect(rugged_config['gitlab.fullpath']).to eq project.full_path
expect(project.repository.full_path).to eq project.full_path
end
it "doesn't send move notifications" do
@ -770,10 +768,6 @@ RSpec.describe Projects::TransferService do
end
end
def rugged_config
rugged_repo(project.repository).config
end
def project_namespace_in_sync(group)
project.reload
expect(project.namespace).to eq(group)

View File

@ -208,6 +208,7 @@ RSpec.configure do |config|
include StubFeatureFlags
include StubSnowplow
include StubMember
if ENV['CI'] || ENV['RETRIES']
# This includes the first try, i.e. tests will be run 4 times before failing.

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
module StubMember
def self.included(base)
Member.prepend(StubbedMember::Member)
ProjectMember.prepend(StubbedMember::ProjectMember)
end
end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
# Extend the ProjectMember & GroupMember class with the ability to
# to run project_authorizations refresh jobs inline.
# This is needed so that calls like `group.add_member(user, access_level)` or `create(:project_member)`
# in the specs can be run without including `:sidekiq_inline` trait.
module StubbedMember
extend ActiveSupport::Concern
module Member
private
def refresh_member_authorized_projects(blocking:)
return super unless blocking
AuthorizedProjectsWorker.new.perform(user_id)
end
end
module ProjectMember
private
def blocking_project_authorizations_refresh
AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker.new.perform(project.id, user.id)
end
end
end

View File

@ -23,8 +23,8 @@ RSpec::Matchers.define :publish_event do |expected_event_class|
def match_data?(actual, expected)
values_match?(actual.keys, expected.keys) &&
actual.keys.each do |key|
values_match?(actual[key], expected[key])
actual.keys.all? do |key|
values_match?(expected[key], actual[key])
end
end

View File

@ -0,0 +1,91 @@
# frozen_string_literal: true
require 'rspec-parameterized'
require 'gitlab-dangerfiles'
require 'gitlab/dangerfiles/spec_helper'
require_relative '../../../tooling/danger/customer_success'
RSpec.describe Tooling::Danger::CustomerSuccess do
include_context "with dangerfile"
let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
let(:customer_success) { fake_danger.new(helper: fake_helper) }
describe 'customer success danger' do
using RSpec::Parameterized::TableSyntax
where do
{
'with data category changes to Ops and no Customer Success::Impact Check label' => {
modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb),
changed_lines: ['-data_category: cat1', '+data_category: operational'],
customer_labeled: false,
impacted: true,
impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml)
},
'with data category changes and Customer Success::Impact Check label' => {
modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml),
changed_lines: ['-data_category: cat1', '+data_category: operational'],
customer_labeled: true,
impacted: false,
impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml)
},
'with metric file changes and no data category changes' => {
modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml),
changed_lines: ['-product_stage: growth'],
customer_labeled: false,
impacted: false,
impacted_files: []
},
'with data category changes from Ops' => {
modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb),
changed_lines: ['-data_category: operational', '+data_category: cat2'],
customer_labeled: false,
impacted: true,
impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml)
},
'with data category removed' => {
modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb),
changed_lines: ['-data_category: operational'],
customer_labeled: false,
impacted: true,
impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml)
},
'with data category added' => {
modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb),
changed_lines: ['+data_category: operational'],
customer_labeled: false,
impacted: true,
impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml)
},
'with data category in uppercase' => {
modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb),
changed_lines: ['+data_category: Operational'],
customer_labeled: false,
impacted: true,
impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml)
}
}
end
with_them do
before do
allow(fake_helper).to receive(:modified_files).and_return(modified_files)
allow(fake_helper).to receive(:changed_lines).and_return(changed_lines)
allow(fake_helper).to receive(:has_scoped_label_with_scope?).and_return(customer_labeled)
allow(fake_helper).to receive(:markdown_list).with(impacted_files)
.and_return(impacted_files.map { |item| "* `#{item}`" }.join("\n"))
end
it 'generates correct message' do
expect(customer_success.build_message).to match_expected_message
end
end
end
def match_expected_message
return be_nil unless impacted
start_with(described_class::CHANGED_SCHEMA_MESSAGE).and(include(*impacted_files))
end
end

View File

@ -30,19 +30,33 @@ RSpec.describe WaitableWorker do
describe '.bulk_perform_and_wait' do
context '1 job' do
it 'inlines the job' do
args_list = [[1]]
expect(worker).to receive(:bulk_perform_inline).with(args_list).and_call_original
expect(Gitlab::AppJsonLogger).to(
receive(:info).with(a_hash_including('message' => 'running inline',
'class' => 'Gitlab::Foo::Bar::DummyWorker',
'job_status' => 'running',
'queue' => 'foo_bar_dummy'))
.once)
it 'runs the jobs asynchronously' do
arguments = [[1]]
worker.bulk_perform_and_wait(args_list)
expect(worker).to receive(:bulk_perform_async).with(arguments)
expect(worker.counter).to eq(1)
worker.bulk_perform_and_wait(arguments)
end
context 'when the feature flag `always_async_project_authorizations_refresh` is turned off' do
before do
stub_feature_flags(always_async_project_authorizations_refresh: false)
end
it 'inlines the job' do
args_list = [[1]]
expect(worker).to receive(:bulk_perform_inline).with(args_list).and_call_original
expect(Gitlab::AppJsonLogger).to(
receive(:info).with(a_hash_including('message' => 'running inline',
'class' => 'Gitlab::Foo::Bar::DummyWorker',
'job_status' => 'running',
'queue' => 'foo_bar_dummy'))
.once)
worker.bulk_perform_and_wait(args_list)
expect(worker.counter).to eq(1)
end
end
end

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
module Tooling
module Danger
module CustomerSuccess
CHANGED_SCHEMA_MESSAGE = <<~MSG
Notification to the Customer Success about changes to files with possible breaking downstream processes, add label `Customer Success::Impact Check`.
/label ~"Customer Success::Impact Check"
The following files require a review:
MSG
FILE_PATH_REGEX = %r{((ee|jh)/)?config/metrics/.+\.yml}.freeze
CATEGORY_CHANGED = /data_category: operational/i.freeze
def build_message
return unless impacted?
CHANGED_SCHEMA_MESSAGE + helper.markdown_list(impacted_files)
end
private
def impacted?
!helper.has_scoped_label_with_scope?('Customer Success') && impacted_files.any?
end
def impacted_files
@impacted_files ||=
metric_files.select do |file|
helper.changed_lines(file).any? { |change| metric_category_changed?(change) }
end.compact
end
def metric_files
helper.modified_files.grep(FILE_PATH_REGEX)
end
def metric_category_changed?(change)
change =~ CATEGORY_CHANGED
end
end
end
end

View File

@ -37,7 +37,7 @@ GEM
rack (2.2.3.1)
rainbow (3.0.0)
regexp_parser (1.8.2)
rexml (3.2.4)
rexml (3.2.5)
rubocop (0.89.1)
parallel (~> 1.10)
parser (>= 2.7.1.1)
@ -66,7 +66,7 @@ GEM
temple (0.8.2)
thread_safe (0.3.6)
tilt (2.0.10)
tzinfo (1.2.8)
tzinfo (1.2.10)
thread_safe (~> 0.1)
unicode-display_width (1.7.0)
zeitwerk (2.4.1)

1410
yarn.lock

File diff suppressed because it is too large Load Diff