From 7eca3f56625526ffa7f263c1fef0fcea34de8ca6 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 13 May 2022 15:07:43 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .rubocop_todo.yml | 27 -- .rubocop_todo/database/multiple_databases.yml | 5 - .rubocop_todo/performance/constant_regexp.yml | 32 +++ .rubocop_todo/rails/index_with.yml | 52 ++++ .rubocop_todo/rspec/scattered_let.yml | 285 +++++++++++++++++++++ .rubocop_todo/style/bare_percent_literals.yml | 115 +++++++++ .rubocop_todo/style/rescue_modifier.yml | 51 ++++ GITALY_SERVER_VERSION | 2 +- app/assets/javascripts/blob_edit/edit_blob.js | 29 ++- .../editor/components/source_editor_toolbar.vue | 6 +- .../components/source_editor_toolbar_button.vue | 74 ++---- .../components/source_editor_toolbar_graphql.js | 53 ++++ app/assets/javascripts/editor/constants.js | 5 +- .../source_editor_markdown_livepreview_ext.js | 108 +++++--- .../editor/extensions/source_editor_toolbar_ext.js | 98 +++++++ .../editor/graphql/add_items.mutation.graphql | 3 + .../editor/graphql/get_item.query.graphql | 9 - .../editor/graphql/remove_items.mutation.graphql | 3 + .../javascripts/editor/graphql/typedefs.graphql | 23 ++ .../editor/graphql/update_item.mutation.graphql | 2 +- app/assets/javascripts/flash.js | 3 +- app/assets/javascripts/group.js | 37 ++- .../javascripts/notes/components/comment_form.vue | 16 +- .../notes/components/comment_type_dropdown.vue | 48 +++- .../javascripts/notes/components/note_body.vue | 5 + .../javascripts/notes/components/note_form.vue | 9 +- .../javascripts/notes/components/note_header.vue | 25 +- .../notes/components/noteable_discussion.vue | 15 +- .../javascripts/notes/components/noteable_note.vue | 20 +- app/assets/javascripts/notes/i18n.js | 14 +- .../vue_shared/security_reports/store/utils.js | 2 +- app/controllers/admin/labels_controller.rb | 1 + app/controllers/autocomplete_controller.rb | 1 + app/controllers/boards/issues_controller.rb | 1 + app/controllers/boards/lists_controller.rb | 1 + app/controllers/dashboard/labels_controller.rb | 1 + app/controllers/dashboard/milestones_controller.rb | 1 + app/controllers/dashboard/todos_controller.rb | 1 + app/controllers/dashboard_controller.rb | 1 + .../groups/autocomplete_sources_controller.rb | 1 + app/controllers/groups/boards_controller.rb | 1 + app/controllers/groups/crm/contacts_controller.rb | 1 + .../groups/crm/organizations_controller.rb | 1 + app/controllers/groups/labels_controller.rb | 1 + app/controllers/groups/milestones_controller.rb | 1 + app/controllers/groups_controller.rb | 1 + .../profiles/notifications_controller.rb | 1 + .../cycle_analytics/value_streams_controller.rb | 1 + .../projects/autocomplete_sources_controller.rb | 1 + app/controllers/projects/boards_controller.rb | 1 + .../projects/cycle_analytics/events_controller.rb | 1 + .../projects/cycle_analytics_controller.rb | 1 + app/controllers/projects/discussions_controller.rb | 1 + app/controllers/projects/issue_links_controller.rb | 1 + app/controllers/projects/issues_controller.rb | 7 + app/controllers/projects/labels_controller.rb | 1 + app/controllers/projects/milestones_controller.rb | 1 + app/controllers/projects/notes_controller.rb | 1 + app/controllers/projects/todos_controller.rb | 1 + app/controllers/projects/work_items_controller.rb | 1 + app/controllers/projects_controller.rb | 1 + app/controllers/sent_notifications_controller.rb | 1 + app/models/group_group_link.rb | 2 + app/models/namespace.rb | 4 +- app/services/ci/job_artifacts/create_service.rb | 2 +- app/views/projects/blob/_editor.html.haml | 2 + ...ix_rules_if_comparison_with_regexp_variable.yml | 8 + .../development/omit_epic_subscribed.yml | 2 +- config/initializers/sidekiq.rb | 2 +- ...ude_from_free_user_cap_to_namespace_settings.rb | 13 + db/schema_migrations/20220511151646 | 1 + db/structure.sql | 1 + doc/.vale/gitlab/spelling-exceptions.txt | 6 + doc/administration/geo/glossary.md | 4 +- .../geo/replication/troubleshooting.md | 4 +- .../geo/replication/version_specific_updates.md | 4 +- doc/administration/gitaly/praefect.md | 2 +- doc/administration/nfs.md | 2 +- .../operations/extra_sidekiq_processes.md | 2 +- .../package_information/licensing.md | 2 +- .../troubleshooting/elasticsearch.md | 2 +- doc/administration/troubleshooting/sidekiq.md | 2 +- doc/api/index.md | 2 +- doc/api/issues.md | 2 +- doc/api/merge_requests.md | 8 +- doc/api/pages_domains.md | 2 +- doc/api/settings.md | 6 +- .../database/scalability/patterns/time_decay.md | 6 +- doc/ci/examples/semantic-release.md | 2 +- doc/ci/services/index.md | 2 +- doc/ci/yaml/index.md | 2 + doc/development/adding_database_indexes.md | 9 +- doc/development/code_intelligence/index.md | 2 +- doc/development/code_review.md | 8 +- doc/development/contributing/design.md | 4 +- .../contributing/merge_request_workflow.md | 4 +- .../database/avoiding_downtime_in_migrations.md | 2 +- doc/development/database/loose_foreign_keys.md | 4 +- doc/development/database/table_partitioning.md | 2 +- doc/development/fe_guide/graphql.md | 2 +- doc/development/migration_style_guide.md | 5 + doc/development/workhorse/index.md | 2 +- doc/install/docker.md | 2 +- doc/install/installation.md | 6 +- doc/update/index.md | 11 + doc/user/search/img/issue_search_by_id.png | Bin 20577 -> 0 bytes doc/user/search/img/issue_search_by_id_v15_0.png | Bin 0 -> 15890 bytes doc/user/search/index.md | 2 +- lib/api/api.rb | 1 + lib/api/boards.rb | 1 + lib/api/ci/runner.rb | 2 +- lib/api/group_boards.rb | 1 + lib/api/group_labels.rb | 1 + lib/api/group_milestones.rb | 1 + lib/api/integrations/jira_connect/subscriptions.rb | 51 ++++ lib/api/issue_links.rb | 1 + lib/api/issues.rb | 1 + lib/api/labels.rb | 1 + lib/api/notification_settings.rb | 1 + lib/api/project_milestones.rb | 1 + lib/api/sidekiq_metrics.rb | 3 +- lib/api/todos.rb | 1 + .../ci/pipeline/expression/lexeme/matches.rb | 7 + .../ci/pipeline/expression/lexeme/not_matches.rb | 7 + .../ci/pipeline/expression/lexeme/pattern.rb | 12 + lib/gitlab/ci/pipeline/expression/lexeme/value.rb | 2 + lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml | 30 +-- .../ci/templates/Jobs/SAST.latest.gitlab-ci.yml | 20 +- .../Security/Secure-Binaries.gitlab-ci.yml | 24 +- lib/gitlab/database.rb | 17 +- .../database/load_balancing/load_balancer.rb | 2 + .../database/migrations/observers/query_log.rb | 2 +- lib/gitlab/sidekiq_config.rb | 14 + lib/gitlab/sidekiq_config/dummy_worker.rb | 4 + lib/gitlab/sidekiq_config/worker.rb | 2 +- lib/tasks/gitlab/db/validate_config.rake | 4 +- locale/gitlab.pot | 54 +++- spec/features/groups_spec.rb | 18 ++ spec/frontend/blob_edit/edit_blob_spec.js | 37 ++- spec/frontend/editor/components/helpers.js | 18 +- .../source_editor_toolbar_button_spec.js | 116 ++------- .../source_editor_toolbar_graphql_spec.js | 112 ++++++++ .../extensions/source_editor_toolbar_ext_spec.js | 156 +++++++++++ .../source_editor_markdown_livepreview_ext_spec.js | 111 +++----- .../frontend/notes/components/comment_form_spec.js | 34 ++- .../notes/components/comment_type_dropdown_spec.js | 32 ++- spec/frontend/notes/components/note_body_spec.js | 90 ++++--- spec/frontend/notes/components/note_form_spec.js | 19 +- spec/frontend/notes/components/note_header_spec.js | 4 +- spec/lib/gitlab/application_context_spec.rb | 1 - .../gitlab/ci/build/rules/rule/clause/if_spec.rb | 74 ++++++ spec/lib/gitlab/ci/build/rules_spec.rb | 13 + .../ci/pipeline/expression/lexeme/matches_spec.rb | 28 ++ .../pipeline/expression/lexeme/not_matches_spec.rb | 28 ++ .../ci/pipeline/expression/lexeme/pattern_spec.rb | 49 +++- .../ci/pipeline/expression/statement_spec.rb | 45 +++- spec/lib/gitlab/database_spec.rb | 34 --- spec/lib/gitlab/sidekiq_config_spec.rb | 36 +++ spec/requests/api/ci/runner/jobs_artifacts_spec.rb | 9 +- .../jira_connect/subscriptions_spec.rb | 86 +++++++ spec/requests/api/sidekiq_metrics_spec.rb | 13 +- .../ci/job_artifacts/create_service_spec.rb | 11 +- .../groups/group_links/destroy_service_spec.rb | 85 +++--- 163 files changed, 2289 insertions(+), 615 deletions(-) create mode 100644 .rubocop_todo/performance/constant_regexp.yml create mode 100644 .rubocop_todo/rails/index_with.yml create mode 100644 .rubocop_todo/rspec/scattered_let.yml create mode 100644 .rubocop_todo/style/bare_percent_literals.yml create mode 100644 .rubocop_todo/style/rescue_modifier.yml create mode 100644 app/assets/javascripts/editor/components/source_editor_toolbar_graphql.js create mode 100644 app/assets/javascripts/editor/extensions/source_editor_toolbar_ext.js create mode 100644 app/assets/javascripts/editor/graphql/add_items.mutation.graphql delete mode 100644 app/assets/javascripts/editor/graphql/get_item.query.graphql create mode 100644 app/assets/javascripts/editor/graphql/remove_items.mutation.graphql create mode 100644 app/assets/javascripts/editor/graphql/typedefs.graphql create mode 100644 config/feature_flags/development/ci_fix_rules_if_comparison_with_regexp_variable.yml create mode 100644 db/migrate/20220511151646_add_exclude_from_free_user_cap_to_namespace_settings.rb create mode 100644 db/schema_migrations/20220511151646 delete mode 100644 doc/user/search/img/issue_search_by_id.png create mode 100644 doc/user/search/img/issue_search_by_id_v15_0.png create mode 100644 lib/api/integrations/jira_connect/subscriptions.rb create mode 100644 spec/frontend/editor/components/source_editor_toolbar_graphql_spec.js create mode 100644 spec/frontend/editor/extensions/source_editor_toolbar_ext_spec.js create mode 100644 spec/lib/gitlab/ci/build/rules/rule/clause/if_spec.rb create mode 100644 spec/requests/api/integrations/jira_connect/subscriptions_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4d2477c199d..05b96a6b88a 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -11,11 +11,6 @@ Gitlab/PolicyRuleBoolean: Exclude: - 'ee/app/policies/ee/identity_provider_policy.rb' -# Offense count: 41 -# Cop supports --auto-correct. -Performance/ConstantRegexp: - Enabled: false - # Offense count: 1428 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. @@ -34,11 +29,6 @@ RSpec/PredicateMatcher: RSpec/RepeatedExampleGroupBody: Enabled: false -# Offense count: 610 -# Cop supports --auto-correct. -RSpec/ScatteredLet: - Enabled: false - # Offense count: 26 # Cop supports --auto-correct. # Configuration parameters: Include. @@ -78,11 +68,6 @@ Rails/CreateTableWithTimestamps: Rails/HasManyOrHasOneDependent: Enabled: false -# Offense count: 47 -# Cop supports --auto-correct. -Rails/IndexWith: - Enabled: false - # Offense count: 118 # Configuration parameters: Include. # Include: app/models/**/*.rb @@ -116,13 +101,6 @@ Rails/WhereExists: Style/AccessorGrouping: Enabled: false -# Offense count: 188 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: percent_q, bare_percent -Style/BarePercentLiterals: - Enabled: false - # Offense count: 42 # Cop supports --auto-correct. Style/CaseLikeIf: @@ -158,8 +136,3 @@ Style/Lambda: # Cop supports --auto-correct. Style/RedundantRegexpEscape: Enabled: false - -# Offense count: 53 -# Cop supports --auto-correct. -Style/RescueModifier: - Enabled: false diff --git a/.rubocop_todo/database/multiple_databases.yml b/.rubocop_todo/database/multiple_databases.yml index 08ce72f7f51..1d0085e1ba6 100644 --- a/.rubocop_todo/database/multiple_databases.yml +++ b/.rubocop_todo/database/multiple_databases.yml @@ -2,7 +2,6 @@ Database/MultipleDatabases: Exclude: - 'config/initializers/active_record_data_types.rb' - - 'config/initializers/sidekiq.rb' - 'db/post_migrate/20210317104032_set_iteration_cadence_automatic_to_false.rb' - 'db/post_migrate/20210811122206_update_external_project_bots.rb' - 'db/post_migrate/20210812013042_remove_duplicate_project_authorizations.rb' @@ -10,10 +9,6 @@ Database/MultipleDatabases: - 'lib/backup/manager.rb' - 'lib/gitlab/background_migration/backfill_projects_with_coverage.rb' - 'lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans.rb' - - 'lib/gitlab/database.rb' - - 'lib/gitlab/database/load_balancing/load_balancer.rb' - - 'lib/gitlab/database/migrations/observers/query_log.rb' - - 'lib/tasks/gitlab/db/validate_config.rake' - 'spec/db/schema_spec.rb' - 'spec/initializers/database_config_spec.rb' - 'spec/lib/backup/manager_spec.rb' diff --git a/.rubocop_todo/performance/constant_regexp.yml b/.rubocop_todo/performance/constant_regexp.yml new file mode 100644 index 00000000000..fb2b7d6ef49 --- /dev/null +++ b/.rubocop_todo/performance/constant_regexp.yml @@ -0,0 +1,32 @@ +--- +# Cop supports --auto-correct. +Performance/ConstantRegexp: + # Offense count: 46 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'app/models/commit.rb' + - 'app/models/commit_range.rb' + - 'app/models/custom_emoji.rb' + - 'app/models/gpg_key.rb' + - 'app/models/merge_request.rb' + - 'app/models/project.rb' + - 'app/models/wiki.rb' + - 'ee/app/models/ee/epic.rb' + - 'lib/banzai/filter/custom_emoji_filter.rb' + - 'lib/gitlab/cleanup/project_uploads.rb' + - 'lib/gitlab/database/reindexing/reindex_concurrently.rb' + - 'lib/gitlab/dependency_linker/base_linker.rb' + - 'lib/gitlab/dependency_linker/composer_json_linker.rb' + - 'lib/gitlab/dependency_linker/godeps_json_linker.rb' + - 'lib/gitlab/dependency_linker/podspec_linker.rb' + - 'lib/gitlab/git.rb' + - 'lib/gitlab/job_waiter.rb' + - 'lib/gitlab/metrics/dashboard/url.rb' + - 'lib/gitlab/path_regex.rb' + - 'lib/gitlab/regex.rb' + - 'scripts/perf/query_limiting_report.rb' + - 'scripts/validate_migration_schema' + - 'spec/models/concerns/token_authenticatable_spec.rb' + - 'spec/scripts/lib/glfm/update_specification_spec.rb' + - 'spec/services/notes/copy_service_spec.rb' diff --git a/.rubocop_todo/rails/index_with.yml b/.rubocop_todo/rails/index_with.yml new file mode 100644 index 00000000000..09339d3fd56 --- /dev/null +++ b/.rubocop_todo/rails/index_with.yml @@ -0,0 +1,52 @@ +--- +# Cop supports --auto-correct. +Rails/IndexWith: + # Offense count: 54 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'app/helpers/ci/jobs_helper.rb' + - 'app/models/ci/build_trace_chunk.rb' + - 'app/models/ci/processable.rb' + - 'app/models/concerns/cached_commit.rb' + - 'app/models/environment.rb' + - 'app/services/concerns/rate_limited_service.rb' + - 'db/post_migrate/20210731132939_backfill_stage_event_hash.rb' + - 'ee/app/models/vulnerabilities/projects_grade.rb' + - 'ee/lib/ee/gitlab/usage_data.rb' + - 'ee/lib/gitlab/auth/group_saml/auth_hash.rb' + - 'ee/lib/gitlab/custom_file_templates.rb' + - 'ee/lib/gitlab/insights/reducers/count_per_label_reducer.rb' + - 'ee/spec/lib/ee/gitlab/application_context_spec.rb' + - 'ee/spec/models/ee/namespace_spec.rb' + - 'ee/spec/models/sca/license_compliance_spec.rb' + - 'ee/spec/views/admin/dashboard/index.html.haml_spec.rb' + - 'lib/api/entities/project_integration.rb' + - 'lib/api/helpers/packages/conan/api_helpers.rb' + - 'lib/banzai/filter/repository_link_filter.rb' + - 'lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url.rb' + - 'lib/gitlab/ci/ansi2html.rb' + - 'lib/gitlab/ci/reports/security/finding.rb' + - 'lib/gitlab/ci/reports/security/identifier.rb' + - 'lib/gitlab/ci/reports/test_suite.rb' + - 'lib/gitlab/database/count/exact_count_strategy.rb' + - 'lib/gitlab/database/migration_helpers.rb' + - 'lib/gitlab/database/obsolete_ignored_columns.rb' + - 'lib/gitlab/issuable_metadata.rb' + - 'lib/gitlab/template/base_template.rb' + - 'lib/gitlab/usage_data.rb' + - 'lib/google_api/cloud_platform/client.rb' + - 'qa/qa/resource/reusable.rb' + - 'scripts/trigger-build.rb' + - 'spec/lib/gitlab/api_authentication/sent_through_builder_spec.rb' + - 'spec/lib/gitlab/conflict/file_spec.rb' + - 'spec/lib/gitlab/import_export/model_configuration_spec.rb' + - 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb' + - 'spec/lib/google_api/cloud_platform/client_spec.rb' + - 'spec/lib/learn_gitlab/onboarding_spec.rb' + - 'spec/models/event_spec.rb' + - 'spec/presenters/projects/security/configuration_presenter_spec.rb' + - 'spec/support/database/multiple_databases.rb' + - 'spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb' + - 'spec/support/shared_examples/models/concerns/sanitizable_shared_examples.rb' + - 'spec/views/admin/dashboard/index.html.haml_spec.rb' diff --git a/.rubocop_todo/rspec/scattered_let.yml b/.rubocop_todo/rspec/scattered_let.yml new file mode 100644 index 00000000000..52f19bf0768 --- /dev/null +++ b/.rubocop_todo/rspec/scattered_let.yml @@ -0,0 +1,285 @@ +--- +# Cop supports --auto-correct. +RSpec/ScatteredLet: + # Offense count: 720 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'ee/spec/features/groups/group_roadmap_spec.rb' + - 'ee/spec/features/merge_trains/two_merge_requests_on_train_spec.rb' + - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb' + - 'ee/spec/finders/security/vulnerability_reads_finder_spec.rb' + - 'ee/spec/graphql/mutations/boards/epic_boards/epic_move_list_spec.rb' + - 'ee/spec/graphql/mutations/boards/epics/create_spec.rb' + - 'ee/spec/graphql/mutations/dast_site_profiles/create_spec.rb' + - 'ee/spec/graphql/mutations/merge_requests/accept_spec.rb' + - 'ee/spec/graphql/mutations/releases/update_spec.rb' + - 'ee/spec/graphql/resolvers/security_orchestration/scan_execution_policy_resolver_spec.rb' + - 'ee/spec/graphql/types/boards/board_epic_type_spec.rb' + - 'ee/spec/graphql/types/instance_security_dashboard_type_spec.rb' + - 'ee/spec/helpers/ee/subscribable_banner_helper_spec.rb' + - 'ee/spec/helpers/trial_status_widget_helper_spec.rb' + - 'ee/spec/lib/banzai/reference_parser/iteration_parser_spec.rb' + - 'ee/spec/lib/ee/audit/compliance_framework_changes_auditor_spec.rb' + - 'ee/spec/lib/ee/gitlab/ci/config_spec.rb' + - 'ee/spec/lib/ee/gitlab/email/handler/service_desk_handler_spec.rb' + - 'ee/spec/lib/gitlab/ci/parsers/security/dast_spec.rb' + - 'ee/spec/lib/gitlab/ci/parsers/security/formatters/dependency_list_spec.rb' + - 'ee/spec/lib/gitlab/ci/templates/dast_api_gitlab_ci_yaml_spec.rb' + - 'ee/spec/lib/gitlab/ci/templates/dast_api_latest_gitlab_ci_yaml_spec.rb' + - 'ee/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb' + - 'ee/spec/lib/gitlab/elastic/bulk_indexer_spec.rb' + - 'ee/spec/lib/gitlab/geo/log_cursor/events/repositories_changed_event_spec.rb' + - 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_updated_event_spec.rb' + - 'ee/spec/lib/gitlab/geo/replication/blob_downloader_spec.rb' + - 'ee/spec/lib/gitlab/git_access_spec.rb' + - 'ee/spec/lib/gitlab/graphql/aggregations/security_orchestration_policies/lazy_dast_profile_aggregate_spec.rb' + - 'ee/spec/lib/gitlab/graphql/aggregations/vulnerability_statistics/lazy_aggregate_spec.rb' + - 'ee/spec/lib/gitlab/insights/reducers/count_per_label_reducer_spec.rb' + - 'ee/spec/lib/gitlab/insights/reducers/label_count_per_period_reducer_spec.rb' + - 'ee/spec/lib/gitlab/usage_data_metrics_spec.rb' + - 'ee/spec/models/analytics/cycle_analytics/group_level_spec.rb' + - 'ee/spec/models/approval_wrapped_any_approver_rule_spec.rb' + - 'ee/spec/models/approvals/scan_finding_wrapped_rule_set_spec.rb' + - 'ee/spec/models/ci/minutes/notification_spec.rb' + - 'ee/spec/models/ci/minutes/quota_spec.rb' + - 'ee/spec/models/ci/pipeline_spec.rb' + - 'ee/spec/models/ee/ci/build_dependencies_spec.rb' + - 'ee/spec/models/ee/namespace/root_storage_size_spec.rb' + - 'ee/spec/models/label_note_spec.rb' + - 'ee/spec/models/sca/license_compliance_spec.rb' + - 'ee/spec/policies/merge_request_policy_spec.rb' + - 'ee/spec/requests/api/graphql/compliance_management/merge_requests/compliance_violations_spec.rb' + - 'ee/spec/requests/api/graphql/group/ci_cd_settings_spec.rb' + - 'ee/spec/requests/api/graphql/group/epic/notes_spec.rb' + - 'ee/spec/requests/api/graphql/group_query_spec.rb' + - 'ee/spec/requests/api/graphql/mutations/boards/epic_boards/epic_move_list_spec.rb' + - 'ee/spec/requests/api/graphql/mutations/incident_management/oncall_rotation/update_spec.rb' + - 'ee/spec/requests/api/graphql/mutations/issues/promote_to_epic_spec.rb' + - 'ee/spec/requests/api/graphql/mutations/security_policy/commit_scan_execution_policy_spec.rb' + - 'ee/spec/requests/api/graphql/project/alert_management/http_integrations_spec.rb' + - 'ee/spec/requests/api/graphql/project/dast_profile_schedule_spec.rb' + - 'ee/spec/requests/api/graphql/project/pipeline/dast_profile_spec.rb' + - 'ee/spec/requests/api/graphql/project/pipelines/dast_profile_spec.rb' + - 'ee/spec/requests/api/internal/base_spec.rb' + - 'ee/spec/requests/api/projects_spec.rb' + - 'ee/spec/requests/api/vulnerability_findings_spec.rb' + - 'ee/spec/requests/git_http_geo_spec.rb' + - 'ee/spec/serializers/status_page/incident_serializer_spec.rb' + - 'ee/spec/services/app_sec/dast/scanner_profiles/update_service_spec.rb' + - 'ee/spec/services/arkose/blocked_users_report_service_spec.rb' + - 'ee/spec/services/arkose/user_verification_service_spec.rb' + - 'ee/spec/services/audit_event_service_spec.rb' + - 'ee/spec/services/audit_events/protected_branch_audit_event_service_spec.rb' + - 'ee/spec/services/ee/issue_links/create_service_spec.rb' + - 'ee/spec/services/epic_issues/create_service_spec.rb' + - 'ee/spec/services/epics/issue_promote_service_spec.rb' + - 'ee/spec/services/gitlab_subscriptions/activate_service_spec.rb' + - 'ee/spec/services/group_saml/saml_provider/create_service_spec.rb' + - 'ee/spec/services/group_saml/saml_provider/update_service_spec.rb' + - 'ee/spec/services/groups/memberships/export_service_spec.rb' + - 'ee/spec/services/incident_management/escalation_policies/create_service_spec.rb' + - 'ee/spec/services/incident_management/oncall_rotations/remove_participant_service_spec.rb' + - 'ee/spec/services/merge_request_approval_settings/update_service_spec.rb' + - 'ee/spec/services/merge_trains/refresh_service_spec.rb' + - 'ee/spec/services/projects/destroy_service_spec.rb' + - 'ee/spec/services/projects/prometheus/alerts/notify_service_spec.rb' + - 'ee/spec/services/quality_management/test_cases/create_service_spec.rb' + - 'ee/spec/services/quick_actions/interpret_service_spec.rb' + - 'ee/spec/services/requirements_management/update_requirement_service_spec.rb' + - 'ee/spec/services/search/group_service_spec.rb' + - 'ee/spec/services/search/project_service_spec.rb' + - 'ee/spec/services/todo_service_spec.rb' + - 'ee/spec/views/shared/_mirror_update_button.html.haml_spec.rb' + - 'ee/spec/views/subscriptions/groups/edit.html.haml_spec.rb' + - 'ee/spec/workers/compliance_management/merge_requests/compliance_violations_worker_spec.rb' + - 'ee/spec/workers/concerns/update_orchestration_policy_configuration_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/1_manage/group/group_audit_logs_1_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/1_manage/project/project_audit_logs_spec.rb' + - 'spec/controllers/projects/artifacts_controller_spec.rb' + - 'spec/controllers/projects/deploy_keys_controller_spec.rb' + - 'spec/controllers/projects/environments_controller_spec.rb' + - 'spec/controllers/projects/issues_controller_spec.rb' + - 'spec/controllers/projects/releases/evidences_controller_spec.rb' + - 'spec/controllers/projects/releases_controller_spec.rb' + - 'spec/finders/ci/daily_build_group_report_results_finder_spec.rb' + - 'spec/finders/concerns/finder_with_cross_project_access_spec.rb' + - 'spec/finders/concerns/finder_with_group_hierarchy_spec.rb' + - 'spec/finders/events_finder_spec.rb' + - 'spec/finders/group_projects_finder_spec.rb' + - 'spec/finders/license_template_finder_spec.rb' + - 'spec/frontend/fixtures/pipelines.rb' + - 'spec/graphql/resolvers/commit_pipelines_resolver_spec.rb' + - 'spec/graphql/resolvers/design_management/version_in_collection_resolver_spec.rb' + - 'spec/graphql/resolvers/design_management/versions_resolver_spec.rb' + - 'spec/graphql/types/ci/job_token_scope_type_spec.rb' + - 'spec/helpers/merge_requests_helper_spec.rb' + - 'spec/lib/banzai/filter/references/project_reference_filter_spec.rb' + - 'spec/lib/banzai/filter/references/user_reference_filter_spec.rb' + - 'spec/lib/banzai/filter/upload_link_filter_spec.rb' + - 'spec/lib/banzai/reference_parser/alert_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/commit_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/commit_range_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/external_issue_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/label_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/merge_request_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/milestone_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/project_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/snippet_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/user_parser_spec.rb' + - 'spec/lib/bulk_imports/projects/pipelines/snippets_repository_pipeline_spec.rb' + - 'spec/lib/gitlab/asciidoc/include_processor_spec.rb' + - 'spec/lib/gitlab/auth/ldap/person_spec.rb' + - 'spec/lib/gitlab/auth/saml/auth_hash_spec.rb' + - 'spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb' + - 'spec/lib/gitlab/background_migration/encrypt_static_object_token_spec.rb' + - 'spec/lib/gitlab/background_migration/legacy_uploads_migrator_spec.rb' + - 'spec/lib/gitlab/background_migration/nullify_orphan_runner_id_on_ci_builds_spec.rb' + - 'spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb' + - 'spec/lib/gitlab/ci/config/external/file/artifact_spec.rb' + - 'spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb' + - 'spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb' + - 'spec/lib/gitlab/ci/status/stage/factory_spec.rb' + - 'spec/lib/gitlab/ci/variables/builder/group_spec.rb' + - 'spec/lib/gitlab/ci/variables/builder/project_spec.rb' + - 'spec/lib/gitlab/ci/yaml_processor_spec.rb' + - 'spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb' + - 'spec/lib/gitlab/database/background_migration/batched_migration_wrapper_spec.rb' + - 'spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb' + - 'spec/lib/gitlab/database/partitioning/partition_manager_spec.rb' + - 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb' + - 'spec/lib/gitlab/database/postgresql_adapter/empty_query_ping_spec.rb' + - 'spec/lib/gitlab/database/reindexing/grafana_notifier_spec.rb' + - 'spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb' + - 'spec/lib/gitlab/diff/formatters/text_formatter_spec.rb' + - 'spec/lib/gitlab/diff/position_spec.rb' + - 'spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb' + - 'spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb' + - 'spec/lib/gitlab/diff/suggestion_diff_spec.rb' + - 'spec/lib/gitlab/diff/suggestion_spec.rb' + - 'spec/lib/gitlab/elasticsearch/logs/lines_spec.rb' + - 'spec/lib/gitlab/email/handler/service_desk_handler_spec.rb' + - 'spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb' + - 'spec/lib/gitlab/error_tracking_spec.rb' + - 'spec/lib/gitlab/git/blame_spec.rb' + - 'spec/lib/gitlab/git/diff_collection_spec.rb' + - 'spec/lib/gitlab/git_access_spec.rb' + - 'spec/lib/gitlab/github_import/parallel_scheduling_spec.rb' + - 'spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb' + - 'spec/lib/gitlab/import_export/project/export_task_spec.rb' + - 'spec/lib/gitlab/jira_import/issue_serializer_spec.rb' + - 'spec/lib/gitlab/lets_encrypt/client_spec.rb' + - 'spec/lib/gitlab/metrics/dashboard/stages/grafana_formatter_spec.rb' + - 'spec/lib/gitlab/metrics/subscribers/external_http_spec.rb' + - 'spec/lib/gitlab/middleware/memory_report_spec.rb' + - 'spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb' + - 'spec/lib/gitlab/pagination/keyset/page_spec.rb' + - 'spec/lib/gitlab/pagination/offset_pagination_spec.rb' + - 'spec/lib/gitlab/patch/database_config_spec.rb' + - 'spec/lib/gitlab/path_regex_spec.rb' + - 'spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb' + - 'spec/lib/gitlab/serializer/pagination_spec.rb' + - 'spec/lib/gitlab/sidekiq_middleware/extra_done_log_metadata_spec.rb' + - 'spec/lib/gitlab/sidekiq_middleware/size_limiter/validator_spec.rb' + - 'spec/lib/gitlab/spamcheck/client_spec.rb' + - 'spec/lib/gitlab/template/finders/global_template_finder_spec.rb' + - 'spec/lib/gitlab/tree_summary_spec.rb' + - 'spec/lib/gitlab/usage/service_ping_report_spec.rb' + - 'spec/lib/gitlab/usage_data_metrics_spec.rb' + - 'spec/lib/gitlab/utils/measuring_spec.rb' + - 'spec/lib/gitlab/zentao/client_spec.rb' + - 'spec/lib/peek/views/external_http_spec.rb' + - 'spec/mailers/emails/in_product_marketing_spec.rb' + - 'spec/migrations/20210421163509_schedule_update_jira_tracker_data_deployment_type_based_on_url_spec.rb' + - 'spec/migrations/20220329175119_remove_leftover_ci_job_artifact_deletions_spec.rb' + - 'spec/models/application_record_spec.rb' + - 'spec/models/ci/build_dependencies_spec.rb' + - 'spec/models/ci/pipeline_spec.rb' + - 'spec/models/concerns/issuable_spec.rb' + - 'spec/models/concerns/manual_inverse_association_spec.rb' + - 'spec/models/concerns/noteable_spec.rb' + - 'spec/models/deploy_keys_project_spec.rb' + - 'spec/models/design_management/design_at_version_spec.rb' + - 'spec/models/diff_note_spec.rb' + - 'spec/models/environment_spec.rb' + - 'spec/models/integration_spec.rb' + - 'spec/models/merge_request_diff_spec.rb' + - 'spec/models/merge_request_spec.rb' + - 'spec/models/milestone_spec.rb' + - 'spec/models/push_event_spec.rb' + - 'spec/models/ssh_host_key_spec.rb' + - 'spec/models/user_spec.rb' + - 'spec/models/users/credit_card_validation_spec.rb' + - 'spec/models/wiki_page_spec.rb' + - 'spec/policies/ci/build_policy_spec.rb' + - 'spec/policies/design_management/design_policy_spec.rb' + - 'spec/policies/group_member_policy_spec.rb' + - 'spec/requests/admin/background_migrations_controller_spec.rb' + - 'spec/requests/api/ci/pipeline_schedules_spec.rb' + - 'spec/requests/api/ci/pipelines_spec.rb' + - 'spec/requests/api/commit_statuses_spec.rb' + - 'spec/requests/api/graphql/ci/groups_spec.rb' + - 'spec/requests/api/graphql/ci/pipelines_spec.rb' + - 'spec/requests/api/graphql/mutations/boards/create_spec.rb' + - 'spec/requests/api/graphql/namespace/projects_spec.rb' + - 'spec/requests/api/graphql/project/issue/design_collection/version_spec.rb' + - 'spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb' + - 'spec/requests/api/graphql/project/issue_spec.rb' + - 'spec/requests/api/graphql/project/milestones_spec.rb' + - 'spec/requests/api/graphql/project/pipeline_spec.rb' + - 'spec/requests/api/graphql/project/release_spec.rb' + - 'spec/requests/api/graphql/user/starred_projects_query_spec.rb' + - 'spec/requests/api/issues/get_group_issues_spec.rb' + - 'spec/requests/api/issues/get_project_issues_spec.rb' + - 'spec/requests/api/issues/post_projects_issues_spec.rb' + - 'spec/requests/api/issues/put_projects_issues_spec.rb' + - 'spec/requests/api/merge_requests_spec.rb' + - 'spec/requests/api/notes_spec.rb' + - 'spec/requests/api/project_clusters_spec.rb' + - 'spec/requests/api/project_export_spec.rb' + - 'spec/requests/api/rubygem_packages_spec.rb' + - 'spec/requests/projects/releases_controller_spec.rb' + - 'spec/rubocop/cop/migration/update_column_in_batches_spec.rb' + - 'spec/scripts/pipeline_test_report_builder_spec.rb' + - 'spec/serializers/build_details_entity_spec.rb' + - 'spec/serializers/ci/job_entity_spec.rb' + - 'spec/serializers/merge_requests/pipeline_entity_spec.rb' + - 'spec/services/ci/change_variable_service_spec.rb' + - 'spec/services/ci/change_variables_service_spec.rb' + - 'spec/services/ci/create_downstream_pipeline_service_spec.rb' + - 'spec/services/ci/create_pipeline_service/logger_spec.rb' + - 'spec/services/ci/create_pipeline_service_spec.rb' + - 'spec/services/ci/destroy_pipeline_service_spec.rb' + - 'spec/services/ci/find_exposed_artifacts_service_spec.rb' + - 'spec/services/ci/pipeline_bridge_status_service_spec.rb' + - 'spec/services/commits/cherry_pick_service_spec.rb' + - 'spec/services/design_management/delete_designs_service_spec.rb' + - 'spec/services/design_management/save_designs_service_spec.rb' + - 'spec/services/discussions/capture_diff_note_positions_service_spec.rb' + - 'spec/services/events/destroy_service_spec.rb' + - 'spec/services/git/base_hooks_service_spec.rb' + - 'spec/services/groups/group_links/update_service_spec.rb' + - 'spec/services/jira_import/cloud_users_mapper_service_spec.rb' + - 'spec/services/jira_import/server_users_mapper_service_spec.rb' + - 'spec/services/lfs/push_service_spec.rb' + - 'spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb' + - 'spec/services/metrics/dashboard/dynamic_embed_service_spec.rb' + - 'spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb' + - 'spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb' + - 'spec/services/notification_service_spec.rb' + - 'spec/services/packages/composer/create_package_service_spec.rb' + - 'spec/services/packages/conan/create_package_file_service_spec.rb' + - 'spec/services/packages/debian/create_package_file_service_spec.rb' + - 'spec/services/packages/debian/generate_distribution_key_service_spec.rb' + - 'spec/services/packages/debian/update_distribution_service_spec.rb' + - 'spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb' + - 'spec/services/snippets/create_service_spec.rb' + - 'spec/services/spam/spam_verdict_service_spec.rb' + - 'spec/services/suggestions/create_service_spec.rb' + - 'spec/services/system_notes/design_management_service_spec.rb' + - 'spec/services/system_notes/merge_requests_service_spec.rb' + - 'spec/services/todo_service_spec.rb' + - 'spec/support/shared_examples/graphql/sorted_paginated_query_shared_examples.rb' + - 'spec/tasks/gitlab/artifacts/migrate_rake_spec.rb' + - 'spec/workers/concerns/gitlab/github_import/object_importer_spec.rb' + - 'spec/workers/packages/debian/generate_distribution_worker_spec.rb' diff --git a/.rubocop_todo/style/bare_percent_literals.yml b/.rubocop_todo/style/bare_percent_literals.yml new file mode 100644 index 00000000000..658c6c22baa --- /dev/null +++ b/.rubocop_todo/style/bare_percent_literals.yml @@ -0,0 +1,115 @@ +--- +# Cop supports --auto-correct. +Style/BarePercentLiterals: + # Offense count: 220 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'app/models/commit.rb' + - 'app/models/concerns/storage/legacy_namespace.rb' + - 'app/models/integrations/datadog.rb' + - 'app/services/feature_flags/base_service.rb' + - 'app/services/repositories/base_service.rb' + - 'app/services/repositories/destroy_rollback_service.rb' + - 'app/services/repositories/destroy_service.rb' + - 'ee/app/services/jira/jql_builder_service.rb' + - 'ee/lib/ee/gitlab/checks/push_rules/file_size_check.rb' + - 'ee/spec/features/projects/environments/environments_spec.rb' + - 'ee/spec/helpers/subscriptions_helper_spec.rb' + - 'ee/spec/lib/banzai/filter/references/iteration_reference_filter_spec.rb' + - 'ee/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb' + - 'ee/spec/lib/gitlab/status_page/filter/image_filter_spec.rb' + - 'ee/spec/requests/api/ci/jobs_spec.rb' + - 'ee/spec/services/geo/container_repository_sync_spec.rb' + - 'lib/banzai/filter/autolink_filter.rb' + - 'lib/banzai/filter/references/reference_filter.rb' + - 'lib/banzai/filter/spaced_link_filter.rb' + - 'lib/banzai/filter/table_of_contents_filter.rb' + - 'lib/banzai/issuable_extractor.rb' + - 'lib/gitlab/authorized_keys.rb' + - 'lib/gitlab/etag_caching/middleware.rb' + - 'lib/gitlab/etag_caching/router/rails.rb' + - 'lib/gitlab/gl_repository/identifier.rb' + - 'lib/gitlab/import_export/repo_restorer.rb' + - 'lib/kramdown/parser/atlassian_document_format.rb' + - 'lib/tasks/tanuki_emoji.rake' + - 'qa/qa/ee/page/dashboard/projects.rb' + - 'qa/qa/ee/page/group/settings/general.rb' + - 'qa/qa/ee/page/project/issue/show.rb' + - 'qa/qa/ee/page/project/job/show.rb' + - 'qa/qa/ee/page/project/packages/index.rb' + - 'qa/qa/ee/page/project/pipeline/show.rb' + - 'qa/qa/ee/page/project/show.rb' + - 'qa/qa/ee/page/project/snippet/index.rb' + - 'qa/qa/ee/page/project/wiki/show.rb' + - 'qa/qa/page/component/design_management.rb' + - 'qa/qa/page/component/select2.rb' + - 'qa/qa/page/element.rb' + - 'qa/qa/page/file/form.rb' + - 'qa/qa/page/project/web_ide/edit.rb' + - 'qa/qa/resource/events/project.rb' + - 'qa/qa/resource/members.rb' + - 'qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/1_manage/group/group_saml_enforced_sso_new_account_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb' + - 'qa/qa/support/page/logging.rb' + - 'qa/spec/runtime/feature_spec.rb' + - 'scripts/regenerate-schema' + - 'scripts/trigger-build.rb' + - 'spec/controllers/import/fogbugz_controller_spec.rb' + - 'spec/controllers/projects/artifacts_controller_spec.rb' + - 'spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb' + - 'spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb' + - 'spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb' + - 'spec/features/projects/artifacts/user_downloads_artifacts_spec.rb' + - 'spec/features/projects/badges/coverage_spec.rb' + - 'spec/features/projects/badges/pipeline_badge_spec.rb' + - 'spec/features/projects/issuable_templates_spec.rb' + - 'spec/features/projects/jobs_spec.rb' + - 'spec/features/projects/pipelines/legacy_pipeline_spec.rb' + - 'spec/features/projects/pipelines/legacy_pipelines_spec.rb' + - 'spec/features/projects/pipelines/pipeline_spec.rb' + - 'spec/features/projects/pipelines/pipelines_spec.rb' + - 'spec/features/uploads/user_uploads_avatar_to_group_spec.rb' + - 'spec/features/uploads/user_uploads_avatar_to_profile_spec.rb' + - 'spec/graphql/resolvers/echo_resolver_spec.rb' + - 'spec/helpers/markup_helper_spec.rb' + - 'spec/lib/banzai/filter/autolink_filter_spec.rb' + - 'spec/lib/banzai/filter/external_link_filter_spec.rb' + - 'spec/lib/banzai/filter/image_link_filter_spec.rb' + - 'spec/lib/banzai/filter/references/label_reference_filter_spec.rb' + - 'spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb' + - 'spec/lib/banzai/pipeline/full_pipeline_spec.rb' + - 'spec/lib/banzai/pipeline/plain_markdown_pipeline_spec.rb' + - 'spec/lib/banzai/reference_parser/commit_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/issue_parser_spec.rb' + - 'spec/lib/banzai/reference_parser/merge_request_parser_spec.rb' + - 'spec/lib/gitlab/diff/highlight_spec.rb' + - 'spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb' + - 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb' + - 'spec/lib/gitlab/highlight_spec.rb' + - 'spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb' + - 'spec/lib/gitlab/pagination/offset_pagination_spec.rb' + - 'spec/lib/gitlab/prometheus/query_variables_spec.rb' + - 'spec/lib/gitlab/reference_extractor_spec.rb' + - 'spec/lib/gitlab/url_sanitizer_spec.rb' + - 'spec/mailers/emails/releases_spec.rb' + - 'spec/mailers/emails/service_desk_spec.rb' + - 'spec/models/deployment_spec.rb' + - 'spec/models/integrations/drone_ci_spec.rb' + - 'spec/models/integrations/teamcity_spec.rb' + - 'spec/models/project_label_spec.rb' + - 'spec/presenters/snippet_blob_presenter_spec.rb' + - 'spec/requests/api/ci/job_artifacts_spec.rb' + - 'spec/requests/api/deployments_spec.rb' + - 'spec/requests/api/graphql/mutations/snippets/destroy_spec.rb' + - 'spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb' + - 'spec/services/prometheus/proxy_variable_substitution_service_spec.rb' + - 'spec/support/banzai/reference_filter_shared_examples.rb' + - 'spec/support/helpers/graphql_helpers.rb' + - 'spec/support/shared_examples/controllers/repository_lfs_file_load_shared_examples.rb' + - 'spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb' + - 'spec/support/shared_examples/graphql/label_fields.rb' + - 'spec/support/shared_examples/lib/banzai/filters/sanitization_filter_shared_examples.rb' + - 'spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb' + - 'spec/views/layouts/_head.html.haml_spec.rb' diff --git a/.rubocop_todo/style/rescue_modifier.yml b/.rubocop_todo/style/rescue_modifier.yml new file mode 100644 index 00000000000..298ef3aece9 --- /dev/null +++ b/.rubocop_todo/style/rescue_modifier.yml @@ -0,0 +1,51 @@ +--- +# Cop supports --auto-correct. +Style/RescueModifier: + # Offense count: 59 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'app/controllers/admin/system_info_controller.rb' + - 'app/controllers/users_controller.rb' + - 'app/finders/ci/daily_build_group_report_results_finder.rb' + - 'app/helpers/blob_helper.rb' + - 'app/models/concerns/diff_positionable_note.rb' + - 'app/models/integrations/jira.rb' + - 'app/models/sent_notification.rb' + - 'app/models/todo.rb' + - 'app/services/security/ci_configuration/sast_parser_service.rb' + - 'config/initializers/active_record_data_types.rb' + - 'config/settings.rb' + - 'ee/app/models/license.rb' + - 'ee/lib/ee/gitlab/background_migration/drop_invalid_remediations.rb' + - 'ee/lib/gitlab/geo.rb' + - 'ee/lib/gitlab/geo/health_check.rb' + - 'lib/api/helpers.rb' + - 'lib/feature.rb' + - 'lib/gitlab/current_settings.rb' + - 'lib/gitlab/dependency_linker/cargo_toml_linker.rb' + - 'lib/gitlab/dependency_linker/json_linker.rb' + - 'lib/gitlab/diff/parser.rb' + - 'lib/gitlab/import_export/after_export_strategy_builder.rb' + - 'lib/gitlab/kubernetes.rb' + - 'lib/gitlab/middleware/read_only/controller.rb' + - 'lib/gitlab/process_management.rb' + - 'lib/gitlab/query_limiting/middleware.rb' + - 'lib/gitlab/quick_actions/command_definition.rb' + - 'lib/gitlab/quick_actions/spend_time_and_date_separator.rb' + - 'lib/gitlab/word_diff/segments/diff_hunk.rb' + - 'lib/gitlab/zentao/client.rb' + - 'lib/tasks/gitlab/praefect.rake' + - 'qa/qa/page/component/access_tokens.rb' + - 'qa/qa/page/profile/ssh_keys.rb' + - 'spec/finders/concerns/finder_with_cross_project_access_spec.rb' + - 'spec/lib/gitlab/database/load_balancing/session_spec.rb' + - 'spec/lib/gitlab/database/migrations/instrumentation_spec.rb' + - 'spec/lib/gitlab/email/handler/service_desk_handler_spec.rb' + - 'spec/lib/gitlab/sidekiq_middleware/monitor_spec.rb' + - 'spec/models/concerns/bulk_insert_safe_spec.rb' + - 'spec/models/design_management/version_spec.rb' + - 'spec/models/group_spec.rb' + - 'spec/models/namespace/traversal_hierarchy_spec.rb' + - 'spec/services/design_management/delete_designs_service_spec.rb' + - 'spec/support/shared_examples/lib/gitlab/config/inheritable_shared_examples.rb' diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index f7c29cb018f..235e115267d 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -60a7383d965aa6a8e69aa2e33a84792cde486cd3 +42fab8fc526215f9426bc9f459f9e6da0951c574 diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js index ee2f6cfb46c..2ee2e199358 100644 --- a/app/assets/javascripts/blob_edit/edit_blob.js +++ b/app/assets/javascripts/blob_edit/edit_blob.js @@ -1,8 +1,8 @@ import $ from 'jquery'; import { SourceEditorExtension } from '~/editor/extensions/source_editor_extension_base'; import { FileTemplateExtension } from '~/editor/extensions/source_editor_file_template_ext'; +import { ToolbarExtension } from '~/editor/extensions/source_editor_toolbar_ext'; import SourceEditor from '~/editor/source_editor'; -import { getBlobLanguage } from '~/editor/utils'; import createFlash from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown'; @@ -36,7 +36,7 @@ export default class EditBlob { import('~/editor/extensions/source_editor_markdown_ext'), import('~/editor/extensions/source_editor_markdown_livepreview_ext'), ]); - this.editor.use([ + this.markdownExtensions = this.editor.use([ { definition: MarkdownExtension }, { definition: MarkdownLivePreview, @@ -48,7 +48,6 @@ export default class EditBlob { message: `${BLOB_EDITOR_ERROR}: ${e}`, }); } - this.hasMarkdownExtension = true; addEditorMarkdownListeners(this.editor); } @@ -58,8 +57,6 @@ export default class EditBlob { const fileContentEl = document.getElementById('file-content'); const form = document.querySelector('.js-edit-blob-form'); - this.hasMarkdownExtension = false; - const rootEditor = new SourceEditor(); this.editor = rootEditor.createInstance({ @@ -67,21 +64,29 @@ export default class EditBlob { blobPath: fileNameEl.value, blobContent: editorEl.innerText, }); - this.editor.use([{ definition: SourceEditorExtension }, { definition: FileTemplateExtension }]); + this.editor.use([ + { definition: SourceEditorExtension }, + { definition: FileTemplateExtension }, + { definition: ToolbarExtension }, + ]); fileNameEl.addEventListener('change', () => { this.editor.updateModelLanguage(fileNameEl.value); - const newLang = getBlobLanguage(fileNameEl.value); - if (newLang === 'markdown') { - if (!this.hasMarkdownExtension) { - this.fetchMarkdownExtension(); - } - } }); form.addEventListener('submit', () => { fileContentEl.value = insertFinalNewline(this.editor.getValue()); }); + + // onDidChangeModelLanguage is part of the native Monaco API + // https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneCodeEditor.html#onDidChangeModelLanguage + this.editor.onDidChangeModelLanguage(({ newLanguage = '', oldLanguage = '' }) => { + if (newLanguage === 'markdown') { + this.fetchMarkdownExtension(); + } else if (oldLanguage === 'markdown') { + this.editor.unuse(this.markdownExtensions); + } + }); } initFileSelectors() { diff --git a/app/assets/javascripts/editor/components/source_editor_toolbar.vue b/app/assets/javascripts/editor/components/source_editor_toolbar.vue index 1427f2df461..2c177634bbe 100644 --- a/app/assets/javascripts/editor/components/source_editor_toolbar.vue +++ b/app/assets/javascripts/editor/components/source_editor_toolbar.vue @@ -55,8 +55,8 @@ export default { id="se-toolbar" class="gl-py-3 gl-px-5 gl-bg-white gl-border-t gl-border-b gl-display-flex gl-justify-content-space-between gl-align-items-center" > - + diff --git a/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue b/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue index 2595d67af34..194b482c12e 100644 --- a/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue +++ b/app/assets/javascripts/editor/components/source_editor_toolbar_button.vue @@ -1,7 +1,5 @@ diff --git a/app/assets/javascripts/editor/components/source_editor_toolbar_graphql.js b/app/assets/javascripts/editor/components/source_editor_toolbar_graphql.js new file mode 100644 index 00000000000..603ba26f22e --- /dev/null +++ b/app/assets/javascripts/editor/components/source_editor_toolbar_graphql.js @@ -0,0 +1,53 @@ +import produce from 'immer'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import typeDefs from '~/editor/graphql/typedefs.graphql'; +import getToolbarItemsQuery from '~/editor/graphql/get_items.query.graphql'; +import createDefaultClient from '~/lib/graphql'; + +Vue.use(VueApollo); + +const resolvers = { + Mutation: { + addToolbarItems: (_, { items = [] }, { cache }) => { + const itemsSourceData = cache.readQuery({ query: getToolbarItemsQuery }); + const data = produce(itemsSourceData, (draftData) => { + const existingNodes = draftData?.items?.nodes || []; + draftData.items = { + nodes: Array.isArray(items) ? [...existingNodes, ...items] : [...existingNodes, items], + }; + }); + cache.writeQuery({ query: getToolbarItemsQuery, data }); + }, + + removeToolbarItems: (_, { ids }, { cache }) => { + const sourceData = cache.readQuery({ query: getToolbarItemsQuery }); + const { + items: { nodes }, + } = sourceData; + const data = produce(sourceData, (draftData) => { + draftData.items.nodes = nodes.filter((item) => !ids.includes(item.id)); + }); + cache.writeQuery({ query: getToolbarItemsQuery, data }); + }, + + updateToolbarItem: (_, { id, propsToUpdate }, { cache }) => { + const itemSourceData = cache.readQuery({ query: getToolbarItemsQuery }); + const data = produce(itemSourceData, (draftData) => { + const existingNodes = draftData?.items?.nodes || []; + draftData.items = { + nodes: existingNodes.map((item) => { + return item.id === id ? { ...item, ...propsToUpdate } : item; + }), + }; + }); + cache.writeQuery({ query: getToolbarItemsQuery, data }); + }, + }, +}; + +const defaultClient = createDefaultClient(resolvers, { typeDefs }); + +export const apolloProvider = new VueApollo({ + defaultClient, +}); diff --git a/app/assets/javascripts/editor/constants.js b/app/assets/javascripts/editor/constants.js index 361122d8890..83cfdd25757 100644 --- a/app/assets/javascripts/editor/constants.js +++ b/app/assets/javascripts/editor/constants.js @@ -1,5 +1,5 @@ import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; -import { s__ } from '~/locale'; +import { s__, __ } from '~/locale'; export const URI_PREFIX = 'gitlab'; export const CONTENT_UPDATE_DEBOUNCE = DEFAULT_DEBOUNCE_AND_THROTTLE_MS; @@ -57,5 +57,8 @@ export const EXTENSION_CI_SCHEMA_FILE_NAME_MATCH = '.gitlab-ci.yml'; export const EXTENSION_MARKDOWN_PREVIEW_PANEL_CLASS = 'md'; export const EXTENSION_MARKDOWN_PREVIEW_PANEL_PARENT_CLASS = 'source-editor-preview'; export const EXTENSION_MARKDOWN_PREVIEW_ACTION_ID = 'markdown-preview'; +export const EXTENSION_MARKDOWN_PREVIEW_HIDE_ACTION_ID = 'markdown-preview-hide'; export const EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH = 0.5; // 50% of the width export const EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY = 250; // ms +export const EXTENSION_MARKDOWN_PREVIEW_LABEL = __('Preview Markdown'); +export const EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL = __('Hide Live Preview'); diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js index 9d53268c340..11cc85c659d 100644 --- a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js +++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js @@ -3,14 +3,17 @@ import { BLOB_PREVIEW_ERROR } from '~/blob_edit/constants'; import createFlash from '~/flash'; import { sanitize } from '~/lib/dompurify'; import axios from '~/lib/utils/axios_utils'; -import { __ } from '~/locale'; import syntaxHighlight from '~/syntax_highlight'; import { EXTENSION_MARKDOWN_PREVIEW_PANEL_CLASS, EXTENSION_MARKDOWN_PREVIEW_ACTION_ID, + EXTENSION_MARKDOWN_PREVIEW_HIDE_ACTION_ID, EXTENSION_MARKDOWN_PREVIEW_PANEL_WIDTH, EXTENSION_MARKDOWN_PREVIEW_PANEL_PARENT_CLASS, EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY, + EXTENSION_MARKDOWN_PREVIEW_LABEL, + EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL, + EDITOR_TOOLBAR_RIGHT_GROUP, } from '../constants'; const fetchPreview = (text, previewMarkdownPath) => { @@ -41,31 +44,58 @@ export class EditorMarkdownPreviewExtension { onSetup(instance, setupOptions) { this.preview = { el: undefined, - action: undefined, + actions: { + preview: undefined, + hide: undefined, + }, shown: false, modelChangeListener: undefined, path: setupOptions.previewMarkdownPath, + actionShowPreviewCondition: instance.createContextKey('toggleLivePreview', true), }; + this.toolbarButtons = []; + this.setupPreviewAction(instance); + if (instance.toolbar) { + this.setupToolbar(instance); + } + } - instance.getModel().onDidChangeLanguage(({ newLanguage, oldLanguage } = {}) => { - if (newLanguage === 'markdown' && oldLanguage !== newLanguage) { - instance.setupPreviewAction(); - } else { - instance.cleanup(); - } - }); + onBeforeUnuse(instance) { + this.cleanup(instance); + const ids = this.toolbarButtons.map((item) => item.id); + if (instance.toolbar) { + instance.toolbar.removeItems(ids); + } + } - instance.onDidChangeModel(() => { - const model = instance.getModel(); - if (model) { - const { language } = model.getLanguageIdentifier(); - instance.cleanup(); - if (language === 'markdown') { - instance.setupPreviewAction(); - } - } - }); + cleanup(instance) { + if (this.preview.modelChangeListener) { + this.preview.modelChangeListener.dispose(); + } + this.preview.actions.preview.dispose(); + this.preview.actions.hide.dispose(); + if (this.preview.shown) { + this.togglePreviewPanel(instance); + this.togglePreviewLayout(instance); + } + this.preview.shown = false; + } + + setupToolbar(instance) { + this.toolbarButtons = [ + { + id: EXTENSION_MARKDOWN_PREVIEW_ACTION_ID, + label: EXTENSION_MARKDOWN_PREVIEW_LABEL, + icon: 'live-preview', + selected: false, + group: EDITOR_TOOLBAR_RIGHT_GROUP, + category: 'primary', + selectedLabel: EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL, + onClick: () => instance.togglePreview(), + }, + ]; + instance.toolbar.addItems(this.toolbarButtons); } togglePreviewLayout(instance) { @@ -103,22 +133,33 @@ export class EditorMarkdownPreviewExtension { setupPreviewAction(instance) { if (instance.getAction(EXTENSION_MARKDOWN_PREVIEW_ACTION_ID)) return; - - this.preview.action = instance.addAction({ - id: EXTENSION_MARKDOWN_PREVIEW_ACTION_ID, - label: __('Preview Markdown'), + const actionBasis = { keybindings: [ // eslint-disable-next-line no-bitwise,no-undef monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KEY_P), ], contextMenuGroupId: 'navigation', contextMenuOrder: 1.5, - // Method that will be executed when the action is triggered. // @param ed The editor instance is passed in as a convenience run(inst) { inst.togglePreview(); }, + }; + + this.preview.actions.preview = instance.addAction({ + ...actionBasis, + id: EXTENSION_MARKDOWN_PREVIEW_ACTION_ID, + label: EXTENSION_MARKDOWN_PREVIEW_LABEL, + + precondition: 'toggleLivePreview', + }); + this.preview.actions.hide = instance.addAction({ + ...actionBasis, + id: EXTENSION_MARKDOWN_PREVIEW_HIDE_ACTION_ID, + label: EXTENSION_MARKDOWN_HIDE_PREVIEW_LABEL, + + precondition: '!toggleLivePreview', }); } @@ -126,18 +167,6 @@ export class EditorMarkdownPreviewExtension { return { markdownPreview: this.preview, - cleanup: (instance) => { - if (this.preview.modelChangeListener) { - this.preview.modelChangeListener.dispose(); - } - this.preview.action.dispose(); - if (this.preview.shown) { - this.togglePreviewPanel(instance); - this.togglePreviewLayout(instance); - } - this.preview.shown = false; - }, - fetchPreview: (instance) => this.fetchPreview(instance), setupPreviewAction: (instance) => this.setupPreviewAction(instance), @@ -149,6 +178,8 @@ export class EditorMarkdownPreviewExtension { this.togglePreviewLayout(instance); this.togglePreviewPanel(instance); + this.preview.actionShowPreviewCondition.set(!this.preview.actionShowPreviewCondition.get()); + if (!this.preview?.shown) { this.preview.modelChangeListener = instance.onDidChangeModelContent( debounce( @@ -161,6 +192,11 @@ export class EditorMarkdownPreviewExtension { } this.preview.shown = !this.preview?.shown; + if (instance.toolbar) { + instance.toolbar.updateItem(EXTENSION_MARKDOWN_PREVIEW_ACTION_ID, { + selected: this.preview.shown, + }); + } }, }; } diff --git a/app/assets/javascripts/editor/extensions/source_editor_toolbar_ext.js b/app/assets/javascripts/editor/extensions/source_editor_toolbar_ext.js new file mode 100644 index 00000000000..9655c8ae76a --- /dev/null +++ b/app/assets/javascripts/editor/extensions/source_editor_toolbar_ext.js @@ -0,0 +1,98 @@ +import Vue from 'vue'; +import getToolbarItemsQuery from '~/editor/graphql/get_items.query.graphql'; +import removeToolbarItemsMutation from '~/editor/graphql/remove_items.mutation.graphql'; +import updateToolbarItemMutation from '~/editor/graphql/update_item.mutation.graphql'; +import addToolbarItemsMutation from '~/editor/graphql/add_items.mutation.graphql'; +import SourceEditorToolbar from '~/editor/components/source_editor_toolbar.vue'; +import { apolloProvider } from '~/editor/components/source_editor_toolbar_graphql'; + +const client = apolloProvider.defaultClient; + +export class ToolbarExtension { + /** + * A required getter returning the extension's name + * We have to provide it for every extension instead of relying on the built-in + * `name` prop because the prop does not survive the webpack's minification + * and the name mangling. + * @returns {string} + */ + static get extensionName() { + return 'ToolbarExtension'; + } + /** + * THE LIFE-CYCLE CALLBACKS + */ + + /** + * Is called before the extension gets used by an instance, + * Use `onSetup` to setup Monaco directly: + * actions, keystrokes, update options, etc. + * Is called only once before the extension gets registered + * + * @param { Object } [instance] The Source Editor instance + * @param { Object } [setupOptions] The setupOptions object + */ + // eslint-disable-next-line class-methods-use-this + onSetup(instance, setupOptions) { + const el = setupOptions?.el || document.getElementById('editor-toolbar'); + ToolbarExtension.setupVue(el); + } + + static setupVue(el) { + client.cache.writeQuery({ query: getToolbarItemsQuery, data: { items: { nodes: [] } } }); + const ToolbarComponent = Vue.extend(SourceEditorToolbar); + + const toolbar = new ToolbarComponent({ + el, + apolloProvider, + }); + toolbar.$mount(); + } + + /** + * The public API of the extension: these are the methods that will be exposed + * to the end user + * @returns {Object} + */ + // eslint-disable-next-line class-methods-use-this + provides() { + return { + toolbar: { + getItem: (id) => { + const items = client.readQuery({ query: getToolbarItemsQuery })?.items?.nodes || []; + return items.find((item) => item.id === id); + }, + getAllItems: () => { + return client.readQuery({ query: getToolbarItemsQuery })?.items?.nodes || []; + }, + addItems: (items = []) => { + return client.mutate({ + mutation: addToolbarItemsMutation, + variables: { + items, + }, + }); + }, + removeItems: (ids = []) => { + client.mutate({ + mutation: removeToolbarItemsMutation, + variables: { + ids, + }, + }); + }, + updateItem: (id = '', propsToUpdate = {}) => { + if (id) { + client.mutate({ + mutation: updateToolbarItemMutation, + variables: { + id, + propsToUpdate, + }, + }); + } + }, + }, + }; + } +} diff --git a/app/assets/javascripts/editor/graphql/add_items.mutation.graphql b/app/assets/javascripts/editor/graphql/add_items.mutation.graphql new file mode 100644 index 00000000000..13afcc04a48 --- /dev/null +++ b/app/assets/javascripts/editor/graphql/add_items.mutation.graphql @@ -0,0 +1,3 @@ +mutation addItems($items: [Item]) { + addToolbarItems(items: $items) @client +} diff --git a/app/assets/javascripts/editor/graphql/get_item.query.graphql b/app/assets/javascripts/editor/graphql/get_item.query.graphql deleted file mode 100644 index 7c8bc09f7b0..00000000000 --- a/app/assets/javascripts/editor/graphql/get_item.query.graphql +++ /dev/null @@ -1,9 +0,0 @@ -query ToolbarItem($id: String!) { - item(id: $id) @client { - id - label - icon - selected - group - } -} diff --git a/app/assets/javascripts/editor/graphql/remove_items.mutation.graphql b/app/assets/javascripts/editor/graphql/remove_items.mutation.graphql new file mode 100644 index 00000000000..627f105b0ec --- /dev/null +++ b/app/assets/javascripts/editor/graphql/remove_items.mutation.graphql @@ -0,0 +1,3 @@ +mutation removeToolbarItems($ids: [ID!]) { + removeToolbarItems(ids: $ids) @client +} diff --git a/app/assets/javascripts/editor/graphql/typedefs.graphql b/app/assets/javascripts/editor/graphql/typedefs.graphql new file mode 100644 index 00000000000..2433ebf6c66 --- /dev/null +++ b/app/assets/javascripts/editor/graphql/typedefs.graphql @@ -0,0 +1,23 @@ +type Item { + id: ID! + label: String! + icon: String + selected: Boolean + group: Int! + category: String + selectedLabel: String +} + +type Items { + nodes: [Item]! +} + +extend type Query { + items: Items +} + +extend type Mutation { + updateToolbarItem(id: ID!, propsToUpdate: Item!): LocalErrors + removeToolbarItems(ids: [ID!]): LocalErrors + addToolbarItems(items: [Item]): LocalErrors +} diff --git a/app/assets/javascripts/editor/graphql/update_item.mutation.graphql b/app/assets/javascripts/editor/graphql/update_item.mutation.graphql index f8424c65181..05c18988c87 100644 --- a/app/assets/javascripts/editor/graphql/update_item.mutation.graphql +++ b/app/assets/javascripts/editor/graphql/update_item.mutation.graphql @@ -1,3 +1,3 @@ -mutation updateItem($id: String!, $propsToUpdate: Item!) { +mutation updateItem($id: ID!, $propsToUpdate: Item!) { updateToolbarItem(id: $id, propsToUpdate: $propsToUpdate) @client } diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js index 24ec16bf20e..c9b6a4f9913 100644 --- a/app/assets/javascripts/flash.js +++ b/app/assets/javascripts/flash.js @@ -207,7 +207,7 @@ const createAlert = function createAlert({ }); }; -/* +/** * Flash banner supports different types of Flash configurations * along with ability to provide actionConfig which can be used to show * additional action or link on banner next to message @@ -223,6 +223,7 @@ const createAlert = function createAlert({ * @param {Boolean} options.fadeTransition Boolean to determine whether to fade the alert out * @param {Boolean} options.captureError Boolean to determine whether to send error to Sentry * @param {Object} options.error Error to be captured in Sentry + * @deprecated Use `createAlert` instead. See https://gitlab.com/gitlab-org/gitlab/-/issues/362334. */ const createFlash = function createFlash({ message, diff --git a/app/assets/javascripts/group.js b/app/assets/javascripts/group.js index b6a6720e7a1..49e7dd28ff6 100644 --- a/app/assets/javascripts/group.js +++ b/app/assets/javascripts/group.js @@ -1,8 +1,13 @@ +import { debounce } from 'lodash'; + import createFlash from '~/flash'; import { __ } from '~/locale'; import { getGroupPathAvailability } from '~/rest_api'; +import axios from '~/lib/utils/axios_utils'; import { slugify } from './lib/utils/text_utility'; +const DEBOUNCE_TIMEOUT_DURATION = 1000; + export default class Group { constructor() { this.groupPaths = Array.from(document.querySelectorAll('.js-autofill-group-path')); @@ -10,7 +15,11 @@ export default class Group { this.parentId = document.getElementById('group_parent_id'); this.updateHandler = this.update.bind(this); this.resetHandler = this.reset.bind(this); - this.updateGroupPathSlugHandler = this.updateGroupPathSlug.bind(this); + this.updateGroupPathSlugHandler = debounce( + this.updateGroupPathSlug.bind(this), + DEBOUNCE_TIMEOUT_DURATION, + ); + this.currentApiRequestController = null; this.groupNames.forEach((groupName) => { groupName.addEventListener('keyup', this.updateHandler); @@ -44,13 +53,23 @@ export default class Group { }); } - updateGroupPathSlug({ currentTarget: { value } = '' } = {}) { - const slug = this.groupPaths[0]?.value || slugify(value); + updateGroupPathSlug({ target: { value } = '' } = {}) { + if (this.currentApiRequestController !== null) { + this.currentApiRequestController.abort(); + } + + this.currentApiRequestController = new AbortController(); + + const slug = slugify(value); if (!slug) return; - getGroupPathAvailability(slug, this.parentId?.value) + getGroupPathAvailability(slug, this.parentId?.value, { + signal: this.currentApiRequestController.signal, + }) .then(({ data }) => data) .then(({ exists, suggests }) => { + this.currentApiRequestController = null; + if (exists && suggests.length) { const [suggestedSlug] = suggests; @@ -63,10 +82,14 @@ export default class Group { }); } }) - .catch(() => + .catch((error) => { + if (axios.isCancel(error)) { + return; + } + createFlash({ message: __('An error occurred while checking group path. Please refresh and try again.'), - }), - ); + }); + }); } } diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index 4a15b810d38..02a815db09c 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -90,9 +90,16 @@ export default { return this.getUserData.id; }, commentButtonTitle() { - return this.noteType === constants.COMMENT - ? this.$options.i18n.comment - : this.$options.i18n.startThread; + const { comment, internalComment, startThread, startInternalThread } = this.$options.i18n; + if (this.getNoteableData.confidential || this.noteIsConfidential) { + return this.noteType === constants.COMMENT ? internalComment : startInternalThread; + } + return this.noteType === constants.COMMENT ? comment : startThread; + }, + textareaPlaceholder() { + return this.getNoteableData.confidential || this.noteIsConfidential + ? this.$options.i18n.bodyPlaceholderInternal + : this.$options.i18n.bodyPlaceholder; }, discussionsRequireResolution() { return this.getNoteableData.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE; @@ -371,7 +378,7 @@ export default { data-testid="comment-field" data-supports-quick-actions="true" :aria-label="$options.i18n.comment" - :placeholder="$options.i18n.bodyPlaceholder" + :placeholder="textareaPlaceholder" @keydown.up="editCurrentUserLastNote()" @keydown.meta.enter="handleEnter()" @keydown.ctrl.enter="handleEnter()" @@ -419,6 +426,7 @@ export default { class="gl-mr-3" :disabled="disableSubmitButton" :tracking-label="trackingLabel" + :is-internal-note="noteIsConfidential" :noteable-display-name="noteableDisplayName" :discussions-require-resolution="discussionsRequireResolution" @click="handleSave" diff --git a/app/assets/javascripts/notes/components/comment_type_dropdown.vue b/app/assets/javascripts/notes/components/comment_type_dropdown.vue index 30ea5d3532e..543be838920 100644 --- a/app/assets/javascripts/notes/components/comment_type_dropdown.vue +++ b/app/assets/javascripts/notes/components/comment_type_dropdown.vue @@ -32,6 +32,11 @@ export default { required: false, default: false, }, + isInternalNote: { + type: Boolean, + required: false, + default: false, + }, noteableDisplayName: { type: String, required: true, @@ -48,18 +53,43 @@ export default { isNoteTypeDiscussion() { return this.noteType === constants.DISCUSSION; }, + dropdownCommentButtonTitle() { + const { comment, internalComment } = this.$options.i18n.submitButton; + + return this.isInternalNote ? internalComment : comment; + }, + dropdownStartThreadButtonTitle() { + const { startThread, startInternalThread } = this.$options.i18n.submitButton; + + return this.isInternalNote ? startInternalThread : startThread; + }, commentButtonTitle() { - return this.noteType === constants.COMMENT - ? this.$options.i18n.comment - : this.$options.i18n.startThread; + const { comment, internalComment, startThread, startInternalThread } = this.$options.i18n; + + if (this.isInternalNote) { + return this.noteType === constants.COMMENT ? internalComment : startInternalThread; + } + return this.noteType === constants.COMMENT ? comment : startThread; }, startDiscussionDescription() { - return this.discussionsRequireResolution - ? this.$options.i18n.discussionThatNeedsResolution - : this.$options.i18n.discussion; + const { + discussionThatNeedsResolution, + internalDiscussionThatNeedsResolution, + discussion, + internalDiscussion, + } = this.$options.i18n; + + if (this.isInternalNote) { + return this.discussionsRequireResolution + ? internalDiscussionThatNeedsResolution + : internalDiscussion; + } + return this.discussionsRequireResolution ? discussionThatNeedsResolution : discussion; }, commentDescription() { - return sprintf(this.$options.i18n.submitButton.commentHelp, { + const { commentHelp, internalCommentHelp } = this.$options.i18n.submitButton; + + return sprintf(this.isInternalNote ? internalCommentHelp : commentHelp, { noteableDisplayName: this.noteableDisplayName, }); }, @@ -101,7 +131,7 @@ export default { :is-checked="isNoteTypeComment" @click.stop.prevent="setNoteTypeToComment" > - {{ $options.i18n.submitButton.comment }} + {{ dropdownCommentButtonTitle }}

