Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-11-09 12:07:48 +00:00
parent 44d4b37b52
commit 7c41737ae5
78 changed files with 787 additions and 574 deletions

View File

@ -308,10 +308,18 @@ Rails/RakeEnvironment:
# Context on why it's disabled: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93419#note_1048223982
Enabled: false
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94064#note_1157289970
Rails/SquishedSQLHeredocs:
Enabled: false
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96675#note_1094403693
Rails/WhereExists:
Enabled: false
# See https://gitlab.com/gitlab-org/gitlab/-/issues/378105#note_1138487716
Rails/HasManyOrHasOneDependent:
Enabled: false
# GitLab ###################################################################
Gitlab/ModuleWithInstanceVariables:

View File

@ -1,154 +0,0 @@
---
Rails/HasManyOrHasOneDependent:
# Offense count: 593
# Temporarily disabled due to too many offenses
Enabled: false
Exclude:
- 'app/models/alert_management/alert.rb'
- 'app/models/analytics/cycle_analytics/project_value_stream.rb'
- 'app/models/analytics/cycle_analytics/stage_event_hash.rb'
- 'app/models/application_setting/term.rb'
- 'app/models/bulk_import.rb'
- 'app/models/bulk_imports/entity.rb'
- 'app/models/bulk_imports/export.rb'
- 'app/models/ci/bridge.rb'
- 'app/models/ci/build.rb'
- 'app/models/ci/pipeline.rb'
- 'app/models/ci/pipeline_schedule.rb'
- 'app/models/ci/processable.rb'
- 'app/models/ci/ref.rb'
- 'app/models/ci/resource_group.rb'
- 'app/models/ci/runner.rb'
- 'app/models/ci/stage.rb'
- 'app/models/ci/trigger.rb'
- 'app/models/ci/trigger_request.rb'
- 'app/models/ci/unit_test.rb'
- 'app/models/clusters/agent.rb'
- 'app/models/clusters/applications/knative.rb'
- 'app/models/clusters/cluster.rb'
- 'app/models/clusters/project.rb'
- 'app/models/commit_status.rb'
- 'app/models/concerns/ci/metadatable.rb'
- 'app/models/concerns/integrations/has_data_fields.rb'
- 'app/models/concerns/issuable.rb'
- 'app/models/concerns/label_eventable.rb'
- 'app/models/concerns/milestone_eventable.rb'
- 'app/models/concerns/packages/debian/distribution.rb'
- 'app/models/concerns/protected_ref.rb'
- 'app/models/concerns/state_eventable.rb'
- 'app/models/concerns/timebox.rb'
- 'app/models/concerns/versioned_description.rb'
- 'app/models/concerns/with_uploads.rb'
- 'app/models/customer_relations/contact.rb'
- 'app/models/deploy_key.rb'
- 'app/models/deploy_token.rb'
- 'app/models/deployment.rb'
- 'app/models/design_management/design.rb'
- 'app/models/design_management/version.rb'
- 'app/models/environment.rb'
- 'app/models/error_tracking/error.rb'
- 'app/models/event.rb'
- 'app/models/experiment.rb'
- 'app/models/fork_network.rb'
- 'app/models/gpg_key.rb'
- 'app/models/group.rb'
- 'app/models/hooks/web_hook.rb'
- 'app/models/integration.rb'
- 'app/models/issue.rb'
- 'app/models/jira_connect_installation.rb'
- 'app/models/label.rb'
- 'app/models/lfs_object.rb'
- 'app/models/list.rb'
- 'app/models/member.rb'
- 'app/models/merge_request.rb'
- 'app/models/merge_request_context_commit.rb'
- 'app/models/milestone.rb'
- 'app/models/namespace.rb'
- 'app/models/namespaces/project_namespace.rb'
- 'app/models/note.rb'
- 'app/models/operations/feature_flag.rb'
- 'app/models/operations/feature_flags/strategy.rb'
- 'app/models/operations/feature_flags/user_list.rb'
- 'app/models/packages/debian/project_distribution.rb'
- 'app/models/packages/dependency.rb'
- 'app/models/packages/dependency_link.rb'
- 'app/models/packages/package.rb'
- 'app/models/packages/package_file.rb'
- 'app/models/pages_domain.rb'
- 'app/models/plan.rb'
- 'app/models/pool_repository.rb'
- 'app/models/project.rb'
- 'app/models/projects/topic.rb'
- 'app/models/prometheus_alert.rb'
- 'app/models/prometheus_metric.rb'
- 'app/models/release.rb'
- 'app/models/snippet.rb'
- 'app/models/terraform/state.rb'
- 'app/models/user.rb'
- 'app/models/wiki_page/meta.rb'
- 'app/models/work_items/type.rb'
- 'app/models/x509_certificate.rb'
- 'app/models/x509_issuer.rb'
- 'ee/app/models/analytics/devops_adoption/enabled_namespace.rb'
- 'ee/app/models/analytics/devops_adoption/snapshot.rb'
- 'ee/app/models/approval_merge_request_rule.rb'
- 'ee/app/models/approval_project_rule.rb'
- 'ee/app/models/boards/epic_board.rb'
- 'ee/app/models/boards/epic_list.rb'
- 'ee/app/models/compliance_management/framework.rb'
- 'ee/app/models/concerns/ee/iteration_eventable.rb'
- 'ee/app/models/concerns/ee/protected_branch.rb'
- 'ee/app/models/concerns/ee/protected_ref.rb'
- 'ee/app/models/concerns/ee/weight_eventable.rb'
- 'ee/app/models/concerns/geo/eventable.rb'
- 'ee/app/models/concerns/issue_widgets/acts_like_requirement.rb'
- 'ee/app/models/concerns/security/scan_execution_policy.rb'
- 'ee/app/models/dast/profile.rb'
- 'ee/app/models/dast_site.rb'
- 'ee/app/models/dast_site_profile.rb'
- 'ee/app/models/dast_site_validation.rb'
- 'ee/app/models/ee/alert_management/alert.rb'
- 'ee/app/models/ee/analytics/cycle_analytics/stage_event_hash.rb'
- 'ee/app/models/ee/board.rb'
- 'ee/app/models/ee/ci/build.rb'
- 'ee/app/models/ee/ci/job_artifact.rb'
- 'ee/app/models/ee/ci/pipeline.rb'
- 'ee/app/models/ee/deployment.rb'
- 'ee/app/models/ee/environment.rb'
- 'ee/app/models/ee/epic.rb'
- 'ee/app/models/ee/group.rb'
- 'ee/app/models/ee/issue.rb'
- 'ee/app/models/ee/iteration.rb'
- 'ee/app/models/ee/label.rb'
- 'ee/app/models/ee/lfs_object.rb'
- 'ee/app/models/ee/merge_request.rb'
- 'ee/app/models/ee/merge_request_diff.rb'
- 'ee/app/models/ee/milestone.rb'
- 'ee/app/models/ee/namespace.rb'
- 'ee/app/models/ee/pages_deployment.rb'
- 'ee/app/models/ee/plan.rb'
- 'ee/app/models/ee/project.rb'
- 'ee/app/models/ee/upload.rb'
- 'ee/app/models/ee/user.rb'
- 'ee/app/models/ee/vulnerability.rb'
- 'ee/app/models/elastic/reindexing_subtask.rb'
- 'ee/app/models/elastic/reindexing_task.rb'
- 'ee/app/models/geo/event.rb'
- 'ee/app/models/geo_node.rb'
- 'ee/app/models/incident_management/escalation_policy.rb'
- 'ee/app/models/incident_management/oncall_participant.rb'
- 'ee/app/models/incident_management/oncall_rotation.rb'
- 'ee/app/models/incident_management/oncall_schedule.rb'
- 'ee/app/models/integrations/gitlab_slack_application.rb'
- 'ee/app/models/iterations/cadence.rb'
- 'ee/app/models/protected_environment.rb'
- 'ee/app/models/protected_environments/approval_rule.rb'
- 'ee/app/models/push_rule.rb'
- 'ee/app/models/saml_provider.rb'
- 'ee/app/models/security/finding.rb'
- 'ee/app/models/security/scan.rb'
- 'ee/app/models/security/training_provider.rb'
- 'ee/app/models/vulnerabilities/finding.rb'
- 'ee/app/models/vulnerabilities/identifier.rb'
- 'ee/app/models/vulnerabilities/remediation.rb'
- 'ee/app/models/vulnerabilities/scanner.rb'

View File

