From e7b6cfeafec270237f1d59d950b2d27b4c7de7d1 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 25 Aug 2021 15:11:14 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitignore | 1 + .../issue_templates/Feature Flag Roll Out.md | 17 +- .rubocop_manual_todo.yml | 24 - Gemfile | 4 +- Gemfile.lock | 12 +- .../stylesheets/startup/startup-signin.scss | 4 +- .../design_at_version_type.rb | 4 +- .../types/design_management/design_fields.rb | 16 +- app/graphql/types/diff_paths_input_type.rb | 4 +- app/graphql/types/environment_type.rb | 4 +- app/graphql/types/eventable_type.rb | 2 +- app/graphql/types/group_type.rb | 6 +- app/graphql/types/merge_request_type.rb | 6 +- app/graphql/types/metadata/kas_type.rb | 2 +- .../types/milestone_wildcard_id_enum.rb | 2 +- app/graphql/types/namespace_type.rb | 2 +- app/graphql/types/notes/note_type.rb | 4 +- app/graphql/types/notes/position_type_enum.rb | 2 +- .../types/packages/composer/json_type.rb | 8 +- .../types/packages/package_details_type.rb | 2 +- .../types/packages/package_file_type.rb | 4 +- .../types/packages/package_tag_type.rb | 8 +- app/graphql/types/packages/package_type.rb | 2 +- app/graphql/types/project_type.rb | 6 +- app/graphql/types/prometheus_alert_type.rb | 2 +- app/graphql/types/query_type.rb | 6 +- app/graphql/types/range_input_type.rb | 4 +- ...lease_asset_link_shared_input_arguments.rb | 2 +- .../types/release_assets_input_type.rb | 2 +- app/graphql/types/release_type.rb | 2 +- .../merge_requests/merge_to_ref_service.rb | 9 +- doc/.vale/gitlab/spelling-exceptions.txt | 1 + doc/api/graphql/reference/index.md | 148 ++-- doc/development/documentation/testing.md | 32 + .../end_to_end/best_practices.md | 8 +- doc/update/index.md | 15 +- lib/api/files.rb | 15 +- package.json | 2 +- qa/Gemfile | 8 +- qa/Gemfile.lock | 2 +- qa/qa.rb | 722 ++---------------- qa/qa/ce/strategy.rb | 4 - qa/qa/flow/saml.rb | 2 +- qa/qa/git/repository.rb | 1 - qa/qa/page/project/monitor/metrics/show.rb | 2 - qa/qa/page/project/settings/ci_cd.rb | 4 +- qa/qa/page/view.rb | 2 - qa/qa/resource/api_fabricator.rb | 2 +- qa/qa/resource/ci_variable.rb | 2 +- qa/qa/resource/issue.rb | 2 - qa/qa/resource/kubernetes_cluster/base.rb | 2 - qa/qa/resource/label_base.rb | 2 - qa/qa/resource/members.rb | 4 +- qa/qa/resource/merge_request.rb | 2 - qa/qa/resource/merge_request_from_fork.rb | 2 - qa/qa/resource/package.rb | 2 - qa/qa/resource/project.rb | 2 - .../resource/project_imported_from_github.rb | 4 +- qa/qa/resource/project_imported_from_url.rb | 2 - qa/qa/resource/project_issue_note.rb | 2 - qa/qa/resource/protected_branch.rb | 2 - qa/qa/resource/registry_repository.rb | 2 - qa/qa/resource/repository/project_push.rb | 2 - qa/qa/resource/repository/push.rb | 3 - qa/qa/resource/runner.rb | 2 - qa/qa/resource/ssh_key.rb | 2 +- qa/qa/resource/user.rb | 2 - qa/qa/resource/wiki/group_page.rb | 2 - qa/qa/runtime/allure_report.rb | 2 - qa/qa/runtime/api/repository_storage_moves.rb | 2 +- qa/qa/runtime/application_settings.rb | 4 +- qa/qa/runtime/browser.rb | 1 - qa/qa/runtime/env.rb | 1 - qa/qa/runtime/feature.rb | 6 +- qa/qa/runtime/fixtures.rb | 2 +- qa/qa/runtime/ip_address.rb | 4 +- qa/qa/runtime/release.rb | 4 - qa/qa/runtime/search.rb | 4 +- qa/qa/service/docker_run/gitlab_runner.rb | 1 - qa/qa/service/kubernetes_cluster.rb | 2 - .../1_manage/import_large_github_repo_spec.rb | 2 - .../closes_issue_via_pushing_a_commit_spec.rb | 2 +- .../default_branch_name_setting_spec.rb | 2 - .../api/3_create/repository/files_spec.rb | 1 - .../project_archive_compare_spec.rb | 3 +- .../api/5_package/container_registry_spec.rb | 2 +- .../login_via_instance_wide_saml_sso_spec.rb | 7 +- .../1_manage/project/dashboard_images_spec.rb | 2 - .../email/trigger_email_notification_spec.rb | 2 +- .../2_plan/issue/export_as_csv_spec.rb | 2 - .../jenkins/jenkins_build_status_spec.rb | 1 - .../jira/jira_basic_integration_spec.rb | 2 +- .../repository/add_file_template_spec.rb | 2 - .../push_over_http_file_size_spec.rb | 2 +- .../web_ide/add_file_template_spec.rb | 2 - .../pipeline_with_protected_variable_spec.rb | 2 - ...lude_multiple_files_from_a_project_spec.rb | 2 - .../merge_mr_when_pipline_is_blocked_spec.rb | 2 - .../pipeline/mr_event_rule_pipeline_spec.rb | 2 - ...variables_to_downstream_via_bridge_spec.rb | 2 - ...trigger_child_pipeline_with_manual_spec.rb | 2 - .../4_verify/pipeline/trigger_matrix_spec.rb | 2 - .../4_verify/runner/register_runner_spec.rb | 2 +- .../testing/view_code_coverage_spec.rb | 2 +- .../5_package/composer_registry_spec.rb | 2 - .../5_package/maven_repository_spec.rb | 2 - .../5_package/nuget_repository_spec.rb | 2 - .../create_project_with_auto_devops_spec.rb | 4 +- qa/qa/specs/runner.rb | 1 - qa/qa/support/api.rb | 4 +- qa/qa/support/helpers/stub_env.rb | 46 ++ qa/qa/support/matchers/eventually_matcher.rb | 141 ++++ qa/qa/support/matchers/have_matcher.rb | 36 + qa/qa/support/matchers/have_text.rb | 52 ++ qa/qa/tools/delete_projects.rb | 2 +- qa/qa/tools/delete_subgroups.rb | 2 +- qa/qa/tools/delete_test_ssh_keys.rb | 2 +- qa/qa/tools/generate_perf_testdata.rb | 4 +- qa/qa/vendor/jira/jira_api.rb | 2 +- qa/qa/vendor/saml_idp/page/base.rb | 2 +- qa/qa/vendor/saml_idp/page/login.rb | 2 +- qa/spec/git/repository_spec.rb | 2 +- qa/spec/page/logging_spec.rb | 1 - qa/spec/resource/base_spec.rb | 2 +- qa/spec/runtime/api/client_spec.rb | 2 +- qa/spec/runtime/env_spec.rb | 2 +- qa/spec/runtime/namespace_spec.rb | 2 +- qa/spec/runtime/release_spec.rb | 19 - qa/spec/spec_helper.rb | 13 +- qa/spec/specs/allure_report_spec.rb | 4 +- .../specs/helpers/context_selector_spec.rb | 2 +- qa/spec/specs/helpers/quarantine_spec.rb | 2 +- qa/spec/specs/parallel_runner_spec.rb | 2 +- .../support/allure_metadata_formatter_spec.rb | 2 +- qa/spec/support/helpers/stub_env.rb | 42 - .../support/matchers/eventually_matcher.rb | 133 ---- qa/spec/support/matchers/have_matcher.rb | 30 - qa/spec/support/matchers/have_text.rb | 48 -- qa/spec/support/repeater_spec.rb | 2 - qa/spec/support/retrier_spec.rb | 3 - qa/spec/support/waiter_spec.rb | 2 - spec/deprecation_toolkit_env.rb | 6 +- .../components/modals/leave_modal_spec.js | 8 +- .../__snapshots__/memory_graph_spec.js.snap | 1 - spec/requests/api/files_spec.rb | 13 + .../merge_to_ref_service_spec.rb | 28 +- .../prevent_cross_database_modification.rb | 4 +- ...revent_cross_database_modification_spec.rb | 19 + spec/tooling/graphql/docs/renderer_spec.rb | 4 +- yarn.lock | 8 +- 150 files changed, 671 insertions(+), 1314 deletions(-) create mode 100644 qa/qa/support/helpers/stub_env.rb create mode 100644 qa/qa/support/matchers/eventually_matcher.rb create mode 100644 qa/qa/support/matchers/have_matcher.rb create mode 100644 qa/qa/support/matchers/have_text.rb delete mode 100644 qa/spec/support/helpers/stub_env.rb delete mode 100644 qa/spec/support/matchers/eventually_matcher.rb delete mode 100644 qa/spec/support/matchers/have_matcher.rb delete mode 100644 qa/spec/support/matchers/have_text.rb diff --git a/.gitignore b/.gitignore index d1d2bfde1aa..7dbfe96cebb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.mo *.edit.po *.rej +.dir-locals.el .DS_Store .bundle .chef diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md index ec6e5dfd7d4..1576f6e8f53 100644 --- a/.gitlab/issue_templates/Feature Flag Roll Out.md +++ b/.gitlab/issue_templates/Feature Flag Roll Out.md @@ -38,6 +38,8 @@ Are there any other stages or teams involved that need to be kept in the loop? - `gitlab-org/gitlab` project +- `gitlab-org/gitlab-foss` project +- `gitlab-com/www-gitlab-com` project - `gitlab-org`/`gitlab-com` groups - ... @@ -79,19 +81,24 @@ Are there any other stages or teams involved that need to be kept in the loop? - [ ] Ensure that documentation has been updated ([More info](https://docs.gitlab.com/ee/development/documentation/feature_flags.html#features-that-became-enabled-by-default)). - [ ] Announce on [the feature issue](ISSUE LINK) an estimated time this will be enabled on GitLab.com. - [ ] If the feature might impact the user experience, notify `#support_gitlab-com` and your team channel ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#communicate-the-change)). -- [ ] If the feature flag in code has [an actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), enable it on GitLab.com for [testing groups/projects](#testing-groupsprojectsusers). - - [ ] `/chatops run feature set --= true` -- [ ] Verify that the feature works as expected. Posting the QA result in this issue is preferable. ### Global rollout on production +All `/chatops` commands that target production should be done in the `#production` slack channel for visibility. + +- [ ] Confirm the feature flag is enabled on `staging` without incident +- [ ] Roll out the feature to targeted testing projects/groups first + - [ ] `/chatops run feature set --project=gitlab-org/gitlab true` + - [ ] `/chatops run feature set --project=gitlab-org/gitlab-foss true` + - [ ] `/chatops run feature set --project=gitlab-com/www-gitlab-com true` + - [ ] [Incrementally roll out](https://docs.gitlab.com/ee/development/feature_flags/controls.html#process) the feature. - If the feature flag in code has [an actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), perform **actor-based** rollout. - [ ] `/chatops run feature set --actors` - If the feature flag in code does **NOT** have [an actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), perform time-based rollout (**random** rollout). - [ ] `/chatops run feature set ` - - Enable the feature globally on production environment. - - [ ] `/chatops run feature set true` +- [ ] Verify the change has the desired outcome with the limited rollout before enabling the feature globally on production. +- [ ] Enable the feature globally on production environment. `/chatops run feature set true` - [ ] Announce on [the feature issue](ISSUE LINK) that the feature has been globally enabled. - [ ] Wait for [at least one day for the verification term](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/#including-a-feature-behind-feature-flag-in-the-final-release). diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index b68508db993..9580192ce99 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -23,30 +23,6 @@ Graphql/Descriptions: - 'ee/app/graphql/types/vulnerability_severity_enum.rb' - 'ee/app/graphql/types/vulnerability_state_enum.rb' - 'ee/app/graphql/types/vulnerability_confidence_enum.rb' - - 'app/graphql/types/design_management/design_at_version_type.rb' - - 'app/graphql/types/design_management/design_fields.rb' - - 'app/graphql/types/diff_paths_input_type.rb' - - 'app/graphql/types/environment_type.rb' - - 'app/graphql/types/eventable_type.rb' - - 'app/graphql/types/group_type.rb' - - 'app/graphql/types/merge_request_type.rb' - - 'app/graphql/types/metadata/kas_type.rb' - - 'app/graphql/types/milestone_wildcard_id_enum.rb' - - 'app/graphql/types/namespace_type.rb' - - 'app/graphql/types/notes/note_type.rb' - - 'app/graphql/types/notes/position_type_enum.rb' - - 'app/graphql/types/packages/composer/json_type.rb' - - 'app/graphql/types/packages/package_details_type.rb' - - 'app/graphql/types/packages/package_file_type.rb' - - 'app/graphql/types/packages/package_tag_type.rb' - - 'app/graphql/types/packages/package_type.rb' - - 'app/graphql/types/project_type.rb' - - 'app/graphql/types/prometheus_alert_type.rb' - - 'app/graphql/types/query_type.rb' - - 'app/graphql/types/range_input_type.rb' - - 'app/graphql/types/release_asset_link_shared_input_arguments.rb' - - 'app/graphql/types/release_assets_input_type.rb' - - 'app/graphql/types/release_type.rb' - 'app/graphql/types/repository/blob_type.rb' - 'app/graphql/types/root_storage_statistics_type.rb' - 'app/graphql/types/snippet_type.rb' diff --git a/Gemfile b/Gemfile index 83b1b0ba25e..df805a6bcf9 100644 --- a/Gemfile +++ b/Gemfile @@ -310,7 +310,7 @@ gem 'pg_query', '~> 2.1' gem 'premailer-rails', '~> 1.10.3' # LabKit: Tracing and Correlation -gem 'gitlab-labkit', '~> 0.21.0' +gem 'gitlab-labkit', '~> 0.21.1' # Thrift is a dependency of gitlab-labkit, we want a version higher than 0.14.0 # because of https://gitlab.com/gitlab-org/gitlab/-/issues/321900 gem 'thrift', '>= 0.14.0' @@ -479,7 +479,7 @@ gem 'gitaly', '~> 14.2.0.pre.rc2' # KAS GRPC protocol definitions gem 'kas-grpc', '~> 0.0.2' -gem 'grpc', '~> 1.38.0' +gem 'grpc', '~> 1.30.2' gem 'google-protobuf', '~> 3.17.1' diff --git a/Gemfile.lock b/Gemfile.lock index 0980814bafb..658a7c68fa3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -475,10 +475,10 @@ GEM fog-json (~> 1.2.0) mime-types ms_rest_azure (~> 0.12.0) - gitlab-labkit (0.21.0) + gitlab-labkit (0.21.1) actionpack (>= 5.0.0, < 7.0.0) activesupport (>= 5.0.0, < 7.0.0) - grpc (~> 1.38) + grpc (~> 1.30.2) jaeger-client (~> 1.1) opentracing (~> 0.4) pg_query (~> 2.1) @@ -573,8 +573,8 @@ GEM graphql (~> 1.6) html-pipeline (~> 2.8) sass (~> 3.4) - grpc (1.38.0) - google-protobuf (~> 3.15) + grpc (1.30.2) + google-protobuf (~> 3.12) googleapis-common-protos-types (~> 1.0) gssapi (1.2.0) ffi (>= 1.0.1) @@ -1477,7 +1477,7 @@ DEPENDENCIES gitlab-dangerfiles (~> 2.3.0) gitlab-experiment (~> 0.6.4) gitlab-fog-azure-rm (~> 1.1.1) - gitlab-labkit (~> 0.21.0) + gitlab-labkit (~> 0.21.1) gitlab-license (~> 2.0) gitlab-mail_room (~> 0.0.9) gitlab-markup (~> 1.7.1) @@ -1499,7 +1499,7 @@ DEPENDENCIES graphlient (~> 0.4.0) graphql (~> 1.11.8) graphql-docs (~> 1.6.0) - grpc (~> 1.38.0) + grpc (~> 1.30.2) gssapi guard-rspec haml_lint (~> 0.36.0) diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss index 070ab36e0b3..cd0a10bd3a0 100644 --- a/app/assets/stylesheets/startup/startup-signin.scss +++ b/app/assets/stylesheets/startup/startup-signin.scss @@ -315,9 +315,9 @@ fieldset:disabled a.btn { -moz-appearance: none; } .gl-form-input:disabled, -.gl-form-input:not(.form-control-plaintext):read-only, +.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only, .gl-form-input.form-control:disabled, -.gl-form-input.form-control:not(.form-control-plaintext):read-only { +.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only { background-color: #fafafa; color: #868686; box-shadow: inset 0 0 0 1px #dbdbdb; diff --git a/app/graphql/types/design_management/design_at_version_type.rb b/app/graphql/types/design_management/design_at_version_type.rb index 4240b8f3aae..0dc93072e4f 100644 --- a/app/graphql/types/design_management/design_at_version_type.rb +++ b/app/graphql/types/design_management/design_at_version_type.rb @@ -18,12 +18,12 @@ module Types field :version, Types::DesignManagement::VersionType, null: false, - description: 'The version this design-at-versions is pinned to.' + description: 'Version this design-at-versions is pinned to.' field :design, Types::DesignManagement::DesignType, null: false, - description: 'The underlying design.' + description: 'Underlying design.' def cached_stateful_version(_parent) version diff --git a/app/graphql/types/design_management/design_fields.rb b/app/graphql/types/design_management/design_fields.rb index 7779c3f1bcb..75f1aaa8c60 100644 --- a/app/graphql/types/design_management/design_fields.rb +++ b/app/graphql/types/design_management/design_fields.rb @@ -7,12 +7,12 @@ module Types field_class Types::BaseField - field :id, GraphQL::Types::ID, description: 'The ID of this design.', null: false - field :project, Types::ProjectType, null: false, description: 'The project the design belongs to.' - field :issue, Types::IssueType, null: false, description: 'The issue the design belongs to.' - field :filename, GraphQL::Types::String, null: false, description: 'The filename of the design.' - field :full_path, GraphQL::Types::String, null: false, description: 'The full path to the design file.' - field :image, GraphQL::Types::String, null: false, extras: [:parent], description: 'The URL of the full-sized image.' + field :id, GraphQL::Types::ID, description: 'ID of this design.', null: false + field :project, Types::ProjectType, null: false, description: 'Project the design belongs to.' + field :issue, Types::IssueType, null: false, description: 'Issue the design belongs to.' + field :filename, GraphQL::Types::String, null: false, description: 'Filename of the design.' + field :full_path, GraphQL::Types::String, null: false, description: 'Full path to the design file.' + field :image, GraphQL::Types::String, null: false, extras: [:parent], description: 'URL of the full-sized image.' field :image_v432x230, GraphQL::Types::String, null: true, extras: [:parent], description: 'The URL of the design resized to fit within the bounds of 432x230. ' \ 'This will be `null` if the image has not been generated' @@ -20,7 +20,7 @@ module Types null: false, calls_gitaly: true, extras: [:parent], - description: 'The diff refs for this design.' + description: 'Diff refs for this design.' field :event, Types::DesignManagement::DesignVersionEventEnum, null: false, extras: [:parent], @@ -29,7 +29,7 @@ module Types GraphQL::Types::Int, null: false, method: :user_notes_count, - description: 'The total count of user-created notes for this design.' + description: 'Total count of user-created notes for this design.' def diff_refs(parent:) version = cached_stateful_version(parent) diff --git a/app/graphql/types/diff_paths_input_type.rb b/app/graphql/types/diff_paths_input_type.rb index e1d3d58411c..cdcff1a7e34 100644 --- a/app/graphql/types/diff_paths_input_type.rb +++ b/app/graphql/types/diff_paths_input_type.rb @@ -3,8 +3,8 @@ module Types class DiffPathsInputType < BaseInputObject argument :old_path, GraphQL::Types::String, required: false, - description: 'The path of the file on the start sha.' + description: 'Path of the file on the start SHA.' argument :new_path, GraphQL::Types::String, required: false, - description: 'The path of the file on the head sha.' + description: 'Path of the file on the HEAD SHA.' end end diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb index 267ca944198..aba83f559fa 100644 --- a/app/graphql/types/environment_type.rb +++ b/app/graphql/types/environment_type.rb @@ -19,7 +19,7 @@ module Types description: 'State of the environment, for example: available/stopped.' field :path, GraphQL::Types::String, null: false, - description: 'The path to the environment.' + description: 'Path to the environment.' field :metrics_dashboard, Types::Metrics::DashboardType, null: true, description: 'Metrics dashboard schema for the environment.', @@ -28,6 +28,6 @@ module Types field :latest_opened_most_severe_alert, Types::AlertManagement::AlertType, null: true, - description: 'The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned.' + description: 'Most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned.' end end diff --git a/app/graphql/types/eventable_type.rb b/app/graphql/types/eventable_type.rb index eba2154e7fa..9a02079b7ab 100644 --- a/app/graphql/types/eventable_type.rb +++ b/app/graphql/types/eventable_type.rb @@ -4,6 +4,6 @@ module Types module EventableType include Types::BaseInterface - field :events, Types::EventType.connection_type, null: true, description: 'A list of events associated with the object.' + field :events, Types::EventType.connection_type, null: true, description: 'List of events associated with the object.' end end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index baf0fa80fc3..6aa30fff86d 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -33,12 +33,12 @@ module Types type: GraphQL::Types::String, null: true, method: :project_creation_level_str, - description: 'The permission level required to create projects in the group.' + description: 'Permission level required to create projects in the group.' field :subgroup_creation_level, type: GraphQL::Types::String, null: true, method: :subgroup_creation_level_str, - description: 'The permission level required to create subgroups within the group.' + description: 'Permission level required to create subgroups within the group.' field :require_two_factor_authentication, type: GraphQL::Types::Boolean, @@ -101,7 +101,7 @@ module Types field :label, Types::LabelType, null: true, - description: 'A label available on this group.' do + description: 'Label available on this group.' do argument :title, type: GraphQL::Types::String, required: true, diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 8e6b5421ede..004ac364487 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -64,7 +64,7 @@ module Types description: 'Diff head SHA of the merge request.' field :diff_stats, [Types::DiffStatsType], null: true, calls_gitaly: true, description: 'Details about which files were changed in this merge request.' do - argument :path, GraphQL::Types::String, required: false, description: 'A specific file-path.' + argument :path, GraphQL::Types::String, required: false, description: 'Specific file path.' end field :diff_stats_summary, Types::DiffStatsSummaryType, null: true, calls_gitaly: true, @@ -129,14 +129,14 @@ module Types description: 'Number of downvotes for the merge request.' field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline, - description: 'The pipeline running on the branch HEAD of the merge request.' + description: 'Pipeline running on the branch HEAD of the merge request.' field :pipelines, null: true, description: 'Pipelines for the merge request. Note: for performance reasons, no more than the most recent 500 pipelines will be returned.', resolver: Resolvers::MergeRequestPipelinesResolver field :milestone, Types::MilestoneType, null: true, - description: 'The milestone of the merge request.' + description: 'Milestone of the merge request.' field :assignees, type: Types::MergeRequests::AssigneeType.connection_type, null: true, diff --git a/app/graphql/types/metadata/kas_type.rb b/app/graphql/types/metadata/kas_type.rb index a947986fa60..54a8a6ec40d 100644 --- a/app/graphql/types/metadata/kas_type.rb +++ b/app/graphql/types/metadata/kas_type.rb @@ -12,7 +12,7 @@ module Types field :version, GraphQL::Types::String, null: true, description: 'KAS version.' field :external_url, GraphQL::Types::String, null: true, - description: 'The URL used by the Agents to communicate with KAS.' + description: 'URL used by the Agents to communicate with KAS.' end end end diff --git a/app/graphql/types/milestone_wildcard_id_enum.rb b/app/graphql/types/milestone_wildcard_id_enum.rb index b5b339b1e5b..d950d361526 100644 --- a/app/graphql/types/milestone_wildcard_id_enum.rb +++ b/app/graphql/types/milestone_wildcard_id_enum.rb @@ -6,7 +6,7 @@ module Types description 'Milestone ID wildcard values' value 'NONE', 'No milestone is assigned.' - value 'ANY', 'A milestone is assigned.' + value 'ANY', 'Milestone is assigned.' value 'STARTED', 'An open, started milestone (start date <= today).' value 'UPCOMING', 'An open milestone due in the future (due date >= today).' end diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index 4cc543f477a..3c5994ac559 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -40,7 +40,7 @@ module Types field :package_settings, Types::Namespace::PackageSettingsType, null: true, - description: 'The package settings for the namespace.' + description: 'Package settings for the namespace.' field :shared_runners_setting, Types::Namespace::SharedRunnersSettingEnum, diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb index fa33428114c..da6ea83401d 100644 --- a/app/graphql/types/notes/note_type.rb +++ b/app/graphql/types/notes/note_type.rb @@ -40,9 +40,9 @@ module Types field :updated_at, Types::TimeType, null: false, description: "Timestamp of the note's last activity." field :discussion, Types::Notes::DiscussionType, null: true, - description: 'The discussion this note is a part of.' + description: 'Discussion this note is a part of.' field :position, Types::Notes::DiffPositionType, null: true, - description: 'The position of this note on a diff.' + description: 'Position of this note on a diff.' field :confidential, GraphQL::Types::Boolean, null: true, description: 'Indicates if this note is confidential.', method: :confidential? diff --git a/app/graphql/types/notes/position_type_enum.rb b/app/graphql/types/notes/position_type_enum.rb index 18934636670..157b0b4b884 100644 --- a/app/graphql/types/notes/position_type_enum.rb +++ b/app/graphql/types/notes/position_type_enum.rb @@ -6,7 +6,7 @@ module Types graphql_name 'DiffPositionType' description 'Type of file the position refers to' - value 'text', description: "A text file." + value 'text', description: "Text file." value 'image', description: "An image." end end diff --git a/app/graphql/types/packages/composer/json_type.rb b/app/graphql/types/packages/composer/json_type.rb index d2bd62ca74d..6c121043301 100644 --- a/app/graphql/types/packages/composer/json_type.rb +++ b/app/graphql/types/packages/composer/json_type.rb @@ -8,10 +8,10 @@ module Types graphql_name 'PackageComposerJsonType' description 'Represents a composer JSON file' - field :name, GraphQL::Types::String, null: true, description: 'The name set in the Composer JSON file.' - field :type, GraphQL::Types::String, null: true, description: 'The type set in the Composer JSON file.' - field :license, GraphQL::Types::String, null: true, description: 'The license set in the Composer JSON file.' - field :version, GraphQL::Types::String, null: true, description: 'The version set in the Composer JSON file.' + field :name, GraphQL::Types::String, null: true, description: 'Name set in the Composer JSON file.' + field :type, GraphQL::Types::String, null: true, description: 'Type set in the Composer JSON file.' + field :license, GraphQL::Types::String, null: true, description: 'License set in the Composer JSON file.' + field :version, GraphQL::Types::String, null: true, description: 'Version set in the Composer JSON file.' end end end diff --git a/app/graphql/types/packages/package_details_type.rb b/app/graphql/types/packages/package_details_type.rb index f52b1f02519..59a4885e87e 100644 --- a/app/graphql/types/packages/package_details_type.rb +++ b/app/graphql/types/packages/package_details_type.rb @@ -8,7 +8,7 @@ module Types authorize :read_package field :versions, ::Types::Packages::PackageType.connection_type, null: true, - description: 'The other versions of the package.' + description: 'Other versions of the package.' field :package_files, Types::Packages::PackageFileType.connection_type, null: true, description: 'Package files.' diff --git a/app/graphql/types/packages/package_file_type.rb b/app/graphql/types/packages/package_file_type.rb index f77c40de8d8..8cc0f9b984a 100644 --- a/app/graphql/types/packages/package_file_type.rb +++ b/app/graphql/types/packages/package_file_type.rb @@ -8,8 +8,8 @@ module Types authorize :read_package field :id, ::Types::GlobalIDType[::Packages::PackageFile], null: false, description: 'ID of the file.' - field :created_at, Types::TimeType, null: false, description: 'The created date.' - field :updated_at, Types::TimeType, null: false, description: 'The updated date.' + field :created_at, Types::TimeType, null: false, description: 'Created date.' + field :updated_at, Types::TimeType, null: false, description: 'Updated date.' field :size, GraphQL::Types::String, null: false, description: 'Size of the package file.' field :file_name, GraphQL::Types::String, null: false, description: 'Name of the package file.' field :download_path, GraphQL::Types::String, null: false, description: 'Download path of the package file.' diff --git a/app/graphql/types/packages/package_tag_type.rb b/app/graphql/types/packages/package_tag_type.rb index 450f3fc8e9c..f1f96c42e27 100644 --- a/app/graphql/types/packages/package_tag_type.rb +++ b/app/graphql/types/packages/package_tag_type.rb @@ -7,10 +7,10 @@ module Types description 'Represents a package tag' authorize :read_package - field :id, GraphQL::Types::ID, null: false, description: 'The ID of the tag.' - field :name, GraphQL::Types::String, null: false, description: 'The name of the tag.' - field :created_at, Types::TimeType, null: false, description: 'The created date.' - field :updated_at, Types::TimeType, null: false, description: 'The updated date.' + field :id, GraphQL::Types::ID, null: false, description: 'ID of the tag.' + field :name, GraphQL::Types::String, null: false, description: 'Name of the tag.' + field :created_at, Types::TimeType, null: false, description: 'Created date.' + field :updated_at, Types::TimeType, null: false, description: 'Updated date.' end end end diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb index b8654ebd2c6..f3fa79cc08c 100644 --- a/app/graphql/types/packages/package_type.rb +++ b/app/graphql/types/packages/package_type.rb @@ -23,7 +23,7 @@ module Types field :metadata, Types::Packages::MetadataType, null: true, description: 'Package metadata.' field :versions, ::Types::Packages::PackageType.connection_type, null: true, - description: 'The other versions of the package.', + description: 'Other versions of the package.', deprecated: { reason: 'This field is now only returned in the PackageDetailsType', milestone: '13.11' } field :status, Types::Packages::PackageStatusEnum, null: false, description: 'Package status.' diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 4530826dd85..aef46a05a2f 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -118,7 +118,7 @@ module Types field :autoclose_referenced_issues, GraphQL::Types::Boolean, null: true, description: 'Indicates if issues referenced by merge requests and commits within the default branch are closed automatically.' field :suggestion_commit_message, GraphQL::Types::String, null: true, - description: 'The commit message used to apply merge request suggestions.' + description: 'Commit message used to apply merge request suggestions.' field :squash_read_only, GraphQL::Types::Boolean, null: false, method: :squash_readonly?, description: 'Indicates if `squashReadOnly` is enabled.' @@ -310,7 +310,7 @@ module Types field :container_expiration_policy, Types::ContainerExpirationPolicyType, null: true, - description: 'The container expiration policy of the project.' + description: 'Container expiration policy of the project.' field :container_repositories, Types::ContainerRepositoryType.connection_type, @@ -324,7 +324,7 @@ module Types field :label, Types::LabelType, null: true, - description: 'A label available on this project.' do + description: 'Label available on this project.' do argument :title, GraphQL::Types::String, required: true, description: 'Title of the label.' diff --git a/app/graphql/types/prometheus_alert_type.rb b/app/graphql/types/prometheus_alert_type.rb index 8327848032a..789f1d6eb5f 100644 --- a/app/graphql/types/prometheus_alert_type.rb +++ b/app/graphql/types/prometheus_alert_type.rb @@ -15,6 +15,6 @@ module Types field :humanized_text, GraphQL::Types::String, null: false, - description: 'The human-readable text of the alert condition.' + description: 'Human-readable text of the alert condition.' end end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 7e9cd615719..71897644991 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -62,7 +62,7 @@ module Types argument :id, type: ::Types::GlobalIDType[::ContainerRepository], required: true, - description: 'The global ID of the container repository.' + description: 'Global ID of the container repository.' end field :package, @@ -84,13 +84,13 @@ module Types field :issue, Types::IssueType, null: true, description: 'Find an issue.' do - argument :id, ::Types::GlobalIDType[::Issue], required: true, description: 'The global ID of the issue.' + argument :id, ::Types::GlobalIDType[::Issue], required: true, description: 'Global ID of the issue.' end field :merge_request, Types::MergeRequestType, null: true, description: 'Find a merge request.' do - argument :id, ::Types::GlobalIDType[::MergeRequest], required: true, description: 'The global ID of the merge request.' + argument :id, ::Types::GlobalIDType[::MergeRequest], required: true, description: 'Global ID of the merge request.' end field :instance_statistics_measurements, diff --git a/app/graphql/types/range_input_type.rb b/app/graphql/types/range_input_type.rb index e31b8ecd811..9580b37d6c0 100644 --- a/app/graphql/types/range_input_type.rb +++ b/app/graphql/types/range_input_type.rb @@ -8,11 +8,11 @@ module Types @subtypes[[type, closed]] ||= Class.new(self) do argument :start, type, required: closed, - description: 'The start of the range.' + description: 'Start of the range.' argument :end, type, required: closed, - description: 'The end of the range.' + description: 'End of the range.' end end diff --git a/app/graphql/types/release_asset_link_shared_input_arguments.rb b/app/graphql/types/release_asset_link_shared_input_arguments.rb index 37a6cdd55c9..f622a11deea 100644 --- a/app/graphql/types/release_asset_link_shared_input_arguments.rb +++ b/app/graphql/types/release_asset_link_shared_input_arguments.rb @@ -19,7 +19,7 @@ module Types argument :link_type, Types::ReleaseAssetLinkTypeEnum, required: false, default_value: 'other', - description: 'The type of the asset link.' + description: 'Type of the asset link.' end end end diff --git a/app/graphql/types/release_assets_input_type.rb b/app/graphql/types/release_assets_input_type.rb index 2c8d3de3495..0e591dd3742 100644 --- a/app/graphql/types/release_assets_input_type.rb +++ b/app/graphql/types/release_assets_input_type.rb @@ -7,6 +7,6 @@ module Types argument :links, [Types::ReleaseAssetLinkInputType], required: false, - description: 'A list of asset links to associate to the release.' + description: 'List of asset links to associate to the release.' end end diff --git a/app/graphql/types/release_type.rb b/app/graphql/types/release_type.rb index 5e8f00b2b0a..6dda93c7329 100644 --- a/app/graphql/types/release_type.rb +++ b/app/graphql/types/release_type.rb @@ -49,7 +49,7 @@ module Types field :commit, Types::CommitType, null: true, complexity: 10, calls_gitaly: true, - description: 'The commit associated with the release.' + description: 'Commit associated with the release.' def commit return if release.sha.nil? diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb index eda652c4b9a..4aabd1ca799 100644 --- a/app/services/merge_requests/merge_to_ref_service.rb +++ b/app/services/merge_requests/merge_to_ref_service.rb @@ -13,12 +13,12 @@ module MergeRequests class MergeToRefService < MergeRequests::MergeBaseService extend ::Gitlab::Utils::Override - def execute(merge_request) + def execute(merge_request, cache_merge_to_ref_calls = false) @merge_request = merge_request error_check! - commit_id = commit + commit_id = commit(cache_merge_to_ref_calls) raise_error('Conflicts detected during merge') unless commit_id @@ -65,8 +65,9 @@ module MergeRequests params[:allow_conflicts] || false end - def commit - if Feature.enabled?(:cache_merge_to_ref_calls, project, default_enabled: false) + def commit(cache_merge_to_ref_calls = false) + if cache_merge_to_ref_calls && + Feature.enabled?(:cache_merge_to_ref_calls, project, default_enabled: false) Rails.cache.fetch(cache_key, expires_in: 1.day) do extracted_merge_to_ref end diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt index 43ff584b550..e4deabff66c 100644 --- a/doc/.vale/gitlab/spelling-exceptions.txt +++ b/doc/.vale/gitlab/spelling-exceptions.txt @@ -209,6 +209,7 @@ fixup Flawfinder Flowdock Fluentd +Flycheck Forgerock formatters Fugit diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index c081addb24a..2758e1ad2f7 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -74,7 +74,7 @@ Returns [`ContainerRepositoryDetails`](#containerrepositorydetails). | Name | Type | Description | | ---- | ---- | ----------- | -| `id` | [`ContainerRepositoryID!`](#containerrepositoryid) | The global ID of the container repository. | +| `id` | [`ContainerRepositoryID!`](#containerrepositoryid) | Global ID of the container repository. | ### `Query.currentLicense` @@ -185,7 +185,7 @@ Returns [`Issue`](#issue). | Name | Type | Description | | ---- | ---- | ----------- | -| `id` | [`IssueID!`](#issueid) | The global ID of the issue. | +| `id` | [`IssueID!`](#issueid) | Global ID of the issue. | ### `Query.iteration` @@ -219,7 +219,7 @@ Returns [`MergeRequest`](#mergerequest). | Name | Type | Description | | ---- | ---- | ----------- | -| `id` | [`MergeRequestID!`](#mergerequestid) | The global ID of the merge request. | +| `id` | [`MergeRequestID!`](#mergerequestid) | Global ID of the merge request. | ### `Query.metadata` @@ -1186,7 +1186,7 @@ Input type: `CreateDiffNoteInput` | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `confidential` | [`Boolean`](#boolean) | Confidentiality flag of a note. Default is false. | | `noteableId` | [`NoteableID!`](#noteableid) | Global ID of the resource to add a note to. | -| `position` | [`DiffPositionInput!`](#diffpositioninput) | The position of this note on a diff. | +| `position` | [`DiffPositionInput!`](#diffpositioninput) | Position of this note on a diff. | #### Fields @@ -1236,7 +1236,7 @@ Input type: `CreateImageDiffNoteInput` | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `confidential` | [`Boolean`](#boolean) | Confidentiality flag of a note. Default is false. | | `noteableId` | [`NoteableID!`](#noteableid) | Global ID of the resource to add a note to. | -| `position` | [`DiffImagePositionInput!`](#diffimagepositioninput) | The position of this note on a diff. | +| `position` | [`DiffImagePositionInput!`](#diffimagepositioninput) | Position of this note on a diff. | #### Fields @@ -3601,7 +3601,7 @@ Input type: `ReleaseAssetLinkCreateInput` | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `directAssetPath` | [`String`](#string) | Relative path for a direct asset link. | -| `linkType` | [`ReleaseAssetLinkType`](#releaseassetlinktype) | The type of the asset link. | +| `linkType` | [`ReleaseAssetLinkType`](#releaseassetlinktype) | Type of the asset link. | | `name` | [`String!`](#string) | Name of the asset link. | | `projectPath` | [`ID!`](#id) | Full path of the project the asset link is associated with. | | `tagName` | [`String!`](#string) | Name of the associated release's tag. | @@ -3757,7 +3757,7 @@ Input type: `RepositionImageDiffNoteInput` | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `id` | [`DiffNoteID!`](#diffnoteid) | Global ID of the DiffNote to update. | -| `position` | [`UpdateDiffImagePositionInput!`](#updatediffimagepositioninput) | The position of this note on a diff. | +| `position` | [`UpdateDiffImagePositionInput!`](#updatediffimagepositioninput) | Position of this note on a diff. | #### Fields @@ -4251,7 +4251,7 @@ Input type: `UpdateImageDiffNoteInput` | `body` | [`String`](#string) | Content of the note. | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `id` | [`NoteID!`](#noteid) | Global ID of the note to update. | -| `position` | [`UpdateDiffImagePositionInput`](#updatediffimagepositioninput) | The position of this note on a diff. | +| `position` | [`UpdateDiffImagePositionInput`](#updatediffimagepositioninput) | Position of this note on a diff. | #### Fields @@ -7752,7 +7752,7 @@ Represents an epic on an issue board. | `dueDateFixed` | [`Time`](#time) | Fixed due date of the epic. | | `dueDateFromMilestones` | [`Time`](#time) | Inherited due date of the epic from milestones. | | `dueDateIsFixed` | [`Boolean`](#boolean) | Indicates if the due date has been manually set. | -| `events` | [`EventConnection`](#eventconnection) | A list of events associated with the object. (see [Connections](#connections)) | +| `events` | [`EventConnection`](#eventconnection) | List of events associated with the object. (see [Connections](#connections)) | | `group` | [`Group!`](#group) | Group to which the epic belongs. | | `hasChildren` | [`Boolean!`](#boolean) | Indicates if the epic has children. | | `hasIssues` | [`Boolean!`](#boolean) | Indicates if the epic has direct issues. | @@ -8580,18 +8580,18 @@ A single design. | Name | Type | Description | | ---- | ---- | ----------- | -| `diffRefs` | [`DiffRefs!`](#diffrefs) | The diff refs for this design. | +| `diffRefs` | [`DiffRefs!`](#diffrefs) | Diff refs for this design. | | `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | | `event` | [`DesignVersionEvent!`](#designversionevent) | How this design was changed in the current version. | -| `filename` | [`String!`](#string) | The filename of the design. | -| `fullPath` | [`String!`](#string) | The full path to the design file. | -| `id` | [`ID!`](#id) | The ID of this design. | -| `image` | [`String!`](#string) | The URL of the full-sized image. | +| `filename` | [`String!`](#string) | Filename of the design. | +| `fullPath` | [`String!`](#string) | Full path to the design file. | +| `id` | [`ID!`](#id) | ID of this design. | +| `image` | [`String!`](#string) | URL of the full-sized image. | | `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated. | -| `issue` | [`Issue!`](#issue) | The issue the design belongs to. | +| `issue` | [`Issue!`](#issue) | Issue the design belongs to. | | `notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) | -| `notesCount` | [`Int!`](#int) | The total count of user-created notes for this design. | -| `project` | [`Project!`](#project) | The project the design belongs to. | +| `notesCount` | [`Int!`](#int) | Total count of user-created notes for this design. | +| `project` | [`Project!`](#project) | Project the design belongs to. | #### Fields with arguments @@ -8636,18 +8636,18 @@ A design pinned to a specific version. The image field reflects the design as of | Name | Type | Description | | ---- | ---- | ----------- | -| `design` | [`Design!`](#design) | The underlying design. | -| `diffRefs` | [`DiffRefs!`](#diffrefs) | The diff refs for this design. | +| `design` | [`Design!`](#design) | Underlying design. | +| `diffRefs` | [`DiffRefs!`](#diffrefs) | Diff refs for this design. | | `event` | [`DesignVersionEvent!`](#designversionevent) | How this design was changed in the current version. | -| `filename` | [`String!`](#string) | The filename of the design. | -| `fullPath` | [`String!`](#string) | The full path to the design file. | -| `id` | [`ID!`](#id) | The ID of this design. | -| `image` | [`String!`](#string) | The URL of the full-sized image. | +| `filename` | [`String!`](#string) | Filename of the design. | +| `fullPath` | [`String!`](#string) | Full path to the design file. | +| `id` | [`ID!`](#id) | ID of this design. | +| `image` | [`String!`](#string) | URL of the full-sized image. | | `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated. | -| `issue` | [`Issue!`](#issue) | The issue the design belongs to. | -| `notesCount` | [`Int!`](#int) | The total count of user-created notes for this design. | -| `project` | [`Project!`](#project) | The project the design belongs to. | -| `version` | [`DesignVersion!`](#designversion) | The version this design-at-versions is pinned to. | +| `issue` | [`Issue!`](#issue) | Issue the design belongs to. | +| `notesCount` | [`Int!`](#int) | Total count of user-created notes for this design. | +| `project` | [`Project!`](#project) | Project the design belongs to. | +| `version` | [`DesignVersion!`](#designversion) | Version this design-at-versions is pinned to. | ### `DesignCollection` @@ -8995,9 +8995,9 @@ Describes where code is deployed for a project. | Name | Type | Description | | ---- | ---- | ----------- | | `id` | [`ID!`](#id) | ID of the environment. | -| `latestOpenedMostSevereAlert` | [`AlertManagementAlert`](#alertmanagementalert) | The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned. | +| `latestOpenedMostSevereAlert` | [`AlertManagementAlert`](#alertmanagementalert) | Most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned. | | `name` | [`String!`](#string) | Human-readable name of the environment. | -| `path` | [`String!`](#string) | The path to the environment. | +| `path` | [`String!`](#string) | Path to the environment. | | `state` | [`String!`](#string) | State of the environment, for example: available/stopped. | #### Fields with arguments @@ -9037,7 +9037,7 @@ Represents an epic. | `dueDateFixed` | [`Time`](#time) | Fixed due date of the epic. | | `dueDateFromMilestones` | [`Time`](#time) | Inherited due date of the epic from milestones. | | `dueDateIsFixed` | [`Boolean`](#boolean) | Indicates if the due date has been manually set. | -| `events` | [`EventConnection`](#eventconnection) | A list of events associated with the object. (see [Connections](#connections)) | +| `events` | [`EventConnection`](#eventconnection) | List of events associated with the object. (see [Connections](#connections)) | | `group` | [`Group!`](#group) | Group to which the epic belongs. | | `hasChildren` | [`Boolean!`](#boolean) | Indicates if the epic has children. | | `hasIssues` | [`Boolean!`](#boolean) | Indicates if the epic has direct issues. | @@ -9616,10 +9616,10 @@ four standard [pagination arguments](#connection-pagination-arguments): | `lfsEnabled` | [`Boolean`](#boolean) | Indicates if Large File Storage (LFS) is enabled for namespace. | | `mentionsDisabled` | [`Boolean`](#boolean) | Indicates if a group is disabled from getting mentioned. | | `name` | [`String!`](#string) | Name of the namespace. | -| `packageSettings` | [`PackageSettings`](#packagesettings) | The package settings for the namespace. | +| `packageSettings` | [`PackageSettings`](#packagesettings) | Package settings for the namespace. | | `parent` | [`Group`](#group) | Parent group. | | `path` | [`String!`](#string) | Path of the namespace. | -| `projectCreationLevel` | [`String`](#string) | The permission level required to create projects in the group. | +| `projectCreationLevel` | [`String`](#string) | Permission level required to create projects in the group. | | `repositorySizeExcessProjectCount` | [`Int!`](#int) | Number of projects in the root namespace where the repository size exceeds the limit. | | `requestAccessEnabled` | [`Boolean`](#boolean) | Indicates if users can request access to namespace. | | `requireTwoFactorAuthentication` | [`Boolean`](#boolean) | Indicates if all users in this group are required to set up two-factor authentication. | @@ -9628,7 +9628,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | `sharedRunnersSetting` | [`SharedRunnersSetting`](#sharedrunnerssetting) | Shared runners availability for the namespace and its descendants. | | `stats` | [`GroupStats`](#groupstats) | Group statistics. | | `storageSizeLimit` | [`Float`](#float) | Total storage limit of the root namespace in bytes. | -| `subgroupCreationLevel` | [`String`](#string) | The permission level required to create subgroups within the group. | +| `subgroupCreationLevel` | [`String`](#string) | Permission level required to create subgroups within the group. | | `temporaryStorageIncreaseEndsOn` | [`Time`](#time) | Date until the temporary storage increase is active. | | `totalRepositorySize` | [`Float`](#float) | Total repository size of all projects in the root namespace in bytes. | | `totalRepositorySizeExcess` | [`Float`](#float) | Total excess repository size of all projects in the root namespace in bytes. | @@ -9913,7 +9913,7 @@ four standard [pagination arguments](#connection-pagination-arguments): ##### `Group.label` -A label available on this group. +Label available on this group. Returns [`Label`](#label). @@ -10587,7 +10587,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | Name | Type | Description | | ---- | ---- | ----------- | | `enabled` | [`Boolean!`](#boolean) | Indicates whether the Kubernetes Agent Server is enabled. | -| `externalUrl` | [`String`](#string) | The URL used by the Agents to communicate with KAS. | +| `externalUrl` | [`String`](#string) | URL used by the Agents to communicate with KAS. | | `version` | [`String`](#string) | KAS version. | ### `Label` @@ -10695,7 +10695,7 @@ Maven metadata. | `forceRemoveSourceBranch` | [`Boolean`](#boolean) | Indicates if the project settings will lead to source branch deletion after merge. | | `hasCi` | [`Boolean!`](#boolean) | Indicates if the merge request has CI. | | `hasSecurityReports` | [`Boolean!`](#boolean) | Indicates if the source branch has any security reports. | -| `headPipeline` | [`Pipeline`](#pipeline) | The pipeline running on the branch HEAD of the merge request. | +| `headPipeline` | [`Pipeline`](#pipeline) | Pipeline running on the branch HEAD of the merge request. | | `humanTimeEstimate` | [`String`](#string) | Human-readable time estimate of the merge request. | | `humanTotalTimeSpent` | [`String`](#string) | Human-readable total time reported as spent on the merge request. | | `id` | [`ID!`](#id) | ID of the merge request. | @@ -10713,7 +10713,7 @@ Maven metadata. | `mergeable` | [`Boolean!`](#boolean) | Indicates if the merge request is mergeable. | | `mergeableDiscussionsState` | [`Boolean`](#boolean) | Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged. | | `mergedAt` | [`Time`](#time) | Timestamp of when the merge request was merged, null if not merged. | -| `milestone` | [`Milestone`](#milestone) | The milestone of the merge request. | +| `milestone` | [`Milestone`](#milestone) | Milestone of the merge request. | | `notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) | | `participants` | [`UserCoreConnection`](#usercoreconnection) | Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes. (see [Connections](#connections)) | | `project` | [`Project!`](#project) | Alias for target_project. | @@ -10780,7 +10780,7 @@ Returns [`[DiffStats!]`](#diffstats). | Name | Type | Description | | ---- | ---- | ----------- | -| `path` | [`String`](#string) | A specific file-path. | +| `path` | [`String`](#string) | Specific file path. | ##### `MergeRequest.pipelines` @@ -11397,7 +11397,7 @@ Contains statistics about a milestone. | `isTemporaryStorageIncreaseEnabled` | [`Boolean!`](#boolean) | Status of the temporary storage increase. | | `lfsEnabled` | [`Boolean`](#boolean) | Indicates if Large File Storage (LFS) is enabled for namespace. | | `name` | [`String!`](#string) | Name of the namespace. | -| `packageSettings` | [`PackageSettings`](#packagesettings) | The package settings for the namespace. | +| `packageSettings` | [`PackageSettings`](#packagesettings) | Package settings for the namespace. | | `path` | [`String!`](#string) | Path of the namespace. | | `repositorySizeExcessProjectCount` | [`Int!`](#int) | Number of projects in the root namespace where the repository size exceeds the limit. | | `requestAccessEnabled` | [`Boolean`](#boolean) | Indicates if users can request access to namespace. | @@ -11476,9 +11476,9 @@ Represents the network policy. | `bodyHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `note`. | | `confidential` | [`Boolean`](#boolean) | Indicates if this note is confidential. | | `createdAt` | [`Time!`](#time) | Timestamp of the note creation. | -| `discussion` | [`Discussion`](#discussion) | The discussion this note is a part of. | +| `discussion` | [`Discussion`](#discussion) | Discussion this note is a part of. | | `id` | [`NoteID!`](#noteid) | ID of the note. | -| `position` | [`DiffPosition`](#diffposition) | The position of this note on a diff. | +| `position` | [`DiffPosition`](#diffposition) | Position of this note on a diff. | | `project` | [`Project`](#project) | Project associated with the note. | | `resolvable` | [`Boolean!`](#boolean) | Indicates if the object can be resolved. | | `resolved` | [`Boolean!`](#boolean) | Indicates if the object is resolved. | @@ -11580,10 +11580,10 @@ Represents a composer JSON file. | Name | Type | Description | | ---- | ---- | ----------- | -| `license` | [`String`](#string) | The license set in the Composer JSON file. | -| `name` | [`String`](#string) | The name set in the Composer JSON file. | -| `type` | [`String`](#string) | The type set in the Composer JSON file. | -| `version` | [`String`](#string) | The version set in the Composer JSON file. | +| `license` | [`String`](#string) | License set in the Composer JSON file. | +| `name` | [`String`](#string) | Name set in the Composer JSON file. | +| `type` | [`String`](#string) | Type set in the Composer JSON file. | +| `version` | [`String`](#string) | Version set in the Composer JSON file. | ### `PackageDependency` @@ -11631,7 +11631,7 @@ Represents a package details in the Package Registry. Note that this type is in | `tags` | [`PackageTagConnection`](#packagetagconnection) | Package tags. (see [Connections](#connections)) | | `updatedAt` | [`Time!`](#time) | Date of most recent update. | | `version` | [`String`](#string) | Version string. | -| `versions` | [`PackageConnection`](#packageconnection) | The other versions of the package. (see [Connections](#connections)) | +| `versions` | [`PackageConnection`](#packageconnection) | Other versions of the package. (see [Connections](#connections)) | ### `PackageFile` @@ -11641,7 +11641,7 @@ Represents a package file. | Name | Type | Description | | ---- | ---- | ----------- | -| `createdAt` | [`Time!`](#time) | The created date. | +| `createdAt` | [`Time!`](#time) | Created date. | | `downloadPath` | [`String!`](#string) | Download path of the package file. | | `fileMd5` | [`String`](#string) | Md5 of the package file. | | `fileMetadata` | [`PackageFileMetadata`](#packagefilemetadata) | File metadata. | @@ -11650,7 +11650,7 @@ Represents a package file. | `fileSha256` | [`String`](#string) | Sha256 of the package file. | | `id` | [`PackagesPackageFileID!`](#packagespackagefileid) | ID of the file. | | `size` | [`String!`](#string) | Size of the package file. | -| `updatedAt` | [`Time!`](#time) | The updated date. | +| `updatedAt` | [`Time!`](#time) | Updated date. | ### `PackageFileRegistry` @@ -11690,10 +11690,10 @@ Represents a package tag. | Name | Type | Description | | ---- | ---- | ----------- | -| `createdAt` | [`Time!`](#time) | The created date. | -| `id` | [`ID!`](#id) | The ID of the tag. | -| `name` | [`String!`](#string) | The name of the tag. | -| `updatedAt` | [`Time!`](#time) | The updated date. | +| `createdAt` | [`Time!`](#time) | Created date. | +| `id` | [`ID!`](#id) | ID of the tag. | +| `name` | [`String!`](#string) | Name of the tag. | +| `updatedAt` | [`Time!`](#time) | Updated date. | ### `PageInfo` @@ -11910,7 +11910,7 @@ Represents vulnerability finding of a security report on the pipeline. | `clusterAgents` | [`ClusterAgentConnection`](#clusteragentconnection) | Cluster agents associated with the project. (see [Connections](#connections)) | | `codeCoverageSummary` | [`CodeCoverageSummary`](#codecoveragesummary) | Code coverage summary associated with the project. | | `complianceFrameworks` | [`ComplianceFrameworkConnection`](#complianceframeworkconnection) | Compliance frameworks associated with the project. (see [Connections](#connections)) | -| `containerExpirationPolicy` | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | The container expiration policy of the project. | +| `containerExpirationPolicy` | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | Container expiration policy of the project. | | `containerRegistryEnabled` | [`Boolean`](#boolean) | Indicates if Container Registry is enabled for the current user. | | `containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the project. | | `createdAt` | [`Time`](#time) | Timestamp of the project creation. | @@ -11966,7 +11966,7 @@ Represents vulnerability finding of a security report on the pipeline. | `sshUrlToRepo` | [`String`](#string) | URL to connect to the project via SSH. | | `starCount` | [`Int!`](#int) | Number of times the project has been starred. | | `statistics` | [`ProjectStatistics`](#projectstatistics) | Statistics of the project. | -| `suggestionCommitMessage` | [`String`](#string) | The commit message used to apply merge request suggestions. | +| `suggestionCommitMessage` | [`String`](#string) | Commit message used to apply merge request suggestions. | | `tagList` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.12. Use `topics`. | | `terraformStates` | [`TerraformStateConnection`](#terraformstateconnection) | Terraform states associated with the project. (see [Connections](#connections)) | | `topics` | [`[String!]`](#string) | List of project topics. | @@ -12408,7 +12408,7 @@ four standard [pagination arguments](#connection-pagination-arguments): ##### `Project.label` -A label available on this project. +Label available on this project. Returns [`Label`](#label). @@ -12896,7 +12896,7 @@ The alert condition for Prometheus. | Name | Type | Description | | ---- | ---- | ----------- | -| `humanizedText` | [`String!`](#string) | The human-readable text of the alert condition. | +| `humanizedText` | [`String!`](#string) | Human-readable text of the alert condition. | | `id` | [`ID!`](#id) | ID of the alert condition. | ### `PushRules` @@ -12950,7 +12950,7 @@ Represents a release. | ---- | ---- | ----------- | | `assets` | [`ReleaseAssets`](#releaseassets) | Assets of the release. | | `author` | [`UserCore`](#usercore) | User that created the release. | -| `commit` | [`Commit`](#commit) | The commit associated with the release. | +| `commit` | [`Commit`](#commit) | Commit associated with the release. | | `createdAt` | [`Time`](#time) | Timestamp of when the release was created. | | `description` | [`String`](#string) | Description (also known as "release notes") of the release. | | `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | @@ -15100,7 +15100,7 @@ Type of file the position refers to. | Value | Description | | ----- | ----------- | | `image` | An image. | -| `text` | A text file. | +| `text` | Text file. | ### `DoraMetricBucketingInterval` @@ -15522,7 +15522,7 @@ Milestone ID wildcard values. | Value | Description | | ----- | ----------- | -| `ANY` | A milestone is assigned. | +| `ANY` | Milestone is assigned. | | `NONE` | No milestone is assigned. | | `STARTED` | An open, started milestone (start date <= today). | | `UPCOMING` | An open milestone due in the future (due date >= today). | @@ -16787,16 +16787,16 @@ Implementations: | Name | Type | Description | | ---- | ---- | ----------- | -| `diffRefs` | [`DiffRefs!`](#diffrefs) | The diff refs for this design. | +| `diffRefs` | [`DiffRefs!`](#diffrefs) | Diff refs for this design. | | `event` | [`DesignVersionEvent!`](#designversionevent) | How this design was changed in the current version. | -| `filename` | [`String!`](#string) | The filename of the design. | -| `fullPath` | [`String!`](#string) | The full path to the design file. | -| `id` | [`ID!`](#id) | The ID of this design. | -| `image` | [`String!`](#string) | The URL of the full-sized image. | +| `filename` | [`String!`](#string) | Filename of the design. | +| `fullPath` | [`String!`](#string) | Full path to the design file. | +| `id` | [`ID!`](#id) | ID of this design. | +| `image` | [`String!`](#string) | URL of the full-sized image. | | `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated. | -| `issue` | [`Issue!`](#issue) | The issue the design belongs to. | -| `notesCount` | [`Int!`](#int) | The total count of user-created notes for this design. | -| `project` | [`Project!`](#project) | The project the design belongs to. | +| `issue` | [`Issue!`](#issue) | Issue the design belongs to. | +| `notesCount` | [`Int!`](#int) | Total count of user-created notes for this design. | +| `project` | [`Project!`](#project) | Project the design belongs to. | #### `Entry` @@ -16828,7 +16828,7 @@ Implementations: | Name | Type | Description | | ---- | ---- | ----------- | -| `events` | [`EventConnection`](#eventconnection) | A list of events associated with the object. (see [Connections](#connections)) | +| `events` | [`EventConnection`](#eventconnection) | List of events associated with the object. (see [Connections](#connections)) | #### `MemberInterface` @@ -17251,8 +17251,8 @@ Input type for DastSiteProfile authentication. | Name | Type | Description | | ---- | ---- | ----------- | -| `newPath` | [`String`](#string) | The path of the file on the head sha. | -| `oldPath` | [`String`](#string) | The path of the file on the start sha. | +| `newPath` | [`String`](#string) | Path of the file on the HEAD SHA. | +| `oldPath` | [`String`](#string) | Path of the file on the start SHA. | ### `DiffPositionInput` @@ -17434,7 +17434,7 @@ Fields that are available when modifying a release asset link. | Name | Type | Description | | ---- | ---- | ----------- | | `directAssetPath` | [`String`](#string) | Relative path for a direct asset link. | -| `linkType` | [`ReleaseAssetLinkType`](#releaseassetlinktype) | The type of the asset link. | +| `linkType` | [`ReleaseAssetLinkType`](#releaseassetlinktype) | Type of the asset link. | | `name` | [`String!`](#string) | Name of the asset link. | | `url` | [`String!`](#string) | URL of the asset link. | @@ -17446,7 +17446,7 @@ Fields that are available when modifying release assets. | Name | Type | Description | | ---- | ---- | ----------- | -| `links` | [`[ReleaseAssetLinkInput!]`](#releaseassetlinkinput) | A list of asset links to associate to the release. | +| `links` | [`[ReleaseAssetLinkInput!]`](#releaseassetlinkinput) | List of asset links to associate to the release. | ### `SastCiConfigurationAnalyzersEntityInput` @@ -17505,8 +17505,8 @@ A time-frame defined as a closed inclusive range of two dates. | Name | Type | Description | | ---- | ---- | ----------- | -| `end` | [`Date!`](#date) | The end of the range. | -| `start` | [`Date!`](#date) | The start of the range. | +| `end` | [`Date!`](#date) | End of the range. | +| `start` | [`Date!`](#date) | Start of the range. | ### `UpdateDiffImagePositionInput` diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md index 2ade6c1e71d..7f88d11d41f 100644 --- a/doc/development/documentation/testing.md +++ b/doc/development/documentation/testing.md @@ -319,6 +319,38 @@ To configure Vale in your editor, install one of the following as appropriate: cases, `vale` should work. To find the location, run `which vale` in a terminal. - Vim [ALE plugin](https://github.com/dense-analysis/ale). +- Emacs [Flycheck extension](https://github.com/flycheck/flycheck). + This requires some configuration: + + - `Flycheck` supports `markdownlint-cli` out of the box, but you must point it + to the `.markdownlint.yml` at the base of the project directory. A `.dir-locals.el` + file can accomplish this: + + ```lisp + ;; Place this code in a file called `.dir-locals.el` at the root of the gitlab project. + ((markdown-mode . ((flycheck-markdown-markdownlint-cli-config . ".markdownlint.yml")))) + + ``` + + - A minimal configuration for Flycheck to work with Vale could look like this: + + ```lisp + (flycheck-define-checker vale + "A checker for prose" + :command ("vale" "--output" "line" "--no-wrap" + source) + :standard-input nil + :error-patterns + ((error line-start (file-name) ":" line ":" column ":" (id (one-or-more (not (any ":")))) ":" (message) line-end)) + :modes (markdown-mode org-mode text-mode) + :next-checkers ((t . markdown-markdownlint-cli)) + ) + + (add-to-list 'flycheck-checkers 'vale) + ``` + + In this setup the `markdownlint` checker is set as a "next" checker from the defined `vale` checker. + Enabling this custom Vale checker provides error linting from both Vale and markdownlint. We don't use [Vale Server](https://errata-ai.github.io/vale/#using-vale-with-a-text-editor-or-another-third-party-application). diff --git a/doc/development/testing_guide/end_to_end/best_practices.md b/doc/development/testing_guide/end_to_end/best_practices.md index 74c02d19d0a..d3ef538dd81 100644 --- a/doc/development/testing_guide/end_to_end/best_practices.md +++ b/doc/development/testing_guide/end_to_end/best_practices.md @@ -8,6 +8,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w This is a tailored extension of the Best Practices [found in the testing guide](../best_practices.md). +## Class and module naming + +The QA framework uses [Zeitwerk](https://github.com/fxn/zeitwerk) for class and module autoloading. The default Zeitwerk [inflector](https://github.com/fxn/zeitwerk#zeitwerkinflector) simply converts snake_cased file names to PascalCased module or class names. It is advised to stick to this pattern to avoid manual maintenance of inflections. + +In case custom inflection logic is needed, custom inflectors are added in the [qa.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa.rb) file in the `loader.inflector.inflect` method invocation. + ## Link a test to its test-case issue Every test should have a corresponding issue in the [Quality Test Cases project](https://gitlab.com/gitlab-org/quality/testcases/). @@ -342,7 +348,7 @@ end When something requires waiting to be matched, use `eventually_` matchers with clear wait duration definition. -`Eventually` matchers use the following naming pattern: `eventually_${rspec_matcher_name}`. They are defined in [eventually_matcher.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/spec/support/matchers/eventually_matcher.rb). +`Eventually` matchers use the following naming pattern: `eventually_${rspec_matcher_name}`. They are defined in [eventually_matcher.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/support/matchers/eventually_matcher.rb). ```ruby expect { async_value }.to eventually_eq(value).within(max_duration: 120, max_attempts: 60, reload_page: page) diff --git a/doc/update/index.md b/doc/update/index.md index 4b7e63a8277..dc7be2597fe 100644 --- a/doc/update/index.md +++ b/doc/update/index.md @@ -182,7 +182,7 @@ Find where your version sits in the upgrade path below, and upgrade GitLab accordingly, while also consulting the [version-specific upgrade instructions](#version-specific-upgrading-instructions): -`8.11.Z` -> [`8.12.0`](#upgrades-from-versions-earlier-than-812) -> `8.17.7` -> `9.5.10` -> `10.8.7` -> [`11.11.8`](#1200) -> `12.0.12` -> [`12.1.17`](#1210) -> `12.10.14` -> `13.0.14` -> [`13.1.11`](#1310) -> [latest `13.12.Z`](https://about.gitlab.com/releases/categories/releases/) -> [latest `14.0.Z`](#1400) -> [`14.1.Z`](#1410) -> [latest `14.Y.Z`](https://about.gitlab.com/releases/categories/releases/) +`8.11.Z` -> [`8.12.0`](#upgrades-from-versions-earlier-than-812) -> `8.17.7` -> `9.5.10` -> `10.8.7` -> [`11.11.8`](#1200) -> `12.0.12` -> [`12.1.17`](#1210) -> `12.10.14` -> `13.0.14` -> [`13.1.11`](#1310) -> [`13.8.3`](#1383) -> [latest `13.12.Z`](https://about.gitlab.com/releases/categories/releases/) -> [latest `14.0.Z`](#1400) -> [`14.1.Z`](#1410) -> [latest `14.Y.Z`](https://about.gitlab.com/releases/categories/releases/) The following table, while not exhaustive, shows some examples of the supported upgrade paths. @@ -190,7 +190,7 @@ upgrade paths. | Target version | Your version | Supported upgrade path | Note | | -------------- | ------------ | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `14.1.2` | `13.9.2` | `13.9.2` -> `13.12.9` -> `14.0.7` -> `14.1.2` | Two intermediate versions are required: `13.12` and `14.0`, then `14.1`. | -| `13.5.4` | `12.9.2` | `12.9.2` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.5.4` | Three intermediate versions are required: `12.10`, `13.0` and `13.1`, then `13.5.4`. | +| `13.12.10` | `12.9.2` | `12.9.2` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.8.3` -> `13.12.10` | Four intermediate versions are required: `12.10`, `13.0`, `13.1` and `13.8.3`, then `13.12.10`. | | `13.2.10` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.2.10` | Six intermediate versions are required: `11.11`, `12.0`, `12.1`, `12.10`, `13.0` and `13.1`, then `13.2.10`. | | `12.10.14` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` | Three intermediate versions are required: `11.11`, `12.0` and `12.1`, then `12.10.14`. | | `12.9.5` | `10.4.5` | `10.4.5` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.9.5` | Four intermediate versions are required: `10.8`, `11.11`, `12.0` and `12.1`, then `12.9.5`. | @@ -480,6 +480,17 @@ DETAIL: trigger trigger_0d588df444c8 on table application_settings depends on co To work around this bug, follow the previous steps to complete the update. More details are available [in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/324160). +### 13.8.3 + +GitLab 13.8 includes a background migration to address [an issue with duplicate service records](https://gitlab.com/gitlab-org/gitlab/-/issues/290008). If duplicate services are present, this background migration must complete before a unique index is applied to the services table, which was [introduced in GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52563). Upgrades from GitLab 13.8 and earlier to later versions must include an intermediate upgrade to GitLab 13.8.3 and [must wait until the background migrations complete](#checking-for-background-migrations-before-upgrading) before proceeding. + +If duplicate services are still present, an upgrade to 13.9.x or later results in a failed upgrade with the following error: + +```console +PG::UniqueViolation: ERROR: could not create unique index "index_services_on_project_id_and_type_unique" +DETAIL: Key (project_id, type)=(NNN, ServiceName) is duplicated. +``` + ### 13.6.0 Ruby 2.7.2 is required. GitLab does not start with Ruby 2.6.6 or older versions. diff --git a/lib/api/files.rb b/lib/api/files.rb index f3de7fbe96b..9d2b7cce837 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -35,10 +35,9 @@ module API not_found!('Commit') unless @commit @repo = user_project.repository - @blob = @repo.blob_at(@commit.sha, params[:file_path]) + @blob = @repo.blob_at(@commit.sha, params[:file_path], limit: Gitlab::Git::Blob::LFS_POINTER_MAX_SIZE) not_found!('File') unless @blob - @blob.load_all_data! end def commit_response(attrs) @@ -48,13 +47,21 @@ module API } end + def content_sha + Rails.cache.fetch("blob_content_sha256:#{user_project.full_path}:#{@blob.id}") do + @blob.load_all_data! + + Digest::SHA256.hexdigest(@blob.data) + end + end + def blob_data { file_name: @blob.name, file_path: @blob.path, size: @blob.size, encoding: "base64", - content_sha256: Digest::SHA256.hexdigest(@blob.data), + content_sha256: content_sha, ref: params[:ref], blob_id: @blob.id, commit_id: @commit.id, @@ -154,6 +161,8 @@ module API get ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do assign_file_vars! + @blob.load_all_data! + data = blob_data set_http_headers(data) diff --git a/package.json b/package.json index a1e599bf7a8..b706806bcf6 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@gitlab/favicon-overlay": "2.0.0", "@gitlab/svgs": "1.211.0", "@gitlab/tributejs": "1.0.0", - "@gitlab/ui": "32.2.1", + "@gitlab/ui": "32.2.3", "@gitlab/visual-review-tools": "1.6.1", "@rails/actioncable": "6.1.3-2", "@rails/ujs": "6.1.3-2", diff --git a/qa/Gemfile b/qa/Gemfile index 3ba1244d17e..f3090154085 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' -gem 'gitlab-qa' +gem 'gitlab-qa', require: 'gitlab/qa' gem 'activesupport', '~> 6.1.3.2' # This should stay in sync with the root's Gemfile gem 'allure-rspec', '~> 2.14.1' gem 'capybara', '~> 3.35.0' @@ -10,10 +10,9 @@ gem 'capybara-screenshot', '~> 1.0.23' gem 'rake', '~> 12.3.3' gem 'rspec', '~> 3.10' gem 'selenium-webdriver', '~> 4.0.0.beta4' -gem 'airborne', '~> 0.3.4' +gem 'airborne', '~> 0.3.4', require: false # airborne is messing with rspec sandboxed mode so not requiring by default gem 'rest-client', '~> 2.1.0' -gem 'nokogiri', '~> 1.11.7' -gem 'rspec-retry', '~> 0.6.1' +gem 'rspec-retry', '~> 0.6.1', require: 'rspec/retry' gem 'rspec_junit_formatter', '~> 0.4.1' gem 'faker', '~> 1.6', '>= 1.6.6' gem 'knapsack', '~> 1.17' @@ -24,6 +23,7 @@ gem 'parallel', '~> 1.19' gem 'rspec-parameterized', '~> 0.4.2' gem 'octokit', '~> 4.21' gem 'webdrivers', '~> 4.6' +gem 'zeitwerk', '~> 2.4' gem 'chemlab', '~> 0.7' gem 'chemlab-library-www-gitlab-com', '~> 0.1' diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index 66b635868f8..79ca921dccf 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -221,7 +221,6 @@ DEPENDENCIES faker (~> 1.6, >= 1.6.6) gitlab-qa knapsack (~> 1.17) - nokogiri (~> 1.11.7) octokit (~> 4.21) parallel (~> 1.19) parallel_tests (~> 2.29) @@ -237,6 +236,7 @@ DEPENDENCIES selenium-webdriver (~> 4.0.0.beta4) timecop (~> 0.9.1) webdrivers (~> 4.6) + zeitwerk (~> 2.4) BUNDLED WITH 2.2.22 diff --git a/qa/qa.rb b/qa/qa.rb index 965cc88e50c..89721445f39 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -$: << File.expand_path(__dir__) - Encoding.default_external = 'UTF-8' require_relative '../lib/gitlab' @@ -10,683 +8,49 @@ require_relative '../config/initializers/0_inject_enterprise_edition_module' require_relative 'lib/gitlab' -require 'chemlab' +require 'bundler/setup' +Bundler.require(:default) module QA - ## - # Helper classes to represent frequently used sequences of actions - # (e.g., login) - # - module Flow - autoload :Login, 'qa/flow/login' - autoload :Project, 'qa/flow/project' - autoload :Saml, 'qa/flow/saml' - autoload :User, 'qa/flow/user' - autoload :MergeRequest, 'qa/flow/merge_request' - autoload :Pipeline, 'qa/flow/pipeline' - autoload :SignUp, 'qa/flow/sign_up' - end - - ## - # GitLab QA runtime classes, mostly singletons. - # - module Runtime - autoload :Release, 'qa/runtime/release' - autoload :User, 'qa/runtime/user' - autoload :Namespace, 'qa/runtime/namespace' - autoload :Scenario, 'qa/runtime/scenario' - autoload :Browser, 'qa/runtime/browser' - autoload :Env, 'qa/runtime/env' - autoload :Address, 'qa/runtime/address' - autoload :Path, 'qa/runtime/path' - autoload :Feature, 'qa/runtime/feature' - autoload :Fixtures, 'qa/runtime/fixtures' - autoload :Logger, 'qa/runtime/logger' - autoload :GPG, 'qa/runtime/gpg' - autoload :MailHog, 'qa/runtime/mail_hog' - autoload :IPAddress, 'qa/runtime/ip_address' - autoload :Search, 'qa/runtime/search' - autoload :ApplicationSettings, 'qa/runtime/application_settings' - autoload :AllureReport, 'qa/runtime/allure_report' - - module API - autoload :Client, 'qa/runtime/api/client' - autoload :RepositoryStorageMoves, 'qa/runtime/api/repository_storage_moves' - autoload :Request, 'qa/runtime/api/request' - end - - module Key - autoload :Base, 'qa/runtime/key/base' - autoload :RSA, 'qa/runtime/key/rsa' - autoload :ECDSA, 'qa/runtime/key/ecdsa' - autoload :ED25519, 'qa/runtime/key/ed25519' - end - end - - ## - # GitLab QA fabrication mechanisms - # - module Resource - autoload :ApiFabricator, 'qa/resource/api_fabricator' - autoload :Base, 'qa/resource/base' - - autoload :GroupBase, 'qa/resource/group_base' - autoload :Sandbox, 'qa/resource/sandbox' - autoload :Group, 'qa/resource/group' - autoload :BulkImportGroup, 'qa/resource/bulk_import_group' - autoload :Issue, 'qa/resource/issue' - autoload :ProjectIssueNote, 'qa/resource/project_issue_note' - autoload :Project, 'qa/resource/project' - autoload :LabelBase, 'qa/resource/label_base' - autoload :ProjectLabel, 'qa/resource/project_label' - autoload :GroupLabel, 'qa/resource/group_label' - autoload :MergeRequest, 'qa/resource/merge_request' - autoload :ProjectImportedFromGithub, 'qa/resource/project_imported_from_github' - autoload :ProjectImportedFromURL, 'qa/resource/project_imported_from_url' - autoload :MergeRequestFromFork, 'qa/resource/merge_request_from_fork' - autoload :DeployKey, 'qa/resource/deploy_key' - autoload :DeployToken, 'qa/resource/deploy_token' - autoload :ProtectedBranch, 'qa/resource/protected_branch' - autoload :Pipeline, 'qa/resource/pipeline' - autoload :CiVariable, 'qa/resource/ci_variable' - autoload :Runner, 'qa/resource/runner' - autoload :PersonalAccessToken, 'qa/resource/personal_access_token' - autoload :PersonalAccessTokenCache, 'qa/resource/personal_access_token_cache' - autoload :ProjectAccessToken, 'qa/resource/project_access_token' - autoload :User, 'qa/resource/user' - autoload :ProjectMilestone, 'qa/resource/project_milestone' - autoload :GroupMilestone, 'qa/resource/group_milestone' - autoload :Members, 'qa/resource/members' - autoload :File, 'qa/resource/file' - autoload :Fork, 'qa/resource/fork' - autoload :SSHKey, 'qa/resource/ssh_key' - autoload :Snippet, 'qa/resource/snippet' - autoload :Tag, 'qa/resource/tag' - autoload :ProjectMember, 'qa/resource/project_member' - autoload :ProjectSnippet, 'qa/resource/project_snippet' - autoload :UserGPG, 'qa/resource/user_gpg' - autoload :Visibility, 'qa/resource/visibility' - autoload :ProjectSnippet, 'qa/resource/project_snippet' - autoload :Design, 'qa/resource/design' - autoload :RegistryRepository, 'qa/resource/registry_repository' - autoload :Package, 'qa/resource/package' - autoload :PipelineSchedules, 'qa/resource/pipeline_schedules' - autoload :ImportProject, 'qa/resource/import_project' - - module KubernetesCluster - autoload :Base, 'qa/resource/kubernetes_cluster/base' - autoload :ProjectCluster, 'qa/resource/kubernetes_cluster/project_cluster' - end - - module Clusters - autoload :Agent, 'qa/resource/clusters/agent.rb' - autoload :AgentToken, 'qa/resource/clusters/agent_token.rb' - end - - module Events - autoload :Base, 'qa/resource/events/base' - autoload :Project, 'qa/resource/events/project' - end - - module Repository - autoload :Commit, 'qa/resource/repository/commit' - autoload :Push, 'qa/resource/repository/push' - autoload :ProjectPush, 'qa/resource/repository/project_push' - autoload :WikiPush, 'qa/resource/repository/wiki_push' - end - - module Wiki - autoload :ProjectPage, 'qa/resource/wiki/project_page' - autoload :GroupPage, 'qa/resource/wiki/group_page' - end - end - - ## - # GitLab QA Scenarios - # - module Scenario - ## - # Support files - # - autoload :Bootable, 'qa/scenario/bootable' - autoload :Actable, 'qa/scenario/actable' - autoload :Template, 'qa/scenario/template' - autoload :SharedAttributes, 'qa/scenario/shared_attributes' - - ## - # Test scenario entrypoints. - # - module Test - autoload :Instance, 'qa/scenario/test/instance' - module Instance - autoload :All, 'qa/scenario/test/instance/all' - autoload :Smoke, 'qa/scenario/test/instance/smoke' - autoload :Airgapped, 'qa/scenario/test/instance/airgapped' - end - - module Integration - autoload :Github, 'qa/scenario/test/integration/github' - autoload :LDAPNoTLS, 'qa/scenario/test/integration/ldap_no_tls' - autoload :LDAPNoServer, 'qa/scenario/test/integration/ldap_no_server' - autoload :LDAPTLS, 'qa/scenario/test/integration/ldap_tls' - autoload :InstanceSAML, 'qa/scenario/test/integration/instance_saml' - autoload :Kubernetes, 'qa/scenario/test/integration/kubernetes' - autoload :Mattermost, 'qa/scenario/test/integration/mattermost' - autoload :ObjectStorage, 'qa/scenario/test/integration/object_storage' - autoload :SMTP, 'qa/scenario/test/integration/smtp' - autoload :SSHTunnel, 'qa/scenario/test/integration/ssh_tunnel' - autoload :Registry, 'qa/scenario/test/integration/registry' - end - - module Sanity - autoload :Framework, 'qa/scenario/test/sanity/framework' - autoload :Selectors, 'qa/scenario/test/sanity/selectors' - end - end - end - - ## - # Classes describing structure of GitLab, pages, menus etc. - # - # Needed to execute click-driven-only black-box tests. - # - module Page - autoload :Base, 'qa/page/base' - autoload :View, 'qa/page/view' - autoload :Element, 'qa/page/element' - autoload :PageConcern, 'qa/page/page_concern' - autoload :Validator, 'qa/page/validator' - autoload :Validatable, 'qa/page/validatable' - - module SubMenus - autoload :Common, 'qa/page/sub_menus/common' - end - - module Main - autoload :Login, 'qa/page/main/login' - autoload :Menu, 'qa/page/main/menu' - autoload :OAuth, 'qa/page/main/oauth' - autoload :TwoFactorAuth, 'qa/page/main/two_factor_auth' - autoload :Terms, 'qa/page/main/terms' - end - - module Registration - autoload :SignUp, 'qa/page/registration/sign_up' - autoload :Welcome, 'qa/page/registration/welcome' - end - - module Settings - autoload :Common, 'qa/page/settings/common' - end - - module Dashboard - autoload :Projects, 'qa/page/dashboard/projects' - autoload :Groups, 'qa/page/dashboard/groups' - autoload :Welcome, 'qa/page/dashboard/welcome' - autoload :Todos, 'qa/page/dashboard/todos' - - module Snippet - autoload :New, 'qa/page/dashboard/snippet/new' - autoload :Index, 'qa/page/dashboard/snippet/index' - autoload :Show, 'qa/page/dashboard/snippet/show' - autoload :Edit, 'qa/page/dashboard/snippet/edit' - end - end - - module Group - autoload :New, 'qa/page/group/new' - autoload :Show, 'qa/page/group/show' - autoload :Menu, 'qa/page/group/menu' - autoload :Members, 'qa/page/group/members' - autoload :BulkImport, 'qa/page/group/bulk_import' - autoload :DependencyProxy, 'qa/page/group/dependency_proxy' - - module Milestone - autoload :Index, 'qa/page/group/milestone/index' - autoload :New, 'qa/page/group/milestone/new' - end - - module SubMenus - autoload :Common, 'qa/page/group/sub_menus/common' - end - - module Settings - autoload :General, 'qa/page/group/settings/general' - autoload :PackageRegistries, 'qa/page/group/settings/package_registries' - end - end - - module Milestone - autoload :Index, 'qa/page/milestone/index' - autoload :New, 'qa/page/milestone/new' - autoload :Show, 'qa/page/milestone/show' - end - - module File - autoload :Form, 'qa/page/file/form' - autoload :Show, 'qa/page/file/show' - autoload :Edit, 'qa/page/file/edit' - - module Shared - autoload :CommitMessage, 'qa/page/file/shared/commit_message' - autoload :CommitButton, 'qa/page/file/shared/commit_button' - autoload :Editor, 'qa/page/file/shared/editor' - end - end - - module Project - autoload :New, 'qa/page/project/new' - autoload :Show, 'qa/page/project/show' - autoload :Activity, 'qa/page/project/activity' - autoload :Menu, 'qa/page/project/menu' - autoload :Members, 'qa/page/project/members' - - module Artifact - autoload :Show, 'qa/page/project/artifact/show' - end - - module Branches - autoload :Show, 'qa/page/project/branches/show' - end - - module Commit - autoload :Show, 'qa/page/project/commit/show' - end - - module Import - autoload :Github, 'qa/page/project/import/github' - autoload :RepoByURL, 'qa/page/project/import/repo_by_url' - end - - module Pipeline - autoload :Index, 'qa/page/project/pipeline/index' - autoload :Show, 'qa/page/project/pipeline/show' - autoload :New, 'qa/page/project/pipeline/new' - end - - module PipelineEditor - autoload :Show, 'qa/page/project/pipeline_editor/show' - end - - module Tag - autoload :Index, 'qa/page/project/tag/index' - autoload :New, 'qa/page/project/tag/new' - autoload :Show, 'qa/page/project/tag/show' - end - - module Job - autoload :Show, 'qa/page/project/job/show' - end - - module Packages - autoload :Index, 'qa/page/project/packages/index' - autoload :Show, 'qa/page/project/packages/show' - end - - module Registry - autoload :Show, 'qa/page/project/registry/show' - end - - module Settings - autoload :Advanced, 'qa/page/project/settings/advanced' - autoload :Main, 'qa/page/project/settings/main' - autoload :Repository, 'qa/page/project/settings/repository' - autoload :CICD, 'qa/page/project/settings/ci_cd' - autoload :Integrations, 'qa/page/project/settings/integrations' - autoload :GeneralPipelines, 'qa/page/project/settings/general_pipelines' - autoload :AutoDevops, 'qa/page/project/settings/auto_devops' - autoload :DeployKeys, 'qa/page/project/settings/deploy_keys' - autoload :DeployTokens, 'qa/page/project/settings/deploy_tokens' - autoload :ProtectedBranches, 'qa/page/project/settings/protected_branches' - autoload :CiVariables, 'qa/page/project/settings/ci_variables' - autoload :Runners, 'qa/page/project/settings/runners' - autoload :MergeRequest, 'qa/page/project/settings/merge_request' - autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories' - autoload :ProtectedTags, 'qa/page/project/settings/protected_tags' - autoload :DefaultBranch, 'qa/page/project/settings/default_branch' - autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions' - autoload :AccessTokens, 'qa/page/project/settings/access_tokens' - - module Services - autoload :Jira, 'qa/page/project/settings/services/jira' - autoload :Jenkins, 'qa/page/project/settings/services/jenkins' - autoload :Prometheus, 'qa/page/project/settings/services/prometheus' - end - autoload :Monitor, 'qa/page/project/settings/monitor' - autoload :Alerts, 'qa/page/project/settings/alerts' - autoload :Integrations, 'qa/page/project/settings/integrations' - end - - module SubMenus - autoload :CiCd, 'qa/page/project/sub_menus/ci_cd' - autoload :Common, 'qa/page/project/sub_menus/common' - autoload :Issues, 'qa/page/project/sub_menus/issues' - autoload :Monitor, 'qa/page/project/sub_menus/monitor' - autoload :Deployments, 'qa/page/project/sub_menus/deployments' - autoload :Infrastructure, 'qa/page/project/sub_menus/infrastructure' - autoload :Repository, 'qa/page/project/sub_menus/repository' - autoload :Settings, 'qa/page/project/sub_menus/settings' - autoload :Project, 'qa/page/project/sub_menus/project' - autoload :Packages, 'qa/page/project/sub_menus/packages' - end - - module Issue - autoload :New, 'qa/page/project/issue/new' - autoload :Show, 'qa/page/project/issue/show' - autoload :Index, 'qa/page/project/issue/index' - autoload :JiraImport, 'qa/page/project/issue/jira_import' - end - - module Fork - autoload :New, 'qa/page/project/fork/new' - end - - module Milestone - autoload :New, 'qa/page/project/milestone/new' - autoload :Index, 'qa/page/project/milestone/index' - end - - module Deployments - module Environments - autoload :Index, 'qa/page/project/deployments/environments/index' - end - end - - module Infrastructure - module Kubernetes - autoload :Index, 'qa/page/project/infrastructure/kubernetes/index' - autoload :Add, 'qa/page/project/infrastructure/kubernetes/add' - autoload :AddExisting, 'qa/page/project/infrastructure/kubernetes/add_existing' - autoload :Show, 'qa/page/project/infrastructure/kubernetes/show' - end - end - - module Monitor - module Metrics - autoload :Show, 'qa/page/project/monitor/metrics/show' - end - - module Incidents - autoload :Index, 'qa/page/project/monitor/incidents/index' - end - end - - module Wiki - autoload :Edit, 'qa/page/project/wiki/edit' - autoload :Show, 'qa/page/project/wiki/show' - autoload :GitAccess, 'qa/page/project/wiki/git_access' - autoload :List, 'qa/page/project/wiki/list' - end - - module WebIDE - autoload :Edit, 'qa/page/project/web_ide/edit' - end - - module Snippet - autoload :New, 'qa/page/project/snippet/new' - autoload :Show, 'qa/page/project/snippet/show' - autoload :Index, 'qa/page/project/snippet/index' - end - - module Secure - autoload :ConfigurationForm, 'qa/page/project/secure/configuration_form' - end - end - - module Profile - autoload :Menu, 'qa/page/profile/menu' - autoload :PersonalAccessTokens, 'qa/page/profile/personal_access_tokens' - autoload :SSHKeys, 'qa/page/profile/ssh_keys' - autoload :Emails, 'qa/page/profile/emails' - autoload :Password, 'qa/page/profile/password' - autoload :TwoFactorAuth, 'qa/page/profile/two_factor_auth' - - module Accounts - autoload :Show, 'qa/page/profile/accounts/show' - end - end - - module User - autoload :Show, 'qa/page/user/show' - end - - module Issuable - autoload :New, 'qa/page/issuable/new' - end - - module Alert - autoload :AutoDevopsAlert, 'qa/page/alert/auto_devops_alert' - autoload :FreeTrial, 'qa/page/alert/free_trial' - end - - module Layout - autoload :Banner, 'qa/page/layout/banner' - autoload :Flash, 'qa/page/layout/flash' - autoload :PerformanceBar, 'qa/page/layout/performance_bar' - end - - module Label - autoload :New, 'qa/page/label/new' - autoload :Index, 'qa/page/label/index' - end - - module MergeRequest - autoload :New, 'qa/page/merge_request/new' - autoload :Show, 'qa/page/merge_request/show' - end - - module Admin - autoload :Menu, 'qa/page/admin/menu' - autoload :NewSession, 'qa/page/admin/new_session' - - module Settings - autoload :General, 'qa/page/admin/settings/general' - autoload :MetricsAndProfiling, 'qa/page/admin/settings/metrics_and_profiling' - autoload :Network, 'qa/page/admin/settings/network' - - module Component - autoload :IpLimits, 'qa/page/admin/settings/component/ip_limits' - autoload :OutboundRequests, 'qa/page/admin/settings/component/outbound_requests' - autoload :AccountAndLimit, 'qa/page/admin/settings/component/account_and_limit' - autoload :PerformanceBar, 'qa/page/admin/settings/component/performance_bar' - autoload :SignUpRestrictions, 'qa/page/admin/settings/component/sign_up_restrictions' - end - end - - module Overview - module Users - autoload :Index, 'qa/page/admin/overview/users/index' - autoload :Show, 'qa/page/admin/overview/users/show' - end - - module Groups - autoload :Index, 'qa/page/admin/overview/groups/index' - autoload :Show, 'qa/page/admin/overview/groups/show' - autoload :Edit, 'qa/page/admin/overview/groups/edit' - end - end - end - - module Mattermost - autoload :Main, 'qa/page/mattermost/main' - autoload :Login, 'qa/page/mattermost/login' - end - - module Search - autoload :Results, 'qa/page/search/results' - end - - ## - # Classes describing components that are used by several pages. - # - module Component - autoload :Breadcrumbs, 'qa/page/component/breadcrumbs' - autoload :CiBadgeLink, 'qa/page/component/ci_badge_link' - autoload :ClonePanel, 'qa/page/component/clone_panel' - autoload :DesignManagement, 'qa/page/component/design_management' - autoload :LazyLoader, 'qa/page/component/lazy_loader' - autoload :LegacyClonePanel, 'qa/page/component/legacy_clone_panel' - autoload :Dropzone, 'qa/page/component/dropzone' - autoload :GroupsFilter, 'qa/page/component/groups_filter' - autoload :Select2, 'qa/page/component/select2' - autoload :DropdownFilter, 'qa/page/component/dropdown_filter' - autoload :UsersSelect, 'qa/page/component/users_select' - autoload :Note, 'qa/page/component/note' - autoload :ConfirmModal, 'qa/page/component/confirm_modal' - autoload :CustomMetric, 'qa/page/component/custom_metric' - autoload :DesignManagement, 'qa/page/component/design_management' - autoload :ProjectSelector, 'qa/page/component/project_selector' - autoload :Snippet, 'qa/page/component/snippet' - autoload :NewSnippet, 'qa/page/component/new_snippet' - autoload :InviteMembersModal, 'qa/page/component/invite_members_modal' - autoload :Wiki, 'qa/page/component/wiki' - autoload :WikiSidebar, 'qa/page/component/wiki_sidebar' - autoload :WikiPageForm, 'qa/page/component/wiki_page_form' - autoload :AccessTokens, 'qa/page/component/access_tokens' - autoload :CommitModal, 'qa/page/component/commit_modal' - autoload :VisibilitySetting, 'qa/page/component/visibility_setting' - autoload :ContentEditor, 'qa/page/component/content_editor' - - module Import - autoload :Gitlab, 'qa/page/component/import/gitlab' - autoload :Selection, 'qa/page/component/import/selection' - end - - module Issuable - autoload :Common, 'qa/page/component/issuable/common' - autoload :Sidebar, 'qa/page/component/issuable/sidebar' - end - - module IssueBoard - autoload :Show, 'qa/page/component/issue_board/show' - end - - module WebIDE - autoload :Alert, 'qa/page/component/web_ide/alert' - - module Modal - autoload :CreateNewFile, 'qa/page/component/web_ide/modal/create_new_file' - end - end - - module Project - autoload :Templates, 'qa/page/component/project/templates' - end - end - - module Trials - autoload :New, 'qa/page/trials/new' - autoload :Select, 'qa/page/trials/select' - end - - module Modal - autoload :DeleteWiki, 'qa/page/modal/delete_wiki' - end - end - - ## - # Classes describing operations on Git repositories. - # - module Git - autoload :Repository, 'qa/git/repository' - autoload :Location, 'qa/git/location' - end - - ## - # Classes describing services being part of GitLab and how we can interact - # with these services, like through the shell. - # - module Service - autoload :Shellout, 'qa/service/shellout' - autoload :KubernetesCluster, 'qa/service/kubernetes_cluster' - autoload :Omnibus, 'qa/service/omnibus' - autoload :PraefectManager, 'qa/service/praefect_manager' - - module ClusterProvider - autoload :Base, 'qa/service/cluster_provider/base' - autoload :Gcloud, 'qa/service/cluster_provider/gcloud' - autoload :Minikube, 'qa/service/cluster_provider/minikube' - autoload :K3d, 'qa/service/cluster_provider/k3d' - autoload :K3s, 'qa/service/cluster_provider/k3s' - autoload :K3sCilium, 'qa/service/cluster_provider/k3s_cilium' - end - - module DockerRun - autoload :Base, 'qa/service/docker_run/base' - autoload :Jenkins, 'qa/service/docker_run/jenkins' - autoload :LDAP, 'qa/service/docker_run/ldap' - autoload :Maven, 'qa/service/docker_run/maven' - autoload :NodeJs, 'qa/service/docker_run/node_js' - autoload :GitlabRunner, 'qa/service/docker_run/gitlab_runner' - autoload :MailHog, 'qa/service/docker_run/mail_hog' - autoload :SamlIdp, 'qa/service/docker_run/saml_idp' - autoload :K3s, 'qa/service/docker_run/k3s' - end - end - - ## - # Classes that make it possible to execute features tests. - # - module Specs - autoload :Config, 'qa/specs/config' - autoload :Runner, 'qa/specs/runner' - autoload :ParallelRunner, 'qa/specs/parallel_runner' - autoload :LoopRunner, 'qa/specs/loop_runner' - - module Helpers - autoload :ContextSelector, 'qa/specs/helpers/context_selector' - autoload :ContextFormatter, 'qa/specs/helpers/context_formatter' - autoload :Quarantine, 'qa/specs/helpers/quarantine' - autoload :QuarantineFormatter, 'qa/specs/helpers/quarantine_formatter' - autoload :RSpec, 'qa/specs/helpers/rspec' - end - end - - ## - # Classes that describe the structure of vendor/third party application pages - # - module Vendor - module SAMLIdp - module Page - autoload :Base, 'qa/vendor/saml_idp/page/base' - autoload :Login, 'qa/vendor/saml_idp/page/login' - end - end - - module Jenkins - module Page - autoload :Base, 'qa/vendor/jenkins/page/base' - autoload :Login, 'qa/vendor/jenkins/page/login' - autoload :Configure, 'qa/vendor/jenkins/page/configure' - autoload :NewCredentials, 'qa/vendor/jenkins/page/new_credentials' - autoload :NewJob, 'qa/vendor/jenkins/page/new_job' - autoload :LastJobConsole, 'qa/vendor/jenkins/page/last_job_console' - autoload :ConfigureJob, 'qa/vendor/jenkins/page/configure_job' - end - end - - module Jira - autoload :JiraAPI, 'qa/vendor/jira/jira_api' - end - end - - # Classes that provide support to other parts of the framework. - # - module Support - module Page - autoload :Logging, 'qa/support/page/logging' - end - autoload :Api, 'qa/support/api' - autoload :Dates, 'qa/support/dates' - autoload :Repeater, 'qa/support/repeater' - autoload :Run, 'qa/support/run' - autoload :Retrier, 'qa/support/retrier' - autoload :Waiter, 'qa/support/waiter' - autoload :WaitForRequests, 'qa/support/wait_for_requests' - autoload :OTP, 'qa/support/otp' - autoload :SSH, 'qa/support/ssh' - autoload :AllureMetadataFormatter, 'qa/support/allure_metadata_formatter.rb' - end + root = "#{__dir__}/qa" + + loader = Zeitwerk::Loader.new + loader.push_dir(root, namespace: QA) + + loader.ignore("#{root}/specs/features") + + loader.inflector.inflect( + "ce" => "CE", + "ee" => "EE", + "api" => "API", + "ssh" => "SSH", + "ssh_key" => "SSHKey", + "ssh_keys" => "SSHKeys", + "ecdsa" => "ECDSA", + "ed25519" => "ED25519", + "rsa" => "RSA", + "ldap" => "LDAP", + "ldap_tls" => "LDAPTLS", + "ldap_no_tls" => "LDAPNoTLS", + "ldap_no_server" => "LDAPNoServer", + "rspec" => "RSpec", + "web_ide" => "WebIDE", + "ci_cd" => "CiCd", + "repo_by_url" => "RepoByURL", + "oauth" => "OAuth", + "saml_sso_sign_in" => "SamlSSOSignIn", + "saml_sso_sign_up" => "SamlSSOSignUp", + "group_saml" => "GroupSAML", + "instance_saml" => "InstanceSAML", + "saml_sso" => "SamlSSO", + "ldap_sync" => "LDAPSync", + "ip_address" => "IPAddress", + "gpg" => "GPG", + "user_gpg" => "UserGPG", + "smtp" => "SMTP", + "otp" => "OTP", + "jira_api" => "JiraAPI" + ) + + loader.setup end - -QA::Runtime::Release.extend_autoloads! diff --git a/qa/qa/ce/strategy.rb b/qa/qa/ce/strategy.rb index 018a1eb1bfc..71c538c20a0 100644 --- a/qa/qa/ce/strategy.rb +++ b/qa/qa/ce/strategy.rb @@ -5,10 +5,6 @@ module QA module Strategy extend self - def extend_autoloads! - # noop - end - def perform_before_hooks # The login page could take some time to load the first time it is visited. # We visit the login page and wait for it to properly load only once before the tests. diff --git a/qa/qa/flow/saml.rb b/qa/qa/flow/saml.rb index 7cbaba9fbd5..1280f59c3c2 100644 --- a/qa/qa/flow/saml.rb +++ b/qa/qa/flow/saml.rb @@ -67,7 +67,7 @@ module QA end def login_to_idp_if_required(username, password) - Vendor::SAMLIdp::Page::Login.perform { |login_page| login_page.login_if_required(username, password) } + Vendor::SamlIdp::Page::Login.perform { |login_page| login_page.login_if_required(username, password) } end end end diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb index 24a148e9330..356e509a81d 100644 --- a/qa/qa/git/repository.rb +++ b/qa/qa/git/repository.rb @@ -4,7 +4,6 @@ require 'cgi' require 'uri' require 'fileutils' require 'tmpdir' -require 'securerandom' module QA module Git diff --git a/qa/qa/page/project/monitor/metrics/show.rb b/qa/qa/page/project/monitor/metrics/show.rb index 07ceb108fa3..0129ee06cb6 100644 --- a/qa/qa/page/project/monitor/metrics/show.rb +++ b/qa/qa/page/project/monitor/metrics/show.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Page module Project diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb index c537db34a51..6df285cdd93 100644 --- a/qa/qa/page/project/settings/ci_cd.rb +++ b/qa/qa/page/project/settings/ci_cd.rb @@ -4,7 +4,7 @@ module QA module Page module Project module Settings - class CICD < Page::Base + class CiCd < Page::Base include QA::Page::Settings::Common view 'app/views/projects/settings/ci_cd/show.html.haml' do @@ -43,4 +43,4 @@ module QA end end -QA::Page::Project::Settings::CICD.prepend_mod_with("Page::Project::Settings::CICD", namespace: QA) +QA::Page::Project::Settings::CiCd.prepend_mod_with("Page::Project::Settings::CiCd", namespace: QA) diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index 613059b2d32..fa17b8fe302 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'pathname' - module QA module Page class View diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb index 034feb4e90f..c1533577657 100644 --- a/qa/qa/resource/api_fabricator.rb +++ b/qa/qa/resource/api_fabricator.rb @@ -55,7 +55,7 @@ module QA end end - include Support::Api + include Support::API attr_writer :api_resource, :api_response def api_put(body = api_put_body) diff --git a/qa/qa/resource/ci_variable.rb b/qa/qa/resource/ci_variable.rb index 0b9f4eb6635..ef663bb613f 100644 --- a/qa/qa/resource/ci_variable.rb +++ b/qa/qa/resource/ci_variable.rb @@ -22,7 +22,7 @@ module QA Page::Project::Menu.perform(&:go_to_ci_cd_settings) - Page::Project::Settings::CICD.perform do |setting| + Page::Project::Settings::CiCd.perform do |setting| setting.expand_ci_variables do |page| page.click_add_variable page.fill_variable(key, value, masked) diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb index d20813e9f2a..9214d4eff4a 100644 --- a/qa/qa/resource/issue.rb +++ b/qa/qa/resource/issue.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class Issue < Base diff --git a/qa/qa/resource/kubernetes_cluster/base.rb b/qa/qa/resource/kubernetes_cluster/base.rb index 38bca48be17..b3812d60431 100644 --- a/qa/qa/resource/kubernetes_cluster/base.rb +++ b/qa/qa/resource/kubernetes_cluster/base.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource module KubernetesCluster diff --git a/qa/qa/resource/label_base.rb b/qa/qa/resource/label_base.rb index 14ddd0809ea..8f6534cb451 100644 --- a/qa/qa/resource/label_base.rb +++ b/qa/qa/resource/label_base.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource # Base label class for GroupLabel and ProjectLabel diff --git a/qa/qa/resource/members.rb b/qa/qa/resource/members.rb index c8f9feeca15..83adb10c3a0 100644 --- a/qa/qa/resource/members.rb +++ b/qa/qa/resource/members.rb @@ -12,7 +12,7 @@ module QA QA::Runtime::Logger.debug(%Q[Adding user #{user.username} to #{full_path} #{self.class.name}]) response = post Runtime::API::Request.new(api_client, api_members_path).url, { user_id: user.id, access_level: access_level } - response.code == QA::Support::Api::HTTP_STATUS_CREATED + response.code == QA::Support::API::HTTP_STATUS_CREATED end end @@ -31,7 +31,7 @@ module QA QA::Runtime::Logger.debug(%Q[Sharing #{self.class.name} with #{group.name}]) response = post Runtime::API::Request.new(api_client, api_share_path).url, { group_id: group.id, group_access: access_level } - response.code == QA::Support::Api::HTTP_STATUS_CREATED + response.code == QA::Support::API::HTTP_STATUS_CREATED end end diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb index 93b5fc3ef6b..1fea6feb910 100644 --- a/qa/qa/resource/merge_request.rb +++ b/qa/qa/resource/merge_request.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class MergeRequest < Base diff --git a/qa/qa/resource/merge_request_from_fork.rb b/qa/qa/resource/merge_request_from_fork.rb index b0367df64ed..4eebbdf0a52 100644 --- a/qa/qa/resource/merge_request_from_fork.rb +++ b/qa/qa/resource/merge_request_from_fork.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class MergeRequestFromFork < MergeRequest diff --git a/qa/qa/resource/package.rb b/qa/qa/resource/package.rb index 0e8c3ee95de..b3decb1e2ab 100644 --- a/qa/qa/resource/package.rb +++ b/qa/qa/resource/package.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class Package < Base diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb index 53b8a9b0246..5ad55090f8c 100644 --- a/qa/qa/resource/project.rb +++ b/qa/qa/resource/project.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class Project < Base diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb index 8aa19555d50..cffeed7a64b 100644 --- a/qa/qa/resource/project_imported_from_github.rb +++ b/qa/qa/resource/project_imported_from_github.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'octokit' - module QA module Resource class ProjectImportedFromGithub < Resource::Project @@ -68,7 +66,7 @@ module QA response = post(request_url(api_trigger_mirror_pull_path), nil) Runtime::Logger.info "Mirror pull request response: #{response}" - response.code == Support::Api::HTTP_STATUS_OK + response.code == Support::API::HTTP_STATUS_OK end end diff --git a/qa/qa/resource/project_imported_from_url.rb b/qa/qa/resource/project_imported_from_url.rb index f159a174840..9880504d886 100644 --- a/qa/qa/resource/project_imported_from_url.rb +++ b/qa/qa/resource/project_imported_from_url.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class ProjectImportedFromURL < Resource::Project diff --git a/qa/qa/resource/project_issue_note.rb b/qa/qa/resource/project_issue_note.rb index 0eb34380332..a68c68c660a 100644 --- a/qa/qa/resource/project_issue_note.rb +++ b/qa/qa/resource/project_issue_note.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class ProjectIssueNote < Base diff --git a/qa/qa/resource/protected_branch.rb b/qa/qa/resource/protected_branch.rb index 7eb5442a964..7db6450acf8 100644 --- a/qa/qa/resource/protected_branch.rb +++ b/qa/qa/resource/protected_branch.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class ProtectedBranch < Base diff --git a/qa/qa/resource/registry_repository.rb b/qa/qa/resource/registry_repository.rb index 3de409232dd..148af353a25 100644 --- a/qa/qa/resource/registry_repository.rb +++ b/qa/qa/resource/registry_repository.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class RegistryRepository < Base diff --git a/qa/qa/resource/repository/project_push.rb b/qa/qa/resource/repository/project_push.rb index ef4873e9483..d0e94951f3b 100644 --- a/qa/qa/resource/repository/project_push.rb +++ b/qa/qa/resource/repository/project_push.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource module Repository diff --git a/qa/qa/resource/repository/push.rb b/qa/qa/resource/repository/push.rb index f5b6040d927..00bed7ed546 100644 --- a/qa/qa/resource/repository/push.rb +++ b/qa/qa/resource/repository/push.rb @@ -1,8 +1,5 @@ # frozen_string_literal: true -require 'pathname' -require 'securerandom' - module QA module Resource module Repository diff --git a/qa/qa/resource/runner.rb b/qa/qa/resource/runner.rb index 2a0823d648e..3c448816100 100644 --- a/qa/qa/resource/runner.rb +++ b/qa/qa/resource/runner.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class Runner < Base diff --git a/qa/qa/resource/ssh_key.rb b/qa/qa/resource/ssh_key.rb index 52526275cb0..9e178a425dd 100644 --- a/qa/qa/resource/ssh_key.rb +++ b/qa/qa/resource/ssh_key.rb @@ -72,7 +72,7 @@ module QA Support::Retrier.retry_until(max_duration: QA::EE::Runtime::Geo.max_db_replication_time, sleep_interval: 3) do response = get Runtime::API::Request.new(api_client, api_get_path).url - response.code == QA::Support::Api::HTTP_STATUS_OK && + response.code == QA::Support::API::HTTP_STATUS_OK && parse_body(response)[:title].include?(title) end end diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb index a978b8c017d..01de1a73422 100644 --- a/qa/qa/resource/user.rb +++ b/qa/qa/resource/user.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource class User < Base diff --git a/qa/qa/resource/wiki/group_page.rb b/qa/qa/resource/wiki/group_page.rb index 83beaf097ca..1e40426a389 100644 --- a/qa/qa/resource/wiki/group_page.rb +++ b/qa/qa/resource/wiki/group_page.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Resource module Wiki diff --git a/qa/qa/runtime/allure_report.rb b/qa/qa/runtime/allure_report.rb index bf49141566a..8ad2562301c 100644 --- a/qa/qa/runtime/allure_report.rb +++ b/qa/qa/runtime/allure_report.rb @@ -12,8 +12,6 @@ module QA def configure! return unless Env.generate_allure_report? - require 'allure-rspec' - configure_allure configure_attachments configure_rspec diff --git a/qa/qa/runtime/api/repository_storage_moves.rb b/qa/qa/runtime/api/repository_storage_moves.rb index d1d44bd1ab5..c3b2095be32 100644 --- a/qa/qa/runtime/api/repository_storage_moves.rb +++ b/qa/qa/runtime/api/repository_storage_moves.rb @@ -5,7 +5,7 @@ module QA module API module RepositoryStorageMoves extend self - extend Support::Api + extend Support::API RepositoryStorageMovesError = Class.new(RuntimeError) diff --git a/qa/qa/runtime/application_settings.rb b/qa/qa/runtime/application_settings.rb index 0b2aef47576..55a5ae9d06c 100644 --- a/qa/qa/runtime/application_settings.rb +++ b/qa/qa/runtime/application_settings.rb @@ -4,7 +4,7 @@ module QA module Runtime class ApplicationSettings class << self - include Support::Api + include Support::API APPLICATION_SETTINGS_PATH = '/application/settings' @@ -18,7 +18,7 @@ module QA QA::Runtime::Logger.info("Setting application settings: #{application_settings}") r = put(Runtime::API::Request.new(api_client, APPLICATION_SETTINGS_PATH).url, **application_settings) - raise "Couldn't set application settings #{application_settings.inspect}" unless r.code == QA::Support::Api::HTTP_STATUS_OK + raise "Couldn't set application settings #{application_settings.inspect}" unless r.code == QA::Support::API::HTTP_STATUS_OK end def get_application_settings diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 9097690de57..370c05edb86 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -4,7 +4,6 @@ require 'rspec/core' require 'rspec/expectations' require 'capybara/rspec' require 'capybara-screenshot/rspec' -require 'selenium-webdriver' require 'webdrivers/chromedriver' require 'webdrivers/geckodriver' diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index a076d8db9e0..16c8c4aff3e 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'active_support/deprecation' -require 'gitlab/qa' require 'uri' module QA diff --git a/qa/qa/runtime/feature.rb b/qa/qa/runtime/feature.rb index 7011f46542b..58408524f54 100644 --- a/qa/qa/runtime/feature.rb +++ b/qa/qa/runtime/feature.rb @@ -8,7 +8,7 @@ module QA class << self # Documentation: https://docs.gitlab.com/ee/api/features.html - include Support::Api + include Support::API SetFeatureError = Class.new(RuntimeError) AuthorizationError = Class.new(RuntimeError) @@ -17,7 +17,7 @@ module QA def remove(key) request = Runtime::API::Request.new(api_client, "/features/#{key}") response = delete(request.url) - unless response.code == QA::Support::Api::HTTP_STATUS_NO_CONTENT + unless response.code == QA::Support::API::HTTP_STATUS_NO_CONTENT raise SetFeatureError, "Deleting feature flag #{key} failed with `#{response}`." end end @@ -100,7 +100,7 @@ module QA scopes[:user] = scopes[:user].username if scopes.key?(:user) request = Runtime::API::Request.new(api_client, "/features/#{key}") response = post(request.url, scopes.merge({ value: value })) - unless response.code == QA::Support::Api::HTTP_STATUS_CREATED + unless response.code == QA::Support::API::HTTP_STATUS_CREATED raise SetFeatureError, "Setting feature flag #{key} to #{value} failed with `#{response}`." end end diff --git a/qa/qa/runtime/fixtures.rb b/qa/qa/runtime/fixtures.rb index ed051b18a9a..05dee4bfce5 100644 --- a/qa/qa/runtime/fixtures.rb +++ b/qa/qa/runtime/fixtures.rb @@ -5,7 +5,7 @@ require 'tmpdir' module QA module Runtime module Fixtures - include Support::Api + include Support::API TemplateNotFoundError = Class.new(RuntimeError) diff --git a/qa/qa/runtime/ip_address.rb b/qa/qa/runtime/ip_address.rb index f370882e5c7..bec5c412a6a 100644 --- a/qa/qa/runtime/ip_address.rb +++ b/qa/qa/runtime/ip_address.rb @@ -4,7 +4,7 @@ require 'socket' module QA module Runtime module IPAddress - include Support::Api + include Support::API HostUnreachableError = Class.new(StandardError) LOOPBACK_ADDRESS = '127.0.0.1' @@ -15,7 +15,7 @@ module QA # we use the public facing IP address ip_address = if Env.running_in_ci? && !URI.parse(Scenario.gitlab_address).host.include?('test') response = get(PUBLIC_IP_ADDRESS_API) - raise HostUnreachableError, "#{PUBLIC_IP_ADDRESS_API} is unreachable" unless response.code == Support::Api::HTTP_STATUS_OK + raise HostUnreachableError, "#{PUBLIC_IP_ADDRESS_API} is unreachable" unless response.code == Support::API::HTTP_STATUS_OK response.body elsif page.current_host.include?('localhost') diff --git a/qa/qa/runtime/release.rb b/qa/qa/runtime/release.rb index 029c8fc037e..c0a090ef552 100644 --- a/qa/qa/runtime/release.rb +++ b/qa/qa/runtime/release.rb @@ -13,10 +13,6 @@ module QA # CE to EE. # class Release - def initialize - require "qa/#{version.downcase}/strategy" - end - def version @version ||= ::File.directory?("#{__dir__}/../ee") ? :EE : :CE end diff --git a/qa/qa/runtime/search.rb b/qa/qa/runtime/search.rb index 2a5db97cdad..a0ad84285be 100644 --- a/qa/qa/runtime/search.rb +++ b/qa/qa/runtime/search.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true -require 'securerandom' - module QA module Runtime module Search extend self - extend Support::Api + extend Support::API RETRY_MAX_ITERATION = 10 RETRY_SLEEP_INTERVAL = 12 diff --git a/qa/qa/service/docker_run/gitlab_runner.rb b/qa/qa/service/docker_run/gitlab_runner.rb index 63fbf758231..595d47bf162 100644 --- a/qa/qa/service/docker_run/gitlab_runner.rb +++ b/qa/qa/service/docker_run/gitlab_runner.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'resolv' -require 'securerandom' module QA module Service diff --git a/qa/qa/service/kubernetes_cluster.rb b/qa/qa/service/kubernetes_cluster.rb index adef1b46af2..674bcdca9bb 100644 --- a/qa/qa/service/kubernetes_cluster.rb +++ b/qa/qa/service/kubernetes_cluster.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true -require 'securerandom' require 'mkmf' -require 'pathname' module QA module Service diff --git a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb index 69222a23275..e3c7af94381 100644 --- a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'octokit' - # rubocop:disable Rails/Pluck module QA # Only executes in custom job/pipeline diff --git a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb index 8b8c9b4c8b1..32984021915 100644 --- a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb +++ b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb @@ -4,7 +4,7 @@ require 'airborne' module QA RSpec.describe 'Plan' do - include Support::Api + include Support::API describe 'Issue' do let(:issue) do diff --git a/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb b/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb index f86bbee05c2..6ca7cc0916d 100644 --- a/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA RSpec.describe 'Create' do describe 'Default branch name instance setting', :requires_admin, :skip_live_env do diff --git a/qa/qa/specs/features/api/3_create/repository/files_spec.rb b/qa/qa/specs/features/api/3_create/repository/files_spec.rb index 1099234537a..532cf305c14 100644 --- a/qa/qa/specs/features/api/3_create/repository/files_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/files_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'airborne' -require 'securerandom' module QA RSpec.describe 'API basics' do diff --git a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb index c65d981d99a..3ba0574e618 100644 --- a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb +++ b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true require 'airborne' -require 'securerandom' require 'digest' module QA RSpec.describe 'Create' do describe 'Compare archives of different user projects with the same name and check they\'re different' do - include Support::Api + include Support::API let(:project_name) { "project-archive-download-#{SecureRandom.hex(8)}" } let(:archive_types) { %w(tar.gz tar.bz2 tar zip) } diff --git a/qa/qa/specs/features/api/5_package/container_registry_spec.rb b/qa/qa/specs/features/api/5_package/container_registry_spec.rb index f79a3ebbe03..7049d648238 100644 --- a/qa/qa/specs/features/api/5_package/container_registry_spec.rb +++ b/qa/qa/specs/features/api/5_package/container_registry_spec.rb @@ -4,7 +4,7 @@ require 'airborne' module QA RSpec.describe 'Package', only: { subdomain: %i[staging pre] } do - include Support::Api + include Support::API describe 'Container Registry' do let(:api_client) { Runtime::API::Client.new(:gitlab) } diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb index 6cd486bc84b..ceca7844477 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb @@ -3,12 +3,15 @@ module QA RSpec.describe 'Manage', :orchestrated, :instance_saml do describe 'Instance wide SAML SSO' do - it 'user logs in to gitlab with SAML SSO', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/671' do + it( + 'user logs in to gitlab with SAML SSO', + testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/671' + ) do Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.perform(&:sign_in_with_saml) - Vendor::SAMLIdp::Page::Login.perform do |login_page| + Vendor::SamlIdp::Page::Login.perform do |login_page| login_page.login('user1', 'user1pass') end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb index 6e0ed4adb63..20d222c7e92 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/dashboard_images_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'nokogiri' - module QA RSpec.describe 'Manage', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/212145', type: :stale } do describe 'Check for broken images', :requires_admin do diff --git a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb index d561e5d113c..74e1f8e1966 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb @@ -3,7 +3,7 @@ module QA RSpec.describe 'Plan', :orchestrated, :smtp, :requires_admin do describe 'Email Notification' do - include Support::Api + include Support::API let!(:user) do Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb index a23474ad6f2..1cedf3e2170 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA RSpec.describe 'Plan', :reliable do describe 'Issues list' do diff --git a/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb b/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb index 734ff160937..ed86cc5d19b 100644 --- a/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -require 'securerandom' module QA RSpec.describe 'Create', :requires_admin, :skip_live_env, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/195179', type: :flaky } do diff --git a/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb b/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb index 449795f9707..6395ecf2251 100644 --- a/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/jira/jira_basic_integration_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - include Support::Api + include Support::API describe 'Jira integration', :jira, :orchestrated, :requires_admin do let(:jira_project_key) { 'JITP' } diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb index c02632c2c60..3da73c8fa72 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA RSpec.describe 'Create' do describe 'File templates' do diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb index 1423e3c45ce..7de07c59169 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb @@ -9,7 +9,7 @@ module QA # tests are run in parallel). # See: https://gitlab.com/gitlab-org/gitlab/-/issues/218620#note_361634705 - include Support::Api + include Support::API before(:context) do @project = Resource::Project.fabricate_via_api! do |p| diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb index 1e3cb0e2ffc..70c9c9beeb8 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA RSpec.describe 'Create' do describe 'Web IDE file templates' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb index 4938ae3f969..0c140297ea4 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'faker' - module QA RSpec.describe 'Verify', :runner do describe 'Pipeline with protected variable' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb index c2ea568dbad..c4577ca6027 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'faker' - module QA RSpec.describe 'Verify', :runner do describe 'Include multiple files from a project' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb index b43581289ef..f0e8705d664 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'faker' - module QA RSpec.describe 'Verify', :runner do context 'When pipeline is blocked' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb index 47b36b55c8c..53a10dab9fc 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'faker' - module QA RSpec.describe 'Verify', :runner do context 'When job is configured to only run on merge_request_events' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb index adacedb36ab..ded418ac85b 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'faker' - module QA RSpec.describe 'Verify', :runner do describe 'Pass dotenv variables to downstream via bridge' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb index c89cda73711..2eaf58113b5 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'faker' - module QA RSpec.describe 'Verify', :runner do describe "Trigger child pipeline with 'when:manual'" do diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb index d87fa0f5127..930d5a4ff54 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'faker' - module QA RSpec.describe 'Verify', :runner do describe 'Trigger matrix' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb index 916b809ebc1..1fb373ebbec 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb @@ -21,7 +21,7 @@ module QA runner.project.visit! Page::Project::Menu.perform(&:go_to_ci_cd_settings) - Page::Project::Settings::CICD.perform do |settings| + Page::Project::Settings::CiCd.perform do |settings| sleep 5 # Runner should register within 5 seconds settings.expand_runners_settings do |page| diff --git a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb index 7d3f8f2b1d4..f0cc234d159 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb @@ -49,7 +49,7 @@ module QA def configure_code_coverage(coverage_tool_pattern) Page::Project::Menu.perform(&:go_to_ci_cd_settings) - Page::Project::Settings::CICD.perform do |settings| + Page::Project::Settings::CiCd.perform do |settings| settings.expand_general_pipelines do |coverage| coverage.configure_coverage_regex(coverage_tool_pattern) end diff --git a/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb index 61c71b062ae..2e1b22bad1e 100644 --- a/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/composer_registry_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA RSpec.describe 'Package', :orchestrated, :packages, :object_storage do describe 'Composer Repository' do diff --git a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb index fb92616ffc5..092caacf1c8 100644 --- a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA RSpec.describe 'Package', :orchestrated, :packages, :reliable, :object_storage do describe 'Maven Repository' do diff --git a/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb index 1f62b285798..f6955d6f089 100644 --- a/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/nuget_repository_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' - module QA RSpec.describe 'Package', :orchestrated, :packages, :object_storage do describe 'NuGet Repository' do diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index 1dcc02095f6..6cb1f8be88f 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'pathname' - module QA RSpec.describe 'Configure' do let(:project) do @@ -102,7 +100,7 @@ module QA project.visit! Page::Project::Menu.perform(&:go_to_ci_cd_settings) - Page::Project::Settings::CICD.perform(&:expand_auto_devops) + Page::Project::Settings::CiCd.perform(&:expand_auto_devops) Page::Project::Settings::AutoDevops.perform(&:enable_autodevops) # Create AutoDevOps repo diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb index bd9907611c7..d7d64834e7a 100644 --- a/qa/qa/specs/runner.rb +++ b/qa/qa/specs/runner.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'knapsack' require 'rspec/core' require 'rspec/expectations' diff --git a/qa/qa/support/api.rb b/qa/qa/support/api.rb index 579227b4f7a..205ddf7ad3a 100644 --- a/qa/qa/support/api.rb +++ b/qa/qa/support/api.rb @@ -1,10 +1,8 @@ # frozen_string_literal: true -require 'rest-client' - module QA module Support - module Api + module API HTTP_STATUS_OK = 200 HTTP_STATUS_CREATED = 201 HTTP_STATUS_NO_CONTENT = 204 diff --git a/qa/qa/support/helpers/stub_env.rb b/qa/qa/support/helpers/stub_env.rb new file mode 100644 index 00000000000..d6514788c24 --- /dev/null +++ b/qa/qa/support/helpers/stub_env.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb +module QA + module Support + module Helpers + module StubEnv + def stub_env(key_or_hash, value = nil) + init_stub unless env_stubbed? + + if key_or_hash.is_a? Hash + key_or_hash.each { |k, v| add_stubbed_value(k, v) } + else + add_stubbed_value key_or_hash, value + end + end + + private + + STUBBED_KEY = '__STUBBED__' + + def add_stubbed_value(key, value) + allow(ENV).to receive(:[]).with(key).and_return(value) + allow(ENV).to receive(:key?).with(key).and_return(true) + allow(ENV).to receive(:fetch).with(key).and_return(value) + allow(ENV).to receive(:fetch).with(key, anything) do |_, default_val| + value || default_val + end + end + + def env_stubbed? + ENV[STUBBED_KEY] + end + + def init_stub + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:key?).and_call_original + allow(ENV).to receive(:fetch).and_call_original + # Prevent secrets from leaking in CI + allow(ENV).to receive(:inspect).and_return([]) + add_stubbed_value(STUBBED_KEY, true) + end + end + end + end +end diff --git a/qa/qa/support/matchers/eventually_matcher.rb b/qa/qa/support/matchers/eventually_matcher.rb new file mode 100644 index 00000000000..d380dfeb5bf --- /dev/null +++ b/qa/qa/support/matchers/eventually_matcher.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +# Rspec matcher with build in retry logic +# +# USAGE: +# +# Basic +# expect { Something.that.takes.time.to_appear }.to eventually_eq(expected_result) +# expect { Something.that.takes.time.to_appear }.not_to eventually_eq(expected_result) +# +# With duration and attempts override +# expect { Something.that.takes.time.to_appear }.to( +# eventually_eq(expected_result).within(max_duration: 10, max_attempts: 5) +# ) + +module QA + module Support + module Matchers + module EventuallyMatcher + %w[ + eq + be + include + be_truthy + be_falsey + be_empty + ].each do |op| + RSpec::Matchers.define(:"eventually_#{op}") do |*expected| + chain(:within) do |kwargs = {}| + @retry_args = kwargs + @retry_args[:sleep_interval] = 0.5 unless @retry_args[:sleep_interval] + end + + def supports_block_expectations? + true + end + + match { |actual| wait_and_check(actual, :default_expectation) } + + match_when_negated { |actual| wait_and_check(actual, :when_negated_expectation) } + + description do + "eventually #{operator_msg} #{expected.inspect}" + end + + failure_message do + "#{e}:\nexpected to #{description}, last attempt was #{@result.nil? ? 'nil' : @result}" + end + + failure_message_when_negated do + "#{e}:\nexpected not to #{description}, last attempt was #{@result.nil? ? 'nil' : @result}" + end + + # Execute rspec expectation within retrier + # + # @param [Proc] actual + # @param [Symbol] expectation_name + # @return [Boolean] + def wait_and_check(actual, expectation_name) + attempt = 0 + + QA::Runtime::Logger.debug("Running eventually matcher with '#{operator_msg}' operator") + QA::Support::Retrier.retry_until(**@retry_args) do + QA::Runtime::Logger.debug("evaluating expectation, attempt: #{attempt += 1}") + + public_send(expectation_name, actual) + rescue RSpec::Expectations::ExpectationNotMetError, QA::Resource::ApiFabricator::ResourceNotFoundError + false + end + rescue QA::Support::Repeater::RetriesExceededError, QA::Support::Repeater::WaitExceededError => e + @e = e + false + end + + # Execute rspec expectation + # + # @param [Proc] actual + # @return [void] + def default_expectation(actual) + expect(result(&actual)).to public_send(*expectation_args) + end + + # Execute negated rspec expectation + # + # @param [Proc] actual + # @return [void] + def when_negated_expectation(actual) + expect(result(&actual)).not_to public_send(*expectation_args) + end + + # Result of actual block + # + # @return [Object] + def result + @result = yield + end + + # Error message placeholder to indicate waiter did not fail properly + # This message should not appear under normal circumstances since it should + # always be assigned from repeater + # + # @return [String] + def e + @e ||= 'Waiter did not fail!' + end + + # Operator message + # + # @return [String] + def operator_msg + case operator + when 'eq' then 'equal' + else operator + end + end + + # Expect operator + # + # @return [String] + def operator + @operator ||= name.to_s.match(/eventually_(.+?)$/).to_a[1].to_s + end + + # Expectation args + # + # @return [String, Array] + def expectation_args + if operator.include?('truthy') || operator.include?('falsey') || operator.include?('empty') + operator + elsif operator == "include" && expected.is_a?(Array) + [operator, *expected] + else + [operator, expected] + end + end + end + end + end + end + end +end diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb new file mode 100644 index 00000000000..7001f53a7b7 --- /dev/null +++ b/qa/qa/support/matchers/have_matcher.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module QA + module Support + module Matchers + module HaveMatcher + PREDICATE_TARGETS = %w[ + element + file_content + assignee + child_pipeline + content + design + file + issue + job + package + pipeline + related_issue_item + snippet_description + tag + ].each do |predicate| + RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs| + match do |page_object| + page_object.public_send("has_#{predicate}?", *args, **kwargs) + end + + match_when_negated do |page_object| + page_object.public_send("has_no_#{predicate}?", *args, **kwargs) + end + end + end + end + end + end +end diff --git a/qa/qa/support/matchers/have_text.rb b/qa/qa/support/matchers/have_text.rb new file mode 100644 index 00000000000..2bae2971be3 --- /dev/null +++ b/qa/qa/support/matchers/have_text.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module QA + module Support + module Matchers + class HaveText + def initialize(expected_text, **kwargs) + @expected_text = expected_text + @kwargs = kwargs + end + + def matches?(actual) + @actual = wrap(actual) + @actual.has_text?(@expected_text, **@kwargs) + end + + def does_not_match?(actual) + @actual = wrap(actual) + @actual.has_no_text?(@expected_text, **@kwargs) + end + + def failure_message + "expected to find text \"#{@expected_text}\" in \"#{normalized_actual_text}\"" + end + + def failure_message_when_negated + "expected not to find text \"#{@expected_text}\" in \"#{normalized_actual_text}\"" + end + + def normalized_actual_text + @actual.text.gsub(/\s+/, " ") + end + + # From https://github.com/teamcapybara/capybara/blob/fe5940c6afbfe32152df936ce03ad1371ae05354/lib/capybara/rspec/matchers/base.rb#L66 + def wrap(actual) + actual = actual.to_capybara_node if actual.respond_to?(:to_capybara_node) + @context_el = if actual.respond_to?(:has_selector?) + actual + else + Capybara.string(actual.to_s) + end + end + end + + def have_text(text, **kwargs) # rubocop:disable Naming/PredicateName + HaveText.new(text, **kwargs) + end + + alias_method :have_content, :have_text + end + end +end diff --git a/qa/qa/tools/delete_projects.rb b/qa/qa/tools/delete_projects.rb index 8a690373a37..240901eea6f 100644 --- a/qa/qa/tools/delete_projects.rb +++ b/qa/qa/tools/delete_projects.rb @@ -10,7 +10,7 @@ require_relative '../../qa' module QA module Tools class DeleteProjects - include Support::Api + include Support::API def initialize raise ArgumentError, "Please provide GITLAB_ADDRESS environment variable" unless ENV['GITLAB_ADDRESS'] diff --git a/qa/qa/tools/delete_subgroups.rb b/qa/qa/tools/delete_subgroups.rb index b9e3ed66013..2734a702536 100644 --- a/qa/qa/tools/delete_subgroups.rb +++ b/qa/qa/tools/delete_subgroups.rb @@ -10,7 +10,7 @@ require_relative '../../qa' module QA module Tools class DeleteSubgroups - include Support::Api + include Support::API def initialize raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS'] diff --git a/qa/qa/tools/delete_test_ssh_keys.rb b/qa/qa/tools/delete_test_ssh_keys.rb index dea6930de1e..58ab4865336 100644 --- a/qa/qa/tools/delete_test_ssh_keys.rb +++ b/qa/qa/tools/delete_test_ssh_keys.rb @@ -15,7 +15,7 @@ require_relative '../../qa' module QA module Tools class DeleteTestSSHKeys - include Support::Api + include Support::API ITEMS_PER_PAGE = '100' diff --git a/qa/qa/tools/generate_perf_testdata.rb b/qa/qa/tools/generate_perf_testdata.rb index ec1aa20c3b8..8e5da94e7e6 100644 --- a/qa/qa/tools/generate_perf_testdata.rb +++ b/qa/qa/tools/generate_perf_testdata.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'securerandom' -require 'faker' require 'yaml' require_relative '../../qa' # This script generates testdata for Performance Testing. @@ -12,7 +10,7 @@ require_relative '../../qa' module QA module Tools class GeneratePerfTestdata - include Support::Api + include Support::API def initialize raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS'] diff --git a/qa/qa/vendor/jira/jira_api.rb b/qa/qa/vendor/jira/jira_api.rb index 65b080df3d0..64af824418d 100644 --- a/qa/qa/vendor/jira/jira_api.rb +++ b/qa/qa/vendor/jira/jira_api.rb @@ -5,7 +5,7 @@ module QA module Jira class JiraAPI include Scenario::Actable - include Support::Api + include Support::API def base_url host = QA::Runtime::Env.jira_hostname || 'localhost' diff --git a/qa/qa/vendor/saml_idp/page/base.rb b/qa/qa/vendor/saml_idp/page/base.rb index 286cb0a8cd8..39413a64d5a 100644 --- a/qa/qa/vendor/saml_idp/page/base.rb +++ b/qa/qa/vendor/saml_idp/page/base.rb @@ -2,7 +2,7 @@ module QA module Vendor - module SAMLIdp + module SamlIdp module Page class Base include Capybara::DSL diff --git a/qa/qa/vendor/saml_idp/page/login.rb b/qa/qa/vendor/saml_idp/page/login.rb index 041b4a0feee..dc6925109f7 100644 --- a/qa/qa/vendor/saml_idp/page/login.rb +++ b/qa/qa/vendor/saml_idp/page/login.rb @@ -4,7 +4,7 @@ require 'capybara/dsl' module QA module Vendor - module SAMLIdp + module SamlIdp module Page class Login < Page::Base def login(username, password) diff --git a/qa/spec/git/repository_spec.rb b/qa/spec/git/repository_spec.rb index 77639c54b79..6b100f9dc16 100644 --- a/qa/spec/git/repository_spec.rb +++ b/qa/spec/git/repository_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe QA::Git::Repository do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv shared_context 'unresolvable git directory' do let(:repo_uri) { 'http://foo/bar.git' } diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb index 3e1011dcd2a..7c521f60b84 100644 --- a/qa/spec/page/logging_spec.rb +++ b/qa/spec/page/logging_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'capybara/dsl' -require 'logger' RSpec.describe QA::Support::Page::Logging do let(:page) { double.as_null_object } diff --git a/qa/spec/resource/base_spec.rb b/qa/spec/resource/base_spec.rb index c6dd56b5f47..b24ced9e310 100644 --- a/qa/spec/resource/base_spec.rb +++ b/qa/spec/resource/base_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe QA::Resource::Base do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv let(:resource) { spy('resource') } let(:location) { 'http://location' } diff --git a/qa/spec/runtime/api/client_spec.rb b/qa/spec/runtime/api/client_spec.rb index 36ee563de39..c8439df3b35 100644 --- a/qa/spec/runtime/api/client_spec.rb +++ b/qa/spec/runtime/api/client_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe QA::Runtime::API::Client do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv describe 'initialization' do it 'defaults to :gitlab address' do diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb index 1d702b70d10..fb18311bb52 100644 --- a/qa/spec/runtime/env_spec.rb +++ b/qa/spec/runtime/env_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe QA::Runtime::Env do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv shared_examples 'boolean method' do |**kwargs| it_behaves_like 'boolean method with parameter', kwargs diff --git a/qa/spec/runtime/namespace_spec.rb b/qa/spec/runtime/namespace_spec.rb index 92836862864..04d4769b07b 100644 --- a/qa/spec/runtime/namespace_spec.rb +++ b/qa/spec/runtime/namespace_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe QA::Runtime::Namespace do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv describe '.name' do context 'when CACHE_NAMESPACE_NAME is not defined' do diff --git a/qa/spec/runtime/release_spec.rb b/qa/spec/runtime/release_spec.rb index b4e278fb546..29871cbe301 100644 --- a/qa/spec/runtime/release_spec.rb +++ b/qa/spec/runtime/release_spec.rb @@ -30,23 +30,4 @@ RSpec.describe QA::Runtime::Release do end end end - - context 'when release version does not have extension strategy' do - before do - allow_any_instance_of(described_class) - .to receive(:version).and_return('something') - end - - describe '#strategy' do - it 'raises error' do - expect { subject.strategy }.to raise_error(LoadError) - end - end - - describe 'delegated class methods' do - it 'raises error' do - expect { described_class.some_method(2, 3) }.to raise_error(LoadError) - end - end - end end diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb index 0df7b94b894..6bc889ebc49 100644 --- a/qa/spec/spec_helper.rb +++ b/qa/spec/spec_helper.rb @@ -1,18 +1,16 @@ # frozen_string_literal: true require_relative '../qa' -require 'rspec/retry' -require 'rspec-parameterized' + +require 'securerandom' +require 'pathname' require 'active_support/core_ext/hash' require 'active_support/core_ext/object/blank' require_relative 'qa_deprecation_toolkit_env' QaDeprecationToolkitEnv.configure! -if ENV['CI'] && QA::Runtime::Env.knapsack? && !ENV['NO_KNAPSACK'] - require 'knapsack' - Knapsack::Adapters::RSpecAdapter.bind -end +Knapsack::Adapters::RSpecAdapter.bind if ENV['CI'] && QA::Runtime::Env.knapsack? && !ENV['NO_KNAPSACK'] QA::Runtime::Browser.configure! QA::Runtime::AllureReport.configure! @@ -24,7 +22,8 @@ Dir[::File.join(__dir__, "support/shared_contexts/*.rb")].sort.each { |f| requir Dir[::File.join(__dir__, "support/shared_examples/*.rb")].sort.each { |f| require f } RSpec.configure do |config| - config.include ::Matchers + config.include QA::Support::Matchers::EventuallyMatcher + config.include QA::Support::Matchers::HaveMatcher config.add_formatter QA::Specs::Helpers::ContextFormatter config.add_formatter QA::Specs::Helpers::QuarantineFormatter diff --git a/qa/spec/specs/allure_report_spec.rb b/qa/spec/specs/allure_report_spec.rb index 27bc0dd3d1d..d17fb8e41d0 100644 --- a/qa/spec/specs/allure_report_spec.rb +++ b/qa/spec/specs/allure_report_spec.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true -require 'allure-rspec' - describe QA::Runtime::AllureReport do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv let(:rspec_config) { double('RSpec::Core::Configuration', 'add_formatter': nil, after: nil) } diff --git a/qa/spec/specs/helpers/context_selector_spec.rb b/qa/spec/specs/helpers/context_selector_spec.rb index cbdbe6698ae..1492008972d 100644 --- a/qa/spec/specs/helpers/context_selector_spec.rb +++ b/qa/spec/specs/helpers/context_selector_spec.rb @@ -3,7 +3,7 @@ require 'rspec/core/sandbox' RSpec.describe QA::Specs::Helpers::ContextSelector do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv include QA::Specs::Helpers::RSpec around do |ex| diff --git a/qa/spec/specs/helpers/quarantine_spec.rb b/qa/spec/specs/helpers/quarantine_spec.rb index 548a8510988..f064aa0b9af 100644 --- a/qa/spec/specs/helpers/quarantine_spec.rb +++ b/qa/spec/specs/helpers/quarantine_spec.rb @@ -3,7 +3,7 @@ require 'rspec/core/sandbox' RSpec.describe QA::Specs::Helpers::Quarantine do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv include QA::Specs::Helpers::RSpec around do |ex| diff --git a/qa/spec/specs/parallel_runner_spec.rb b/qa/spec/specs/parallel_runner_spec.rb index c2d28bf81fb..d77b50fbe09 100644 --- a/qa/spec/specs/parallel_runner_spec.rb +++ b/qa/spec/specs/parallel_runner_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe QA::Specs::ParallelRunner do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv before do allow(QA::Runtime::Scenario).to receive(:attributes).and_return(parallel: true) diff --git a/qa/spec/support/allure_metadata_formatter_spec.rb b/qa/spec/support/allure_metadata_formatter_spec.rb index cb208642716..52a40eff771 100644 --- a/qa/spec/support/allure_metadata_formatter_spec.rb +++ b/qa/spec/support/allure_metadata_formatter_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true describe QA::Support::AllureMetadataFormatter do - include Helpers::StubENV + include QA::Support::Helpers::StubEnv let(:formatter) { described_class.new(StringIO.new) } diff --git a/qa/spec/support/helpers/stub_env.rb b/qa/spec/support/helpers/stub_env.rb deleted file mode 100644 index de8d2f47adf..00000000000 --- a/qa/spec/support/helpers/stub_env.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb -module Helpers - module StubENV - def stub_env(key_or_hash, value = nil) - init_stub unless env_stubbed? - - if key_or_hash.is_a? Hash - key_or_hash.each { |k, v| add_stubbed_value(k, v) } - else - add_stubbed_value key_or_hash, value - end - end - - private - - STUBBED_KEY = '__STUBBED__' - - def add_stubbed_value(key, value) - allow(ENV).to receive(:[]).with(key).and_return(value) - allow(ENV).to receive(:key?).with(key).and_return(true) - allow(ENV).to receive(:fetch).with(key).and_return(value) - allow(ENV).to receive(:fetch).with(key, anything) do |_, default_val| - value || default_val - end - end - - def env_stubbed? - ENV[STUBBED_KEY] - end - - def init_stub - allow(ENV).to receive(:[]).and_call_original - allow(ENV).to receive(:key?).and_call_original - allow(ENV).to receive(:fetch).and_call_original - # Prevent secrets from leaking in CI - allow(ENV).to receive(:inspect).and_return([]) - add_stubbed_value(STUBBED_KEY, true) - end - end -end diff --git a/qa/spec/support/matchers/eventually_matcher.rb b/qa/spec/support/matchers/eventually_matcher.rb deleted file mode 100644 index 7a35a3165ae..00000000000 --- a/qa/spec/support/matchers/eventually_matcher.rb +++ /dev/null @@ -1,133 +0,0 @@ -# frozen_string_literal: true - -# Rspec matcher with build in retry logic -# -# USAGE: -# -# Basic -# expect { Something.that.takes.time.to_appear }.to eventually_eq(expected_result) -# expect { Something.that.takes.time.to_appear }.not_to eventually_eq(expected_result) -# -# With duration and attempts override -# expect { Something.that.takes.time.to_appear }.to eventually_eq(expected_result).within(max_duration: 10, max_attempts: 5) - -module Matchers - %w[ - eq - be - include - be_truthy - be_falsey - be_empty - ].each do |op| - RSpec::Matchers.define(:"eventually_#{op}") do |*expected| - chain(:within) do |kwargs = {}| - @retry_args = kwargs - @retry_args[:sleep_interval] = 0.5 unless @retry_args[:sleep_interval] - end - - def supports_block_expectations? - true - end - - match { |actual| wait_and_check(actual, :default_expectation) } - - match_when_negated { |actual| wait_and_check(actual, :when_negated_expectation) } - - description do - "eventually #{operator_msg} #{expected.inspect}" - end - - failure_message do - "#{e}:\nexpected to #{description}, last attempt was #{@result.nil? ? 'nil' : @result}" - end - - failure_message_when_negated do - "#{e}:\nexpected not to #{description}, last attempt was #{@result.nil? ? 'nil' : @result}" - end - - # Execute rspec expectation within retrier - # - # @param [Proc] actual - # @param [Symbol] expectation_name - # @return [Boolean] - def wait_and_check(actual, expectation_name) - attempt = 0 - - QA::Runtime::Logger.debug("Running eventually matcher with '#{operator_msg}' operator") - QA::Support::Retrier.retry_until(**@retry_args) do - QA::Runtime::Logger.debug("evaluating expectation, attempt: #{attempt += 1}") - - public_send(expectation_name, actual) - rescue RSpec::Expectations::ExpectationNotMetError, QA::Resource::ApiFabricator::ResourceNotFoundError - false - end - rescue QA::Support::Repeater::RetriesExceededError, QA::Support::Repeater::WaitExceededError => e - @e = e - false - end - - # Execute rspec expectation - # - # @param [Proc] actual - # @return [void] - def default_expectation(actual) - expect(result(&actual)).to public_send(*expectation_args) - end - - # Execute negated rspec expectation - # - # @param [Proc] actual - # @return [void] - def when_negated_expectation(actual) - expect(result(&actual)).not_to public_send(*expectation_args) - end - - # Result of actual block - # - # @return [Object] - def result - @result = yield - end - - # Error message placeholder to indicate waiter did not fail properly - # This message should not appear under normal circumstances since it should - # always be assigned from repeater - # - # @return [String] - def e - @e ||= 'Waiter did not fail!' - end - - # Operator message - # - # @return [String] - def operator_msg - case operator - when 'eq' then 'equal' - else operator - end - end - - # Expect operator - # - # @return [String] - def operator - @operator ||= name.to_s.match(/eventually_(.+?)$/).to_a[1].to_s - end - - # Expectation args - # - # @return [String, Array] - def expectation_args - if operator.include?('truthy') || operator.include?('falsey') || operator.include?('empty') - operator - elsif operator == "include" && expected.is_a?(Array) - [operator, *expected] - else - [operator, expected] - end - end - end - end -end diff --git a/qa/spec/support/matchers/have_matcher.rb b/qa/spec/support/matchers/have_matcher.rb deleted file mode 100644 index 81288b97e6f..00000000000 --- a/qa/spec/support/matchers/have_matcher.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Matchers - PREDICATE_TARGETS = %w[ - element - file_content - assignee - child_pipeline - content - design - file - issue - job - package - pipeline - related_issue_item - snippet_description - tag - ].each do |predicate| - RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs| - match do |page_object| - page_object.public_send("has_#{predicate}?", *args, **kwargs) # rubocop:disable GitlabSecurity/PublicSend - end - - match_when_negated do |page_object| - page_object.public_send("has_no_#{predicate}?", *args, **kwargs) # rubocop:disable GitlabSecurity/PublicSend - end - end - end -end diff --git a/qa/spec/support/matchers/have_text.rb b/qa/spec/support/matchers/have_text.rb deleted file mode 100644 index 4e6fbf1f6d6..00000000000 --- a/qa/spec/support/matchers/have_text.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -module Matchers - class HaveText - def initialize(expected_text, **kwargs) - @expected_text = expected_text - @kwargs = kwargs - end - - def matches?(actual) - @actual = wrap(actual) - @actual.has_text?(@expected_text, **@kwargs) - end - - def does_not_match?(actual) - @actual = wrap(actual) - @actual.has_no_text?(@expected_text, **@kwargs) - end - - def failure_message - "expected to find text \"#{@expected_text}\" in \"#{normalized_actual_text}\"" - end - - def failure_message_when_negated - "expected not to find text \"#{@expected_text}\" in \"#{normalized_actual_text}\"" - end - - def normalized_actual_text - @actual.text.gsub(/\s+/, " ") - end - - # From https://github.com/teamcapybara/capybara/blob/fe5940c6afbfe32152df936ce03ad1371ae05354/lib/capybara/rspec/matchers/base.rb#L66 - def wrap(actual) - actual = actual.to_capybara_node if actual.respond_to?(:to_capybara_node) - @context_el = if actual.respond_to?(:has_selector?) - actual - else - Capybara.string(actual.to_s) - end - end - end - - def have_text(text, **kwargs) # rubocop:disable Naming/PredicateName - HaveText.new(text, **kwargs) - end - - alias_method :have_content, :have_text -end diff --git a/qa/spec/support/repeater_spec.rb b/qa/spec/support/repeater_spec.rb index 18ccbf250cb..da8d6b18fb0 100644 --- a/qa/spec/support/repeater_spec.rb +++ b/qa/spec/support/repeater_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'logger' -require 'timecop' require 'active_support/core_ext/integer/time' RSpec.describe QA::Support::Repeater do diff --git a/qa/spec/support/retrier_spec.rb b/qa/spec/support/retrier_spec.rb index 4e27915553c..9ad3e85fea9 100644 --- a/qa/spec/support/retrier_spec.rb +++ b/qa/spec/support/retrier_spec.rb @@ -1,8 +1,5 @@ # frozen_string_literal: true -require 'logger' -require 'timecop' - RSpec.describe QA::Support::Retrier do before do logger = ::Logger.new $stdout diff --git a/qa/spec/support/waiter_spec.rb b/qa/spec/support/waiter_spec.rb index 5b0c2c95d0d..d0b216b5dc1 100644 --- a/qa/spec/support/waiter_spec.rb +++ b/qa/spec/support/waiter_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'logger' - RSpec.describe QA::Support::Waiter do before do logger = ::Logger.new $stdout diff --git a/spec/deprecation_toolkit_env.rb b/spec/deprecation_toolkit_env.rb index f76cd5b396c..17d8e0955e7 100644 --- a/spec/deprecation_toolkit_env.rb +++ b/spec/deprecation_toolkit_env.rb @@ -56,8 +56,12 @@ module DeprecationToolkitEnv # In this case, we recommend to add a silence together with an issue to patch or update # the dependency causing the problem. # See https://gitlab.com/gitlab-org/gitlab/-/commit/aea37f506bbe036378998916d374966c031bf347#note_647515736 + # + # - ruby/lib/grpc/generic/interceptors.rb: https://gitlab.com/gitlab-org/gitlab/-/issues/339305 def self.allowed_kwarg_warning_paths - %w[] + %w[ + ruby/lib/grpc/generic/interceptors.rb + ] end def self.configure! diff --git a/spec/frontend/members/components/modals/leave_modal_spec.js b/spec/frontend/members/components/modals/leave_modal_spec.js index ea9eb7bf923..1dc913e5c78 100644 --- a/spec/frontend/members/components/modals/leave_modal_spec.js +++ b/spec/frontend/members/components/modals/leave_modal_spec.js @@ -99,10 +99,14 @@ describe('LeaveModal', () => { }); }); - it("does NOT display oncall schedules list when member's user is NOT a part of on-call schedules ", () => { + it("does NOT display oncall schedules list when member's user is NOT a part of on-call schedules ", async () => { + wrapper.destroy(); + const memberWithoutOncallSchedules = cloneDeep(member); - delete (memberWithoutOncallSchedules, 'user.oncallSchedules'); + delete memberWithoutOncallSchedules.user.oncallSchedules; createComponent({ member: memberWithoutOncallSchedules }); + await nextTick(); + expect(findOncallSchedulesList().exists()).toBe(false); }); }); diff --git a/spec/frontend/vue_shared/components/__snapshots__/memory_graph_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/memory_graph_spec.js.snap index f4f9cc288f9..87eaabf4e98 100644 --- a/spec/frontend/vue_shared/components/__snapshots__/memory_graph_spec.js.snap +++ b/spec/frontend/vue_shared/components/__snapshots__/memory_graph_spec.js.snap @@ -9,7 +9,6 @@ exports[`MemoryGraph Render chart should draw container with chart 1`] = ` data="Nov 12 2019 19:17:33,2.87,Nov 12 2019 19:18:33,2.78,Nov 12 2019 19:19:33,2.78,Nov 12 2019 19:20:33,3.01" height="25" tooltiplabel="MB" - variant="gray900" /> `; diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 869df06b60c..0b898496dd6 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -95,6 +95,19 @@ RSpec.describe API::Files do expect(response.headers['X-Gitlab-Content-Sha256']).to eq('c440cd09bae50c4632cc58638ad33c6aa375b6109d811e76a9cc3a613c1e8887') end + it 'caches sha256 of the content', :use_clean_rails_redis_caching do + head api(route(file_path), current_user, **options), params: params + + expect(Rails.cache.fetch("blob_content_sha256:#{project.full_path}:#{response.headers['X-Gitlab-Blob-Id']}")) + .to eq('c440cd09bae50c4632cc58638ad33c6aa375b6109d811e76a9cc3a613c1e8887') + + expect_next_instance_of(Gitlab::Git::Blob) do |instance| + expect(instance).not_to receive(:load_all_data!) + end + + head api(route(file_path), current_user, **options), params: params + end + it 'returns file by commit sha' do # This file is deleted on HEAD file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee" diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb index 8fc12c6c2b1..d824475275e 100644 --- a/spec/services/merge_requests/merge_to_ref_service_spec.rb +++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb @@ -43,12 +43,22 @@ RSpec.describe MergeRequests::MergeToRefService do # warm the cache # - service.execute(merge_request) + service.execute(merge_request, true) end - it 'caches the response', :request_store do - expect { 3.times { service.execute(merge_request) } } - .not_to change(Gitlab::GitalyClient, :get_request_count) + context 'when cache_merge_to_ref_calls parameter is true' do + it 'caches the response', :request_store do + expect { 3.times { service.execute(merge_request, true) } } + .not_to change(Gitlab::GitalyClient, :get_request_count) + end + end + + context 'when cache_merge_to_ref_calls parameter is false' do + it 'does not cache the response', :request_store do + expect(Gitlab::GitalyClient).to receive(:call).at_least(3).times.and_call_original + + 3.times { service.execute(merge_request, false) } + end end end @@ -58,13 +68,15 @@ RSpec.describe MergeRequests::MergeToRefService do # warm the cache # - service.execute(merge_request) + service.execute(merge_request, true) end - it 'does not cache the response', :request_store do - expect(Gitlab::GitalyClient).to receive(:call).at_least(3).times.and_call_original + [true, false].each do |cache_merge_to_ref_calls| + it 'does not cache the response, regardless of cache_merge_to_ref_calls state', :request_store do + expect(Gitlab::GitalyClient).to receive(:call).at_least(3).times.and_call_original - 3.times { service.execute(merge_request) } + 3.times { service.execute(merge_request, cache_merge_to_ref_calls) } + end end end end diff --git a/spec/support/database/prevent_cross_database_modification.rb b/spec/support/database/prevent_cross_database_modification.rb index 587d1fec586..b4c968e3c41 100644 --- a/spec/support/database/prevent_cross_database_modification.rb +++ b/spec/support/database/prevent_cross_database_modification.rb @@ -74,7 +74,9 @@ module Database return if cross_database_context[:transaction_depth_by_db].values.all?(&:zero?) - tables = PgQuery.parse(sql).dml_tables + parsed_query = PgQuery.parse(sql) + tables = sql.downcase.include?(' for update') ? parsed_query.tables : parsed_query.dml_tables + return if tables.empty? cross_database_context[:modified_tables_by_db][database].merge(tables) diff --git a/spec/support_specs/database/prevent_cross_database_modification_spec.rb b/spec/support_specs/database/prevent_cross_database_modification_spec.rb index 5ea465356a1..e86559bb14a 100644 --- a/spec/support_specs/database/prevent_cross_database_modification_spec.rb +++ b/spec/support_specs/database/prevent_cross_database_modification_spec.rb @@ -99,6 +99,25 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do end end end + + context 'when executing a SELECT FOR UPDATE query' do + def run_queries + project.touch + pipeline.lock! + end + + context 'outside transaction' do + it { expect { run_queries }.not_to raise_error } + end + + context 'when data modification happens in a transaction' do + it 'raises error' do + Project.transaction do + expect { run_queries }.to raise_error /Cross-database data modification/ + end + end + end + end end context 'when CI association is modified through project' do diff --git a/spec/tooling/graphql/docs/renderer_spec.rb b/spec/tooling/graphql/docs/renderer_spec.rb index de5ec928921..1c9605304ff 100644 --- a/spec/tooling/graphql/docs/renderer_spec.rb +++ b/spec/tooling/graphql/docs/renderer_spec.rb @@ -535,8 +535,8 @@ RSpec.describe Tooling::Graphql::Docs::Renderer do | Name | Type | Description | | ---- | ---- | ----------- | - | `end` | [`Date!`](#date) | The end of the range. | - | `start` | [`Date!`](#date) | The start of the range. | + | `end` | [`Date!`](#date) | End of the range. | + | `start` | [`Date!`](#date) | Start of the range. | DOC end diff --git a/yarn.lock b/yarn.lock index 3799b96cca7..1c3a9b91e91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1233,10 +1233,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8" integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw== -"@gitlab/ui@32.2.1": - version "32.2.1" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.2.1.tgz#e019124af981e8ceffd39f30cf08d315c53d4ac8" - integrity sha512-19qe30gHtBG7g7wJy36bvS+ji1puJwVzAwqJOFXAh3axSa0Getyjyl9t5gmfwmZ2HehFTWLlThXppclnJVCEGA== +"@gitlab/ui@32.2.3": + version "32.2.3" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.2.3.tgz#1ac6169e370c21ec71ea3b18c5d077ab08e122b5" + integrity sha512-kT7XTawdXOzKkQeTjbzRawrpRLCeZj/xqQH6BECJ/IkporJle8CLR955HdvrS67lj8cYAOg4uOL7JjTYtltoPA== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "2.18.1"