{{ commentDescription }}

@@ -111,7 +141,7 @@ export default { data-qa-selector="discussion_menu_item" @click.stop.prevent="setNoteTypeToDiscussion" > - {{ $options.i18n.submitButton.startThread }} + {{ dropdownStartThreadButtonTitle }}

{{ startDiscussionDescription }}

diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue index fe17a061c0a..6c9bc4461c2 100644 --- a/app/assets/javascripts/notes/components/note_body.vue +++ b/app/assets/javascripts/notes/components/note_body.vue @@ -4,6 +4,7 @@ import { GlSafeHtmlDirective } from '@gitlab/ui'; import { escape } from 'lodash'; import { mapActions, mapGetters, mapState } from 'vuex'; +import { __ } from '~/locale'; import '~/behaviors/markdown/render_gfm'; import Suggestions from '~/vue_shared/components/markdown/suggestions.vue'; import autosave from '../mixins/autosave'; @@ -69,6 +70,9 @@ export default { noteBody() { return this.note.note; }, + saveButtonTitle() { + return this.note.confidential ? __('Save internal note') : __('Save comment'); + }, hasSuggestion() { return this.note.suggestions && this.note.suggestions.length; }, @@ -180,6 +184,7 @@ export default { :note-id="note.id" :line="line" :note="note" + :save-button-title="saveButtonTitle" :help-page-path="helpPagePath" :discussion="discussion" :resolve-discussion="note.resolve_discussion" diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index c1e763d81ee..5dd032abd72 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -8,9 +8,11 @@ import markdownField from '~/vue_shared/components/markdown/field.vue'; import eventHub from '../event_hub'; import issuableStateMixin from '../mixins/issuable_state'; import resolvable from '../mixins/resolvable'; +import { COMMENT_FORM } from '../i18n'; import CommentFieldLayout from './comment_field_layout.vue'; export default { + i18n: COMMENT_FORM, name: 'NoteForm', components: { markdownField, @@ -133,6 +135,11 @@ export default { .some((n) => n.current_user?.can_resolve_discussion) || this.isDraft ); }, + textareaPlaceholder() { + return this.discussionNote?.confidential + ? this.$options.i18n.bodyPlaceholderInternal + : this.$options.i18n.bodyPlaceholder; + }, noteHash() { if (this.noteId) { return `#note_${this.noteId}`; @@ -350,7 +357,7 @@ export default { data-qa-selector="reply_field" dir="auto" :aria-label="__('Reply to comment')" - :placeholder="__('Write a comment or drag your files here…')" + :placeholder="textareaPlaceholder" @keydown.meta.enter="handleKeySubmit()" @keydown.ctrl.enter="handleKeySubmit()" @keydown.exact.up="editMyLastNote()" diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue index 11b427b9346..1ad9d593ccc 100644 --- a/app/assets/javascripts/notes/components/note_header.vue +++ b/app/assets/javascripts/notes/components/note_header.vue @@ -1,6 +1,7 @@