@ -1,215 +0,0 @@
---
# Cop supports --auto-correct.
Rails/SquishedSQLHeredocs:
# Offense count: 356
# Temporarily disabled due to too many offenses
Enabled: false
Exclude:
- 'app/finders/members_finder.rb'
- 'app/models/analytics/cycle_analytics/stage_event_hash.rb'
- 'app/models/ci/resource_group.rb'
- 'app/models/clusters/clusters_hierarchy.rb'
- 'app/models/concerns/analytics/cycle_analytics/stage_event_model.rb'
- 'app/models/concerns/has_environment_scope.rb'
- 'app/models/customer_relations/contact.rb'
- 'app/models/customer_relations/organization.rb'
- 'app/models/deployment.rb'
- 'app/models/issue/metrics.rb'
- 'app/models/merge_request/metrics.rb'
- 'app/models/namespace/traversal_hierarchy.rb'
- 'app/models/namespaces/traversal/linear.rb'
- 'app/models/project.rb'
- 'app/models/user.rb'
- 'app/services/issuable/destroy_label_links_service.rb'
- 'app/services/issues/relative_position_rebalancing_service.rb'
- 'app/services/projects/fetch_statistics_increment_service.rb'
- 'app/services/todos/destroy/destroyed_issuable_service.rb'
- 'app/workers/users/deactivate_dormant_users_worker.rb'
- 'db/migrate/20210323155010_populate_dismissal_information_for_vulnerabilities.rb'
- 'db/migrate/20210601080039_group_protected_environments_add_index_and_constraint.rb'
- 'db/migrate/20210611100359_rebuild_index_for_cadence_iterations_automation.rb'
- 'db/migrate/20210617022324_create_incident_management_pending_alert_escalations.rb'
- 'db/migrate/20210621043337_rename_services_to_integrations.rb'
- 'db/migrate/20210621044000_rename_services_indexes_to_integrations.rb'
- 'db/migrate/20210706152139_add_index_type_to_postgres_indexes_view.rb'
- 'db/migrate/20210719145532_add_foreign_keys_view.rb'
- 'db/migrate/20210721135638_add_triggers_to_integrations_type_new.rb'
- 'db/migrate/20210721174453_remove_schedule_and_status_null_constraints_from_pending_escalations_alert.rb'
- 'db/migrate/20210722150102_operations_feature_flags_correct_flexible_rollout_values.rb'
- 'db/migrate/20210730194555_create_incident_management_pending_issue_escalations.rb'
- 'db/migrate/20210818175949_update_integrations_trigger_type_new_on_insert.rb'
- 'db/migrate/20210825104656_create_analytics_cycle_analytics_merge_request_stage_events.rb'
- 'db/migrate/20210825110016_create_analytics_cycle_analytics_issue_stage_events.rb'
- 'db/migrate/20210826122748_create_loose_foreign_keys_deleted_records.rb'
- 'db/migrate/20210826145509_add_function_for_inserting_deleted_records.rb'
- 'db/migrate/20210903054158_recreate_stage_issue_events_table_with_bigints.rb'
- 'db/migrate/20210906100021_delete_project_namespace_trigger.rb'
- 'db/migrate/20210929032555_create_verification_codes.rb'
- 'db/migrate/20211005092428_drop_time_range_partitioned_loose_fk.rb'
- 'db/migrate/20211005093558_add_range_partitioned_loose_fk_table.rb'
- 'db/migrate/20211005100112_recreate_loose_fk_insert_function.rb'
- 'db/migrate/20211007090229_create_issue_search_table.rb'
- 'db/migrate/20211011141242_create_namespaces_sync_trigger.rb'
- 'db/migrate/20211011141243_create_projects_sync_trigger.rb'
- 'db/migrate/20211012015903_next_traversal_ids_sibling_function.rb'
- 'db/migrate/20211018161447_fix_double_entries_in_postgres_index_view.rb'
- 'db/migrate/20211112155416_populate_default_value_for_personal_access_tokens_prefix.rb'
- 'db/migrate/20211118103439_remove_hardcoded_partition_from_loose_fk_trigger_function.rb'
- 'db/migrate/20211123135255_create_batched_background_migration_job_transition_logs.rb'
- 'db/migrate/20220106111958_add_insert_or_update_vulnerability_reads_trigger.rb'
- 'db/migrate/20220106112043_add_update_vulnerability_reads_trigger.rb'
- 'db/migrate/20220106112085_add_update_vulnerability_reads_location_trigger.rb'
- 'db/migrate/20220106163326_add_has_issues_on_vulnerability_reads_trigger.rb'
- 'db/migrate/20220208171826_update_default_scan_method_of_dast_site_profile.rb'
- 'db/migrate/20220211214605_update_integrations_trigger_type_new_on_insert_null_safe.rb'
- 'db/migrate/20220213100000_remove_integration_type_triggers.rb'
- 'db/migrate/20220304052335_remove_not_null_contraint_on_title_from_sprints.rb'
- 'db/migrate/20220321234317_remove_all_issuable_escalation_statuses.rb'
- 'db/migrate/20220329110630_add_ci_namespace_mirrors_unnest_index_on_traversal_ids.rb'
- 'db/migrate/20220412060931_add_nullify_build_data_trigger_on_merge_request_metrics.rb'
- 'db/migrate/20220413124200_add_view_for_per_table_autovacuum_status.rb'
- 'db/migrate/20220415015143_replace_iterations_cadence_date_range_constraint.rb'
- 'db/migrate/20220422200633_fix_view_for_per_table_autovacuum_status.rb'
- 'db/migrate/20220422220507_remove_tmp_index_supporting_leaky_regex_cleanup.rb'
- 'db/post_migrate/20210302074524_backfill_namespace_statistics_with_wiki_size.rb'
- 'db/post_migrate/20210311045138_set_traversal_ids_for_gitlab_org_group_staging.rb'
- 'db/post_migrate/20210311045139_set_traversal_ids_for_gitlab_org_group_com.rb'
- 'db/post_migrate/20210311093723_add_partial_index_on_ci_pipelines_by_cancelable_status_and_users.rb'
- 'db/post_migrate/20210317104032_set_iteration_cadence_automatic_to_false.rb'
- 'db/post_migrate/20210331105335_drop_non_partitioned_audit_events.rb'
- 'db/post_migrate/20210430134202_copy_adoption_snapshot_namespace.rb'
- 'db/post_migrate/20210430135954_copy_adoption_segments_namespace.rb'
- 'db/post_migrate/20210525075724_clean_up_pending_builds_table.rb'
- 'db/post_migrate/20210609125005_drop_non_partitioned_web_hook_logs.rb'
- 'db/post_migrate/20210610102413_migrate_protected_attribute_to_pending_builds.rb'
- 'db/post_migrate/20210610141711_disable_expiration_policies_linked_to_no_container_images.rb'
- 'db/post_migrate/20210708011426_finalize_ci_builds_metadata_bigint_conversion.rb'
- 'db/post_migrate/20210721174521_add_non_null_constraint_for_escalation_rule_on_pending_alert_escalations.rb'
- 'db/post_migrate/20210812013042_remove_duplicate_project_authorizations.rb'
- 'db/post_migrate/20210907211557_finalize_ci_builds_bigint_conversion.rb'
- 'db/post_migrate/20210910194952_update_report_type_for_existing_approval_project_rules.rb'
- 'db/post_migrate/20211105135157_drop_ci_build_trace_sections.rb'
- 'db/post_migrate/20211112113300_remove_ci_pipeline_chat_data_fk_on_chat_names.rb'
- 'db/post_migrate/20211130165043_backfill_sequence_column_for_sprints_table.rb'
- 'db/post_migrate/20211206161271_add_indexes_for_primary_email_cleanup_migration.rb'
- 'db/post_migrate/20211220064757_drop_temporary_indexes_for_primary_email_migration.rb'
- 'db/post_migrate/20220128155251_remove_dangling_running_builds.rb'
- 'db/post_migrate/20220204095121_backfill_namespace_statistics_with_dependency_proxy_size.rb'
- 'db/post_migrate/20220204110725_backfill_cycle_analytics_aggregations.rb'
- 'db/post_migrate/20220213103859_remove_integrations_type.rb'
- 'db/post_migrate/20220309084954_remove_leftover_external_pull_request_deletions.rb'
- 'db/post_migrate/20220318111040_add_indexes_for_primary_email_second_cleanup_migration.rb'
- 'db/post_migrate/20220318111949_drop_temporary_indexes_for_primary_email_migration_second_cleanup.rb'
- 'db/post_migrate/20220329175119_remove_leftover_ci_job_artifact_deletions.rb'
- 'db/post_migrate/20220420135946_update_batched_background_migration_arguments.rb'
- 'ee/app/models/dora/daily_metrics.rb'
- 'ee/app/models/ee/group.rb'
- 'ee/app/models/ee/issue.rb'
- 'ee/app/models/iterations/cadence.rb'
- 'ee/app/models/vulnerabilities/statistic.rb'
- 'ee/app/services/analytics/cycle_analytics/consistency_check_service.rb'
- 'ee/app/services/security/ingestion/tasks/ingest_vulnerability_statistics.rb'
- 'ee/app/services/vulnerabilities/historical_statistics/adjustment_service.rb'
- 'ee/app/services/vulnerabilities/statistics/adjustment_service.rb'
- 'ee/app/services/vulnerabilities/statistics/update_service.rb'
- 'ee/db/geo/migrate/20170906174622_remove_duplicates_from_project_registry.rb'
- 'ee/db/geo/migrate/20180510223634_set_resync_flag_for_retried_projects.rb'
- 'ee/db/geo/post_migrate/20210217020154_add_unique_index_on_container_repository_registry.rb'
- 'ee/db/geo/post_migrate/20210217020156_add_unique_index_on_terraform_state_version_registry.rb'
- 'ee/lib/ee/gitlab/background_migration/backfill_iteration_cadence_id_for_boards.rb'
- 'ee/lib/ee/gitlab/background_migration/create_security_setting.rb'
- 'ee/lib/ee/gitlab/background_migration/populate_latest_pipeline_ids.rb'
- 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb'
- 'ee/lib/ee/gitlab/background_migration/populate_status_column_of_security_scans.rb'
- 'ee/lib/ee/gitlab/background_migration/populate_test_reports_issue_id.rb'
- 'ee/lib/ee/gitlab/background_migration/update_vulnerability_occurrences_location.rb'
- 'ee/lib/ee/gitlab/usage_data.rb'
- 'ee/lib/gitlab/geo/base_batcher.rb'
- 'ee/spec/models/ee/user_spec.rb'
- 'lib/gitlab/background_migration/backfill_ci_namespace_mirrors.rb'
- 'lib/gitlab/background_migration/backfill_ci_project_mirrors.rb'
- 'lib/gitlab/background_migration/backfill_group_features.rb'
- 'lib/gitlab/background_migration/backfill_integrations_type_new.rb'
- 'lib/gitlab/background_migration/backfill_issue_search_data.rb'
- 'lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb'
- 'lib/gitlab/background_migration/backfill_namespace_traversal_ids_children.rb'
- 'lib/gitlab/background_migration/backfill_project_settings.rb'
- 'lib/gitlab/background_migration/backfill_projects_with_coverage.rb'
- 'lib/gitlab/background_migration/backfill_upvotes_count_on_issues.rb'
- 'lib/gitlab/background_migration/disable_expiration_policies_linked_to_no_container_images.rb'
- 'lib/gitlab/background_migration/encrypt_static_object_token.rb'
- 'lib/gitlab/background_migration/fix_duplicate_project_name_and_path.rb'
- 'lib/gitlab/background_migration/fix_first_mentioned_in_commit_at.rb'
- 'lib/gitlab/background_migration/fix_projects_without_project_feature.rb'
- 'lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb'
- 'lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature.rb'
- 'lib/gitlab/background_migration/populate_container_repository_migration_plan.rb'
- 'lib/gitlab/background_migration/populate_topics_non_private_projects_count.rb'
- 'lib/gitlab/background_migration/populate_topics_total_projects_count_cache.rb'
- 'lib/gitlab/background_migration/populate_vulnerability_reads.rb'
- 'lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb'
- 'lib/gitlab/background_migration/update_timelogs_null_spent_at.rb'
- 'lib/gitlab/background_migration/update_timelogs_project_id.rb'
- 'lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group.rb'
- 'lib/gitlab/database/bulk_update.rb'
- 'lib/gitlab/database/count/tablesample_count_strategy.rb'
- 'lib/gitlab/database/load_balancing/load_balancer.rb'
- 'lib/gitlab/database/migration_helpers.rb'
- 'lib/gitlab/database/migration_helpers/loose_foreign_key_helpers.rb'
- 'lib/gitlab/database/migration_helpers/v2.rb'
- 'lib/gitlab/database/migrations/batched_background_migration_helpers.rb'
- 'lib/gitlab/database/migrations/observers/query_statistics.rb'
- 'lib/gitlab/database/partitioning/replace_table.rb'
- 'lib/gitlab/database/partitioning/single_numeric_list_partition.rb'
- 'lib/gitlab/database/partitioning/sliding_list_strategy.rb'
- 'lib/gitlab/database/partitioning/time_partition.rb'
- 'lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table.rb'
- 'lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb'
- 'lib/gitlab/database/postgres_hll/batch_distinct_counter.rb'
- 'lib/gitlab/database/schema_helpers.rb'
- 'lib/gitlab/database/schema_migrations/migrations.rb'
- 'lib/gitlab/database/unidirectional_copy_trigger.rb'
- 'lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition.rb'
- 'lib/gitlab/graphql/pagination/keyset/conditions/null_condition.rb'
- 'lib/gitlab/pagination/keyset/in_operator_optimization/query_builder.rb'
- 'lib/gitlab/sql/glob.rb'
- 'lib/tasks/dev.rake'
- 'qa/qa/service/praefect_manager.rb'
- 'spec/db/schema_spec.rb'
- 'spec/initializers/00_rails_disable_joins_spec.rb'
- 'spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb'
- 'spec/lib/gitlab/database/migration_helpers/restrict_gitlab_schema_spec.rb'
- 'spec/lib/gitlab/database/migration_helpers_spec.rb'
- 'spec/lib/gitlab/database/migrations/observers/query_statistics_spec.rb'
- 'spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb'
- 'spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb'
- 'spec/lib/gitlab/database/partitioning/partition_manager_spec.rb'
- 'spec/lib/gitlab/database/partitioning/replace_table_spec.rb'
- 'spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb'
- 'spec/lib/gitlab/database/partitioning/time_partition_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
- 'spec/lib/gitlab/database/partitioning_spec.rb'
- 'spec/lib/gitlab/database/postgres_foreign_key_spec.rb'
- 'spec/lib/gitlab/database/postgres_index_bloat_estimate_spec.rb'
- 'spec/lib/gitlab/database/postgres_index_spec.rb'
- 'spec/lib/gitlab/database/postgres_partition_spec.rb'
- 'spec/lib/gitlab/database/postgres_partitioned_table_spec.rb'
- 'spec/lib/gitlab/database/reindexing/reindex_concurrently_spec.rb'
- 'spec/lib/gitlab/database/reindexing_spec.rb'
- 'spec/lib/gitlab/database/schema_migrations/migrations_spec.rb'
- 'spec/lib/gitlab/database/similarity_score_spec.rb'
- 'spec/lib/gitlab/database/unidirectional_copy_trigger_spec.rb'
- 'spec/lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition_spec.rb'
- 'spec/lib/gitlab/graphql/pagination/keyset/conditions/null_condition_spec.rb'
- 'spec/lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy_spec.rb'
- 'spec/lib/gitlab/pagination/keyset/order_spec.rb'
- 'spec/models/application_record_spec.rb'
- 'spec/models/concerns/after_commit_queue_spec.rb'
- 'spec/support/db_cleaner.rb'
- 'spec/support/helpers/database/partitioning_helpers.rb'
- 'spec/support/helpers/database/table_schema_helpers.rb'
- 'spec/support/helpers/database/trigger_helpers.rb'
- 'spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb'

