Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
46f35a6167
commit
9c5341dd08
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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: []
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
31ea786fbf0a7874b44efcb1f8b43bc4536d9b7e
|
||||
2720ae51a9acae55951c54268649a5cd0e2fa5ba
|
||||
|
|
|
|||
3
Gemfile
3
Gemfile
|
|
@ -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'
|
||||
|
|
|
|||
24
Gemfile.lock
24
Gemfile.lock
|
|
@ -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)!
|
||||
|
|
|
|||
|
|
@ -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 browser’s 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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
markdown(customer_success.build_message)
|
||||
|
|
@ -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
|
||||
|
|
@ -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',
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -34061,6 +34061,9 @@ msgstr ""
|
|||
msgid "Runners|upgrade recommended"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runner|Owner"
|
||||
msgstr ""
|
||||
|
||||
msgid "Running"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
13
package.json
13
package.json
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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' }],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ describe('RunnerProjects', () => {
|
|||
name,
|
||||
fullName: nameWithNamespace,
|
||||
avatarUrl,
|
||||
isOwner: true, // first project is always owner
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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' }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module StubMember
|
||||
def self.included(base)
|
||||
Member.prepend(StubbedMember::Member)
|
||||
ProjectMember.prepend(StubbedMember::ProjectMember)
|
||||
end
|
||||
end
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue