Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-06-11 18:10:13 +00:00
parent 62cd7010ef
commit e58ce90f14
345 changed files with 2499 additions and 1209 deletions

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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"

View File

@ -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() {

View File

@ -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!"

View File

@ -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

View File

@ -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,

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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';

View File

@ -1,6 +1,7 @@
#import "~/runner/graphql/runner_details.fragment.graphql"
query getRunner($id: CiRunnerID!) {
runner(id: $id) {
id
runnerType
...RunnerDetails
}
}

View File

@ -0,0 +1,12 @@
fragment RunnerDetails on CiRunner {
id
runnerType
active
accessLevel
runUntagged
locked
ipAddress
description
maximumTimeout
tagList
}

View File

@ -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
}

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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')

View File

@ -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')

View File

@ -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

View 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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 } }

View File

@ -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

View File

@ -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

View File

@ -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") }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
e5b552b21c40b83b95442341838ad5951dcac7dd473194c49630d20ce6a46ae2

View File

@ -0,0 +1 @@
9b16e17189d4db708553ce0d9dada1ce097be75433c3a8c09a6102e897e3123a

View File

@ -0,0 +1 @@
ec4cd687062118b30e516ed7c36677dda056f25c4d96c6ee0b503e457b5a18d4

View File

@ -0,0 +1 @@
ae2829a06f02ff3e1adc977f5e789b17d1f760e6aaa40be44586cc6a90870c4a

View File

@ -0,0 +1 @@
824e0930de14587f6ccaeb6b5fbec16676d243550a2dfd3a5999b67dfc16d4c8

View File

@ -0,0 +1 @@
95e4b697f5c5b18935b73bbeb0c42c96e3e5abde9e4f9e179d1a93a891a0694b

View File

@ -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);

View File

@ -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.

View File

@ -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
```

View File

@ -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

View File

@ -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),

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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).

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,7 +2,7 @@
module Gitlab
module ImportExport
module JSON
module Json
class LegacyReader
class File < LegacyReader
include Gitlab::Utils::StrongMemoize

View File

@ -2,7 +2,7 @@
module Gitlab
module ImportExport
module JSON
module Json
class LegacyWriter
include Gitlab::ImportExport::CommandLineUtil

View File

@ -2,7 +2,7 @@
module Gitlab
module ImportExport
module JSON
module Json
class NdjsonReader
MAX_JSON_DOCUMENT_SIZE = 50.megabytes

View File

@ -2,7 +2,7 @@
module Gitlab
module ImportExport
module JSON
module Json
class NdjsonWriter
include Gitlab::ImportExport::CommandLineUtil

View File

@ -2,7 +2,7 @@
module Gitlab
module ImportExport
module JSON
module Json
class StreamingSerializer
include Gitlab::ImportExport::CommandLineUtil

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -2,7 +2,7 @@
module Serializers
# Make the resulting hash have deep indifferent access
class JSON
class Json
class << self
def dump(obj)
obj

View File

@ -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 ""

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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|

View File

@ -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|

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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