View File

@ -3,7 +3,6 @@ RSpec/FactoryBot/AvoidCreate:
Exclude:
- 'ee/spec/presenters/approval_rule_presenter_spec.rb'
- 'ee/spec/presenters/audit_event_presenter_spec.rb'
- 'ee/spec/presenters/ci/build_presenter_spec.rb'
- 'ee/spec/presenters/ci/build_runner_presenter_spec.rb'
- 'ee/spec/presenters/ci/minutes/usage_presenter_spec.rb'
- 'ee/spec/presenters/ci/pipeline_presenter_spec.rb'

View File

@ -89,6 +89,8 @@ export default {
:default-max-date="maxDate"
:same-day-selection="includeSelectedDate"
:tooltip="maxDateRangeTooltip"
:from-label="__('From')"
:to-label="__('To')"
theme="animate-picker"
start-picker-class="js-daterange-picker-from gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-lg-align-items-center gl-lg-mr-3 gl-mb-2 gl-lg-mb-0"
end-picker-class="js-daterange-picker-to gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-lg-align-items-center gl-mb-2 gl-lg-mb-0"

View File

@ -240,7 +240,7 @@ export default {
</template>
<template #header>
<gl-dropdown-section-header>{{ __('Projects') }}</gl-dropdown-section-header>
<gl-search-box-by-type v-model.trim="searchTerm" />
<gl-search-box-by-type v-model.trim="searchTerm" :placeholder="__('Search')" />
</template>
<template #highlighted-items>
<gl-dropdown-item

View File

@ -62,7 +62,11 @@ export default {
return {
primary: {
text: __('Yes, delete project'),
attributes: [{ variant: 'danger' }, { disabled: this.confirmDisabled }],
attributes: [
{ variant: 'danger' },
{ disabled: this.confirmDisabled },
{ 'data-qa-selector': 'confirm_delete_button' },
],
},
cancel: {
text: __('Cancel, keep project'),
@ -97,9 +101,13 @@ export default {
<input type="hidden" name="_method" value="delete" />
<input :value="csrfToken" type="hidden" name="authenticity_token" />
<gl-button v-gl-modal="modalId" category="primary" variant="danger">{{
$options.strings.deleteProject
}}</gl-button>
<gl-button
v-gl-modal="modalId"
category="primary"
variant="danger"
data-qa-selector="delete_button"
>{{ $options.strings.deleteProject }}</gl-button
>
<gl-modal
ref="removeModal"
@ -168,6 +176,7 @@ export default {
v-model="userInput"
name="confirm_name_input"
type="text"
data-qa-selector="confirm_name_field"
/>
<slot name="modal-footer"></slot>
</div>

View File

@ -45,6 +45,9 @@ export default {
if (this.status === 'closed') return 'gl-bg-red-50';
return null;
},
hasActionsSlot() {
return this.$scopedSlots.actions?.()?.length;
},
},
};
</script>
@ -72,15 +75,18 @@ export default {
<div class="gl-display-flex gl-w-full">
<div
:class="{
'gl-display-flex': actions.length,
'gl-display-flex gl-align-items-center': actions.length,
'gl-md-display-flex gl-align-items-center': !actions.length,
}"
class="media-body"
>
<slot></slot>
<div
:class="{ 'gl-flex-direction-column-reverse': !actions.length }"
class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
:class="{
'gl-flex-direction-column-reverse gl-md-flex-direction-row gl-flex-wrap gl-justify-content-end': !actions.length,
'gl-md-pt-0 gl-pt-3': hasActionsSlot,
}"
class="gl-display-flex gl-font-size-0 gl-ml-auto gl-gap-3"
>
<slot name="actions">
<actions v-if="actions.length" :tertiary-buttons="actions" />

View File

@ -26,7 +26,7 @@ export default {
<template>
<state-container :mr="mr" status="failed">
<span
class="gl-ml-3 gl-font-weight-bold gl-w-100 gl-flex-grow-1 gl-md-mr-3 gl-ml-0! gl-text-body!"
class="gl-ml-3 gl-font-weight-bold gl-w-100 gl-flex-grow-1 gl-md-mr-3 gl-ml-0! gl-text-body! gl-align-self-start"
>
{{ s__('mrWidget|Merge blocked: all threads must be resolved.') }}
</span>
@ -34,7 +34,7 @@ export default {
<gl-button
v-if="mr.createIssueToResolveDiscussionsPath"
:href="mr.createIssueToResolveDiscussionsPath"
class="js-create-issue gl-align-self-start gl-vertical-align-top gl-mr-2"
class="js-create-issue gl-align-self-start gl-vertical-align-top"
size="small"
variant="confirm"
category="secondary"
@ -43,7 +43,7 @@ export default {
</gl-button>
<gl-button
data-testid="jump-to-first"
class="gl-mb-2 gl-md-mb-0 gl-align-self-start gl-vertical-align-top"
class="gl-align-self-start gl-vertical-align-top"
size="small"
variant="confirm"
category="primary"

View File

@ -8,7 +8,7 @@
.top-area
= gl_tabs_nav({ class: 'gl-flex-grow-1 gl-border-0' }) do
= gl_tab_link_to _("Your groups"), dashboard_groups_path
= gl_tab_link_to _("Explore public groups"), explore_groups_path
= gl_tab_link_to _("Explore public groups"), explore_groups_path, data: { qa_selector: "public_groups_tab" }
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'

View File

@ -21,6 +21,8 @@ metadata:
description: Operations related to CI/CD variables
- name: cluster_agents
description: Operations related to the GitLab agent for Kubernetes
- name: clusters
description: Operations related to clusters
- name: ci_resource_groups
description: Operations to manage job concurrency with resource groups
- name: deploy_keys

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class ChangeMemberNamespaceIdNotNull < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
add_not_null_constraint :members, :member_namespace_id, validate: false
end
def down
remove_not_null_constraint :members, :member_namespace_id
end
end

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class ValidateEnvironmentIdOnDeployments < Gitlab::Database::Migration[2.0]
def up
validate_foreign_key :deployments, :environment_id
end
def down
# no-op
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class ValidateNotNullConstraintOnMemberNamespaceId < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
CONSTRAINT_NAME = 'check_508774aac0'
def up
validate_not_null_constraint :members, :member_namespace_id, constraint_name: CONSTRAINT_NAME
end
def down
# no-op
end
end

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class ValidateFkMemberNamespaceId < Gitlab::Database::Migration[2.0]
CONSTRAINT_NAME = 'fk_2f85abf8f1'
def up
validate_foreign_key :members, :member_namespace_id, name: CONSTRAINT_NAME
end
def down
# no-op
end
end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
class RemoveOldMemberNamespaceIdFk < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
TARGET_COLUMN = :member_namespace_id
def up
with_lock_retries do
remove_foreign_key_if_exists(:members, column: TARGET_COLUMN, name: fk_name(TARGET_COLUMN))
end
end
def down
add_concurrent_foreign_key(
:members,
:namespaces,
column: TARGET_COLUMN,
name: fk_name(TARGET_COLUMN),
on_delete: :nullify
)
end
def fk_name(column_name)
# generate a FK name
concurrent_foreign_key_name(:members, column_name)
end
end

View File

@ -0,0 +1 @@
6f0ce1b68310b3194aa7b6219d79570e8179d449f49d828800f90f70d9242f38

View File

@ -0,0 +1 @@
248aecf9fa53146f2c1f7771fd60adf720fa8c0d2bd33d71c6177b185e4248d1

View File

@ -0,0 +1 @@
499f7b3951c9792d2a8f204b72c474a42e8301b487fa9f68080dd5bb5db0c64c

View File

@ -0,0 +1 @@
b633df04851493d7d4b5d7da79ba3057f6f2c302e507b4f963596edf9cbfcb88

View File

@ -0,0 +1 @@
f5295b135cd395a59c7afc6a9d999201f9ea1174aab893d31ead398aa8c0f8bb

View File

@ -17354,7 +17354,8 @@ CREATE TABLE members (
state smallint DEFAULT 0,
invite_email_success boolean DEFAULT true NOT NULL,
member_namespace_id bigint,
member_role_id bigint
member_role_id bigint,
CONSTRAINT check_508774aac0 CHECK ((member_namespace_id IS NOT NULL))
);
CREATE SEQUENCE members_id_seq
@ -32623,7 +32624,7 @@ CREATE TRIGGER trigger_update_vulnerability_reads_on_vulnerability_update AFTER
CREATE TRIGGER users_loose_fk_trigger AFTER DELETE ON users REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
ALTER TABLE ONLY deployments
ADD CONSTRAINT fk_009fd21147 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE NOT VALID;
ADD CONSTRAINT fk_009fd21147 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE;
ALTER TABLE ONLY epics
ADD CONSTRAINT fk_013c9f36ca FOREIGN KEY (due_date_sourcing_epic_id) REFERENCES epics(id) ON DELETE SET NULL;
@ -32797,7 +32798,7 @@ ALTER TABLE ONLY vulnerability_merge_request_links
ADD CONSTRAINT fk_2ef3954596 FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id) ON DELETE CASCADE;
ALTER TABLE ONLY members
ADD CONSTRAINT fk_2f85abf8f1 FOREIGN KEY (member_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE NOT VALID;
ADD CONSTRAINT fk_2f85abf8f1 FOREIGN KEY (member_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY analytics_cycle_analytics_group_stages
ADD CONSTRAINT fk_3078345d6d FOREIGN KEY (stage_event_hash_id) REFERENCES analytics_cycle_analytics_stage_event_hashes(id) ON DELETE CASCADE;
@ -33210,9 +33211,6 @@ ALTER TABLE ONLY epics
ALTER TABLE ONLY dast_profiles
ADD CONSTRAINT fk_aa76ef30e9 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY members
ADD CONSTRAINT fk_aa82dcc1c6 FOREIGN KEY (member_namespace_id) REFERENCES namespaces(id) ON DELETE SET NULL;
ALTER TABLE ONLY alert_management_alerts
ADD CONSTRAINT fk_aad61aedca FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE SET NULL;

View File

@ -128,9 +128,7 @@ These additional CI/CD minutes:
- Are carried over to the next month, if any remain at the end of the month.
- Are valid for 12 months from date of purchase or until all minutes are consumed, whichever comes first. Expiry of minutes is not currently enforced.
If you use more CI/CD minutes than your monthly quota, when you purchase more,
those CI/CD minutes are deducted from your quota. For example, with a GitLab SaaS
Premium license:
For example, with a GitLab SaaS Premium license:
- You have `10,000` monthly minutes.
- You purchase an additional `5,000` minutes.
@ -271,9 +269,9 @@ the next month.
For example:
- On **1st April**, you purchase `5,000` CI/CD minutes.
- During April, you use only `3,000` of the `5,000` minutes.
- On **1st May**, the remaining `2,000` minutes roll over and are added to your monthly quota.
- On **1st April**, you purchase `5,000` additional CI/CD minutes.
- During April, you use only `3,000` of the `5,000` additional minutes.
- On **1st May**, the unused minute roll over, so you have `2,000` additional minutes available for May.
Additional CI/CD minutes are a one-time purchase and do not renew or refresh each month.

View File

@ -18,8 +18,8 @@ for your GitLab instance). For example, <https://gitlab.com/public>.
You can control the visibility of individual features with
[project feature settings](permissions.md#project-features).
The visibility setting of a project must be the same as or less restrictive
than the visibility of its parent group.
The visibility setting of a project must be at least as restrictive
as the visibility of its parent group.
For example, a private group can include only private projects,
while a public group can include private, internal, and public projects.

View File

@ -14,16 +14,28 @@ module API
end
namespace 'admin' do
desc "Get list of all instance clusters" do
detail "This feature was introduced in GitLab 13.2."
desc 'List instance clusters' do
detail 'This feature was introduced in GitLab 13.2. Returns a list of instance clusters.'
success Entities::Cluster
failure [
{ code: 403, message: 'Forbidden' }
]
is_array true
tags %w[clusters]
end
get '/clusters' do
authorize! :read_cluster, clusterable_instance
present paginate(clusters_for_current_user), with: Entities::Cluster
end
desc "Get a single instance cluster" do
detail "This feature was introduced in GitLab 13.2."
desc 'Get a single instance cluster' do
detail 'This feature was introduced in GitLab 13.2. Returns a single instance cluster.'
success Entities::Cluster
failure [
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: "The cluster ID"
@ -34,8 +46,15 @@ module API
present cluster, with: Entities::Cluster
end
desc "Add an instance cluster" do
detail "This feature was introduced in GitLab 13.2."
desc 'Add existing instance cluster' do
detail 'This feature was introduced in GitLab 13.2. Adds an existing Kubernetes instance cluster.'
success Entities::Cluster
failure [
{ code: 400, message: 'Validation error' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@ -67,8 +86,15 @@ module API
end
end
desc "Update an instance cluster" do
detail "This feature was introduced in GitLab 13.2."
desc 'Edit instance cluster' do
detail 'This feature was introduced in GitLab 13.2. Updates an existing instance cluster.'
success Entities::Cluster
failure [
{ code: 400, message: 'Validation error' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@ -98,8 +124,14 @@ module API
end
end
desc "Remove a cluster" do
detail "This feature was introduced in GitLab 13.2."
desc 'Delete instance cluster' do
detail 'This feature was introduced in GitLab 13.2. Deletes an existing instance cluster. Does not remove existing resources within the connected Kubernetes cluster.'
success Entities::Cluster
failure [
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: "The cluster ID"

View File

@ -172,6 +172,7 @@ module API
# Keep in alphabetical order
mount ::API::AccessRequests
mount ::API::Admin::Ci::Variables
mount ::API::Admin::InstanceClusters
mount ::API::Appearance
mount ::API::Applications
mount ::API::BroadcastMessages
@ -179,6 +180,7 @@ module API
mount ::API::Ci::ResourceGroups
mount ::API::Ci::Runner
mount ::API::Ci::Runners
mount ::API::Ci::Variables
mount ::API::Clusters::AgentTokens
mount ::API::Clusters::Agents
mount ::API::Commits
@ -191,6 +193,7 @@ module API
mount ::API::FeatureFlagsUserLists
mount ::API::Features
mount ::API::FreezePeriods
mount ::API::GroupClusters
mount ::API::GroupExport
mount ::API::ImportBitbucketServer
mount ::API::ImportGithub
@ -200,15 +203,18 @@ module API
mount ::API::Metadata
mount ::API::PersonalAccessTokens::SelfInformation
mount ::API::PersonalAccessTokens
mount ::API::ProjectClusters
mount ::API::ProjectExport
mount ::API::ProjectHooks
mount ::API::ProjectRepositoryStorageMoves
mount ::API::ProjectSnippets
mount ::API::ProjectSnapshots
mount ::API::ProjectTemplates
mount ::API::ProtectedBranches
mount ::API::ProtectedTags
mount ::API::Releases
mount ::API::Release::Links
mount ::API::RemoteMirrors
mount ::API::Repositories
mount ::API::ResourceAccessTokens
mount ::API::Snippets
@ -226,7 +232,6 @@ module API
# Keep in alphabetical order
mount ::API::Admin::BatchedBackgroundMigrations
mount ::API::Admin::InstanceClusters
mount ::API::Admin::PlanLimits
mount ::API::Admin::Sidekiq
mount ::API::AlertManagementAlerts
@ -241,7 +246,6 @@ module API
mount ::API::Ci::Pipelines
mount ::API::Ci::SecureFiles
mount ::API::Ci::Triggers
mount ::API::Ci::Variables
mount ::API::CommitStatuses
mount ::API::ComposerPackages
mount ::API::ConanInstancePackages
@ -262,7 +266,6 @@ module API
mount ::API::GoProxy
mount ::API::GroupAvatar
mount ::API::GroupBoards
mount ::API::GroupClusters
mount ::API::GroupContainerRepositories
mount ::API::GroupDebianDistributions
mount ::API::GroupImport
@ -295,7 +298,6 @@ module API
mount ::API::PackageFiles
mount ::API::Pages
mount ::API::PagesDomains
mount ::API::ProjectClusters
mount ::API::ProjectContainerRepositories
mount ::API::ProjectDebianDistributions
mount ::API::ProjectEvents
@ -303,11 +305,9 @@ module API
mount ::API::ProjectMilestones
mount ::API::ProjectPackages
mount ::API::ProjectStatistics
mount ::API::ProjectTemplates
mount ::API::Projects
mount ::API::ProtectedTags
mount ::API::PypiPackages
mount ::API::RemoteMirrors
mount ::API::ResourceLabelEvents
mount ::API::ResourceMilestoneEvents
mount ::API::ResourceStateEvents

View File

@ -13,12 +13,13 @@ module API
helpers ::API::Helpers::VariablesHelpers
params do
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :id, types: [String, Integer], desc: 'The ID of a project or URL-encoded NAMESPACE/PROJECT_NAME of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get project variables' do
success Entities::Ci::Variable
tags %w[ci_variables]
end
params do
use :pagination
@ -28,13 +29,15 @@ module API
present paginate(variables), with: Entities::Ci::Variable
end
desc 'Get a specific variable from a project' do
desc 'Get the details of a single variable from a project' do
success Entities::Ci::Variable
failure [{ code: 404, message: 'Variable Not Found' }]
tags %w[ci_variables]
end
params do
requires :key, type: String, desc: 'The key of the variable'
requires :key, type: String, desc: 'The key of a variable'
optional :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
optional :environment_scope, type: String, desc: 'The environment scope of the variable'
optional :environment_scope, type: String, desc: 'The environment scope of a variable'
end
end
# rubocop: disable CodeReuse/ActiveRecord
@ -48,15 +51,17 @@ module API
desc 'Create a new variable in a project' do
success Entities::Ci::Variable
failure [{ code: 400, message: '400 Bad Request' }]
tags %w[ci_variables]
end
route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
requires :key, type: String, desc: 'The key of the variable'
requires :value, type: String, desc: 'The value of the variable'
requires :key, type: String, desc: 'The key of a variable'
requires :value, type: String, desc: 'The value of a variable'
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
optional :raw, type: Boolean, desc: 'Whether the variable will be expanded'
optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
end
post ':id/variables' do
@ -75,18 +80,20 @@ module API
desc 'Update an existing variable from a project' do
success Entities::Ci::Variable
failure [{ code: 404, message: 'Variable Not Found' }]
tags %w[ci_variables]
end
route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
optional :key, type: String, desc: 'The key of the variable'
optional :value, type: String, desc: 'The value of the variable'
optional :key, type: String, desc: 'The key of a variable'
optional :value, type: String, desc: 'The value of a variable'
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
optional :environment_scope, type: String, desc: 'The environment_scope of a variable'
optional :raw, type: Boolean, desc: 'Whether the variable will be expanded'
optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
optional :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
optional :environment_scope, type: String, desc: 'The environment scope of the variable'
optional :environment_scope, type: String, desc: 'The environment scope of a variable'
end
end
# rubocop: disable CodeReuse/ActiveRecord
@ -110,9 +117,11 @@ module API
desc 'Delete an existing variable from a project' do
success Entities::Ci::Variable
failure [{ code: 404, message: 'Variable Not Found' }]
tags %w[ci_variables]
end
params do
requires :key, type: String, desc: 'The key of the variable'
requires :key, type: String, desc: 'The key of a variable'
optional :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
optional :environment_scope, type: String, desc: 'The environment scope of the variable'
end

View File

@ -4,12 +4,25 @@ module API
module Entities
# Serializes a Licensee::License
class License < Entities::LicenseBasic
expose :popular?, as: :popular
expose(:description) { |license| license.meta['description'] }
expose(:conditions) { |license| license.meta['conditions'] }
expose(:permissions) { |license| license.meta['permissions'] }
expose(:limitations) { |license| license.meta['limitations'] }
expose :content
expose :popular?, as: :popular, documentation: { type: 'boolean' }
expose :description, documentation: { type: 'string', example: 'A simple license' } do |license|
license.meta['description']
end
expose :conditions, documentation: { type: 'string', is_array: true, example: 'include-copyright' } do |license|
license.meta['conditions']
end
expose :permissions, documentation: { type: 'string', is_array: true, example: 'commercial-use' } do |license|
license.meta['permissions']
end
expose :limitations, documentation: { type: 'string', is_array: true, example: 'liability' } do |license|
license.meta['limitations']
end
expose :content, documentation: { type: 'string', example: 'GNU GENERAL PUBLIC LICENSE' }
end
end
end

View File

@ -4,8 +4,10 @@ module API
module Entities
# Serializes a Gitlab::Git::DeclaredLicense
class LicenseBasic < Grape::Entity
expose :key, :name, :nickname
expose :url, as: :html_url
expose :key, documentation: { type: 'string', example: 'gpl-3.0' }
expose :name, documentation: { type: 'string', example: 'GNU General Public License v3.0' }
expose :nickname, documentation: { type: 'string', example: 'GNU GPLv3' }
expose :url, as: :html_url, documentation: { example: 'http://choosealicense.com/licenses/gpl-3.0' }
# This was dropped:
# https://github.com/github/choosealicense.com/commit/325806b42aa3d5b78e84120327ec877bc936dbdd#diff-66df8f1997786f7052d29010f2cbb4c66391d60d24ca624c356acc0ab986f139

View File

@ -3,16 +3,16 @@
module API
module Entities
class RemoteMirror < Grape::Entity
expose :id
expose :enabled
expose :safe_url, as: :url
expose :update_status
expose :last_update_at
expose :last_update_started_at
expose :last_successful_update_at
expose :last_error
expose :only_protected_branches
expose :keep_divergent_refs
expose :id, documentation: { type: 'integer', example: 101486 }
expose :enabled, documentation: { type: 'boolean', example: true }
expose :safe_url, as: :url, documentation: { type: 'string', example: 'https://*****:*****@example.com/gitlab/example.git' }
expose :update_status, documentation: { type: 'string', example: 'finished' }
expose :last_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
expose :last_update_started_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
expose :last_successful_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:31:55.864Z' }
expose :last_error, documentation: { type: 'integer', example: 'The remote mirror URL is invalid.' }
expose :only_protected_branches, documentation: { type: 'boolean' }
expose :keep_divergent_refs, documentation: { type: 'boolean' }
end
end
end

View File

@ -3,8 +3,8 @@
module API
module Entities
class TemplatesList < Grape::Entity
expose :key
expose :name
expose :key, documentation: { type: 'string', example: 'mit' }
expose :name, documentation: { type: 'string', example: 'MIT License' }
end
end
end

View File

@ -16,8 +16,14 @@ module API
requires :id, type: String, desc: 'The ID of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all clusters from the group' do
desc 'List group clusters' do
detail 'This feature was introduced in GitLab 12.1. Returns a list of group clusters.'
success Entities::Cluster
failure [
{ code: 403, message: 'Forbidden' }
]
is_array true
tags %w[clusters]
end
params do
use :pagination
@ -28,8 +34,14 @@ module API
present paginate(clusters_for_current_user), with: Entities::Cluster
end
desc 'Get specific cluster for the group' do
desc 'Get a single group cluster' do
detail 'This feature was introduced in GitLab 12.1. Gets a single group cluster.'
success Entities::ClusterGroup
failure [
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@ -40,8 +52,15 @@ module API
present cluster, with: Entities::ClusterGroup
end
desc 'Adds an existing cluster' do
desc 'Add existing cluster to group' do
detail 'This feature was introduced in GitLab 12.1. Adds an existing Kubernetes cluster to the group.'
success Entities::ClusterGroup
failure [
{ code: 400, message: 'Validation error' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@ -73,8 +92,15 @@ module API
end
end
desc 'Update an existing cluster' do
desc 'Edit group cluster' do
detail 'This feature was introduced in GitLab 12.1. Updates an existing group cluster.'
success Entities::ClusterGroup
failure [
{ code: 400, message: 'Validation error' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@ -104,8 +130,14 @@ module API
end
end
desc 'Remove a cluster' do
desc 'Delete group cluster' do
detail 'This feature was introduced in GitLab 12.1. Deletes an existing group cluster. Does not remove existing resources within the connected Kubernetes cluster.'
success Entities::ClusterGroup
failure [
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The Cluster ID'

View File

@ -17,8 +17,9 @@ module API
included do
helpers do
params :pagination do
optional :page, type: Integer, default: 1, desc: 'Current page number'
optional :per_page, type: Integer, default: 20, desc: 'Number of items per page', except_values: [0]
optional :page, type: Integer, default: 1, desc: 'Current page number', documentation: { example: 1 }
optional :per_page, type: Integer, default: 20,
desc: 'Number of items per page', except_values: [0], documentation: { example: 20 }
end
def verify_pagination_params!

View File

@ -16,9 +16,14 @@ module API
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all clusters from the project' do
detail 'This feature was introduced in GitLab 11.7.'
desc 'List project clusters' do
detail 'This feature was introduced in GitLab 11.7. Returns a list of project clusters.'
success Entities::Cluster
failure [
{ code: 403, message: 'Forbidden' }
]
is_array true
tags %w[clusters]
end
params do
use :pagination
@ -29,9 +34,14 @@ module API
present paginate(clusters_for_current_user), with: Entities::Cluster
end
desc 'Get specific cluster for the project' do
detail 'This feature was introduced in GitLab 11.7.'
desc 'Get a single project cluster' do
detail 'This feature was introduced in GitLab 11.7. Gets a single project cluster.'
success Entities::ClusterProject
failure [
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@ -42,9 +52,15 @@ module API
present cluster, with: Entities::ClusterProject
end
desc 'Adds an existing cluster' do
detail 'This feature was introduced in GitLab 11.7.'
desc 'Add existing cluster to project' do
detail 'This feature was introduced in GitLab 11.7. Adds an existing Kubernetes cluster to the project.'
success Entities::ClusterProject
failure [
{ code: 400, message: 'Validation error' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@ -76,9 +92,15 @@ module API
end
end
desc 'Update an existing cluster' do
detail 'This feature was introduced in GitLab 11.7.'
desc 'Edit project cluster' do
detail 'This feature was introduced in GitLab 11.7. Updates an existing project cluster.'
success Entities::ClusterProject
failure [
{ code: 400, message: 'Validation error' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@ -108,9 +130,14 @@ module API
end
end
desc 'Remove a cluster' do
detail 'This feature was introduced in GitLab 11.7.'
desc 'Delete project cluster' do
detail 'This feature was introduced in GitLab 11.7. Deletes an existing project cluster. Does not remove existing resources within the connected Kubernetes cluster.'
success Entities::ClusterProject
failure [
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not found' }
]
tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The Cluster ID'

View File

@ -21,6 +21,12 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of templates available to this project' do
detail 'This endpoint was introduced in GitLab 11.4'
is_array true
success Entities::TemplatesList
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
end
params do
use :pagination
@ -33,13 +39,24 @@ module API
desc 'Download a template available to this project' do
detail 'This endpoint was introduced in GitLab 11.4'
success Entities::License
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
end
params do
requires :name, type: String, desc: 'The name of the template'
requires :name, type: String,
desc: 'The key of the template, as obtained from the collection endpoint.', documentation: { example: 'MIT' }
optional :source_template_project_id, type: Integer,
desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name'
optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses'
optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses'
desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name',
documentation: { example: 1 }
optional :project, type: String,
desc: 'The project name to use when expanding placeholders in the template. Only affects licenses',
documentation: { example: 'GitLab' }
optional :fullname, type: String,
desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses',
documentation: { example: 'GitLab B.V.' }
end
get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do

View File

@ -15,7 +15,13 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "List the project's remote mirrors" do
success Entities::RemoteMirror
success code: 200, model: Entities::RemoteMirror
is_array true
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
tags %w[remote_mirrors]
end
params do
use :pagination
@ -26,7 +32,12 @@ module API
end
desc 'Get a single remote mirror' do
success Entities::RemoteMirror
success code: 200, model: Entities::RemoteMirror
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
@ -38,13 +49,21 @@ module API
end
desc 'Create remote mirror for a project' do
success Entities::RemoteMirror
success code: 201, model: Entities::RemoteMirror
failure [
{ code: 400, message: 'Bad request' },
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
tags %w[remote_mirrors]
end
params do
requires :url, type: String, desc: 'The URL for a remote mirror'
optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
requires :url, type: String, desc: 'The URL for a remote mirror', documentation: { example: 'https://*****:*****@example.com/gitlab/example.git' }
optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled', documentation: { example: false }
optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored',
documentation: { example: false }
optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target',
documentation: { example: false }
end
post ':id/remote_mirrors' do
create_params = declared_params(include_missing: false)
@ -59,13 +78,21 @@ module API
end
desc 'Update the attributes of a single remote mirror' do
success Entities::RemoteMirror
success code: 200, model: Entities::RemoteMirror
failure [
{ code: 400, message: 'Bad request' },
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled', documentation: { example: true }
optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored',
documentation: { example: false }
optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target',
documentation: { example: false }
end
put ':id/remote_mirrors/:mirror_id' do
mirror = user_project.remote_mirrors.find(params[:mirror_id])
@ -88,6 +115,13 @@ module API
desc 'Delete a single remote mirror' do
detail 'This feature was introduced in GitLab 14.10'
success code: 204
failure [
{ code: 400, message: 'Bad request' },
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'

View File

@ -433,16 +433,16 @@ module API
success Entities::SSHKey
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :user_id, type: Integer, desc: 'The ID of the user'
requires :key, type: String, desc: 'The new SSH key'
requires :title, type: String, desc: 'The title of the new SSH key'
optional :expires_at, type: DateTime, desc: 'The expiration date of the SSH key in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)'
end
# rubocop: disable CodeReuse/ActiveRecord
post ":id/keys", feature_category: :authentication_and_authorization do
post ":user_id/keys", feature_category: :authentication_and_authorization do
authenticated_as_admin!
user = User.find_by(id: params.delete(:id))
user = User.find_by(id: params.delete(:user_id))
not_found!('User') unless user
key = ::Keys::CreateService.new(current_user, declared_params(include_missing: false).merge(user: user)).execute

View File

@ -209,6 +209,12 @@ module Gitlab
'in the body of your migration class'
end
if partition?(table_name)
raise ArgumentError, 'remove_concurrent_index can not be used on a partitioned ' \
'table. Please use remove_concurrent_partitioned_index_by_name on the partitioned table ' \
'as we need to remove the index on the parent table'
end
options = options.merge({ algorithm: :concurrently })
unless index_exists?(table_name, column_name, **options)
@ -238,6 +244,12 @@ module Gitlab
'in the body of your migration class'
end
if partition?(table_name)
raise ArgumentError, 'remove_concurrent_index_by_name can not be used on a partitioned ' \
'table. Please use remove_concurrent_partitioned_index_by_name on the partitioned table ' \
'as we need to remove the index on the parent table'
end
index_name = index_name[:name] if index_name.is_a?(Hash)
raise 'remove_concurrent_index_by_name must get an index name as the second argument' if index_name.blank?

View File

@ -10,13 +10,17 @@ module Gitlab::UsageDataCounters
expanded_template_name = expand_template_name(template)
return unless expanded_template_name
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(
ci_template_event_name(expanded_template_name, config_source), values: project.id
)
event_name = ci_template_event_name(expanded_template_name, config_source)
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: project.id)
namespace = project.namespace
if Feature.enabled?(:route_hll_to_snowplow, namespace)
Gitlab::Tracking.event(name, 'ci_templates_unique', namespace: namespace, user: user, project: project)
context = Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
event: event_name).to_context
label = 'redis_hll_counters.ci_templates.ci_templates_total_unique_counts_monthly'
Gitlab::Tracking.event(name, 'ci_templates_unique', namespace: namespace,
project: project, context: [context], user: user,
label: label)
end
end

View File

@ -4,7 +4,7 @@ source 'https://rubygems.org'
gem 'gitlab-qa', '~> 8', '>= 8.10.1', require: 'gitlab/qa'
gem 'activesupport', '~> 6.1.4.7' # This should stay in sync with the root's Gemfile
gem 'allure-rspec', '~> 2.18.0'
gem 'allure-rspec', '~> 2.19.0'
gem 'capybara', '~> 3.38.0'
gem 'capybara-screenshot', '~> 1.0.26'
gem 'rake', '~> 13', '>= 13.0.6'

View File

@ -15,10 +15,10 @@ GEM
rack-test (>= 1.1.0, < 2.0)
rest-client (>= 2.0.2, < 3.0)
rspec (~> 3.8)
allure-rspec (2.18.0)
allure-ruby-commons (= 2.18.0)
allure-rspec (2.19.0)
allure-ruby-commons (= 2.19.0)
rspec-core (>= 3.8, < 4)
allure-ruby-commons (2.18.0)
allure-ruby-commons (2.19.0)
mime-types (>= 3.3, < 4)
oj (>= 3.10, < 4)
require_all (>= 2, < 4)
@ -184,7 +184,7 @@ GEM
octokit (6.0.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
oj (3.13.21)
oj (3.13.23)
os (1.1.4)
parallel (1.22.1)
parallel_tests (4.0.0)
@ -301,7 +301,7 @@ PLATFORMS
DEPENDENCIES
activesupport (~> 6.1.4.7)
airborne (~> 0.3.7)
allure-rspec (~> 2.18.0)
allure-rspec (~> 2.19.0)
capybara (~> 3.38.0)
capybara-screenshot (~> 1.0.26)
chemlab (~> 0.10)
@ -338,4 +338,4 @@ DEPENDENCIES
zeitwerk (~> 2.4)
BUNDLED WITH
2.3.24
2.3.25

View File

@ -37,7 +37,9 @@ module QA
Page::Main::Menu.perform(&:not_signed_in?)
end
raise "Failed user registration attempt. Registration was expected to #{user.expect_fabrication_success ? 'succeed' : 'fail'} but #{success ? 'succeeded' : 'failed'}." unless success
return if success
raise "Failed user registration attempt. Registration was expected to #{user.expect_fabrication_success ? 'succeed' : 'fail'} but #{success ? 'succeeded' : 'failed'}."
end
def disable_sign_ups

View File

@ -28,6 +28,10 @@ module QA
click_link(username)
end
end
def has_username?(username)
has_element?(:user_row_content, text: username, wait: 1)
end
end
end
end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
module QA
module Page
module Component
module DeleteModal
extend QA::Page::PageConcern
def self.included(base)
super
base.view 'app/assets/javascripts/projects/components/shared/delete_button.vue' do
element :confirm_name_field
element :confirm_delete_button
end
end
def fill_confirmation_path(text)
fill_element(:confirm_name_field, text)
end
def wait_for_delete_button_enabled
wait_until(reload: false) do
!find_element(:confirm_delete_button).disabled?
end
end
def confirm_delete
wait_for_delete_button_enabled
click_element(:confirm_delete_button)
end
end
end
end
end

View File

@ -16,6 +16,10 @@ module QA
base.view 'app/assets/javascripts/groups/components/groups.vue' do
element :groups_list_tree_container
end
base.view 'app/views/dashboard/_groups_head.html.haml' do
element :public_groups_tab
end
end
private
@ -28,9 +32,24 @@ module QA
# groups_list_tree_container means we have the complete filtered list
# of groups
has_element?(:groups_list_tree_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
# If there are no groups we'll know immediately because we filtered the list
return false if page.has_text?('No groups or projects matched your search', wait: 0)
if page.has_text?('No groups or projects matched your search',
wait: 0) || page.has_text?('No groups matched your search', wait: 0)
return false unless has_element?(:public_groups_tab)
# Try for public groups
click_element(:public_groups_tab)
# Filter and submit to reload the page and only retrieve the filtered results
find_element(:groups_filter_field).set(name).send_keys(:return)
# Since we submitted after filtering, the presence of
# groups_list_tree_container means we have the complete filtered list
# of groups
has_element?(:groups_list_tree_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
return false if page.has_text?('No groups or projects matched your search',
wait: 0) || page.has_text?('No groups matched your search', wait: 0)
end
# The name will be present as filter input so we check for a link, not text
page.has_link?(name, wait: 0)

View File

@ -31,7 +31,7 @@ module QA
end
def create
click_button 'Create group'
click_element(:create_group_button)
end
def create_subgroup

View File

@ -64,6 +64,8 @@ module QA
end
def add_description(description)
return unless has_element?(:project_description, wait: 1)
fill_in 'project_description', with: description
end

View File

@ -6,8 +6,13 @@ module QA
module Settings
class Advanced < Page::Base
include QA::Page::Component::ConfirmModal
include QA::Page::Component::DeleteModal
include Component::NamespaceSelect
view 'app/assets/javascripts/projects/components/shared/delete_button.vue' do
element :delete_button
end
view 'app/views/projects/edit.html.haml' do
element :project_path_field
element :change_path_button
@ -88,6 +93,13 @@ module QA
click_confirmation_ok_button
end
def delete_project!(project_name)
click_element :delete_button
fill_confirmation_path(project_name)
wait_for_delete_button_enabled
confirm_delete
end
private
def wait_for_transfer_project_content

View File

@ -22,8 +22,20 @@ module QA
new.tap(&prepare_block)
end
def fabricate_via_api_unless_fips!
if QA::Support::FIPS.enabled?
fabricate!
else
fabricate_via_api!
end
end
def fabricate!(*args, &prepare_block)
fabricate_via_api!(*args, &prepare_block)
if QA::Support::FIPS.enabled?
fabricate_via_browser_ui!(*args, &prepare_block)
else
fabricate_via_api!(*args, &prepare_block)
end
rescue NotImplementedError
fabricate_via_browser_ui!(*args, &prepare_block)
end
@ -95,7 +107,7 @@ module QA
Support::FabricationTracker.save_fabrication(:"#{fabrication_method}_fabrication", fabrication_time)
unless resource.retrieved_from_cache
unless resource.retrieved_from_cache || QA::Support::FIPS.enabled?
Tools::TestResourceDataProcessor.collect(
resource: resource,
info: resource.identifier,

View File

@ -18,8 +18,14 @@ module QA
end
attribute :sandbox do
Sandbox.fabricate_via_api! do |sandbox|
sandbox.api_client = api_client
if QA::Support::FIPS.enabled?
Resource::Sandbox.fabricate! do |sandbox|
sandbox.path = Runtime::Namespace.sandbox_name
end
else
Sandbox.fabricate_via_api! do |sandbox|
sandbox.api_client = api_client
end
end
end

View File

@ -10,8 +10,8 @@ module QA
def add_member(user, access_level = AccessLevel::DEVELOPER)
Support::Retrier.retry_until do
QA::Runtime::Logger.info(%(Adding user #{user.username} to #{full_path} #{self.class.name}))
response = post Runtime::API::Request.new(api_client, api_members_path).url, { user_id: user.id, access_level: access_level }
response = post Runtime::API::Request.new(api_client, api_members_path).url,
{ user_id: user.id, access_level: access_level }
break true if response.code == QA::Support::API::HTTP_STATUS_CREATED
break true if response.body.include?('Member already exists')
end
@ -31,7 +31,8 @@ module QA
Support::Retrier.retry_until do
QA::Runtime::Logger.info(%(Sharing #{self.class.name} with #{group.name}))
response = post Runtime::API::Request.new(api_client, api_share_path).url, { group_id: group.id, group_access: access_level }
response = post Runtime::API::Request.new(api_client, api_share_path).url,
{ group_id: group.id, group_access: access_level }
response.code == QA::Support::API::HTTP_STATUS_CREATED
end
end

View File

@ -479,6 +479,16 @@ module QA
end
end
def remove_via_browser_ui!
Page::Project::Menu.perform(&:go_to_general_settings)
Page::Project::Settings::Main.perform(&:expand_advanced_settings)
Page::Project::Settings::Advanced.perform do |advanced|
advanced.delete_project!(full_path)
end
end
# Calls the API endpoint that triggers the backend service that performs repository housekeeping (garbage
# collection and similar tasks).
def perform_housekeeping

View File

@ -10,7 +10,9 @@ module QA
class << self
# Force top level group creation via UI if test is executed on dot_com environment
def fabricate!(*args, &prepare_block)
return fabricate_via_browser_ui!(*args, &prepare_block) if Specs::Helpers::ContextSelector.dot_com?
if Specs::Helpers::ContextSelector.dot_com? || QA::Support::FIPS.enabled?
return fabricate_via_browser_ui!(*args, &prepare_block)
end
fabricate_via_api!(*args, &prepare_block)
rescue NotImplementedError

View File

@ -79,11 +79,22 @@ module QA
defined?(@username) && defined?(@password)
end
def has_user?(user)
Flow::Login.while_signed_in_as_admin do
Page::Main::Menu.perform(&:go_to_admin_area)
Page::Admin::Menu.perform(&:go_to_users_overview)
Page::Admin::Overview::Users::Index.perform do |index|
index.search_user(user.username)
index.has_username?(user.username)
end
end
end
def fabricate!
# Don't try to log-out if we're not logged-in
Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
if credentials_given?
if credentials_given? || has_user?(self)
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(user: self)
end
@ -144,7 +155,7 @@ module QA
end
def self.fabricate_or_use(username = nil, password = nil)
if Runtime::Env.signup_disabled?
if Runtime::Env.signup_disabled? || !QA::Support::FIPS.enabled?
fabricate_via_api! do |user|
user.username = username
user.password = password

View File

@ -4,8 +4,8 @@ module QA
module Runtime
module Key
class ED25519 < Base
def initialize
super('ed25519', 256)
def initialize(bits = 256)
super('ed25519', bits)
end
end
end

View File

@ -3,8 +3,17 @@
module QA
RSpec.describe 'Plan', :smoke, product_group: :project_management do
describe 'Issue creation' do
let(:project) { Resource::Project.fabricate_via_api! }
let(:closed_issue) { Resource::Issue.fabricate_via_api! { |issue| issue.project = project } }
let(:project) do
Resource::Project.fabricate_via_api_unless_fips! do |project|
project.name = "project-create-issue-#{SecureRandom.hex(8)}"
project.personal_namespace = Runtime::User.username
project.description = nil
end
end
let(:closed_issue) do
Resource::Issue.fabricate_via_api_unless_fips! { |issue| issue.project = project }
end
before do
Flow::Login.sign_in
@ -55,7 +64,7 @@ module QA
end
before do
Resource::Issue.fabricate_via_api! { |issue| issue.project = project }.visit!
Resource::Issue.fabricate_via_api_unless_fips! { |issue| issue.project = project }.visit!
end
# The following example is excluded from running in `review-qa-smoke` job

View File

@ -3,9 +3,12 @@
module QA
RSpec.describe 'Plan', :smoke, product_group: :project_management do
describe 'mention' do
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:user) do
Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
end
let(:project) do
Resource::Project.fabricate_via_api! do |project|
Resource::Project.fabricate_via_api_unless_fips! do |project|
project.name = 'project-to-test-mention'
project.visibility = 'private'
end
@ -14,14 +17,33 @@ module QA
before do
Flow::Login.sign_in
project.add_member(user)
if QA::Support::FIPS.enabled?
# Ensure user exists
user
Flow::Login.sign_in_as_admin
project.visit!
Page::Project::Menu.perform(&:click_members)
Page::Project::Members.perform do |members|
members.add_member(user.username)
end
else
project.visit!
project.add_member(user)
end
Resource::Issue.fabricate_via_api! do |issue|
issue.project = project
end.visit!
if QA::Support::FIPS.enabled?
Resource::Issue.fabricate_via_browser_ui! do |issue|
issue.project = project
end.visit!
else
Resource::Issue.fabricate_via_api! do |issue|
issue.project = project
end.visit!
end
end
it 'mentions another user in an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do
it 'mentions another user in an issue',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do
Page::Project::Issue::Show.perform do |show|
at_username = "@#{user.username}"

View File

@ -18,7 +18,7 @@ module QA
it(
'creates a basic merge request',
:smoke,
:smoke, :skip_fips_env,
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347738'
) do
Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|

View File

@ -2,8 +2,9 @@
module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', :smoke, product_group: :source_code do
it 'user using a personal access token pushes code to the repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do
describe 'Git push over HTTP', :smoke, :skip_fips_env, product_group: :source_code do
it 'user using a personal access token pushes code to the repository',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do
Flow::Login.sign_in
access_token = Resource::PersonalAccessToken.fabricate!.token

View File

@ -3,7 +3,8 @@
module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', product_group: :source_code do
it 'user pushes code to the repository', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do
it 'user pushes code to the repository', :smoke, :skip_fips_env,
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do
Flow::Login.sign_in
Resource::Repository::ProjectPush.fabricate! do |push|
@ -18,7 +19,8 @@ module QA
end
end
it 'pushes to a project using a specific Praefect repository storage', :smoke, :requires_admin, :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do
it 'pushes to a project using a specific Praefect repository storage', :smoke, :skip_fips_env, :requires_admin,
:requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do
Flow::Login.sign_in_as_admin
project = Resource::Project.fabricate_via_api! do |storage_project|

View File

@ -26,7 +26,8 @@ module QA
Flow::Login.sign_in
end
it 'pushes code to the repository via SSH', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do
it 'pushes code to the repository via SSH', :smoke, :skip_fips_env,
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project
push.ssh_key = @key
@ -41,7 +42,8 @@ module QA
end
end
it 'pushes multiple branches and tags together', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do
it 'pushes multiple branches and tags together', :smoke, :skip_fips_env,
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do
branches = []
tags = []
Git::Repository.perform do |repository|

View File

@ -17,6 +17,15 @@ module QA
Flow::Login.sign_in
end
after do
if QA::Support::FIPS.enabled?
snippet.visit!
Page::Dashboard::Snippet::Show.perform(&:click_delete_button)
else
snippet.remove_via_api!
end
end
it 'user creates a personal snippet', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347799' do
snippet

View File

@ -4,7 +4,7 @@ module QA
RSpec.describe 'Verify' do
describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_authoring do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
Resource::Project.fabricate_via_api_unless_fips! do |project|
project.name = 'project-with-ci-variables'
project.description = 'project with CI variables'
end

View File

@ -35,7 +35,7 @@ module QA
keys = [
['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348022', Runtime::Key::RSA, 8192, true],
['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348021', Runtime::Key::ECDSA, 521, true],
['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348020', Runtime::Key::ED25519, false]
['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348020', Runtime::Key::ED25519, 256, false]
]
supported_keys =

View File

@ -5,7 +5,7 @@ module QA
module Support
class FIPS
def self.enabled?
%(1 true yes).include?(ENV['FIPS'].to_s)
%w[1 true yes].include?(ENV['FIPS'].to_s)
end
end
end

View File

@ -87,12 +87,46 @@ RSpec.describe QA::Resource::Base do
end
context 'when resource supports fabrication via the API' do
it 'calls .fabricate_via_browser_ui!' do
it 'calls .fabricate_via_api!!' do
expect(described_class).to receive(:fabricate_via_api!)
described_class.fabricate!
end
end
context 'when FIPS mode is enabled' do
before do
stub_env('FIPS', '1')
end
it 'calls .fabricate_via_browser_ui!' do
expect(described_class).to receive(:fabricate_via_browser_ui!)
described_class.fabricate!
end
end
end
describe '.fabricate_via_api_unless_fips!' do
context 'when FIPS mode is not enabled' do
it 'calls .fabricate_via_api!!' do
expect(described_class).to receive(:fabricate_via_api!)
described_class.fabricate_via_api_unless_fips!
end
end
context 'when FIPS mode is enabled' do
before do
stub_env('FIPS', '1')
end
it 'calls .fabricate_via_browser_ui!' do
expect(described_class).to receive(:fabricate_via_browser_ui!)
described_class.fabricate_via_api_unless_fips!
end
end
end
describe '.fabricate_via_api!' do

View File

@ -116,4 +116,31 @@ RSpec.describe QA::Resource::User do
expect(subject).to be_credentials_given
end
end
describe '#has_user?' do
let(:index_mock) do
instance_double(QA::Page::Admin::Overview::Users::Index)
end
users = [
['foo', true],
['bar', false]
]
users.each do |(username, found)|
it "returns #{found} when has_username returns #{found}" do
subject.username = username
allow(QA::Flow::Login).to receive(:while_signed_in_as_admin).and_yield
allow(QA::Page::Main::Menu).to receive(:perform)
allow(QA::Page::Admin::Menu).to receive(:perform)
allow(QA::Page::Admin::Overview::Users::Index).to receive(:perform).and_yield(index_mock)
expect(index_mock).to receive(:search_user).with(username)
expect(index_mock).to receive(:has_username?).with(username).and_return(found)
expect(subject.has_user?(subject)).to eq(found)
end
end
end
end

View File

@ -8,8 +8,13 @@ fi
# Tag with commit SHA by default
QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:${CI_COMMIT_SHA}"
# For branches, tag with slugified branch name. For tags, use the tag directly
QA_IMAGE_BRANCH="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:${CI_COMMIT_TAG:-$CI_COMMIT_REF_SLUG}"
# with v prefix removed
IMAGE_TAG=${CI_COMMIT_TAG#v}
IMAGE_TAG=${IMAGE_TAG:-$CI_COMMIT_REF_SLUG}
QA_IMAGE_BRANCH="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:${IMAGE_TAG}"
DESTINATIONS="--destination=${QA_IMAGE} --destination=${QA_IMAGE_BRANCH}"

View File

@ -14,6 +14,8 @@ main_report = JSON.parse(File.read(main_report_file))
new_report = main_report.dup
ARGV.each do |report_file|
next unless File.exist?(report_file)
report = JSON.parse(File.read(report_file))
# Remove existing values

View File

@ -60,6 +60,9 @@ function update_tests_metadata() {
scripts/flaky_examples/prune-old-flaky-examples "${FLAKY_RSPEC_SUITE_REPORT_PATH}"
if [[ "$CI_PIPELINE_SOURCE" == "schedule" ]]; then
if [[ -n "$RSPEC_PROFILING_PGSSLKEY" ]]; then
chmod 0600 $RSPEC_PROFILING_PGSSLKEY
fi
PGSSLMODE=$RSPEC_PROFILING_PGSSLMODE PGSSLROOTCERT=$RSPEC_PROFILING_PGSSLROOTCERT PGSSLCERT=$RSPEC_PROFILING_PGSSLCERT PGSSLKEY=$RSPEC_PROFILING_PGSSLKEY scripts/insert-rspec-profiling-data
else
echo "Not inserting profiling data as the pipeline is not a scheduled one."

View File

@ -19,6 +19,7 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
<gl-button-stub
buttontextclasses=""
category="primary"
data-qa-selector="delete_button"
icon=""
role="button"
size="medium"
@ -102,6 +103,7 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
</p>
<gl-form-input-stub
data-qa-selector="confirm_name_field"
id="confirm_name_input"
name="confirm_name_input"
type="text"

View File

@ -20,6 +20,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
<gl-button-stub
buttontextclasses=""
category="primary"
data-qa-selector="delete_button"
icon=""
role="button"
size="medium"
@ -103,6 +104,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
</p>
<gl-form-input-stub
data-qa-selector="confirm_name_field"
id="confirm_name_input"
name="confirm_name_input"
type="text"

View File

@ -44,7 +44,7 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have
class="gl-display-flex gl-w-full"
>
<div
class="media-body gl-display-flex"
class="media-body gl-display-flex gl-align-items-center"
>
<h4
@ -70,7 +70,7 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have
</h4>
<div
class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
class="gl-display-flex gl-font-size-0 gl-ml-auto gl-gap-3"
>
<div
class="gl-display-flex gl-align-items-flex-start"
@ -221,7 +221,7 @@ exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have c
class="gl-display-flex gl-w-full"
>
<div
class="media-body gl-display-flex"
class="media-body gl-display-flex gl-align-items-center"
>
<h4
@ -247,7 +247,7 @@ exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have c
</h4>
<div
class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
class="gl-display-flex gl-font-size-0 gl-ml-auto gl-gap-3"
>
<div
class="gl-display-flex gl-align-items-flex-start"

View File

@ -469,6 +469,37 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
model.remove_concurrent_index(:users, :foo)
end
context 'when targeting a partition table' do
let(:schema) { 'public' }
let(:partition_table_name) { '_test_partition_01' }
let(:identifier) { "#{schema}.#{partition_table_name}" }
let(:index_name) { '_test_partitioned_index' }
let(:partition_index_name) { '_test_partition_01_partition_id_idx' }
let(:column_name) { 'partition_id' }
before do
model.execute(<<~SQL)
CREATE TABLE public._test_partitioned_table (
id serial NOT NULL,
partition_id serial NOT NULL,
PRIMARY KEY (id, partition_id)
) PARTITION BY LIST(partition_id);
CREATE INDEX #{index_name} ON public._test_partitioned_table(#{column_name});
CREATE TABLE #{identifier} PARTITION OF public._test_partitioned_table
FOR VALUES IN (1);
SQL
end
context 'when dropping an index on the partition table' do
it 'raises ArgumentError' do
expect { model.remove_concurrent_index(partition_table_name, column_name) }
.to raise_error(ArgumentError, /use remove_concurrent_partitioned_index_by_name/)
end
end
end
describe 'by index name' do
before do
allow(model).to receive(:index_exists_by_name?).with(:users, "index_x_by_y").and_return(true)
@ -510,6 +541,36 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
model.remove_concurrent_index_by_name(:users, "index_x_by_y")
end
context 'when targeting a partition table' do
let(:schema) { 'public' }
let(:partition_table_name) { '_test_partition_01' }
let(:identifier) { "#{schema}.#{partition_table_name}" }
let(:index_name) { '_test_partitioned_index' }
let(:partition_index_name) { '_test_partition_01_partition_id_idx' }
before do
model.execute(<<~SQL)
CREATE TABLE public._test_partitioned_table (
id serial NOT NULL,
partition_id serial NOT NULL,
PRIMARY KEY (id, partition_id)
) PARTITION BY LIST(partition_id);
CREATE INDEX #{index_name} ON public._test_partitioned_table(partition_id);
CREATE TABLE #{identifier} PARTITION OF public._test_partitioned_table
FOR VALUES IN (1);
SQL
end
context 'when dropping an index on the partition table' do
it 'raises ArgumentError' do
expect { model.remove_concurrent_index_by_name(partition_table_name, partition_index_name) }
.to raise_error(ArgumentError, /use remove_concurrent_partitioned_index_by_name/)
end
end
end
end
end
end

View File

@ -3,8 +3,10 @@
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
let(:database_metric_class) { Class.new(described_class) }
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
metric_class.start { Issue.minimum(:id) }
@ -38,7 +40,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with metric options specified with custom batch_size' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
metric_class.start { Issue.minimum(:id) }
@ -60,7 +62,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with start and finish not called' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
end.new(time_frame: 'all')
@ -73,7 +75,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with availability defined' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
metric_class.available? { false }
@ -87,7 +89,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with availability not defined' do
subject do
Class.new(described_class) do
database_metric_class do
relation { Issue }
operation :count
end.new(time_frame: 'all')
@ -100,7 +102,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with cache_start_and_finish_as called' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
metric_class.start { Issue.minimum(:id) }
@ -123,7 +125,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with estimate_batch_distinct_count' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation(:estimate_batch_distinct_count)
metric_class.start { Issue.minimum(:id) }
@ -139,7 +141,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
let(:buckets) { double('Buckets').as_null_object }
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation(:estimate_batch_distinct_count) do |result|
result.foo
@ -163,7 +165,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with custom timestamp column' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
metric_class.timestamp_column :last_edited_at
@ -171,6 +173,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
end
it 'calculates a correct result' do
create(:issue, last_edited_at: 40.days.ago)
create(:issue, last_edited_at: 5.days.ago)
expect(subject.value).to eq(1)
@ -179,14 +182,14 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with default timestamp column' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
end.new(time_frame: '28d')
end
it 'calculates a correct result' do
create(:issue, last_edited_at: 5.days.ago)
create(:issue, created_at: 40.days.ago)
create(:issue, created_at: 5.days.ago)
expect(subject.value).to eq(1)
@ -195,15 +198,15 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with additional parameters passed via options' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation ->(options) { Issue.where(confidential: options[:confidential]) }
metric_class.operation :count
end.new(time_frame: '28d', options: { confidential: true })
end
it 'calculates a correct result' do
create(:issue, last_edited_at: 5.days.ago, confidential: true)
create(:issue, last_edited_at: 5.days.ago, confidential: false)
create(:issue, created_at: 5.days.ago, confidential: true)
create(:issue, created_at: 5.days.ago, confidential: false)
expect(subject.value).to eq(1)
end
@ -212,7 +215,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with unimplemented operation method used' do
subject do
described_class.tap do |metric_class|
database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :invalid_operation
end.new(time_frame: 'all')

View File

@ -12,6 +12,10 @@ RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
shared_examples 'tracks template' do
let(:subject) { described_class.track_unique_project_event(project: project, template: template_path, config_source: config_source, user: user) }
let(:template_name) do
expanded_template_name = described_class.expand_template_name(template_path)
described_class.ci_template_event_name(expanded_template_name, config_source)
end
it "has an event defined for template" do
expect do
@ -20,33 +24,18 @@ RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
end
it "tracks template" do
expanded_template_name = described_class.expand_template_name(template_path)
expected_template_event_name = described_class.ci_template_event_name(expanded_template_name, config_source)
expect(Gitlab::UsageDataCounters::HLLRedisCounter).to(receive(:track_event)).with(expected_template_event_name, values: project.id)
expect(Gitlab::UsageDataCounters::HLLRedisCounter).to(receive(:track_event)).with(template_name, values: project.id)
subject
end
context 'Snowplow' do
it 'event is not tracked if FF is disabled' do
stub_feature_flags(route_hll_to_snowplow: false)
subject
expect_no_snowplow_event
end
it 'tracks event' do
subject
expect_snowplow_event(
category: described_class.to_s,
action: 'ci_templates_unique',
namespace: project.namespace,
user: user,
project: project
)
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
let(:feature_flag_name) { :route_hll_to_snowplow }
let(:category) { described_class.to_s }
let(:action) { 'ci_templates_unique' }
let(:namespace) { project.namespace }
let(:label) { 'redis_hll_counters.ci_templates.ci_templates_total_unique_counts_monthly' }
let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: template_name).to_context] }
end
end

View File

@ -7,7 +7,7 @@ require (
github.com/BurntSushi/toml v1.2.1
github.com/FZambia/sentinel v1.1.1
github.com/alecthomas/chroma/v2 v2.3.0
github.com/aws/aws-sdk-go v1.44.131
github.com/aws/aws-sdk-go v1.44.133
github.com/disintegration/imaging v1.6.2
github.com/getsentry/raven-go v0.2.0
github.com/golang-jwt/jwt/v4 v4.4.2

View File

@ -227,8 +227,8 @@ github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.68/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.131 h1:kd61x79ax0vyiC/SZ9X1hKh8E0pt1BUOOcVBJEFhxkg=
github.com/aws/aws-sdk-go v1.44.131/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.133 h1:+pWxt9nyKc0jf33rORBaQ93KPjYpmIIy3ozVXdJ82Oo=
github.com/aws/aws-sdk-go v1.44.133/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/aws/aws-sdk-go-v2 v1.16.8 h1:gOe9UPR98XSf7oEJCcojYg+N2/jCRm4DdeIsP85pIyQ=
github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw=