Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
62cd7010ef
commit
e58ce90f14
|
@ -47,7 +47,6 @@
|
|||
- rspec_profiling/
|
||||
- tmp/capybara/
|
||||
- tmp/memory_test/
|
||||
- tmp/feature_flags/
|
||||
- log/*.log
|
||||
reports:
|
||||
junit: junit_rspec.xml
|
||||
|
@ -222,6 +221,11 @@ static-analysis:
|
|||
script:
|
||||
- run_timed_command "retry yarn install --frozen-lockfile"
|
||||
- scripts/static-analysis
|
||||
artifacts:
|
||||
expire_in: 31d
|
||||
when: always
|
||||
paths:
|
||||
- tmp/feature_flags/
|
||||
|
||||
static-analysis as-if-foss:
|
||||
extends:
|
||||
|
@ -460,25 +464,9 @@ rspec:coverage:
|
|||
rspec:feature-flags:
|
||||
extends:
|
||||
- .coverage-base
|
||||
- .rails:rules:rspec-feature-flags
|
||||
- .static-analysis:rules:ee-and-foss
|
||||
stage: post-test
|
||||
# We cannot use needs since it would mean needing 84 jobs (since most are parallelized)
|
||||
# so we use `dependencies` here.
|
||||
dependencies:
|
||||
- setup-test-env
|
||||
- rspec migration pg12
|
||||
- rspec unit pg12
|
||||
- rspec integration pg12
|
||||
- rspec system pg12
|
||||
- rspec-ee migration pg12
|
||||
- rspec-ee unit pg12
|
||||
- rspec-ee integration pg12
|
||||
- rspec-ee system pg12
|
||||
- rspec-ee unit pg12 geo
|
||||
- rspec-ee integration pg12 geo
|
||||
- rspec-ee system pg12 geo
|
||||
- memory-static
|
||||
- memory-on-boot
|
||||
needs: ["static-analysis"]
|
||||
script:
|
||||
- !reference [.minimal-bundle-install, script]
|
||||
- if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then
|
||||
|
|
|
@ -932,14 +932,6 @@
|
|||
- <<: *if-merge-request-title-run-all-rspec
|
||||
when: always
|
||||
|
||||
.rails:rules:rspec-feature-flags:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-default-branch-schedule-2-hourly
|
||||
allow_failure: true
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:default-branch-schedule-nightly--code-backstage:
|
||||
rules:
|
||||
- <<: *if-default-branch-schedule-nightly
|
||||
|
|
|
@ -1354,284 +1354,6 @@ RSpec/AnyInstanceOf:
|
|||
- 'spec/workers/wait_for_cluster_creation_worker_spec.rb'
|
||||
- 'ee/spec/workers/security/auto_fix_worker_spec.rb'
|
||||
|
||||
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/331835
|
||||
RSpec/HaveEnqueuedSidekiqJob:
|
||||
Exclude:
|
||||
- 'ee/spec/lib/gitlab/geo/log_cursor/events/job_artifact_deleted_event_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_deleted_event_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_renamed_event_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_updated_event_spec.rb'
|
||||
- 'ee/spec/models/ci/pipeline_spec.rb'
|
||||
- 'ee/spec/models/concerns/elastic/project_wiki_spec.rb'
|
||||
- 'ee/spec/models/concerns/elastic/projects_search_spec.rb'
|
||||
- 'ee/spec/models/ee/alert_management/alert_spec.rb'
|
||||
- 'ee/spec/models/ee/user_spec.rb'
|
||||
- 'ee/spec/models/elasticsearch_indexed_namespace_spec.rb'
|
||||
- 'ee/spec/models/elasticsearch_indexed_project_spec.rb'
|
||||
- 'ee/spec/models/gitlab/seat_link_data_spec.rb'
|
||||
- 'ee/spec/models/group_wiki_spec.rb'
|
||||
- 'ee/spec/models/namespace_statistics_spec.rb'
|
||||
- 'ee/spec/models/project_feature_spec.rb'
|
||||
- 'ee/spec/models/project_import_state_spec.rb'
|
||||
- 'ee/spec/models/project_spec.rb'
|
||||
- 'ee/spec/requests/api/elasticsearch_indexed_namespaces_spec.rb'
|
||||
- 'ee/spec/requests/api/graphql/mutations/requirements_management/export_requirements_spec.rb'
|
||||
- 'ee/spec/requests/api/project_mirror_spec.rb'
|
||||
- 'ee/spec/requests/api/projects_spec.rb'
|
||||
- 'ee/spec/services/admin/email_service_spec.rb'
|
||||
- 'ee/spec/services/application_settings/update_service_spec.rb'
|
||||
- 'ee/spec/services/auto_merge/merge_train_service_spec.rb'
|
||||
- 'ee/spec/services/ci_cd/github_setup_service_spec.rb'
|
||||
- 'ee/spec/services/dast_site_validations/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/git/branch_push_service_spec.rb'
|
||||
- 'ee/spec/services/ee/merge_requests/handle_assignees_change_service_spec.rb'
|
||||
- 'ee/spec/services/ee/merge_requests/update_service_spec.rb'
|
||||
- 'ee/spec/services/elastic/process_initial_bookkeeping_service_spec.rb'
|
||||
- 'ee/spec/services/epics/update_dates_service_spec.rb'
|
||||
- 'ee/spec/services/geo/container_repository_sync_service_spec.rb'
|
||||
- 'ee/spec/services/geo/design_repository_sync_service_spec.rb'
|
||||
- 'ee/spec/services/geo/framework_repository_sync_service_spec.rb'
|
||||
- 'ee/spec/services/geo/hashed_storage_attachments_migration_service_spec.rb'
|
||||
- 'ee/spec/services/geo/hashed_storage_migration_service_spec.rb'
|
||||
- 'ee/spec/services/geo/project_housekeeping_service_spec.rb'
|
||||
- 'ee/spec/services/geo/rename_repository_service_spec.rb'
|
||||
- 'ee/spec/services/geo/repository_destroy_service_spec.rb'
|
||||
- 'ee/spec/services/groups/transfer_service_spec.rb'
|
||||
- 'ee/spec/services/milestones/destroy_service_spec.rb'
|
||||
- 'ee/spec/services/projects/transfer_service_spec.rb'
|
||||
- 'ee/spec/services/security/store_report_service_spec.rb'
|
||||
- 'ee/spec/services/status_page/trigger_publish_service_spec.rb'
|
||||
- 'ee/spec/services/web_hook_service_spec.rb'
|
||||
- 'ee/spec/support/shared_examples/models/concerns/verifiable_replicator_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/quick_actions/issue/status_page_quick_actions_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/services/base_sync_service_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/status_page/trigger_publish_shared_examples.rb'
|
||||
- 'ee/spec/workers/build_finished_worker_spec.rb'
|
||||
- 'ee/spec/workers/elastic_remove_expired_namespace_subscriptions_from_index_cron_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/container_repository_sync_dispatch_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/design_repository_shard_sync_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/file_download_dispatch_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/registry_sync_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/repositories_clean_up_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/repository_shard_sync_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/repository_verification/primary/batch_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/repository_verification/primary/shard_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/repository_verification/secondary/scheduler_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/repository_verification/secondary/shard_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/secondary/registry_consistency_worker_spec.rb'
|
||||
- 'ee/spec/workers/incident_management/oncall_rotations/persist_all_rotations_shifts_job_spec.rb'
|
||||
- 'ee/spec/workers/post_receive_spec.rb'
|
||||
- 'ee/spec/workers/store_security_reports_worker_spec.rb'
|
||||
- 'ee/spec/workers/sync_seat_link_worker_spec.rb'
|
||||
- 'spec/controllers/admin/clusters_controller_spec.rb'
|
||||
- 'spec/controllers/admin/services_controller_spec.rb'
|
||||
- 'spec/controllers/chaos_controller_spec.rb'
|
||||
- 'spec/controllers/groups/clusters_controller_spec.rb'
|
||||
- 'spec/controllers/groups_controller_spec.rb'
|
||||
- 'spec/controllers/projects/clusters_controller_spec.rb'
|
||||
- 'spec/controllers/projects/issues_controller_spec.rb'
|
||||
- 'spec/controllers/projects/merge_requests_controller_spec.rb'
|
||||
- 'spec/controllers/projects/pipeline_schedules_controller_spec.rb'
|
||||
- 'spec/controllers/projects/registry/repositories_controller_spec.rb'
|
||||
- 'spec/controllers/projects/settings/ci_cd_controller_spec.rb'
|
||||
- 'spec/controllers/repositories/git_http_controller_spec.rb'
|
||||
- 'spec/features/admin/admin_uses_repository_checks_spec.rb'
|
||||
- 'spec/features/clusters/installing_applications_shared_examples.rb'
|
||||
- 'spec/features/issues/csv_spec.rb'
|
||||
- 'spec/graphql/mutations/container_repositories/destroy_spec.rb'
|
||||
- 'spec/graphql/mutations/merge_requests/accept_spec.rb'
|
||||
- 'spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb'
|
||||
- 'spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb'
|
||||
- 'spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/notes_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/jira_import/issues_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/pages_transfer_spec.rb'
|
||||
- 'spec/models/abuse_report_spec.rb'
|
||||
- 'spec/models/ci/build_spec.rb'
|
||||
- 'spec/models/ci/build_trace_chunk_spec.rb'
|
||||
- 'spec/models/ci/job_artifact_spec.rb'
|
||||
- 'spec/models/ci/pipeline_spec.rb'
|
||||
- 'spec/models/ci/processable_spec.rb'
|
||||
- 'spec/models/clusters/integrations/prometheus_spec.rb'
|
||||
- 'spec/models/commit_status_spec.rb'
|
||||
- 'spec/models/concerns/reactive_caching_spec.rb'
|
||||
- 'spec/models/deployment_spec.rb'
|
||||
- 'spec/models/diff_note_spec.rb'
|
||||
- 'spec/models/integrations/emails_on_push_spec.rb'
|
||||
- 'spec/models/issue_spec.rb'
|
||||
- 'spec/models/jira_import_state_spec.rb'
|
||||
- 'spec/models/key_spec.rb'
|
||||
- 'spec/models/lfs_object_spec.rb'
|
||||
- 'spec/models/lfs_objects_project_spec.rb'
|
||||
- 'spec/models/merge_request_spec.rb'
|
||||
- 'spec/models/namespace/aggregation_schedule_spec.rb'
|
||||
- 'spec/models/namespace_spec.rb'
|
||||
- 'spec/models/operations/feature_flag_spec.rb'
|
||||
- 'spec/models/packages/package_spec.rb'
|
||||
- 'spec/models/pages_domain_spec.rb'
|
||||
- 'spec/models/pool_repository_spec.rb'
|
||||
- 'spec/models/project_import_state_spec.rb'
|
||||
- 'spec/models/project_services/prometheus_service_spec.rb'
|
||||
- 'spec/models/project_spec.rb'
|
||||
- 'spec/models/project_statistics_spec.rb'
|
||||
- 'spec/models/project_wiki_spec.rb'
|
||||
- 'spec/models/remote_mirror_spec.rb'
|
||||
- 'spec/models/sentry_issue_spec.rb'
|
||||
- 'spec/models/snippet_statistics_spec.rb'
|
||||
- 'spec/models/user_spec.rb'
|
||||
- 'spec/models/x509_certificate_spec.rb'
|
||||
- 'spec/requests/api/dependency_proxy_spec.rb'
|
||||
- 'spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb'
|
||||
- 'spec/requests/api/group_import_spec.rb'
|
||||
- 'spec/requests/api/merge_requests_spec.rb'
|
||||
- 'spec/requests/api/project_container_repositories_spec.rb'
|
||||
- 'spec/requests/api/project_packages_spec.rb'
|
||||
- 'spec/requests/lfs_http_spec.rb'
|
||||
- 'spec/services/admin/propagate_integration_service_spec.rb'
|
||||
- 'spec/services/admin/propagate_service_template_spec.rb'
|
||||
- 'spec/services/application_settings/update_service_spec.rb'
|
||||
- 'spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb'
|
||||
- 'spec/services/branches/delete_merged_service_spec.rb'
|
||||
- 'spec/services/branches/delete_service_spec.rb'
|
||||
- 'spec/services/bulk_import_service_spec.rb'
|
||||
- 'spec/services/bulk_imports/export_service_spec.rb'
|
||||
- 'spec/services/ci/create_pipeline_service_spec.rb'
|
||||
- 'spec/services/ci/list_config_variables_service_spec.rb'
|
||||
- 'spec/services/ci/pipeline_schedule_service_spec.rb'
|
||||
- 'spec/services/ci/play_bridge_service_spec.rb'
|
||||
- 'spec/services/ci/test_failure_history_service_spec.rb'
|
||||
- 'spec/services/ci/update_build_state_service_spec.rb'
|
||||
- 'spec/services/clusters/applications/create_service_spec.rb'
|
||||
- 'spec/services/clusters/applications/schedule_update_service_spec.rb'
|
||||
- 'spec/services/clusters/applications/update_service_spec.rb'
|
||||
- 'spec/services/clusters/cleanup/app_service_spec.rb'
|
||||
- 'spec/services/clusters/cleanup/project_namespace_service_spec.rb'
|
||||
- 'spec/services/clusters/create_service_spec.rb'
|
||||
- 'spec/services/container_expiration_policy_service_spec.rb'
|
||||
- 'spec/services/deployments/create_service_spec.rb'
|
||||
- 'spec/services/design_management/delete_designs_service_spec.rb'
|
||||
- 'spec/services/discussions/resolve_service_spec.rb'
|
||||
- 'spec/services/feature_flags/create_service_spec.rb'
|
||||
- 'spec/services/feature_flags/update_service_spec.rb'
|
||||
- 'spec/services/git/branch_hooks_service_spec.rb'
|
||||
- 'spec/services/git/branch_push_service_spec.rb'
|
||||
- 'spec/services/git/tag_push_service_spec.rb'
|
||||
- 'spec/services/grafana/proxy_service_spec.rb'
|
||||
- 'spec/services/groups/import_export/import_service_spec.rb'
|
||||
- 'spec/services/groups/transfer_service_spec.rb'
|
||||
- 'spec/services/groups/update_service_spec.rb'
|
||||
- 'spec/services/incident_management/pager_duty/process_webhook_service_spec.rb'
|
||||
- 'spec/services/issuable/bulk_update_service_spec.rb'
|
||||
- 'spec/services/issues/create_service_spec.rb'
|
||||
- 'spec/services/issues/update_service_spec.rb'
|
||||
- 'spec/services/members/destroy_service_spec.rb'
|
||||
- 'spec/services/merge_requests/handle_assignees_change_service_spec.rb'
|
||||
- 'spec/services/merge_requests/merge_service_spec.rb'
|
||||
- 'spec/services/merge_requests/mergeability_check_service_spec.rb'
|
||||
- 'spec/services/merge_requests/resolve_todos_service_spec.rb'
|
||||
- 'spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb'
|
||||
- 'spec/services/notes/create_service_spec.rb'
|
||||
- 'spec/services/notification_service_spec.rb'
|
||||
- 'spec/services/onboarding_progress_service_spec.rb'
|
||||
- 'spec/services/packages/composer/create_package_service_spec.rb'
|
||||
- 'spec/services/packages/debian/process_changes_service_spec.rb'
|
||||
- 'spec/services/packages/go/sync_packages_service_spec.rb'
|
||||
- 'spec/services/pages/delete_service_spec.rb'
|
||||
- 'spec/services/post_receive_service_spec.rb'
|
||||
- 'spec/services/projects/after_rename_service_spec.rb'
|
||||
- 'spec/services/projects/create_service_spec.rb'
|
||||
- 'spec/services/projects/group_links/create_service_spec.rb'
|
||||
- 'spec/services/projects/group_links/destroy_service_spec.rb'
|
||||
- 'spec/services/projects/repository_languages_service_spec.rb'
|
||||
- 'spec/services/projects/transfer_service_spec.rb'
|
||||
- 'spec/services/projects/update_service_spec.rb'
|
||||
- 'spec/services/prometheus/proxy_service_spec.rb'
|
||||
- 'spec/services/resource_access_tokens/revoke_service_spec.rb'
|
||||
- 'spec/services/snippets/destroy_service_spec.rb'
|
||||
- 'spec/services/snippets/update_statistics_service_spec.rb'
|
||||
- 'spec/services/tags/destroy_service_spec.rb'
|
||||
- 'spec/services/todos/destroy/entity_leave_service_spec.rb'
|
||||
- 'spec/services/web_hook_service_spec.rb'
|
||||
- 'spec/support/services/clusters/create_service_shared.rb'
|
||||
- 'spec/support/shared_examples/controllers/access_tokens_controller_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/models/update_project_statistics_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/alert_management/alert_processing/incident_creation_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb'
|
||||
- 'spec/tasks/gitlab/storage_rake_spec.rb'
|
||||
- 'spec/uploaders/external_diff_uploader_spec.rb'
|
||||
- 'spec/uploaders/lfs_object_uploader_spec.rb'
|
||||
- 'spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb'
|
||||
- 'spec/workers/build_finished_worker_spec.rb'
|
||||
- 'spec/workers/bulk_import_worker_spec.rb'
|
||||
- 'spec/workers/bulk_imports/entity_worker_spec.rb'
|
||||
- 'spec/workers/bulk_imports/pipeline_worker_spec.rb'
|
||||
- 'spec/workers/deployments/execute_hooks_worker_spec.rb'
|
||||
- 'spec/workers/deployments/hooks_worker_spec.rb'
|
||||
- 'spec/workers/export_csv_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/advance_stage_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_pull_requests_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/github_import/stage/import_repository_worker_spec.rb'
|
||||
- 'spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb'
|
||||
- 'spec/workers/issue_placement_worker_spec.rb'
|
||||
- 'spec/workers/metrics/dashboard/schedule_annotations_prune_worker_spec.rb'
|
||||
- 'spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb'
|
||||
- 'spec/workers/pages_domain_verification_cron_worker_spec.rb'
|
||||
- 'spec/workers/post_receive_spec.rb'
|
||||
- 'spec/workers/project_cache_worker_spec.rb'
|
||||
- 'spec/workers/repository_check/dispatch_worker_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/log_cursor/daemon_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_created_event_spec.rb'
|
||||
- 'ee/spec/models/merge_train_spec.rb'
|
||||
- 'ee/spec/services/iterations/cadences/create_service_spec.rb'
|
||||
- 'ee/spec/workers/incident_management/incident_sla_exceeded_check_worker_spec.rb'
|
||||
- 'ee/spec/workers/iterations/cadences/schedule_create_iterations_worker_spec.rb'
|
||||
- 'spec/controllers/admin/clusters/applications_controller_spec.rb'
|
||||
- 'spec/controllers/groups/clusters/applications_controller_spec.rb'
|
||||
- 'spec/controllers/projects/clusters/applications_controller_spec.rb'
|
||||
- 'spec/controllers/projects/mirrors_controller_spec.rb'
|
||||
- 'spec/lib/gitlab/background_migration_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/parallel_importer_spec.rb'
|
||||
- 'spec/requests/api/ci/pipeline_schedules_spec.rb'
|
||||
- 'spec/services/auto_merge/base_service_spec.rb'
|
||||
- 'spec/services/git/process_ref_changes_service_spec.rb'
|
||||
- 'spec/services/merge_requests/base_service_spec.rb'
|
||||
- 'spec/services/web_hooks/destroy_service_spec.rb'
|
||||
- 'spec/workers/container_expiration_policy_worker_spec.rb'
|
||||
- 'spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb'
|
||||
- 'ee/spec/services/elastic/indexing_control_service_spec.rb'
|
||||
- 'ee/spec/support/shared_examples/lib/gitlab/geo/geo_log_cursor_event_shared_examples.rb'
|
||||
- 'ee/spec/workers/geo/repository_sync_worker_spec.rb'
|
||||
- 'ee/spec/workers/update_all_mirrors_worker_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/parallel_scheduling_spec.rb'
|
||||
- 'spec/models/clusters/cluster_spec.rb'
|
||||
- 'spec/services/clusters/applications/destroy_service_spec.rb'
|
||||
- 'spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/self_monitoring_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/repositories/housekeeping_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/services/schedule_bulk_repository_shard_moves_shared_examples.rb'
|
||||
- 'spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb'
|
||||
- 'spec/workers/concerns/limited_capacity/worker_spec.rb'
|
||||
- 'spec/workers/concerns/reenqueuer_spec.rb'
|
||||
- 'spec/workers/gitlab/phabricator_import/base_worker_spec.rb'
|
||||
- 'spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb'
|
||||
|
||||
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/321982
|
||||
Gitlab/NamespacedClass:
|
||||
Exclude:
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -432,7 +432,6 @@ group :test do
|
|||
gem 'concurrent-ruby', '~> 1.1'
|
||||
gem 'test-prof', '~> 0.12.0'
|
||||
gem 'rspec_junit_formatter'
|
||||
gem 'rspec-sidekiq'
|
||||
gem 'guard-rspec'
|
||||
|
||||
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
|
||||
|
|
|
@ -1090,9 +1090,6 @@ GEM
|
|||
rspec-support (~> 3.10)
|
||||
rspec-retry (0.6.1)
|
||||
rspec-core (> 3.3)
|
||||
rspec-sidekiq (3.1.0)
|
||||
rspec-core (~> 3.0, >= 3.0.0)
|
||||
sidekiq (>= 2.4.0)
|
||||
rspec-support (3.10.2)
|
||||
rspec_junit_formatter (0.4.1)
|
||||
rspec-core (>= 2, < 4, != 2.12.0)
|
||||
|
@ -1608,7 +1605,6 @@ DEPENDENCIES
|
|||
rspec-parameterized
|
||||
rspec-rails (~> 5.0.1)
|
||||
rspec-retry (~> 0.6.1)
|
||||
rspec-sidekiq
|
||||
rspec_junit_formatter
|
||||
rspec_profiling (~> 0.0.6)
|
||||
ruby-fogbugz (~> 0.2.1)
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
} from '~/vue_shared/components/paginated_table_with_search_and_tabs/constants';
|
||||
import PaginatedTableWithSearchAndTabs from '~/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue';
|
||||
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { ALERTS_STATUS_TABS, SEVERITY_LEVELS, trackAlertListViewsOptions } from '../constants';
|
||||
import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query.graphql';
|
||||
|
||||
|
@ -114,6 +115,7 @@ export default {
|
|||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
inject: ['projectPath', 'textQuery', 'assigneeUsernameQuery', 'populatingAlertsHelpUrl'],
|
||||
apollo: {
|
||||
alerts: {
|
||||
|
@ -275,7 +277,7 @@ export default {
|
|||
</gl-sprintf>
|
||||
</gl-alert>
|
||||
|
||||
<alerts-deprecation-warning />
|
||||
<alerts-deprecation-warning v-if="!glFeatures.managedAlertsDeprecation" />
|
||||
|
||||
<paginated-table-with-search-and-tabs
|
||||
:show-error-msg="showErrorMsg"
|
||||
|
|
|
@ -11,6 +11,7 @@ import { s__ } from '~/locale';
|
|||
import AlertsDeprecationWarning from '~/vue_shared/components/alerts_deprecation_warning.vue';
|
||||
import { defaultTimeRange } from '~/vue_shared/constants';
|
||||
import TrackEventDirective from '~/vue_shared/directives/track_event';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { metricStates, keyboardShortcutKeys } from '../constants';
|
||||
import {
|
||||
timeRangeFromUrl,
|
||||
|
@ -46,6 +47,7 @@ export default {
|
|||
GlTooltip: GlTooltipDirective,
|
||||
TrackEvent: TrackEventDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
hasMetrics: {
|
||||
type: Boolean,
|
||||
|
@ -397,7 +399,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div class="prometheus-graphs" data-qa-selector="prometheus_graphs">
|
||||
<alerts-deprecation-warning />
|
||||
<alerts-deprecation-warning v-if="!glFeatures.managedAlertsDeprecation" />
|
||||
|
||||
<dashboard-header
|
||||
v-if="showHeader"
|
||||
|
|
|
@ -21,6 +21,7 @@ import invalidUrl from '~/lib/utils/invalid_url';
|
|||
import { relativePathToAbsolute, getBaseURL, visitUrl, isSafeURL } from '~/lib/utils/url_utility';
|
||||
import { __, n__ } from '~/locale';
|
||||
import TrackEventDirective from '~/vue_shared/directives/track_event';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { panelTypes } from '../constants';
|
||||
|
||||
import { graphDataToCsv } from '../csv_export';
|
||||
|
@ -61,6 +62,7 @@ export default {
|
|||
GlTooltip: GlTooltipDirective,
|
||||
TrackEvent: TrackEventDirective,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
props: {
|
||||
clipboardText: {
|
||||
type: String,
|
||||
|
@ -258,7 +260,8 @@ export default {
|
|||
this.prometheusAlertsAvailable &&
|
||||
this.alertsEndpoint &&
|
||||
this.graphData &&
|
||||
this.hasMetricsInDb
|
||||
this.hasMetricsInDb &&
|
||||
!this.glFeatures.managedAlertsDeprecation
|
||||
);
|
||||
},
|
||||
alertModalId() {
|
||||
|
|
|
@ -22,6 +22,8 @@ export default {
|
|||
<gl-nav class="navbar-sub-nav">
|
||||
<gl-nav-item-dropdown
|
||||
:text="navData.activeTitle"
|
||||
data-qa-selector="navbar_dropdown"
|
||||
:data-qa-title="navData.activeTitle"
|
||||
icon="hamburger"
|
||||
menu-class="gl-mt-3! gl-max-w-none! gl-max-h-none! gl-sm-w-auto! js-top-nav-dropdown-menu"
|
||||
toggle-class="top-nav-toggle js-top-nav-dropdown-toggle gl-px-3!"
|
||||
|
|
|
@ -83,6 +83,7 @@ export default {
|
|||
:slot-key="activeView"
|
||||
class="gl-w-grid-size-40 gl-overflow-hidden gl-py-3 gl-px-5"
|
||||
data-testid="menu-subview"
|
||||
data-qa-selector="menu_subview_container"
|
||||
>
|
||||
<template #projects>
|
||||
<top-nav-container-view
|
||||
|
|
|
@ -3,7 +3,7 @@ import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui';
|
|||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { __, s__ } from '~/locale';
|
||||
import deleteRunnerMutation from '~/runner/graphql/delete_runner.mutation.graphql';
|
||||
import updateRunnerMutation from '~/runner/graphql/update_runner.mutation.graphql';
|
||||
import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql';
|
||||
|
||||
const i18n = {
|
||||
I18N_EDIT: __('Edit'),
|
||||
|
@ -76,7 +76,7 @@ export default {
|
|||
runnerUpdate: { errors },
|
||||
},
|
||||
} = await this.$apollo.mutate({
|
||||
mutation: updateRunnerMutation,
|
||||
mutation: runnerUpdateMutation,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.runner.id,
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<script>
|
||||
import { GlAlert, GlLink } from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { s__ } from '~/locale';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../constants';
|
||||
|
||||
const ALERT_DATA = {
|
||||
[INSTANCE_TYPE]: {
|
||||
title: s__(
|
||||
'Runners|This runner is available to all groups and projects in your GitLab instance.',
|
||||
),
|
||||
message: s__(
|
||||
'Runners|Shared runners are available to every project in a GitLab instance. If you want a runner to build only specific projects, restrict the project in the table below. After you restrict a runner to a project, you cannot change it back to a shared runner.',
|
||||
),
|
||||
variant: 'success',
|
||||
anchor: 'shared-runners',
|
||||
},
|
||||
[GROUP_TYPE]: {
|
||||
title: s__('Runners|This runner is available to all projects and subgroups in a group.'),
|
||||
message: s__(
|
||||
'Runners|Use Group runners when you want all projects in a group to have access to a set of runners.',
|
||||
),
|
||||
variant: 'success',
|
||||
anchor: 'group-runners',
|
||||
},
|
||||
[PROJECT_TYPE]: {
|
||||
title: s__('Runners|This runner is associated with specific projects.'),
|
||||
message: s__(
|
||||
'Runners|You can set up a specific runner to be used by multiple projects but you cannot make this a shared runner.',
|
||||
),
|
||||
variant: 'info',
|
||||
anchor: 'specific-runners',
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlAlert,
|
||||
GlLink,
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
validator(type) {
|
||||
return Boolean(ALERT_DATA[type]);
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
alert() {
|
||||
return ALERT_DATA[this.type];
|
||||
},
|
||||
helpHref() {
|
||||
return helpPagePath('ci/runners/runners_scope', { anchor: this.alert.anchor });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-alert v-if="alert" :variant="alert.variant" :title="alert.title" :dismissible="false">
|
||||
{{ alert.message }}
|
||||
<gl-link :href="helpHref">{{ __('Learn more.') }}</gl-link>
|
||||
</gl-alert>
|
||||
</template>
|
|
@ -3,7 +3,7 @@ import { GlBadge } from '@gitlab/ui';
|
|||
import { s__ } from '~/locale';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../constants';
|
||||
|
||||
const badge = {
|
||||
const BADGE_DATA = {
|
||||
[INSTANCE_TYPE]: {
|
||||
variant: 'success',
|
||||
text: s__('Runners|shared'),
|
||||
|
@ -25,21 +25,22 @@ export default {
|
|||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: false,
|
||||
default: null,
|
||||
validator(type) {
|
||||
return Boolean(BADGE_DATA[type]);
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
variant() {
|
||||
return badge[this.type]?.variant;
|
||||
},
|
||||
text() {
|
||||
return badge[this.type]?.text;
|
||||
badge() {
|
||||
return BADGE_DATA[this.type];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-badge v-if="text" :variant="variant" v-bind="$attrs">
|
||||
{{ text }}
|
||||
<gl-badge v-if="badge" :variant="badge.variant" v-bind="$attrs">
|
||||
{{ badge.text }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
<script>
|
||||
import {
|
||||
GlButton,
|
||||
GlForm,
|
||||
GlFormCheckbox,
|
||||
GlFormGroup,
|
||||
GlFormInputGroup,
|
||||
GlTooltipDirective,
|
||||
} from '@gitlab/ui';
|
||||
import createFlash, { FLASH_TYPES } from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants';
|
||||
import runnerUpdateMutation from '../graphql/runner_update.mutation.graphql';
|
||||
|
||||
const runnerToModel = (runner) => {
|
||||
const {
|
||||
id,
|
||||
description,
|
||||
maximumTimeout,
|
||||
accessLevel,
|
||||
active,
|
||||
locked,
|
||||
runUntagged,
|
||||
tagList = [],
|
||||
} = runner || {};
|
||||
|
||||
return {
|
||||
id,
|
||||
description,
|
||||
maximumTimeout,
|
||||
accessLevel,
|
||||
active,
|
||||
locked,
|
||||
runUntagged,
|
||||
tagList: tagList.join(', '),
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
GlForm,
|
||||
GlFormCheckbox,
|
||||
GlFormGroup,
|
||||
GlFormInputGroup,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
props: {
|
||||
runner: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
saving: false,
|
||||
model: runnerToModel(this.runner),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
canBeLockedToProject() {
|
||||
return this.runner?.runnerType === PROJECT_TYPE;
|
||||
},
|
||||
readonlyIpAddress() {
|
||||
return this.runner?.ipAddress;
|
||||
},
|
||||
updateMutationInput() {
|
||||
const { maximumTimeout, tagList } = this.model;
|
||||
|
||||
return {
|
||||
...this.model,
|
||||
maximumTimeout: maximumTimeout !== '' ? maximumTimeout : null,
|
||||
tagList: tagList
|
||||
.split(',')
|
||||
.map((tag) => tag.trim())
|
||||
.filter((tag) => Boolean(tag)),
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
runner(newVal, oldVal) {
|
||||
if (oldVal === null) {
|
||||
this.model = runnerToModel(newVal);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async onSubmit() {
|
||||
this.saving = true;
|
||||
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
runnerUpdate: { errors },
|
||||
},
|
||||
} = await this.$apollo.mutate({
|
||||
mutation: runnerUpdateMutation,
|
||||
variables: {
|
||||
input: this.updateMutationInput,
|
||||
},
|
||||
});
|
||||
|
||||
if (errors?.length) {
|
||||
this.onError(new Error(errors[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
this.onSuccess();
|
||||
} catch (e) {
|
||||
this.onError(e);
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
},
|
||||
onError(error) {
|
||||
const { message } = error;
|
||||
createFlash({ message });
|
||||
},
|
||||
onSuccess() {
|
||||
createFlash({ message: __('Changes saved.'), type: FLASH_TYPES.SUCCESS });
|
||||
this.model = runnerToModel(this.runner);
|
||||
},
|
||||
},
|
||||
ACCESS_LEVEL_NOT_PROTECTED,
|
||||
ACCESS_LEVEL_REF_PROTECTED,
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-form @submit.prevent="onSubmit">
|
||||
<gl-form-checkbox
|
||||
v-model="model.active"
|
||||
data-testid="runner-field-paused"
|
||||
:value="false"
|
||||
:unchecked-value="true"
|
||||
>
|
||||
{{ __('Paused') }}
|
||||
<template #help>
|
||||
{{ __("Paused runners don't accept new jobs") }}
|
||||
</template>
|
||||
</gl-form-checkbox>
|
||||
|
||||
<gl-form-checkbox
|
||||
v-model="model.accessLevel"
|
||||
data-testid="runner-field-protected"
|
||||
:value="$options.ACCESS_LEVEL_REF_PROTECTED"
|
||||
:unchecked-value="$options.ACCESS_LEVEL_NOT_PROTECTED"
|
||||
>
|
||||
{{ __('Protected') }}
|
||||
<template #help>
|
||||
{{ __('This runner will only run on pipelines triggered on protected branches') }}
|
||||
</template>
|
||||
</gl-form-checkbox>
|
||||
|
||||
<gl-form-checkbox v-model="model.runUntagged" data-testid="runner-field-run-untagged">
|
||||
{{ __('Run untagged jobs') }}
|
||||
<template #help>
|
||||
{{ __('Indicates whether this runner can pick jobs without tags') }}
|
||||
</template>
|
||||
</gl-form-checkbox>
|
||||
|
||||
<gl-form-checkbox
|
||||
v-model="model.locked"
|
||||
data-testid="runner-field-locked"
|
||||
:disabled="!canBeLockedToProject"
|
||||
>
|
||||
{{ __('Lock to current projects') }}
|
||||
<template #help>
|
||||
{{ __('When a runner is locked, it cannot be assigned to other projects') }}
|
||||
</template>
|
||||
</gl-form-checkbox>
|
||||
|
||||
<gl-form-group :label="__('IP Address')" data-testid="runner-field-ip-address">
|
||||
<gl-form-input-group :value="readonlyIpAddress" readonly select-on-click>
|
||||
<template #append>
|
||||
<gl-button
|
||||
v-gl-tooltip.hover
|
||||
:title="__('Copy IP Address')"
|
||||
:aria-label="__('Copy IP Address')"
|
||||
:data-clipboard-text="readonlyIpAddress"
|
||||
icon="copy-to-clipboard"
|
||||
class="d-inline-flex"
|
||||
/>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group :label="__('Description')" data-testid="runner-field-description">
|
||||
<gl-form-input-group v-model="model.description" />
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group
|
||||
data-testid="runner-field-max-timeout"
|
||||
:label="__('Maximum job timeout')"
|
||||
:description="
|
||||
s__(
|
||||
'Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project.',
|
||||
)
|
||||
"
|
||||
>
|
||||
<gl-form-input-group v-model.number="model.maximumTimeout" type="number" />
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group
|
||||
data-testid="runner-field-tags"
|
||||
:label="__('Tags')"
|
||||
:description="
|
||||
__('You can set up jobs to only use runners with specific tags. Separate tags with commas.')
|
||||
"
|
||||
>
|
||||
<gl-form-input-group v-model="model.tagList" />
|
||||
</gl-form-group>
|
||||
|
||||
<div class="form-actions">
|
||||
<gl-button
|
||||
type="submit"
|
||||
variant="confirm"
|
||||
class="js-no-auto-disable"
|
||||
:loading="saving || !runner"
|
||||
>
|
||||
{{ __('Save changes') }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</gl-form>
|
||||
</template>
|
|
@ -31,6 +31,11 @@ export const STATUS_ONLINE = 'ONLINE';
|
|||
export const STATUS_OFFLINE = 'OFFLINE';
|
||||
export const STATUS_NOT_CONNECTED = 'NOT_CONNECTED';
|
||||
|
||||
// CiRunnerAccessLevel
|
||||
|
||||
export const ACCESS_LEVEL_NOT_PROTECTED = 'NOT_PROTECTED';
|
||||
export const ACCESS_LEVEL_REF_PROTECTED = 'REF_PROTECTED';
|
||||
|
||||
// CiRunnerSort
|
||||
|
||||
export const CREATED_DESC = 'CREATED_DESC';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#import "~/runner/graphql/runner_details.fragment.graphql"
|
||||
|
||||
query getRunner($id: CiRunnerID!) {
|
||||
runner(id: $id) {
|
||||
id
|
||||
runnerType
|
||||
...RunnerDetails
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
fragment RunnerDetails on CiRunner {
|
||||
id
|
||||
runnerType
|
||||
active
|
||||
accessLevel
|
||||
runUntagged
|
||||
locked
|
||||
ipAddress
|
||||
description
|
||||
maximumTimeout
|
||||
tagList
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
#import "~/runner/graphql/runner_node.fragment.graphql"
|
||||
#import "~/runner/graphql/runner_details.fragment.graphql"
|
||||
|
||||
mutation runnerUpdate($input: RunnerUpdateInput!) {
|
||||
runnerUpdate(input: $input) {
|
||||
runner {
|
||||
...RunnerNode
|
||||
...RunnerDetails
|
||||
}
|
||||
errors
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
<script>
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import RunnerTypeAlert from '../components/runner_type_alert.vue';
|
||||
import RunnerTypeBadge from '../components/runner_type_badge.vue';
|
||||
import RunnerUpdateForm from '../components/runner_update_form.vue';
|
||||
import { I18N_DETAILS_TITLE, RUNNER_ENTITY_TYPE } from '../constants';
|
||||
import getRunnerQuery from '../graphql/get_runner.query.graphql';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
RunnerTypeAlert,
|
||||
RunnerTypeBadge,
|
||||
RunnerUpdateForm,
|
||||
},
|
||||
i18n: {
|
||||
I18N_DETAILS_TITLE,
|
||||
|
@ -19,7 +23,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
runner: {},
|
||||
runner: null,
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
|
@ -35,9 +39,15 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<h2 class="page-title">
|
||||
{{ sprintf($options.i18n.I18N_DETAILS_TITLE, { runner_id: runnerId }) }}
|
||||
<div>
|
||||
<h2 class="page-title">
|
||||
{{ sprintf($options.i18n.I18N_DETAILS_TITLE, { runner_id: runnerId }) }}
|
||||
|
||||
<runner-type-badge v-if="runner.runnerType" :type="runner.runnerType" />
|
||||
</h2>
|
||||
<runner-type-badge v-if="runner" :type="runner.runnerType" />
|
||||
</h2>
|
||||
|
||||
<runner-type-alert v-if="runner" :type="runner.runnerType" />
|
||||
|
||||
<runner-update-form :runner="runner" class="gl-my-5" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlTable } from '@gitlab/ui';
|
||||
import { GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui';
|
||||
import { reduce } from 'lodash';
|
||||
import {
|
||||
capitalizeFirstCharacter,
|
||||
convertToSentenceCase,
|
||||
splitCamelCase,
|
||||
} from '~/lib/utils/text_utility';
|
||||
import { isSafeURL } from '~/lib/utils/url_utility';
|
||||
import { s__ } from '~/locale';
|
||||
import { PAGE_CONFIG } from '~/vue_shared/alert_details/constants';
|
||||
|
||||
|
@ -30,6 +31,7 @@ const allowedFields = [
|
|||
|
||||
export default {
|
||||
components: {
|
||||
GlLink,
|
||||
GlLoadingIcon,
|
||||
GlTable,
|
||||
},
|
||||
|
@ -94,6 +96,9 @@ export default {
|
|||
isAllowed(fieldName) {
|
||||
return allowedFields.includes(fieldName);
|
||||
},
|
||||
isValidLink(value) {
|
||||
return typeof value === 'string' && isSafeURL(value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -109,5 +114,11 @@ export default {
|
|||
<template #table-busy>
|
||||
<gl-loading-icon size="lg" color="dark" class="gl-mt-5" />
|
||||
</template>
|
||||
<template #cell(value)="{ item: { value } }">
|
||||
<span v-if="!isValidLink(value)">{{ value }}</span>
|
||||
<gl-link v-else :href="value" target="_blank">
|
||||
{{ value }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-table>
|
||||
</template>
|
||||
|
|
|
@ -22,7 +22,12 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-alert v-if="hasManagedPrometheus" variant="warning" class="my-2">
|
||||
<gl-alert
|
||||
v-if="hasManagedPrometheus"
|
||||
variant="warning"
|
||||
class="my-2"
|
||||
data-testid="alerts-deprecation-warning"
|
||||
>
|
||||
<gl-sprintf :message="$options.i18n.alertsDeprecationText">
|
||||
<template #link="{ content }">
|
||||
<gl-link
|
||||
|
|
|
@ -49,10 +49,9 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
before_action only: :show do
|
||||
real_time_feature_flag = :real_time_issue_sidebar
|
||||
real_time_enabled = Gitlab::ActionCable::Config.in_app? || Feature.enabled?(real_time_feature_flag, @project)
|
||||
real_time_enabled = Gitlab::ActionCable::Config.in_app? || Feature.enabled?(:real_time_issue_sidebar, @project)
|
||||
|
||||
push_to_gon_attributes(:features, real_time_feature_flag, real_time_enabled)
|
||||
push_to_gon_attributes(:features, :real_time_issue_sidebar, real_time_enabled)
|
||||
push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:labels_widget, @project, default_enabled: :yaml)
|
||||
|
|
|
@ -12,6 +12,7 @@ module Projects
|
|||
before_action do
|
||||
push_frontend_feature_flag(:prometheus_computed_alerts)
|
||||
push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate)
|
||||
push_frontend_feature_flag(:managed_alerts_deprecation, @project)
|
||||
end
|
||||
|
||||
feature_category :metrics
|
||||
|
|
|
@ -276,7 +276,7 @@ module Nav
|
|||
builder = ::Gitlab::Nav::TopNavMenuBuilder.new
|
||||
builder.add_primary_menu_item(id: 'your', title: _('Your groups'), href: dashboard_groups_path)
|
||||
builder.add_primary_menu_item(id: 'explore', title: _('Explore groups'), href: explore_groups_path)
|
||||
builder.add_secondary_menu_item(id: 'create', title: _('Create group'), href: new_group_path(anchor: 'create-group-pane'))
|
||||
builder.add_secondary_menu_item(id: 'create', title: _('Create group'), href: new_group_path)
|
||||
builder.build
|
||||
end
|
||||
end
|
||||
|
|
|
@ -205,6 +205,8 @@ module Ci
|
|||
end
|
||||
|
||||
scope :with_coverage, -> { where.not(coverage: nil) }
|
||||
scope :without_coverage, -> { where(coverage: nil) }
|
||||
scope :with_coverage_regex, -> { where.not(coverage_regex: nil) }
|
||||
|
||||
scope :for_project, -> (project_id) { where(project_id: project_id) }
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ module Ci
|
|||
validates :build, presence: true
|
||||
validates :secrets, json_schema: { filename: 'build_metadata_secrets' }
|
||||
|
||||
serialize :config_options, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||
serialize :config_variables, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||
serialize :config_options, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize
|
||||
serialize :config_variables, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize
|
||||
|
||||
chronic_duration_attr_reader :timeout_human_readable, :timeout
|
||||
|
||||
|
|
|
@ -644,6 +644,10 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
def update_builds_coverage
|
||||
builds.with_coverage_regex.without_coverage.each(&:update_coverage)
|
||||
end
|
||||
|
||||
def batch_lookup_report_artifact_for_file_type(file_type)
|
||||
latest_report_artifacts
|
||||
.values_at(*::Ci::JobArtifact.associated_file_types_for(file_type.to_s))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
module Ci
|
||||
class PipelineSchedule < ApplicationRecord
|
||||
extend Gitlab::Ci::Model
|
||||
extend ::Gitlab::Utils::Override
|
||||
include Importable
|
||||
include StripAttribute
|
||||
include CronSchedulable
|
||||
|
@ -55,6 +56,13 @@ module Ci
|
|||
variables&.map(&:to_runner_variable) || []
|
||||
end
|
||||
|
||||
override :set_next_run_at
|
||||
def set_next_run_at
|
||||
self.next_run_at = ::Ci::PipelineSchedules::CalculateNextRunService # rubocop: disable CodeReuse/ServiceClass
|
||||
.new(project)
|
||||
.execute(self, fallback_method: method(:calculate_next_run_at))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def worker_cron_expression
|
||||
|
|
|
@ -4,23 +4,28 @@ module CronSchedulable
|
|||
extend ActiveSupport::Concern
|
||||
include Schedulable
|
||||
|
||||
def set_next_run_at
|
||||
self.next_run_at = calculate_next_run_at
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# The `next_run_at` column is set to the actual execution date of worker that
|
||||
# triggers the schedule. This way, a schedule like `*/1 * * * *` won't be triggered
|
||||
# in a short interval when the worker runs irregularly by Sidekiq Memory Killer.
|
||||
def set_next_run_at
|
||||
def calculate_next_run_at
|
||||
now = Time.zone.now
|
||||
|
||||
ideal_next_run = ideal_next_run_from(now)
|
||||
|
||||
self.next_run_at = if ideal_next_run == cron_worker_next_run_from(now)
|
||||
ideal_next_run
|
||||
else
|
||||
cron_worker_next_run_from(ideal_next_run)
|
||||
end
|
||||
if ideal_next_run == cron_worker_next_run_from(now)
|
||||
ideal_next_run
|
||||
else
|
||||
cron_worker_next_run_from(ideal_next_run)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ideal_next_run_from(start_time)
|
||||
next_time_from(start_time, cron, cron_timezone)
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@ class MergeRequestContextCommit < ApplicationRecord
|
|||
validates :sha, presence: true
|
||||
validates :sha, uniqueness: { message: 'has already been added' }
|
||||
|
||||
serialize :trailers, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||
serialize :trailers, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize
|
||||
validates :trailers, json_schema: { filename: 'git_trailers' }
|
||||
|
||||
# Sort by committed date in descending order to ensure latest commits comes on the top
|
||||
|
|
|
@ -12,7 +12,7 @@ class MergeRequestDiffCommit < ApplicationRecord
|
|||
sha_attribute :sha
|
||||
alias_attribute :id, :sha
|
||||
|
||||
serialize :trailers, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||
serialize :trailers, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize
|
||||
validates :trailers, json_schema: { filename: 'git_trailers' }
|
||||
|
||||
# Deprecated; use `bulk_insert!` from `BulkInsertSafe` mixin instead.
|
||||
|
|
|
@ -15,6 +15,9 @@ class IssuePolicy < IssuablePolicy
|
|||
desc "Issue is confidential"
|
||||
condition(:confidential, scope: :subject) { @subject.confidential? }
|
||||
|
||||
desc "Issue is persisted"
|
||||
condition(:persisted, scope: :subject) { @subject.persisted? }
|
||||
|
||||
rule { confidential & ~can_read_confidential }.policy do
|
||||
prevent(*create_read_update_admin_destroy(:issue))
|
||||
prevent :read_issue_iid
|
||||
|
@ -40,6 +43,14 @@ class IssuePolicy < IssuablePolicy
|
|||
enable :create_todo
|
||||
enable :update_subscription
|
||||
end
|
||||
|
||||
rule { ~persisted & can?(:guest_access) }.policy do
|
||||
enable :set_issue_metadata
|
||||
end
|
||||
|
||||
rule { persisted & can?(:admin_issue) }.policy do
|
||||
enable :set_issue_metadata
|
||||
end
|
||||
end
|
||||
|
||||
IssuePolicy.prepend_mod_with('IssuePolicy')
|
||||
|
|
|
@ -28,6 +28,10 @@ class MergeRequestPolicy < IssuablePolicy
|
|||
rule { can_merge }.policy do
|
||||
enable :accept_merge_request
|
||||
end
|
||||
|
||||
rule { can?(:admin_merge_request) }.policy do
|
||||
enable :set_merge_request_metadata
|
||||
end
|
||||
end
|
||||
|
||||
MergeRequestPolicy.prepend_mod_with('MergeRequestPolicy')
|
||||
|
|
|
@ -16,7 +16,7 @@ module BulkImports
|
|||
|
||||
def execute
|
||||
validate_dir
|
||||
validate_decompressed_file_size if Feature.enabled?(:validate_import_decompressed_archive_size)
|
||||
validate_decompressed_file_size if Feature.enabled?(:validate_import_decompressed_archive_size, default_enabled: :yaml)
|
||||
validate_symlink(filepath)
|
||||
|
||||
decompress_file
|
||||
|
|
|
@ -86,7 +86,7 @@ module BulkImports
|
|||
|
||||
# rubocop: disable CodeReuse/Serializer
|
||||
def serializer
|
||||
@serializer ||= ::Gitlab::ImportExport::JSON::StreamingSerializer.new(
|
||||
@serializer ||= ::Gitlab::ImportExport::Json::StreamingSerializer.new(
|
||||
portable,
|
||||
portable_tree,
|
||||
json_writer,
|
||||
|
@ -96,7 +96,7 @@ module BulkImports
|
|||
# rubocop: enable CodeReuse/Serializer
|
||||
|
||||
def json_writer
|
||||
@json_writer ||= ::Gitlab::ImportExport::JSON::NdjsonWriter.new(export_path)
|
||||
@json_writer ||= ::Gitlab::ImportExport::Json::NdjsonWriter.new(export_path)
|
||||
end
|
||||
|
||||
def ndjson_filename
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
module PipelineSchedules
|
||||
class CalculateNextRunService < BaseService
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
def execute(schedule, fallback_method:)
|
||||
@schedule = schedule
|
||||
|
||||
return fallback_method.call unless ::Feature.enabled?(:ci_daily_limit_for_pipeline_schedules, project, default_enabled: :yaml)
|
||||
return fallback_method.call unless plan_cron&.cron_valid?
|
||||
|
||||
now = Time.zone.now
|
||||
|
||||
schedule_next_run = schedule_cron.next_time_from(now)
|
||||
return schedule_next_run if worker_cron.match?(schedule_next_run) && plan_cron.match?(schedule_next_run)
|
||||
|
||||
plan_next_run = plan_cron.next_time_from(now)
|
||||
return plan_next_run if worker_cron.match?(plan_next_run)
|
||||
|
||||
worker_next_run = worker_cron.next_time_from(now)
|
||||
return worker_next_run if plan_cron.match?(worker_next_run)
|
||||
|
||||
worker_cron.next_time_from(plan_next_run)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def schedule_cron
|
||||
strong_memoize(:schedule_cron) do
|
||||
Gitlab::Ci::CronParser.new(@schedule.cron, @schedule.cron_timezone)
|
||||
end
|
||||
end
|
||||
|
||||
def worker_cron
|
||||
strong_memoize(:worker_cron) do
|
||||
Gitlab::Ci::CronParser.new(worker_cron_expression, Time.zone.name)
|
||||
end
|
||||
end
|
||||
|
||||
def plan_cron
|
||||
strong_memoize(:plan_cron) do
|
||||
daily_scheduled_pipeline_limit = project.actual_limits.limit_for(:ci_daily_pipeline_schedule_triggers)
|
||||
|
||||
next unless daily_scheduled_pipeline_limit
|
||||
|
||||
every_x_minutes = (1.day.in_minutes / daily_scheduled_pipeline_limit).to_i
|
||||
|
||||
Gitlab::Ci::CronParser.parse_natural("every #{every_x_minutes} minutes", Time.zone.name)
|
||||
end
|
||||
end
|
||||
|
||||
def worker_cron_expression
|
||||
Settings.cron_jobs['pipeline_schedule_worker']['cron']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -27,8 +27,14 @@ class IssuableBaseService < ::BaseProjectService
|
|||
can?(current_user, ability_name, issuable)
|
||||
end
|
||||
|
||||
def can_set_issuable_metadata?(issuable)
|
||||
ability_name = :"set_#{issuable.to_ability_name}_metadata"
|
||||
|
||||
can?(current_user, ability_name, issuable)
|
||||
end
|
||||
|
||||
def filter_params(issuable)
|
||||
unless can_admin_issuable?(issuable)
|
||||
unless can_set_issuable_metadata?(issuable)
|
||||
params.delete(:milestone)
|
||||
params.delete(:milestone_id)
|
||||
params.delete(:labels)
|
||||
|
@ -45,6 +51,7 @@ class IssuableBaseService < ::BaseProjectService
|
|||
params.delete(:canonical_issue_id)
|
||||
params.delete(:project)
|
||||
params.delete(:discussion_locked)
|
||||
params.delete(:confidential)
|
||||
end
|
||||
|
||||
filter_assignees(issuable)
|
||||
|
|
|
@ -20,17 +20,6 @@ module Issues
|
|||
super
|
||||
end
|
||||
|
||||
override :filter_params
|
||||
def filter_params(issue)
|
||||
super
|
||||
|
||||
# filter confidential in `Issues::UpdateService` and not in `IssuableBaseService#filter_params`
|
||||
# because we do allow users that cannot admin issues to set confidential flag when creating an issue
|
||||
unless can_admin_issuable?(issue)
|
||||
params.delete(:confidential)
|
||||
end
|
||||
end
|
||||
|
||||
def before_update(issue, skip_spam_check: false)
|
||||
return if skip_spam_check
|
||||
|
||||
|
|
|
@ -74,19 +74,11 @@ module Security
|
|||
|
||||
def sast_excluded_analyzers
|
||||
strong_memoize(:sast_excluded_analyzers) do
|
||||
all_analyzers = Security::CiConfiguration::SastBuildAction::SAST_DEFAULT_ANALYZERS.split(', ') rescue []
|
||||
enabled_analyzers = sast_default_analyzers.split(',').map(&:strip) rescue []
|
||||
|
||||
excluded_analyzers = gitlab_ci_yml_attributes["SAST_EXCLUDED_ANALYZERS"] || sast_template_attributes["SAST_EXCLUDED_ANALYZERS"]
|
||||
excluded_analyzers = excluded_analyzers.split(',').map(&:strip) rescue []
|
||||
((all_analyzers - enabled_analyzers) + excluded_analyzers).uniq
|
||||
excluded_analyzers.split(',').map(&:strip) rescue []
|
||||
end
|
||||
end
|
||||
|
||||
def sast_default_analyzers
|
||||
@sast_default_analyzers ||= gitlab_ci_yml_attributes["SAST_DEFAULT_ANALYZERS"] || sast_template_attributes["SAST_DEFAULT_ANALYZERS"]
|
||||
end
|
||||
|
||||
def sast_template_attributes
|
||||
@sast_template_attributes ||= build_sast_attributes(sast_template_content)
|
||||
end
|
||||
|
|
|
@ -10,11 +10,9 @@
|
|||
%h2.page-title
|
||||
= s_('Runners|Runner #%{runner_id}' % { runner_id: @runner.id })
|
||||
= render 'shared/runners/runner_type_badge', runner: @runner
|
||||
|
||||
= render 'shared/runners/runner_type_alert', runner: @runner
|
||||
|
||||
.gl-mb-6
|
||||
= render 'shared/runners/form', runner: @runner, runner_form_url: admin_runner_path(@runner), in_gitlab_com_admin_context: Gitlab.com?
|
||||
= render 'shared/runners/runner_type_alert', runner: @runner
|
||||
.gl-mb-6
|
||||
= render 'shared/runners/form', runner: @runner, runner_form_url: admin_runner_path(@runner), in_gitlab_com_admin_context: Gitlab.com?
|
||||
|
||||
.row
|
||||
.col-md-6
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
-# [1]: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56587
|
||||
%ul.list-unstyled.navbar-sub-nav
|
||||
- if dashboard_nav_link?(:projects)
|
||||
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown", data: { track_label: "projects_dropdown", track_event: "click_dropdown", track_experiment: "new_repo" } }) do
|
||||
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects", data: { track_label: "projects_dropdown", track_event: "click_dropdown", track_experiment: "new_repo" } }) do
|
||||
%button{ type: 'button', data: { toggle: "dropdown" } }
|
||||
= _('Projects')
|
||||
= sprite_icon('chevron-down', css_class: 'caret-down')
|
||||
|
@ -12,7 +12,7 @@
|
|||
= render "layouts/nav/projects_dropdown/show"
|
||||
|
||||
- if dashboard_nav_link?(:groups)
|
||||
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "d-none d-md-block home dropdown header-groups qa-groups-dropdown", data: { track_label: "groups_dropdown", track_event: "click_dropdown" } }) do
|
||||
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "d-none d-md-block home dropdown header-groups", data: { track_label: "groups_dropdown", track_event: "click_dropdown" } }) do
|
||||
%button{ type: 'button', data: { toggle: "dropdown" } }
|
||||
= _('Groups')
|
||||
= sprite_icon('chevron-down', css_class: 'caret-down')
|
||||
|
@ -21,28 +21,28 @@
|
|||
|
||||
- if any_dashboard_nav_link?([:groups, :milestones, :activity, :snippets])
|
||||
= nav_link(html_options: { id: 'nav-more-dropdown', class: "header-more dropdown", data: { track_label: "more_dropdown", track_event: "click_more_link" } }) do
|
||||
%a{ href: "#", data: { toggle: "dropdown", qa_selector: 'more_dropdown' } }
|
||||
%a{ href: "#", data: { toggle: "dropdown" } }
|
||||
= _('More')
|
||||
= sprite_icon('chevron-down', css_class: 'caret-down')
|
||||
.dropdown-menu
|
||||
%ul
|
||||
- if dashboard_nav_link?(:groups)
|
||||
%li.d-md-none
|
||||
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', data: { qa_selector: 'groups_link' } do
|
||||
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups' do
|
||||
= _('Groups')
|
||||
- if dashboard_nav_link?(:activity)
|
||||
= nav_link(path: 'dashboard#activity') do
|
||||
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', data: { qa_selector: 'activity_link' } do
|
||||
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity' do
|
||||
= _('Activity')
|
||||
|
||||
- if dashboard_nav_link?(:milestones)
|
||||
= nav_link(controller: 'dashboard/milestones') do
|
||||
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', data: { qa_selector: 'milestones_link' } do
|
||||
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones' do
|
||||
= _('Milestones')
|
||||
|
||||
- if dashboard_nav_link?(:snippets)
|
||||
= nav_link(controller: 'dashboard/snippets') do
|
||||
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', data: { qa_selector: 'snippets_link' } do
|
||||
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets' do
|
||||
= _('Snippets')
|
||||
|
||||
%li.dropdown
|
||||
|
@ -50,7 +50,7 @@
|
|||
|
||||
- if current_user.admin?
|
||||
= nav_link(controller: 'admin/dashboard') do
|
||||
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link d-xl-none' do
|
||||
= link_to admin_root_path, class: 'admin-icon d-xl-none' do
|
||||
= _('Admin Area')
|
||||
- if Gitlab::CurrentSettings.admin_mode
|
||||
- if header_link?(:admin_mode)
|
||||
|
@ -68,7 +68,7 @@
|
|||
|
||||
- if current_user.admin?
|
||||
= nav_link(controller: 'admin/dashboard', html_options: { class: "d-none d-xl-block"}) do
|
||||
= link_to admin_root_path, class: 'admin-icon qa-admin-area-link', title: _('Admin Area'), aria: { label: _('Admin Area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= link_to admin_root_path, class: 'admin-icon', title: _('Admin Area'), aria: { label: _('Admin Area') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= sprite_icon('admin', size: 18)
|
||||
|
||||
- if Gitlab::CurrentSettings.admin_mode
|
||||
|
|
|
@ -4,19 +4,19 @@
|
|||
-# [1]: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56587
|
||||
- group_meta = { id: @group.id, name: @group.name, namespace: @group.full_name, web_url: group_path(@group), avatar_url: @group.avatar_url } if @group&.persisted?
|
||||
.frequent-items-dropdown-container.with-deprecated-styles
|
||||
.frequent-items-dropdown-sidebar.qa-groups-dropdown-sidebar
|
||||
.frequent-items-dropdown-sidebar
|
||||
%ul
|
||||
= nav_link(path: 'dashboard/groups#index') do
|
||||
= link_to dashboard_groups_path, class: 'qa-your-groups-link', data: { track_label: "groups_dropdown_your_groups", track_event: "click_link" } do
|
||||
= link_to dashboard_groups_path, data: { track_label: "groups_dropdown_your_groups", track_event: "click_link" } do
|
||||
= _('Your groups')
|
||||
= nav_link(path: 'groups#explore') do
|
||||
= link_to explore_groups_path, data: { track_label: "groups_dropdown_explore_groups", track_event: "click_link" } do
|
||||
= _('Explore groups')
|
||||
= nav_link(path: 'groups/new#create-group-pane', html_options: { class: 'gl-border-0 gl-border-t-1 gl-border-solid gl-border-gray-100' }) do
|
||||
= link_to new_group_path(anchor: 'create-group-pane'), data: { track_label: "groups_dropdown_create_group", track_event: "click_link", qa_selector: 'create_group_link' } do
|
||||
= link_to new_group_path(anchor: 'create-group-pane'), data: { track_label: "groups_dropdown_create_group", track_event: "click_link" } do
|
||||
= _('Create group')
|
||||
= nav_link(path: 'groups/new#import-group-pane') do
|
||||
= link_to new_group_path(anchor: 'import-group-pane'), data: { track_label: "groups_dropdown_import_group", track_event: "click_link", qa_selector: 'import_group_link' } do
|
||||
= link_to new_group_path(anchor: 'import-group-pane'), data: { track_label: "groups_dropdown_import_group", track_event: "click_link" } do
|
||||
= _('Import group')
|
||||
.frequent-items-dropdown-content
|
||||
#js-groups-dropdown{ data: { user_name: current_user.username, group: group_meta } }
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
-# [1]: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56587
|
||||
- project_meta = { id: @project.id, name: @project.name, namespace: @project.full_name, web_url: project_path(@project), avatar_url: @project.avatar_url } if @project&.persisted?
|
||||
.frequent-items-dropdown-container.with-deprecated-styles
|
||||
.frequent-items-dropdown-sidebar.qa-projects-dropdown-sidebar
|
||||
.frequent-items-dropdown-sidebar
|
||||
%ul
|
||||
= nav_link(path: 'dashboard/projects#index') do
|
||||
= link_to dashboard_projects_path, class: 'qa-your-projects-link', data: { track_label: "projects_dropdown_your_projects", track_event: "click_link" } do
|
||||
= link_to dashboard_projects_path, data: { track_label: "projects_dropdown_your_projects", track_event: "click_link" } do
|
||||
= _('Your projects')
|
||||
= nav_link(path: 'projects#starred') do
|
||||
= link_to starred_dashboard_projects_path, data: { track_label: "projects_dropdown_starred_projects", track_event: "click_link" } do
|
||||
|
|
|
@ -24,14 +24,6 @@
|
|||
|
||||
= render 'shared/form_elements/description', model: issuable, form: form, project: project
|
||||
|
||||
- if issuable.respond_to?(:confidential)
|
||||
.form-group.row
|
||||
.offset-sm-2.col-sm-10
|
||||
.form-check
|
||||
= form.check_box :confidential, class: 'form-check-input'
|
||||
= form.label :confidential, class: 'form-check-label' do
|
||||
This issue is confidential and should only be visible to team members with at least Reporter access.
|
||||
|
||||
= render 'shared/issuable/form/metadata', issuable: issuable, form: form, project: project, presenter: presenter
|
||||
|
||||
= render_if_exists 'shared/issuable/approvals', issuable: issuable, presenter: presenter, form: form
|
||||
|
|
|
@ -2,11 +2,19 @@
|
|||
- issuable = local_assigns.fetch(:issuable)
|
||||
- presenter = local_assigns.fetch(:presenter)
|
||||
|
||||
- return unless can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
|
||||
- return unless can?(current_user, :"set_#{issuable.to_ability_name}_metadata", issuable)
|
||||
|
||||
- has_due_date = issuable.has_attribute?(:due_date)
|
||||
- form = local_assigns.fetch(:form)
|
||||
|
||||
- if issuable.respond_to?(:confidential)
|
||||
.form-group.row
|
||||
.offset-sm-2.col-sm-10
|
||||
.form-check
|
||||
= form.check_box :confidential, class: 'form-check-input'
|
||||
= form.label :confidential, class: 'form-check-label' do
|
||||
This issue is confidential and should only be visible to team members with at least Reporter access.
|
||||
|
||||
%hr
|
||||
.row
|
||||
%div{ class: (has_due_date ? "col-lg-6" : "col-12") }
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: ci_daily_limit_for_pipeline_schedules
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62826
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332333
|
||||
milestone: '14.0'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
default_enabled: false
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/324086
|
|||
milestone: '13.10'
|
||||
type: development
|
||||
group: group::editor
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/282245
|
|||
milestone: '13.4'
|
||||
type: development
|
||||
group: group::import
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -68,27 +68,3 @@ end
|
|||
if helper.security_mr? && feature_flag_file_added?
|
||||
fail "Feature flags are discouraged from security merge requests. Read the [security documentation](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/utilities/feature_flags.md) for details."
|
||||
end
|
||||
|
||||
if feature_flag_file_added_or_removed?
|
||||
new_mr_title = helper.mr_title.dup
|
||||
new_mr_title << ' [RUN ALL RSPEC]' unless helper.run_all_rspec_mr?
|
||||
new_mr_title << ' [RUN AS-IF-FOSS]' unless helper.run_as_if_foss_mr?
|
||||
|
||||
changes = {}
|
||||
changes[:add_labels] = FEATURE_FLAG_LABEL unless helper.mr_has_labels?(FEATURE_FLAG_LABEL)
|
||||
|
||||
if new_mr_title != helper.mr_title
|
||||
changes[:title] = new_mr_title
|
||||
else
|
||||
message "You're adding or removing a feature flag, your MR title needs to include `[RUN ALL RSPEC] [RUN AS-IF-FOSS]` (we may have updated it automatically for you and started a new MR pipeline) to ensure everything is covered."
|
||||
end
|
||||
|
||||
if changes.any?
|
||||
gitlab.api.update_merge_request(
|
||||
gitlab.mr_json['project_id'],
|
||||
gitlab.mr_json['iid'],
|
||||
**changes
|
||||
)
|
||||
gitlab.api.post("/projects/#{gitlab.mr_json['project_id']}/merge_requests/#{gitlab.mr_json['iid']}/pipelines")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,8 @@ SPECIALIZATIONS = {
|
|||
docs: 'documentation',
|
||||
qa: 'QA',
|
||||
engineering_productivity: 'Engineering Productivity',
|
||||
ci_template: 'ci::templates'
|
||||
ci_template: 'ci::templates',
|
||||
feature_flag: 'feature flag'
|
||||
}.freeze
|
||||
|
||||
labels_to_add = project_helper.changes_by_category.each_with_object([]) do |(category, _changes), memo|
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddVerificationStateAndStartedAtToMrDiffDetailsTable < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
change_table(:merge_request_diff_details) do |t|
|
||||
t.integer :verification_state, default: 0, limit: 2, null: false
|
||||
t.column :verification_started_at, :datetime_with_timezone
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddVerificationIndexesToMergeRequestDiffDetailsTable < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
VERIFICATION_STATE_INDEX_NAME = "index_merge_request_diff_details_on_verification_state"
|
||||
PENDING_VERIFICATION_INDEX_NAME = "index_merge_request_diff_details_pending_verification"
|
||||
FAILED_VERIFICATION_INDEX_NAME = "index_merge_request_diff_details_failed_verification"
|
||||
NEEDS_VERIFICATION_INDEX_NAME = "index_merge_request_diff_details_needs_verification"
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index :merge_request_diff_details, :verification_state, name: VERIFICATION_STATE_INDEX_NAME
|
||||
add_concurrent_index :merge_request_diff_details, :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
|
||||
add_concurrent_index :merge_request_diff_details, :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
|
||||
add_concurrent_index :merge_request_diff_details, :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :merge_request_diff_details, VERIFICATION_STATE_INDEX_NAME
|
||||
remove_concurrent_index_by_name :merge_request_diff_details, PENDING_VERIFICATION_INDEX_NAME
|
||||
remove_concurrent_index_by_name :merge_request_diff_details, FAILED_VERIFICATION_INDEX_NAME
|
||||
remove_concurrent_index_by_name :merge_request_diff_details, NEEDS_VERIFICATION_INDEX_NAME
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RenameSyncSecurityReportApprovalRulesSidekiqQueue < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
sidekiq_queue_migrate 'sync_security_reports_to_report_approval_rules', to: 'ci_sync_reports_to_report_approval_rules'
|
||||
end
|
||||
|
||||
def down
|
||||
sidekiq_queue_migrate 'ci_sync_reports_to_report_approval_rules', to: 'sync_security_reports_to_report_approval_rules'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddCiDailyPipelineScheduleTriggersToPlanLimits < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column(:plan_limits, :ci_daily_pipeline_schedule_triggers, :integer, default: 0, null: false)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class InsertCiDailyPipelineScheduleTriggersPlanLimits < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
EVERY_5_MINUTES = (1.day.in_minutes / 5).to_i
|
||||
EVERY_HOUR = 1.day.in_hours.to_i
|
||||
|
||||
def up
|
||||
return unless Gitlab.com?
|
||||
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'free', EVERY_HOUR)
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'bronze', EVERY_5_MINUTES)
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'silver', EVERY_5_MINUTES)
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'gold', EVERY_5_MINUTES)
|
||||
end
|
||||
|
||||
def down
|
||||
return unless Gitlab.com?
|
||||
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'free', 0)
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'bronze', 0)
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'silver', 0)
|
||||
create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', 'gold', 0)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,48 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FixMissingTraversalIds < ActiveRecord::Migration[6.1]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
ROOTS_MIGRATION = 'BackfillNamespaceTraversalIdsRoots'
|
||||
CHILDREN_MIGRATION = 'BackfillNamespaceTraversalIdsChildren'
|
||||
DOWNTIME = false
|
||||
BATCH_SIZE = 1_000
|
||||
SUB_BATCH_SIZE = 50
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
ROOT_NS_INDEX_NAME = 'tmp_index_namespaces_empty_traversal_ids_with_root_namespaces'
|
||||
CHILD_INDEX_NAME = 'tmp_index_namespaces_empty_traversal_ids_with_child_namespaces'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index :namespaces, :id, where: "parent_id IS NULL AND traversal_ids = '{}'", name: ROOT_NS_INDEX_NAME
|
||||
add_concurrent_index :namespaces, :id, where: "parent_id IS NOT NULL AND traversal_ids = '{}'", name: CHILD_INDEX_NAME
|
||||
|
||||
# Personal namespaces and top-level groups
|
||||
final_delay = queue_background_migration_jobs_by_range_at_intervals(
|
||||
::Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsRoots::Namespace.base_query.where("traversal_ids = '{}'"),
|
||||
ROOTS_MIGRATION,
|
||||
DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
other_job_arguments: [SUB_BATCH_SIZE],
|
||||
track_jobs: true
|
||||
)
|
||||
final_delay += DELAY_INTERVAL
|
||||
|
||||
# Subgroups
|
||||
queue_background_migration_jobs_by_range_at_intervals(
|
||||
::Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsChildren::Namespace.base_query.where("traversal_ids = '{}'"),
|
||||
CHILDREN_MIGRATION,
|
||||
DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
initial_delay: final_delay,
|
||||
other_job_arguments: [SUB_BATCH_SIZE],
|
||||
track_jobs: true
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :namespaces, ROOT_NS_INDEX_NAME
|
||||
remove_concurrent_index_by_name :namespaces, CHILD_INDEX_NAME
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
e5b552b21c40b83b95442341838ad5951dcac7dd473194c49630d20ce6a46ae2
|
|
@ -0,0 +1 @@
|
|||
9b16e17189d4db708553ce0d9dada1ce097be75433c3a8c09a6102e897e3123a
|
|
@ -0,0 +1 @@
|
|||
ec4cd687062118b30e516ed7c36677dda056f25c4d96c6ee0b503e457b5a18d4
|
|
@ -0,0 +1 @@
|
|||
ae2829a06f02ff3e1adc977f5e789b17d1f760e6aaa40be44586cc6a90870c4a
|
|
@ -0,0 +1 @@
|
|||
824e0930de14587f6ccaeb6b5fbec16676d243550a2dfd3a5999b67dfc16d4c8
|
|
@ -0,0 +1 @@
|
|||
95e4b697f5c5b18935b73bbeb0c42c96e3e5abde9e4f9e179d1a93a891a0694b
|
|
@ -14626,6 +14626,8 @@ CREATE TABLE merge_request_diff_details (
|
|||
verification_retry_count smallint,
|
||||
verification_checksum bytea,
|
||||
verification_failure text,
|
||||
verification_state smallint DEFAULT 0 NOT NULL,
|
||||
verification_started_at timestamp with time zone,
|
||||
CONSTRAINT check_81429e3622 CHECK ((char_length(verification_failure) <= 255))
|
||||
);
|
||||
|
||||
|
@ -16242,7 +16244,8 @@ CREATE TABLE plan_limits (
|
|||
helm_max_file_size bigint DEFAULT 5242880 NOT NULL,
|
||||
ci_registered_group_runners integer DEFAULT 1000 NOT NULL,
|
||||
ci_registered_project_runners integer DEFAULT 1000 NOT NULL,
|
||||
web_hook_calls integer DEFAULT 0 NOT NULL
|
||||
web_hook_calls integer DEFAULT 0 NOT NULL,
|
||||
ci_daily_pipeline_schedule_triggers integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE plan_limits_id_seq
|
||||
|
@ -23700,8 +23703,16 @@ CREATE UNIQUE INDEX index_merge_request_cleanup_schedules_on_merge_request_id ON
|
|||
|
||||
CREATE INDEX index_merge_request_diff_commits_on_sha ON merge_request_diff_commits USING btree (sha);
|
||||
|
||||
CREATE INDEX index_merge_request_diff_details_failed_verification ON merge_request_diff_details USING btree (verification_retry_at NULLS FIRST) WHERE (verification_state = 3);
|
||||
|
||||
CREATE INDEX index_merge_request_diff_details_needs_verification ON merge_request_diff_details USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3));
|
||||
|
||||
CREATE INDEX index_merge_request_diff_details_on_merge_request_diff_id ON merge_request_diff_details USING btree (merge_request_diff_id);
|
||||
|
||||
CREATE INDEX index_merge_request_diff_details_on_verification_state ON merge_request_diff_details USING btree (verification_state);
|
||||
|
||||
CREATE INDEX index_merge_request_diff_details_pending_verification ON merge_request_diff_details USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
|
||||
|
||||
CREATE INDEX index_merge_request_diffs_by_id_partial ON merge_request_diffs USING btree (id) WHERE ((files_count > 0) AND ((NOT stored_externally) OR (stored_externally IS NULL)));
|
||||
|
||||
CREATE INDEX index_merge_request_diffs_on_external_diff_store ON merge_request_diffs USING btree (external_diff_store);
|
||||
|
@ -25060,6 +25071,10 @@ CREATE INDEX tmp_idx_deduplicate_vulnerability_occurrences ON vulnerability_occu
|
|||
|
||||
CREATE INDEX tmp_idx_on_namespaces_delayed_project_removal ON namespaces USING btree (id) WHERE (delayed_project_removal = true);
|
||||
|
||||
CREATE INDEX tmp_index_namespaces_empty_traversal_ids_with_child_namespaces ON namespaces USING btree (id) WHERE ((parent_id IS NOT NULL) AND (traversal_ids = '{}'::integer[]));
|
||||
|
||||
CREATE INDEX tmp_index_namespaces_empty_traversal_ids_with_root_namespaces ON namespaces USING btree (id) WHERE ((parent_id IS NULL) AND (traversal_ids = '{}'::integer[]));
|
||||
|
||||
CREATE INDEX tmp_index_on_vulnerabilities_non_dismissed ON vulnerabilities USING btree (id) WHERE (state <> 2);
|
||||
|
||||
CREATE UNIQUE INDEX uniq_pkgs_deb_grp_architectures_on_distribution_id_and_name ON packages_debian_group_architectures USING btree (distribution_id, name);
|
||||
|
|
|
@ -199,19 +199,20 @@ inherited.
|
|||
|
||||
![CI/CD settings - inherited variables](img/inherited_group_variables_v12_5.png)
|
||||
|
||||
### Add a CI/CD variable to an instance
|
||||
### Add a CI/CD variable to an instance **(FREE SELF)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14108) in GitLab 13.0.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/299879) in GitLab 13.11.
|
||||
|
||||
To make a CI/CD variable available to all projects and groups in a GitLab instance,
|
||||
define an instance CI/CD variable.
|
||||
add an instance CI/CD variable. You must have the [Administrator role](../../user/permissions.md).
|
||||
|
||||
You can define instance variables via the UI or [API](../../api/instance_level_ci_variables.md).
|
||||
|
||||
To add an instance variable:
|
||||
|
||||
1. Navigate to your Admin Area's **Settings > CI/CD** and expand the **Variables** section.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD** and expand the **Variables** section.
|
||||
1. Select the **Add variable** button, and fill in the details:
|
||||
|
||||
- **Key**: Must be one line, with no spaces, using only letters, numbers, or `_`.
|
||||
|
@ -286,7 +287,7 @@ does not display in job logs.
|
|||
|
||||
To mask a variable:
|
||||
|
||||
1. Go to **Settings > CI/CD** in the project, group or instance admin area.
|
||||
1. In the project, group, or Admin Area, go to **Settings > CI/CD**.
|
||||
1. Expand the **Variables** section.
|
||||
1. Next to the variable you want to protect, select **Edit**.
|
||||
1. Select the **Mask variable** check box.
|
||||
|
|
|
@ -844,7 +844,7 @@ You have to use a serializer to provide a translation layer:
|
|||
|
||||
```ruby
|
||||
class BuildMetadata
|
||||
serialize :config_options, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||
serialize :config_options, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize
|
||||
end
|
||||
```
|
||||
|
||||
|
|
|
@ -259,9 +259,9 @@ it 'sets the frobulance' do
|
|||
end
|
||||
|
||||
it 'schedules a background job' do
|
||||
subject.execute
|
||||
expect(BackgroundJob).to receive(:perform_async)
|
||||
|
||||
expect(BackgroundJob).to have_enqueued_sidekiq_job
|
||||
subject.execute
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -271,11 +271,11 @@ combining the examples:
|
|||
|
||||
```ruby
|
||||
it 'performs the expected side-effects' do
|
||||
expect(BackgroundJob).to receive(:perform_async)
|
||||
|
||||
expect { subject.execute }
|
||||
.to change(Event, :count).by(1)
|
||||
.and change { arg_0.frobulance }.to('wibble')
|
||||
|
||||
expect(BackgroundJob).to have_enqueued_sidekiq_job
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -738,28 +738,6 @@ The usage of `perform_enqueued_jobs` is useful only for testing delayed mail
|
|||
deliveries, because our Sidekiq workers aren't inheriting from `ApplicationJob`
|
||||
/ `ActiveJob::Base`.
|
||||
|
||||
GitLab uses the [RSpec-Sidekiq](https://github.com/philostler/rspec-sidekiq) gem for expectations.
|
||||
We prefer you check that a job has been enqueued, rather than checking the worker has
|
||||
`received` the `perform_async` method:
|
||||
|
||||
```ruby
|
||||
# bad
|
||||
expect(Worker).to receive(:perform_async).with(1, 'string')
|
||||
# Good
|
||||
expect(Worker).to have_enqueued_sidekiq_job(1, 'string')
|
||||
```
|
||||
|
||||
The only exception to this rule: if the spec actually needs to make sure the job is
|
||||
enqueued only once, or a specific number of times:
|
||||
|
||||
```ruby
|
||||
# good
|
||||
expect(Worker).to receive(:perform_async).with(1, 'string').once
|
||||
```
|
||||
|
||||
If you need test that the job is only enqueued a specific number of times, you will have to disable the cop
|
||||
that enforces usage of `have_enqueued_sidekiq_job` (`RSpec/HaveEnqueuedSidekiqJob`) in that test.
|
||||
|
||||
#### DNS
|
||||
|
||||
DNS requests are stubbed universally in the test suite
|
||||
|
|
|
@ -80,14 +80,16 @@ section of your Prometheus Alertmanager configuration:
|
|||
|
||||
```yaml
|
||||
receivers:
|
||||
name: gitlab
|
||||
webhook_configs:
|
||||
- http_config:
|
||||
bearer_token: 9e1cbfcd546896a9ea8be557caf13a76
|
||||
send_resolved: true
|
||||
url: http://192.168.178.31:3001/root/manual_prometheus/prometheus/alerts/notify.json
|
||||
# Rest of configuration omitted
|
||||
# ...
|
||||
- name: gitlab
|
||||
webhook_configs:
|
||||
- http_config:
|
||||
authorization:
|
||||
type: Bearer
|
||||
credentials: 9e1cbfcd546896a9ea8be557caf13a76
|
||||
send_resolved: true
|
||||
url: http://192.168.178.31:3001/root/manual_prometheus/prometheus/alerts/notify.json
|
||||
# Rest of configuration omitted
|
||||
# ...
|
||||
```
|
||||
|
||||
For GitLab to associate your alerts with an [environment](../../ci/environments/index.md),
|
||||
|
|
|
@ -7,7 +7,8 @@ type: reference, howto
|
|||
|
||||
# Project Import Decompressed Archive Size Limits
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31564) in GitLab 13.2.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31564) in GitLab 13.2.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63025) in GitLab 14.0.
|
||||
|
||||
When using [Project Import](../user/project/settings/import_export.md), the size of the decompressed project archive is limited to 10Gb.
|
||||
|
||||
|
@ -15,7 +16,6 @@ If decompressed size exceeds this limit, `Decompressed archive size validation f
|
|||
|
||||
## Enable/disable size validation
|
||||
|
||||
Decompressed size validation is enabled by default.
|
||||
If you have a project with decompressed size exceeding this limit,
|
||||
it is possible to disable the validation by turning off the
|
||||
`validate_import_decompressed_archive_size` feature flag.
|
||||
|
|
|
@ -116,14 +116,16 @@ If your Auto DevOps project has an active environment that was deployed with the
|
|||
1. If the deployment succeeds, you can safely run `environment:helm-2to3:cleanup`.
|
||||
This deletes all Helm 2 release data from the namespace.
|
||||
|
||||
If you set `BACKUP_HELM2_RELEASES` to a non-empty value, then the
|
||||
the `<environment-name>:helm2to3:migrate` job
|
||||
If you set `BACKUP_HELM2_RELEASES` to a non-empty value, the `<environment-name>:helm2to3:migrate`
|
||||
job saves a backup for 1 week in a job artifact called `helm-2-release-backups`.
|
||||
If you accidentally delete the Helm 2 releases before you are ready, then
|
||||
this backup is in a Kubernetes manifest file that can be restored using
|
||||
`kubectl apply -f $backup`.
|
||||
**WARNING:** This artifact can contain secrets and will be visible to any
|
||||
user who can see your job.
|
||||
`kubectl apply -f $backup`.
|
||||
|
||||
**WARNING:**
|
||||
This artifact can contain secrets and is visible to any
|
||||
user who can see your job.
|
||||
|
||||
1. Remove the `MIGRATE_HELM_2TO3` CI/CD variable.
|
||||
|
||||
#### In-Cluster PostgreSQL Channel 2
|
||||
|
|
|
@ -5,18 +5,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: reference
|
||||
---
|
||||
|
||||
# Continuous Integration and Deployment Admin settings **(FREE SELF)**
|
||||
# Continuous Integration and Deployment Admin Area settings **(FREE SELF)**
|
||||
|
||||
In this area, you will find settings for Auto DevOps, runners, and job artifacts.
|
||||
You can find it in the [Admin Area](index.md) by navigating to
|
||||
**Admin Area > Settings > CI/CD**.
|
||||
The [Admin Area](index.md) has the instance settings for Auto DevOps, runners, and
|
||||
job artifacts.
|
||||
|
||||
## Auto DevOps **(FREE SELF)**
|
||||
## Auto DevOps
|
||||
|
||||
To enable (or disable) [Auto DevOps](../../../topics/autodevops/index.md)
|
||||
for all projects:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Check (or uncheck to disable) the box that says **Default to Auto DevOps pipeline for all projects**.
|
||||
1. Optionally, set up the [Auto DevOps base domain](../../../topics/autodevops/index.md#auto-devops-base-domain)
|
||||
which is used for Auto Deploy and Auto Review Apps.
|
||||
|
@ -28,7 +28,7 @@ From now on, every existing project and newly created ones that don't have a
|
|||
If you want to disable it for a specific project, you can do so in
|
||||
[its settings](../../../topics/autodevops/index.md#enable-or-disable-auto-devops).
|
||||
|
||||
## Maximum artifacts size **(FREE SELF)**
|
||||
## Maximum artifacts size
|
||||
|
||||
The maximum size of the [job artifacts](../../../administration/job_artifacts.md)
|
||||
can be set at:
|
||||
|
@ -45,9 +45,10 @@ To change it at the:
|
|||
|
||||
- Instance level:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. Change the value of maximum artifacts size (in MB).
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Change the value of maximum artifacts size (in MB).
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
- Group level (this overrides the instance setting):
|
||||
|
||||
|
@ -64,14 +65,15 @@ To change it at the:
|
|||
NOTE:
|
||||
The setting at all levels is only available to GitLab administrators.
|
||||
|
||||
## Default artifacts expiration **(FREE SELF)**
|
||||
## Default artifacts expiration
|
||||
|
||||
The default expiration time of the [job artifacts](../../../administration/job_artifacts.md)
|
||||
can be set in the Admin Area of your GitLab instance. The syntax of duration is
|
||||
described in [`artifacts:expire_in`](../../../ci/yaml/README.md#artifactsexpire_in)
|
||||
and the default value is `30 days`.
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Change the value of default expiration time.
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
|
@ -85,9 +87,9 @@ be updated for artifacts created before this setting was changed.
|
|||
The administrator may need to manually search for and expire previously-created
|
||||
artifacts, as described in the [troubleshooting documentation](../../../administration/troubleshooting/gitlab_rails_cheat_sheet.md#remove-artifacts-more-than-a-week-old).
|
||||
|
||||
## Keep the latest artifacts for all jobs in the latest successful pipelines **(CORE ONLY)**
|
||||
## Keep the latest artifacts for all jobs in the latest successful pipelines
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50889) in GitLab Core 13.9.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50889) in GitLab 13.9.
|
||||
|
||||
When enabled (default), the artifacts of the most recent pipeline for each Git ref
|
||||
([branches and tags](https://git-scm.com/book/en/v2/Git-Internals-Git-References))
|
||||
|
@ -101,7 +103,8 @@ If disabled at the instance level, you cannot enable this per-project.
|
|||
|
||||
To disable the setting:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Continuous Integration and Deployment**.
|
||||
1. Clear the **Keep the latest artifacts for all jobs in the latest successful pipelines** checkbox.
|
||||
1. Click **Save changes**
|
||||
|
@ -126,14 +129,13 @@ On GitLab.com, the quota is calculated based on your
|
|||
|
||||
To change the pipelines minutes quota:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Continuous Integration and Deployment**.
|
||||
1. In the **Pipeline minutes quota** box, enter the maximum number of minutes.
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
While the setting in the Admin Area has a global effect, as an admin you can
|
||||
While the setting in the Admin Area has a global effect, as an administrator you can
|
||||
also change each group's pipeline minutes quota to override the global value.
|
||||
|
||||
1. Navigate to the **Admin Area > Overview > Groups** and hit the **Edit**
|
||||
|
@ -141,8 +143,8 @@ also change each group's pipeline minutes quota to override the global value.
|
|||
1. In the **Pipeline Minutes Quota** box, enter the maximum number of minutes.
|
||||
1. Click **Save changes** for the changes to take effect.
|
||||
|
||||
Once saved, you can see the build quota in the group admin view.
|
||||
The quota can also be viewed in the project admin view if shared runners
|
||||
Once saved, you can see the build quota in the group settings.
|
||||
The quota can also be viewed in the project settings if shared runners
|
||||
are enabled.
|
||||
|
||||
![Project admin information](img/admin_project_quota_view.png)
|
||||
|
@ -152,7 +154,7 @@ a group in the **Usage Quotas** page available to the group page settings list.
|
|||
|
||||
![Group pipelines quota](img/group_pipelines_quota.png)
|
||||
|
||||
## Archive jobs **(FREE SELF)**
|
||||
## Archive jobs
|
||||
|
||||
Archiving jobs is useful for reducing the CI/CD footprint on the system by
|
||||
removing some of the capabilities of the jobs (metadata needed to run the job),
|
||||
|
@ -160,12 +162,13 @@ but persisting the traces and artifacts for auditing purposes.
|
|||
|
||||
To set the duration for which the jobs are considered as old and expired:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand the **Continuous Integration and Deployment** section.
|
||||
1. Set the value of **Archive jobs**.
|
||||
1. Hit **Save changes** for the changes to take effect.
|
||||
|
||||
Once that time passes, the jobs are archived and no longer able to be
|
||||
After that time passes, the jobs are archived and no longer able to be
|
||||
retried. Make it empty to never expire jobs. It has to be no less than 1 day,
|
||||
for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>.
|
||||
|
||||
|
@ -178,7 +181,8 @@ As of June 22, 2020 the [value is set](../../gitlab_com/index.md#gitlab-cicd) to
|
|||
The default CI configuration file path for new projects can be set in the Admin
|
||||
Area of your GitLab instance (`.gitlab-ci.yml` if not set):
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Admin Area > Settings > CI/CD**.
|
||||
1. Input the new path in the **Default CI configuration path** field.
|
||||
1. Hit **Save changes** for the changes to take effect.
|
||||
|
||||
|
@ -213,7 +217,8 @@ in the pipeline editor.
|
|||
|
||||
To select a CI/CD template for the required pipeline configuration:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand the **Required pipeline configuration** section.
|
||||
1. Select a CI/CD template from the dropdown.
|
||||
1. Click **Save changes**.
|
||||
|
@ -226,7 +231,8 @@ GitLab administrators can disable the forwarding of npm requests to [npmjs.com](
|
|||
|
||||
To disable it:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand the **Package Registry** section.
|
||||
1. Uncheck **Enable forwarding of npm package requests to npmjs.org**.
|
||||
1. Click **Save changes**.
|
||||
|
@ -239,7 +245,8 @@ GitLab administrators can adjust the maximum allowed file size for each package
|
|||
|
||||
To set the maximum file size:
|
||||
|
||||
1. Go to **Admin Area > Settings > CI/CD**.
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand the **Package Registry** section.
|
||||
1. Find the package type you would like to adjust.
|
||||
1. Enter the maximum file size, in bytes.
|
||||
|
|
|
@ -118,6 +118,9 @@ The **Packages & Registries > Package Registry** entry is removed from the sideb
|
|||
|
||||
## Package workflows
|
||||
|
||||
Learn how to use the GitLab Package Registry to build your own custom package workflow.
|
||||
Learn how to use the GitLab Package Registry to build your own custom package workflow:
|
||||
|
||||
- [Use a project as a package registry](../workflows/project_registry.md) to publish all of your packages to one project.
|
||||
- [Use a project as a package registry](../workflows/project_registry.md)
|
||||
to publish all of your packages to one project.
|
||||
|
||||
- Publish multiple different packages from one [monorepo project](../workflows/working_with_monorepos.md).
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
stage: Package
|
||||
group: Package
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Monorepo package management workflows
|
||||
|
||||
One project or Git repository can contain multiple different subprojects or submodules that are all
|
||||
packaged and published individually.
|
||||
|
||||
## Publishing different packages to the parent project
|
||||
|
||||
The number and name of packages you can publish to one project is not limited.
|
||||
You can accomplish this by setting up different configuration files for each
|
||||
package. See the documentation for the package manager of your choice since
|
||||
each has its own specific files and instructions to follow to publish
|
||||
a given package.
|
||||
|
||||
The example here uses [NPM](../npm_registry/index.md).
|
||||
In this example, `MyProject` is the parent project. It contains a sub-project `Foo` in the
|
||||
`components` directory:
|
||||
|
||||
```plaintext
|
||||
MyProject/
|
||||
|- src/
|
||||
| |- components/
|
||||
| |- Foo/
|
||||
|- package.json
|
||||
```
|
||||
|
||||
The goal is to publish the packages for `MyProject` and `Foo`. Following the instructions in the
|
||||
[GitLab NPM registry documentation](../npm_registry/index.md),
|
||||
you can publish `MyProject` by modifying the `package.json` file with a `publishConfig` section,
|
||||
and by doing one of the following:
|
||||
|
||||
- Modify your local NPM configuration with CLI commands like `npm config set`.
|
||||
- Save a `.npmrc` file in the root of the project specifying these configuration settings.
|
||||
|
||||
If you follow the instructions, you can publish `MyProject` by running `npm publish` from the root
|
||||
directory.
|
||||
|
||||
Publishing `Foo` is almost exactly the same. Simply follow the same steps while in the `Foo`
|
||||
directory. `Foo` needs its own `package.json` file, which you can add manually by using `npm init`.
|
||||
`Foo` also needs its own configuration settings. Since you are publishing to the same place, if you
|
||||
used `npm config set` to set the registry for the parent project, then no additional setup is
|
||||
necessary. If you used an `.npmrc` file, you need an additional `.npmrc` file in the `Foo` directory.
|
||||
Be sure to add `.npmrc` files to the `.gitignore` file or use environment variables in place of your
|
||||
access tokens to prevent your tokens from being exposed. This `.npmrc` file can be identical to the
|
||||
one you used in `MyProject`. You can now run `npm publish` from the `Foo` directory and you can
|
||||
publish `Foo` separately from `MyProject`.
|
||||
|
||||
You could follow a similar process for Conan packages. However, instead of `.npmrc` and
|
||||
`package.json`, you have `conanfile.py` in multiple locations within the project.
|
||||
|
||||
## Publishing to other projects
|
||||
|
||||
A package is associated with a project on GitLab, but the package does not need to be associated
|
||||
with the code in that project. When configuring NPM or Maven, you only use the `Project ID` to set
|
||||
the registry URL that the package uploads to. If you set this to any project that you have access to
|
||||
and update any other configuration similarly depending on the package type, your packages are
|
||||
published to that project. This means you can publish multiple packages to one project, even if
|
||||
their code does not exist in the same place. See the [project registry workflow documentation](project_registry.md)
|
||||
for more information.
|
|
@ -454,33 +454,32 @@ NOTE:
|
|||
In GitLab 11.0, the Master role was renamed to Maintainer.
|
||||
|
||||
GitLab CI/CD permissions rely on the role the user has in GitLab. There are four
|
||||
permission levels in total:
|
||||
roles:
|
||||
|
||||
- admin
|
||||
- maintainer
|
||||
- developer
|
||||
- guest/reporter
|
||||
- Administrator
|
||||
- Maintainer
|
||||
- Developer
|
||||
- Guest/Reporter
|
||||
|
||||
The admin user can perform any action on GitLab CI/CD in scope of the GitLab
|
||||
instance and project. In addition, all admins can use the admin interface under
|
||||
`/admin/runners`.
|
||||
The Administrator role can perform any action on GitLab CI/CD in scope of the GitLab
|
||||
instance and project.
|
||||
|
||||
| Action | Guest, Reporter | Developer |Maintainer| Admin |
|
||||
|---------------------------------------|-----------------|-------------|----------|--------|
|
||||
| See commits and jobs | ✓ | ✓ | ✓ | ✓ |
|
||||
| Retry or cancel job | | ✓ | ✓ | ✓ |
|
||||
| Erase job artifacts and job logs | | ✓ (*1*) | ✓ | ✓ |
|
||||
| Delete project | | | ✓ | ✓ |
|
||||
| Create project | | | ✓ | ✓ |
|
||||
| Change project configuration | | | ✓ | ✓ |
|
||||
| Add specific runners | | | ✓ | ✓ |
|
||||
| Add shared runners | | | | ✓ |
|
||||
| See events in the system | | | | ✓ |
|
||||
| Admin interface | | | | ✓ |
|
||||
| Action | Guest, Reporter | Developer |Maintainer| Administrator |
|
||||
|---------------------------------------|-----------------|-------------|----------|---------------|
|
||||
| See commits and jobs | ✓ | ✓ | ✓ | ✓ |
|
||||
| Retry or cancel job | | ✓ | ✓ | ✓ |
|
||||
| Erase job artifacts and job logs | | ✓ (*1*) | ✓ | ✓ |
|
||||
| Delete project | | | ✓ | ✓ |
|
||||
| Create project | | | ✓ | ✓ |
|
||||
| Change project configuration | | | ✓ | ✓ |
|
||||
| Add specific runners | | | ✓ | ✓ |
|
||||
| Add shared runners | | | | ✓ |
|
||||
| See events in the system | | | | ✓ |
|
||||
| Admin Area | | | | ✓ |
|
||||
|
||||
1. Only if the job was:
|
||||
- Triggered by the user
|
||||
- [In GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/35069) and later, not run for a protected branch
|
||||
- [In GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/35069) and later, run for a non-protected branch.
|
||||
|
||||
### Job permissions
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ module BulkImports
|
|||
end
|
||||
|
||||
def ndjson_reader(tmp_dir)
|
||||
@ndjson_reader ||= Gitlab::ImportExport::JSON::NdjsonReader.new(tmp_dir)
|
||||
@ndjson_reader ||= Gitlab::ImportExport::Json::NdjsonReader.new(tmp_dir)
|
||||
end
|
||||
|
||||
def relative_resource_url(context)
|
||||
|
|
|
@ -6,6 +6,10 @@ module Gitlab
|
|||
VALID_SYNTAX_SAMPLE_TIME_ZONE = 'UTC'
|
||||
VALID_SYNTAX_SAMPLE_CRON = '* * * * *'
|
||||
|
||||
def self.parse_natural(expression, cron_timezone = 'UTC')
|
||||
new(Fugit::Nat.parse(expression)&.original, cron_timezone)
|
||||
end
|
||||
|
||||
def initialize(cron, cron_timezone = 'UTC')
|
||||
@cron = cron
|
||||
@cron_timezone = timezone_name(cron_timezone)
|
||||
|
@ -27,6 +31,10 @@ module Gitlab
|
|||
try_parse_cron(VALID_SYNTAX_SAMPLE_CRON, @cron_timezone).present?
|
||||
end
|
||||
|
||||
def match?(time)
|
||||
cron_line.match?(time)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def timezone_name(timezone)
|
||||
|
|
|
@ -28,9 +28,7 @@ module Gitlab
|
|||
copy_archive
|
||||
|
||||
wait_for_archived_file do
|
||||
# Disable archive validation by default
|
||||
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/235949
|
||||
validate_decompressed_archive_size if Feature.enabled?(:validate_import_decompressed_archive_size)
|
||||
validate_decompressed_archive_size if Feature.enabled?(:validate_import_decompressed_archive_size, default_enabled: :yaml)
|
||||
decompress_archive
|
||||
end
|
||||
rescue StandardError => e
|
||||
|
|
|
@ -55,11 +55,11 @@ module Gitlab
|
|||
def relation_reader
|
||||
strong_memoize(:relation_reader) do
|
||||
if @group_hash.present?
|
||||
ImportExport::JSON::LegacyReader::Hash.new(
|
||||
ImportExport::Json::LegacyReader::Hash.new(
|
||||
@group_hash,
|
||||
relation_names: reader.group_relation_names)
|
||||
else
|
||||
ImportExport::JSON::LegacyReader::File.new(
|
||||
ImportExport::Json::LegacyReader::File.new(
|
||||
File.join(shared.export_path, 'group.json'),
|
||||
relation_names: reader.group_relation_names)
|
||||
end
|
||||
|
|
|
@ -118,7 +118,7 @@ module Gitlab
|
|||
|
||||
def relation_reader
|
||||
strong_memoize(:relation_reader) do
|
||||
ImportExport::JSON::NdjsonReader.new(
|
||||
ImportExport::Json::NdjsonReader.new(
|
||||
File.join(shared.export_path, 'tree')
|
||||
)
|
||||
end
|
||||
|
|
|
@ -42,7 +42,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def serialize(group)
|
||||
ImportExport::JSON::StreamingSerializer.new(
|
||||
ImportExport::Json::StreamingSerializer.new(
|
||||
group,
|
||||
group_tree,
|
||||
json_writer,
|
||||
|
@ -64,7 +64,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def json_writer
|
||||
@json_writer ||= ImportExport::JSON::NdjsonWriter.new(@full_path)
|
||||
@json_writer ||= ImportExport::Json::NdjsonWriter.new(@full_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Gitlab
|
||||
module ImportExport
|
||||
module JSON
|
||||
module Json
|
||||
class LegacyReader
|
||||
class File < LegacyReader
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Gitlab
|
||||
module ImportExport
|
||||
module JSON
|
||||
module Json
|
||||
class LegacyWriter
|
||||
include Gitlab::ImportExport::CommandLineUtil
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Gitlab
|
||||
module ImportExport
|
||||
module JSON
|
||||
module Json
|
||||
class NdjsonReader
|
||||
MAX_JSON_DOCUMENT_SIZE = 50.megabytes
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Gitlab
|
||||
module ImportExport
|
||||
module JSON
|
||||
module Json
|
||||
class NdjsonWriter
|
||||
include Gitlab::ImportExport::CommandLineUtil
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Gitlab
|
||||
module ImportExport
|
||||
module JSON
|
||||
module Json
|
||||
class StreamingSerializer
|
||||
include Gitlab::ImportExport::CommandLineUtil
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ module Gitlab
|
|||
private
|
||||
|
||||
def batch_size(exportable)
|
||||
Gitlab::ImportExport::JSON::StreamingSerializer.batch_size(exportable)
|
||||
Gitlab::ImportExport::Json::StreamingSerializer.batch_size(exportable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,13 +56,13 @@ module Gitlab
|
|||
def ndjson_relation_reader
|
||||
return unless Feature.enabled?(:project_import_ndjson, project.namespace, default_enabled: true)
|
||||
|
||||
ImportExport::JSON::NdjsonReader.new(
|
||||
ImportExport::Json::NdjsonReader.new(
|
||||
File.join(shared.export_path, 'tree')
|
||||
)
|
||||
end
|
||||
|
||||
def legacy_relation_reader
|
||||
ImportExport::JSON::LegacyReader::File.new(
|
||||
ImportExport::Json::LegacyReader::File.new(
|
||||
File.join(shared.export_path, 'project.json'),
|
||||
relation_names: reader.project_relation_names,
|
||||
allowed_path: importable_path
|
||||
|
|
|
@ -14,7 +14,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def save
|
||||
ImportExport::JSON::StreamingSerializer.new(
|
||||
ImportExport::Json::StreamingSerializer.new(
|
||||
exportable,
|
||||
reader.project_tree,
|
||||
json_writer,
|
||||
|
@ -56,10 +56,10 @@ module Gitlab
|
|||
@json_writer ||= begin
|
||||
if ::Feature.enabled?(:project_export_as_ndjson, @project.namespace, default_enabled: true)
|
||||
full_path = File.join(@shared.export_path, 'tree')
|
||||
Gitlab::ImportExport::JSON::NdjsonWriter.new(full_path)
|
||||
Gitlab::ImportExport::Json::NdjsonWriter.new(full_path)
|
||||
else
|
||||
full_path = File.join(@shared.export_path, ImportExport.project_filename)
|
||||
Gitlab::ImportExport::JSON::LegacyWriter.new(full_path, allowed_path: 'project')
|
||||
Gitlab::ImportExport::Json::LegacyWriter.new(full_path, allowed_path: 'project')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ module Gitlab
|
|||
# this is already :/. We could also take a hash and manually check every
|
||||
# entry, but it's much more maintainable to do rely on native Ruby.
|
||||
# rubocop: disable Metrics/ParameterLists
|
||||
def self.build(id:, title:, active: false, icon: '', href: '', view: '', css_class: nil, data: {}, emoji: nil)
|
||||
def self.build(id:, title:, active: false, icon: '', href: '', view: '', css_class: nil, data: nil, emoji: nil)
|
||||
{
|
||||
id: id,
|
||||
title: title,
|
||||
|
@ -17,7 +17,7 @@ module Gitlab
|
|||
href: href,
|
||||
view: view.to_s,
|
||||
css_class: css_class,
|
||||
data: data,
|
||||
data: data || { qa_selector: 'menu_item_link', qa_title: title },
|
||||
emoji: emoji
|
||||
}
|
||||
end
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
module Security
|
||||
module CiConfiguration
|
||||
class SastBuildAction < BaseBuildAction
|
||||
SAST_DEFAULT_ANALYZERS = 'bandit, brakeman, eslint, flawfinder, gosec, kubesec, nodejs-scan, phpcs-security-audit, pmd-apex, security-code-scan, semgrep, sobelow, spotbugs'
|
||||
|
||||
def initialize(auto_devops_enabled, params, existing_gitlab_ci_content)
|
||||
super(auto_devops_enabled, existing_gitlab_ci_content)
|
||||
@variables = variables(params)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Serializers
|
||||
# Make the resulting hash have deep indifferent access
|
||||
class JSON
|
||||
class Json
|
||||
class << self
|
||||
def dump(obj)
|
||||
obj
|
||||
|
|
|
@ -3501,6 +3501,9 @@ msgstr ""
|
|||
msgid "An error occurred while enabling Service Desk."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while fetching ancestors"
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while fetching branches. Retry the search."
|
||||
msgstr ""
|
||||
|
||||
|
@ -8943,6 +8946,9 @@ msgstr ""
|
|||
msgid "Copy ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy IP Address"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy KRB5 clone URL"
|
||||
msgstr ""
|
||||
|
||||
|
@ -28150,6 +28156,9 @@ msgstr ""
|
|||
msgid "Runners|Download latest binary"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|IP Address"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -60,6 +60,10 @@ module QA
|
|||
|
||||
click_element(:connect_instance_button)
|
||||
end
|
||||
|
||||
def switch_to_import_tab
|
||||
click_element("import-group-pane_link")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,25 +19,23 @@ module QA
|
|||
element :todos_shortcut_button, required: true
|
||||
end
|
||||
|
||||
view 'app/views/layouts/nav/_dashboard.html.haml' do
|
||||
view 'app/assets/javascripts/nav/components/top_nav_app.vue' do
|
||||
element :navbar_dropdown
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/nav/components/top_nav_dropdown_menu.vue' do
|
||||
element :menu_subview_container
|
||||
end
|
||||
|
||||
view 'lib/gitlab/nav/top_nav_menu_item.rb' do
|
||||
element :menu_item_link
|
||||
end
|
||||
|
||||
view 'app/helpers/nav/top_nav_helper.rb' do
|
||||
element :admin_area_link
|
||||
element :projects_dropdown, required: true
|
||||
element :groups_dropdown, required: true
|
||||
element :more_dropdown
|
||||
element :projects_dropdown
|
||||
element :groups_dropdown
|
||||
element :snippets_link
|
||||
element :groups_link
|
||||
element :activity_link
|
||||
element :milestones_link
|
||||
end
|
||||
|
||||
view 'app/views/layouts/nav/projects_dropdown/_show.html.haml' do
|
||||
element :projects_dropdown_sidebar
|
||||
element :your_projects_link
|
||||
end
|
||||
|
||||
view 'app/views/layouts/nav/groups_dropdown/_show.html.haml' do
|
||||
element :create_group_link
|
||||
element :import_group_link
|
||||
end
|
||||
|
||||
view 'app/views/layouts/_search.html.haml' do
|
||||
|
@ -46,30 +44,28 @@ module QA
|
|||
|
||||
def go_to_groups
|
||||
within_groups_menu do
|
||||
click_element :your_groups_link
|
||||
click_element(:menu_item_link, title: 'Your groups')
|
||||
end
|
||||
end
|
||||
|
||||
def go_to_import_group
|
||||
def go_to_create_group
|
||||
within_groups_menu do
|
||||
click_element :import_group_link
|
||||
click_element(:menu_item_link, title: 'Create group')
|
||||
end
|
||||
end
|
||||
|
||||
def go_to_projects
|
||||
within_top_menu do
|
||||
click_element :projects_dropdown
|
||||
end
|
||||
go_to_menu_dropdown_option(:projects_dropdown)
|
||||
|
||||
page.within('.qa-projects-dropdown-sidebar') do
|
||||
click_element :your_projects_link
|
||||
within_element(:menu_subview_container) do
|
||||
click_element(:menu_item_link, title: 'Your projects')
|
||||
end
|
||||
end
|
||||
|
||||
def go_to_more_dropdown_option(option_name)
|
||||
def go_to_menu_dropdown_option(option_name)
|
||||
within_top_menu do
|
||||
click_element :more_dropdown
|
||||
click_element option_name
|
||||
click_element(:navbar_dropdown, title: 'Menu')
|
||||
click_element(option_name)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -151,11 +147,17 @@ module QA
|
|||
end
|
||||
|
||||
def has_admin_area_link?(wait: Capybara.default_max_wait_time)
|
||||
has_element?(:admin_area_link, wait: wait)
|
||||
within_top_menu do
|
||||
click_element(:navbar_dropdown, title: 'Menu')
|
||||
has_element?(:admin_area_link, wait: wait)
|
||||
end
|
||||
end
|
||||
|
||||
def has_no_admin_area_link?(wait: Capybara.default_max_wait_time)
|
||||
has_no_element?(:admin_area_link, wait: wait)
|
||||
within_top_menu do
|
||||
click_element(:navbar_dropdown, title: 'Menu')
|
||||
has_no_element?(:admin_area_link, wait: wait)
|
||||
end
|
||||
end
|
||||
|
||||
def click_stop_impersonation_link
|
||||
|
@ -181,15 +183,13 @@ module QA
|
|||
end
|
||||
|
||||
def within_groups_menu(&block)
|
||||
within_top_menu do
|
||||
click_element :groups_dropdown
|
||||
end
|
||||
go_to_menu_dropdown_option(:groups_dropdown)
|
||||
|
||||
page.within('.qa-groups-dropdown-sidebar', &block)
|
||||
within_element(:menu_subview_container, &block)
|
||||
end
|
||||
|
||||
def click_admin_area
|
||||
within_top_menu { click_element :admin_area_link }
|
||||
go_to_menu_dropdown_option(:admin_area_link)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -64,8 +64,11 @@ module QA
|
|||
sandbox.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
|
||||
|
||||
Flow::Login.sign_in(as: user)
|
||||
Page::Main::Menu.new.go_to_import_group
|
||||
Page::Group::New.new.connect_gitlab_instance(Runtime::Scenario.gitlab_address, personal_access_token)
|
||||
Page::Main::Menu.perform(&:go_to_create_group)
|
||||
Page::Group::New.perform do |group|
|
||||
group.switch_to_import_tab
|
||||
group.connect_gitlab_instance(Runtime::Scenario.gitlab_address, personal_access_token)
|
||||
end
|
||||
end
|
||||
|
||||
# Non blocking issues:
|
||||
|
|
|
@ -7,7 +7,7 @@ module QA
|
|||
Flow::Login.sign_in
|
||||
|
||||
Page::Main::Menu.perform do |menu|
|
||||
menu.go_to_more_dropdown_option(:snippets_link)
|
||||
menu.go_to_menu_dropdown_option(:snippets_link)
|
||||
end
|
||||
|
||||
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
|
||||
|
|
|
@ -7,7 +7,7 @@ module QA
|
|||
Flow::Login.sign_in
|
||||
|
||||
Page::Main::Menu.perform do |menu|
|
||||
menu.go_to_more_dropdown_option(:snippets_link)
|
||||
menu.go_to_menu_dropdown_option(:snippets_link)
|
||||
end
|
||||
|
||||
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
|
||||
|
|
|
@ -60,7 +60,7 @@ module QA
|
|||
it "shows correct details of #{snippet_type} including file number" do
|
||||
send(snippet_type)
|
||||
Page::Main::Menu.perform do |menu|
|
||||
menu.go_to_more_dropdown_option(:snippets_link)
|
||||
menu.go_to_menu_dropdown_option(:snippets_link)
|
||||
end
|
||||
|
||||
Page::Dashboard::Snippet::Index.perform do |snippet|
|
||||
|
|
|
@ -32,59 +32,79 @@ module RuboCop
|
|||
|
||||
# Returns true if the given node resides in app/finders or ee/app/finders.
|
||||
def in_finder?(node)
|
||||
in_directory?(node, 'finders')
|
||||
in_app_directory?(node, 'finders')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in app/models or ee/app/models.
|
||||
def in_model?(node)
|
||||
in_directory?(node, 'models')
|
||||
in_app_directory?(node, 'models')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in app/services or ee/app/services.
|
||||
def in_service_class?(node)
|
||||
in_directory?(node, 'services')
|
||||
in_app_directory?(node, 'services')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in app/presenters or
|
||||
# ee/app/presenters.
|
||||
def in_presenter?(node)
|
||||
in_directory?(node, 'presenters')
|
||||
in_app_directory?(node, 'presenters')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in app/serializers or
|
||||
# ee/app/serializers.
|
||||
def in_serializer?(node)
|
||||
in_directory?(node, 'serializers')
|
||||
in_app_directory?(node, 'serializers')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in app/workers or ee/app/workers.
|
||||
def in_worker?(node)
|
||||
in_directory?(node, 'workers')
|
||||
in_app_directory?(node, 'workers')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in app/controllers or
|
||||
# ee/app/controllers.
|
||||
def in_controller?(node)
|
||||
in_directory?(node, 'controllers')
|
||||
in_app_directory?(node, 'controllers')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in app/graphql/types,
|
||||
# ee/app/graphql/types, or ee/app/graphql/ee/types.
|
||||
def in_graphql_types?(node)
|
||||
in_app_directory?(node, 'graphql/types') || in_app_directory?(node, 'graphql/ee/types')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in lib/api or ee/lib/api.
|
||||
def in_api?(node)
|
||||
in_lib_directory?(node, 'api')
|
||||
end
|
||||
|
||||
# Returns true if the given node resides in spec or ee/spec.
|
||||
def in_spec?(node)
|
||||
file_path_for_node(node).start_with?(
|
||||
File.join(ce_lib_directory, 'api'),
|
||||
File.join(ee_lib_directory, 'api')
|
||||
ce_spec_directory,
|
||||
ee_spec_directory
|
||||
)
|
||||
end
|
||||
|
||||
# Returns `true` if the given AST node resides in the given directory,
|
||||
# relative to app and/or ee/app.
|
||||
def in_directory?(node, directory)
|
||||
def in_app_directory?(node, directory)
|
||||
file_path_for_node(node).start_with?(
|
||||
File.join(ce_app_directory, directory),
|
||||
File.join(ee_app_directory, directory)
|
||||
)
|
||||
end
|
||||
|
||||
# Returns `true` if the given AST node resides in the given directory,
|
||||
# relative to lib and/or ee/lib.
|
||||
def in_lib_directory?(node, directory)
|
||||
file_path_for_node(node).start_with?(
|
||||
File.join(ce_lib_directory, directory),
|
||||
File.join(ee_lib_directory, directory)
|
||||
)
|
||||
end
|
||||
|
||||
# Returns the receiver name of a send node.
|
||||
#
|
||||
# For the AST node `(send (const nil? :Foo) ...)` this would return
|
||||
|
@ -149,6 +169,14 @@ module RuboCop
|
|||
File.join(rails_root, 'ee', 'lib')
|
||||
end
|
||||
|
||||
def ce_spec_directory
|
||||
File.join(rails_root, 'spec')
|
||||
end
|
||||
|
||||
def ee_spec_directory
|
||||
File.join(rails_root, 'ee', 'spec')
|
||||
end
|
||||
|
||||
def rails_root
|
||||
File.expand_path('..', __dir__)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../code_reuse_helpers'
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Gitlab
|
||||
# This cop tracks the usage of feature flags among the codebase.
|
||||
#
|
||||
# The files set in `tmp/feature_flags/*.used` can then be used for verification purpose.
|
||||
#
|
||||
class MarkUsedFeatureFlags < RuboCop::Cop::Cop
|
||||
include RuboCop::CodeReuseHelpers
|
||||
|
||||
FEATURE_METHODS = %i[enabled? disabled?].freeze
|
||||
EXPERIMENTATION_METHODS = %i[active?].freeze
|
||||
EXPERIMENT_METHODS = %i[
|
||||
experiment
|
||||
experiment_enabled?
|
||||
push_frontend_experiment
|
||||
].freeze
|
||||
RUGGED_METHODS = %i[
|
||||
use_rugged?
|
||||
].freeze
|
||||
WORKER_METHODS = %i[
|
||||
data_consistency
|
||||
].freeze
|
||||
GRAPHQL_METHODS = %i[
|
||||
field
|
||||
].freeze
|
||||
SELF_METHODS = %i[
|
||||
push_frontend_feature_flag
|
||||
limit_feature_flag=
|
||||
].freeze + EXPERIMENT_METHODS + RUGGED_METHODS + WORKER_METHODS
|
||||
|
||||
RESTRICT_ON_SEND = FEATURE_METHODS + EXPERIMENTATION_METHODS + GRAPHQL_METHODS + SELF_METHODS
|
||||
|
||||
USAGE_DATA_COUNTERS_EVENTS_YAML_GLOBS = [
|
||||
File.expand_path("../../../config/metrics/aggregates/*.yml", __dir__),
|
||||
File.expand_path("../../../lib/gitlab/usage_data_counters/known_events/*.yml", __dir__)
|
||||
].freeze
|
||||
|
||||
DYNAMIC_FEATURE_FLAGS = [
|
||||
:usage_data_static_site_editor_commits, # https://gitlab.com/gitlab-org/gitlab/-/issues/284082
|
||||
:usage_data_static_site_editor_merge_requests # https://gitlab.com/gitlab-org/gitlab/-/issues/284083
|
||||
].freeze
|
||||
|
||||
# Called before all on_... have been called
|
||||
# When refining this method, always call `super`
|
||||
def on_new_investigation
|
||||
super
|
||||
track_dynamic_feature_flags!
|
||||
track_usage_data_counters_known_events!
|
||||
end
|
||||
|
||||
def on_casgn(node)
|
||||
_, lhs_name, rhs = *node
|
||||
|
||||
save_used_feature_flag(rhs.value) if lhs_name == :FEATURE_FLAG
|
||||
end
|
||||
|
||||
def on_send(node)
|
||||
return if in_spec?(node)
|
||||
return unless trackable_flag?(node)
|
||||
|
||||
flag_arg = flag_arg(node)
|
||||
flag_value = flag_value(node)
|
||||
return unless flag_value
|
||||
|
||||
if flag_arg_is_str_or_sym?(node)
|
||||
if caller_is_feature_gitaly?(node)
|
||||
save_used_feature_flag("gitaly_#{flag_value}")
|
||||
else
|
||||
save_used_feature_flag(flag_value)
|
||||
end
|
||||
|
||||
if experiment_method?(node) || experimentation_method?(node)
|
||||
# Additionally, mark experiment-related feature flag as used as well
|
||||
matching_feature_flags = defined_feature_flags.select { |flag| flag == "#{flag_value}_experiment_percentage" }
|
||||
matching_feature_flags.each do |matching_feature_flag|
|
||||
puts_if_ci(node, "The '#{matching_feature_flag}' feature flag tracks the #{flag_value} experiment, which is still in use, so we'll mark it as used.")
|
||||
save_used_feature_flag(matching_feature_flag)
|
||||
end
|
||||
end
|
||||
elsif flag_arg_is_send_type?(node)
|
||||
puts_if_ci(node, "Feature flag is dynamic: '#{flag_value}.")
|
||||
elsif flag_arg_is_dstr_or_dsym?(node)
|
||||
str_prefix = flag_arg.children[0]
|
||||
rest_children = flag_arg.children[1..]
|
||||
|
||||
if rest_children.none? { |child| child.str_type? }
|
||||
matching_feature_flags = defined_feature_flags.select { |flag| flag.start_with?(str_prefix.value) }
|
||||
matching_feature_flags.each do |matching_feature_flag|
|
||||
puts_if_ci(node, "The '#{matching_feature_flag}' feature flag starts with '#{str_prefix.value}', so we'll optimistically mark it as used.")
|
||||
save_used_feature_flag(matching_feature_flag)
|
||||
end
|
||||
else
|
||||
puts_if_ci(node, "Interpolated feature flag name has multiple static string parts, we won't track it.")
|
||||
end
|
||||
else
|
||||
puts_if_ci(node, "Feature flag has an unknown type: #{flag_arg.type}.")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def puts_if_ci(node, text)
|
||||
puts "#{text} (call: `#{node.source}`, source: #{node.location.expression.source_buffer.name})" if ENV['CI']
|
||||
end
|
||||
|
||||
def save_used_feature_flag(feature_flag_name)
|
||||
used_feature_flag_file = File.expand_path("../../../tmp/feature_flags/#{feature_flag_name}.used", __dir__)
|
||||
return if File.exist?(used_feature_flag_file)
|
||||
|
||||
FileUtils.touch(used_feature_flag_file)
|
||||
end
|
||||
|
||||
def class_caller(node)
|
||||
node.children[0]&.const_name.to_s
|
||||
end
|
||||
|
||||
def method_name(node)
|
||||
node.children[1]
|
||||
end
|
||||
|
||||
def flag_arg(node)
|
||||
if worker_method?(node)
|
||||
return unless node.children.size > 3
|
||||
|
||||
node.children[3].each_pair.find do |pair|
|
||||
pair.key.value == :feature_flag
|
||||
end&.value
|
||||
elsif graphql_method?(node)
|
||||
return unless node.children.size > 3
|
||||
|
||||
opts_index = node.children[3].hash_type? ? 3 : 4
|
||||
return unless node.children[opts_index]
|
||||
|
||||
node.children[opts_index].each_pair.find do |pair|
|
||||
pair.key.value == :feature_flag
|
||||
end&.value
|
||||
else
|
||||
arg_index = rugged_method?(node) ? 3 : 2
|
||||
|
||||
node.children[arg_index]
|
||||
end
|
||||
end
|
||||
|
||||
def flag_value(node)
|
||||
flag_arg = flag_arg(node)
|
||||
return unless flag_arg
|
||||
|
||||
if flag_arg.respond_to?(:value)
|
||||
flag_arg.value
|
||||
else
|
||||
flag_arg
|
||||
end.to_s.tr("\n/", ' _')
|
||||
end
|
||||
|
||||
def flag_arg_is_str_or_sym?(node)
|
||||
flag_arg = flag_arg(node)
|
||||
flag_arg.str_type? || flag_arg.sym_type?
|
||||
end
|
||||
|
||||
def flag_arg_is_send_type?(node)
|
||||
flag_arg(node).send_type?
|
||||
end
|
||||
|
||||
def flag_arg_is_dstr_or_dsym?(node)
|
||||
flag = flag_arg(node)
|
||||
(flag.dstr_type? || flag.dsym_type?) && flag.children[0].str_type?
|
||||
end
|
||||
|
||||
def caller_is_feature?(node)
|
||||
class_caller(node) == "Feature"
|
||||
end
|
||||
|
||||
def caller_is_feature_gitaly?(node)
|
||||
class_caller(node) == "Feature::Gitaly"
|
||||
end
|
||||
|
||||
def caller_is_experimentation?(node)
|
||||
class_caller(node) == "Gitlab::Experimentation"
|
||||
end
|
||||
|
||||
def experiment_method?(node)
|
||||
EXPERIMENT_METHODS.include?(method_name(node))
|
||||
end
|
||||
|
||||
def rugged_method?(node)
|
||||
RUGGED_METHODS.include?(method_name(node))
|
||||
end
|
||||
|
||||
def feature_method?(node)
|
||||
FEATURE_METHODS.include?(method_name(node)) && (caller_is_feature?(node) || caller_is_feature_gitaly?(node))
|
||||
end
|
||||
|
||||
def experimentation_method?(node)
|
||||
EXPERIMENTATION_METHODS.include?(method_name(node)) && caller_is_experimentation?(node)
|
||||
end
|
||||
|
||||
def worker_method?(node)
|
||||
WORKER_METHODS.include?(method_name(node))
|
||||
end
|
||||
|
||||
def graphql_method?(node)
|
||||
GRAPHQL_METHODS.include?(method_name(node)) && in_graphql_types?(node)
|
||||
end
|
||||
|
||||
def self_method?(node)
|
||||
SELF_METHODS.include?(method_name(node)) && class_caller(node).empty?
|
||||
end
|
||||
|
||||
def trackable_flag?(node)
|
||||
feature_method?(node) || experimentation_method?(node) || graphql_method?(node) || self_method?(node)
|
||||
end
|
||||
|
||||
# Marking all event's feature flags as used as Gitlab::UsageDataCounters::HLLRedisCounter.track_event{,context}
|
||||
# is mostly used with dynamic event name.
|
||||
def track_dynamic_feature_flags!
|
||||
DYNAMIC_FEATURE_FLAGS.each(&method(:save_used_feature_flag))
|
||||
end
|
||||
|
||||
# Marking all event's feature flags as used as Gitlab::UsageDataCounters::HLLRedisCounter.track_event{,context}
|
||||
# is mostly used with dynamic event name.
|
||||
def track_usage_data_counters_known_events!
|
||||
usage_data_counters_known_event_feature_flags.each(&method(:save_used_feature_flag))
|
||||
end
|
||||
|
||||
def usage_data_counters_known_event_feature_flags
|
||||
USAGE_DATA_COUNTERS_EVENTS_YAML_GLOBS.each_with_object(Set.new) do |glob, memo|
|
||||
Dir.glob(glob).each do |path|
|
||||
YAML.safe_load(File.read(path))&.each do |hash|
|
||||
memo << hash['feature_flag'] if hash['feature_flag']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def defined_feature_flags
|
||||
@defined_feature_flags ||= begin
|
||||
flags_paths = [
|
||||
'config/feature_flags/**/*.yml'
|
||||
]
|
||||
|
||||
# For EE additionally process `ee/` feature flags
|
||||
if File.exist?(File.expand_path('../../../ee/app/models/license.rb', __dir__)) && !%w[true 1].include?(ENV['FOSS_ONLY'].to_s)
|
||||
flags_paths << 'ee/config/feature_flags/**/*.yml'
|
||||
end
|
||||
|
||||
flags_paths.each_with_object([]) do |flags_path, memo|
|
||||
flags_path = File.expand_path("../../../#{flags_path}", __dir__)
|
||||
Dir.glob(flags_path).each do |path|
|
||||
feature_flag_name = File.basename(path, '.yml')
|
||||
|
||||
memo << feature_flag_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,60 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# This cop checks for `expect(worker).to receive(:perform_async)` usage in specs
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# it "enqueues a worker" do
|
||||
# expect(MyWorker).to receive(:perform_async)
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it "enqueues a worker" do
|
||||
# expect(MyWorker).to have_enqueued_sidekiq_job
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# it "enqueues a worker" do
|
||||
# expect(MyWorker).to receive(:perform_async).with(1, 2)
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it "enqueues a worker" do
|
||||
# expect(MyWorker).to have_enqueued_sidekiq_job(1, 2)
|
||||
# end
|
||||
#
|
||||
class HaveEnqueuedSidekiqJob < RuboCop::Cop::Cop
|
||||
MESSAGE = 'Do not use `receive(:perform_async)` to check a job has been enqueued, use `have_enqueued_sidekiq_job` instead.'
|
||||
|
||||
def_node_search :expect_to_receive_perform_async?, <<~PATTERN
|
||||
(send
|
||||
(send nil? :expect ...)
|
||||
{:to :not_to :to_not}
|
||||
{
|
||||
(send nil? :receive (sym :perform_async))
|
||||
|
||||
(send
|
||||
(send nil? :receive (sym :perform_async)) ...
|
||||
)
|
||||
|
||||
(send
|
||||
(send
|
||||
(send nil? :receive (sym :perform_async)) ...
|
||||
) ...
|
||||
)
|
||||
}
|
||||
)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return unless expect_to_receive_perform_async?(node)
|
||||
|
||||
add_offense(node, location: :expression, message: MESSAGE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue