From eed7260f13c0a3139876e3659603f3d803e8fcd7 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 2 Nov 2023 18:12:04 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/CODEOWNERS | 6 +- .gitlab/ci/qa-common/main.gitlab-ci.yml | 2 +- .../issue_templates/AI Project Proposal.md | 24 +- .rubocop_todo/gitlab/doc_url.yml | 1 - .../layout/first_hash_element_indentation.yml | 1 - .../layout/line_continuation_spacing.yml | 2 - ...e_end_string_concatenation_indentation.yml | 1 - .rubocop_todo/layout/line_length.yml | 2 - .rubocop_todo/performance/map_compact.yml | 1 - .rubocop_todo/rspec/context_wording.yml | 2 - .rubocop_todo/rspec/feature_category.yml | 1 - .rubocop_todo/rspec/verified_doubles.yml | 1 - .rubocop_todo/style/format_string.yml | 1 - .rubocop_todo/style/if_unless_modifier.yml | 1 - .../components/pipeline_status_badge.vue | 2 +- .../diffs/components/tree_list.vue | 140 ++---- .../diffs/components/tree_list_height.vue | 108 ++++ .../queries/groups_autocomplete.query.graphql | 10 + .../repository/components/commit_info.vue | 6 +- .../token_access/graphql/cache_config.js | 14 + app/assets/javascripts/token_access/index.js | 3 +- .../components/list_selector/constants.js | 3 +- .../components/list_selector/group_item.vue | 55 +++ .../components/list_selector/index.vue | 52 +- .../list_selector/{user.vue => user_item.vue} | 0 .../stylesheets/framework/variables.scss | 8 +- .../page_bundles/merge_requests.scss | 6 +- .../stylesheets/page_bundles/pipelines.scss | 4 - app/controllers/admin/dashboard_controller.rb | 3 +- app/controllers/groups_controller.rb | 1 + ...user_group_notification_settings_finder.rb | 17 +- app/models/commit.rb | 8 +- app/models/group.rb | 7 +- app/models/namespace.rb | 19 +- app/models/namespace_setting.rb | 10 + .../development/rugged_commit_is_ancestor.yml | 8 - .../development/rugged_commit_tree_entry.yml | 8 - .../development/rugged_find_commit.yml | 8 - .../rugged_list_commits_by_oid.yml | 8 - .../development/rugged_tree_entries.yml | 8 - .../development/rugged_tree_entry.yml | 8 - doc/api/groups.md | 12 +- .../ci_pipeline_components/img/catalogs.png | Bin 30325 -> 0 bytes .../ci_pipeline_components/index.md | 59 +-- doc/ci/chatops/index.md | 61 ++- doc/ci/yaml/index.md | 463 +++++++++--------- .../database/multiple_databases.md | 2 + doc/operations/feature_flags.md | 10 +- doc/user/clusters/agent/user_access.md | 59 ++- doc/user/group/saml_sso/index.md | 40 +- doc/user/packages/generic_packages/index.md | 6 +- .../integrations/gitlab_slack_application.md | 2 +- lib/api/entities/commit_signature.rb | 17 +- lib/api/entities/group.rb | 3 +- lib/api/helpers/groups_helpers.rb | 3 +- .../config_checker/puma_rugged_checker.rb | 28 -- lib/gitlab/git/blob.rb | 2 - lib/gitlab/git/commit.rb | 3 - lib/gitlab/git/ref.rb | 1 - lib/gitlab/git/repository.rb | 1 - lib/gitlab/git/rugged_impl/blob.rb | 107 ---- lib/gitlab/git/rugged_impl/commit.rb | 115 ----- lib/gitlab/git/rugged_impl/ref.rb | 20 - lib/gitlab/git/rugged_impl/repository.rb | 79 --- lib/gitlab/git/rugged_impl/tree.rb | 147 ------ lib/gitlab/git/rugged_impl/use_rugged.rb | 50 -- lib/gitlab/git/tree.rb | 5 - lib/gitlab/gitaly_client/storage_settings.rb | 8 - lib/tasks/gitlab/features.rake | 34 -- locale/gitlab.pot | 3 - .../profiles/notifications_controller_spec.rb | 2 +- spec/features/boards/multiple_boards_spec.rb | 2 +- spec/features/groups/group_settings_spec.rb | 2 +- spec/features/groups/show_spec.rb | 2 +- ...es_merge_request_file_tree_sidebar_spec.rb | 56 ++- .../user_visits_profile_account_page_spec.rb | 17 - ..._visits_profile_authentication_log_spec.rb | 14 +- ...er_visits_profile_preferences_page_spec.rb | 8 +- .../profiles/user_visits_profile_spec.rb | 10 +- .../user_visits_profile_ssh_keys_page_spec.rb | 17 - .../projects/user_uses_shortcuts_spec.rb | 59 ++- .../user_sees_active_nav_items_spec.rb | 63 +++ ...group_notification_settings_finder_spec.rb | 50 +- .../repository/components/commit_info_spec.js | 1 + .../entity_select/entity_select_spec.js | 4 +- .../list_selector/group_item_spec.js | 55 +++ .../components/list_selector/index_spec.js | 125 ++++- .../components/list_selector/mock_data.js | 24 + .../{user_spec.js => user_item_spec.js} | 6 +- spec/helpers/groups_helper_spec.rb | 4 +- .../puma_rugged_checker_spec.rb | 65 --- spec/lib/gitlab/git/blob_spec.rb | 12 - spec/lib/gitlab/git/commit_spec.rb | 24 - .../gitlab/git/rugged_impl/use_rugged_spec.rb | 116 ----- spec/lib/gitlab/git/tree_spec.rb | 118 ----- .../gitaly_client/storage_settings_spec.rb | 18 +- spec/models/commit_spec.rb | 10 - spec/models/group_spec.rb | 11 +- spec/models/namespace_setting_spec.rb | 82 ++-- spec/models/namespace_spec.rb | 11 +- spec/models/notification_recipient_spec.rb | 4 +- spec/models/project_setting_spec.rb | 2 +- spec/models/repository_spec.rb | 14 - spec/requests/api/commits_spec.rb | 10 - spec/requests/api/groups_spec.rb | 6 +- spec/spec_helper.rb | 14 - spec/support/helpers/gitaly_setup.rb | 4 +- spec/support/matchers/navigation_matcher.rb | 12 +- spec/support/rspec_order_todo.yml | 4 - .../multiple_issue_boards_shared_examples.rb | 4 +- .../notification_service_shared_examples.rb | 2 +- 111 files changed, 1198 insertions(+), 1776 deletions(-) create mode 100644 app/assets/javascripts/diffs/components/tree_list_height.vue create mode 100644 app/assets/javascripts/graphql_shared/queries/groups_autocomplete.query.graphql create mode 100644 app/assets/javascripts/token_access/graphql/cache_config.js create mode 100644 app/assets/javascripts/vue_shared/components/list_selector/group_item.vue rename app/assets/javascripts/vue_shared/components/list_selector/{user.vue => user_item.vue} (100%) delete mode 100644 config/feature_flags/development/rugged_commit_is_ancestor.yml delete mode 100644 config/feature_flags/development/rugged_commit_tree_entry.yml delete mode 100644 config/feature_flags/development/rugged_find_commit.yml delete mode 100644 config/feature_flags/development/rugged_list_commits_by_oid.yml delete mode 100644 config/feature_flags/development/rugged_tree_entries.yml delete mode 100644 config/feature_flags/development/rugged_tree_entry.yml delete mode 100644 doc/architecture/blueprints/ci_pipeline_components/img/catalogs.png delete mode 100644 lib/gitlab/config_checker/puma_rugged_checker.rb delete mode 100644 lib/gitlab/git/rugged_impl/blob.rb delete mode 100644 lib/gitlab/git/rugged_impl/commit.rb delete mode 100644 lib/gitlab/git/rugged_impl/ref.rb delete mode 100644 lib/gitlab/git/rugged_impl/repository.rb delete mode 100644 lib/gitlab/git/rugged_impl/tree.rb delete mode 100644 lib/gitlab/git/rugged_impl/use_rugged.rb delete mode 100644 lib/tasks/gitlab/features.rake delete mode 100644 spec/features/profiles/user_visits_profile_account_page_spec.rb delete mode 100644 spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb create mode 100644 spec/features/user_sees_active_nav_items_spec.rb create mode 100644 spec/frontend/vue_shared/components/list_selector/group_item_spec.js rename spec/frontend/vue_shared/components/list_selector/{user_spec.js => user_item_spec.js} (90%) delete mode 100644 spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb delete mode 100644 spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index fcae55a01c1..6e866739b3f 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -325,9 +325,9 @@ Dangerfile /ee/app/assets/javascripts/analytics/analytics_dashboards/index.js /ee/app/assets/javascripts/analytics/analytics_dashboards/router.js /ee/app/assets/javascripts/analytics/analytics_dashboards/constants.js -/ee/app/assets/javascripts/analytics/analytics_dashboards/graphql/queries/get_all_product_analytics_dashboards.query.graphql -/ee/app/assets/javascripts/analytics/analytics_dashboards/graphql/queries/get_product_analytics_dashboard.query.graphql -/ee/app/assets/javascripts/analytics/analytics_dashboards/graphql/queries/get_all_product_analytics_visualizations.query.graphql +/ee/app/assets/javascripts/analytics/analytics_dashboards/graphql/queries/get_all_customizable_dashboards.query.graphql +/ee/app/assets/javascripts/analytics/analytics_dashboards/graphql/queries/get_customizable_dashboard.query.graphql +/ee/app/assets/javascripts/analytics/analytics_dashboards/graphql/queries/get_all_customizable_visualizations.query.graphql /ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/customizable_dashboard.vue /ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/panels_base.vue /ee/app/assets/javascripts/product_analytics/ diff --git a/.gitlab/ci/qa-common/main.gitlab-ci.yml b/.gitlab/ci/qa-common/main.gitlab-ci.yml index f368287b1e7..94236730f6a 100644 --- a/.gitlab/ci/qa-common/main.gitlab-ci.yml +++ b/.gitlab/ci/qa-common/main.gitlab-ci.yml @@ -14,7 +14,7 @@ include: gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE" allure_job_name: "${QA_RUN_TYPE}" - project: gitlab-org/quality/pipeline-common - ref: 7.10.0 + ref: 7.10.2 file: - /ci/base.gitlab-ci.yml - /ci/knapsack-report.yml diff --git a/.gitlab/issue_templates/AI Project Proposal.md b/.gitlab/issue_templates/AI Project Proposal.md index 7cd68ac4158..412d8d138fe 100644 --- a/.gitlab/issue_templates/AI Project Proposal.md +++ b/.gitlab/issue_templates/AI Project Proposal.md @@ -32,13 +32,13 @@ _What [personas](https://about.gitlab.com/handbook/product/personas/#list-of-use ### Success _How will you measure whether this experiment is a success?_ -**UX maturity requirements** _[Experiment to Beta](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#criteria-and-requirements)_ +**UX maturity requirements** _[Experiment to Beta](https://about.gitlab.com/handbook/product/ai/ux-maturity/#criteria-and-requirements)_ | Criteria | Minimum Requirement | Assessment for Beta | | -------- | ------------------- | ------------------- | -| [Problem validation](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#validation-problem-validation)
How well do we understand the problem? | [Mix of evidence and assumptions](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#questions-to-ask) | | -| [Solution validation](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#validation-solution-validation)
How usable is the solution? | [Heuristic Eval](https://about.gitlab.com/handbook/product/ux/ux-scorecards/#option-a-conduct-a-heuristic-evaluation), Grade C | | -| [Improve](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#build-improve)
How successful is the solution? | [Success metrics defined by the team.](https://about.gitlab.com/handbook/product/ux/ux-research/usability-testing/#usability-at-gitlab) | | -| [Design standards](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#design-standards) adherence
How compliant is the solution with our design standards? | Should adhere to ([PJs](https://design.gitlab.com/), [Design](https://docs.gitlab.com/ee/development/contributing/design.html#checklist)) | | +| [Problem validation](https://about.gitlab.com/handbook/product/ai/ux-maturity/#validation-problem-validation)
How well do we understand the problem? | [Mix of evidence and assumptions](https://about.gitlab.com/handbook/product/ai/ux-maturity/#questions-to-ask) | | +| [Solution validation](https://about.gitlab.com/handbook/product/ai/ux-maturity/#validation-solution-validation)
How usable is the solution? | [Usability testing](https://about.gitlab.com/handbook/product/ux/ux-scorecards/#option-b-perform-a-formative-evaluation), Grade C | | +| [Improve](https://about.gitlab.com/handbook/product/ai/ux-maturity/#build-improve)
How successful is the solution? | Quality goals set by the team are reached. | | +| [Design standards](https://about.gitlab.com/handbook/product/ai/ux-maturity/#design-standards) adherence
How compliant is the solution with our design standards? | Should adhere to ([Pajamas](https://design.gitlab.com/), [checklist](https://docs.gitlab.com/ee/development/contributing/design.html#checklist)) | | # [Beta](https://docs.gitlab.com/ee/policy/alpha-beta-support.html#beta) _This section should be completed prior to beginning work on the Beta experience._ @@ -61,7 +61,7 @@ _What assumptions are you making about this problem and the solution?_ ### Problem validation _What validation exists that customers have this problem?_ - + ### Business objective _What business objective will be achieved with this proposal?_ @@ -80,13 +80,13 @@ _What tasks or actions should the user be capable of performing with this featur _How will you measure whether this Beta is a success?_ -**UX maturity requirements** _[Beta to GA](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#criteria-and-requirements)_ +**UX maturity requirements** _[Beta to GA](https://about.gitlab.com/handbook/product/ai/ux-maturity/#criteria-and-requirements)_ | Criteria | Minimum Requirement | Assessment for GA | | -------- | ------------------- | ------------------- | -| [Problem validation](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#validation-problem-validation)
How well do we understand the problem? | [Mix of evidence and assumptions](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#questions-to-ask) | | -| [Solution validation](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#validation-solution-validation)
How usable is the solution? | [Usability Testing](https://about.gitlab.com/handbook/product/ux/ux-scorecards/#option-b-perform-a-formative-evaluation) and/or [Heuristic Eval](https://about.gitlab.com/handbook/product/ux/ux-scorecards/#option-a-conduct-a-heuristic-evaluation), Avg. task pass rate >80%, Grade B | | -| [Improve](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#build-improve)
How successful is the solution? | [Success metrics defined by the team.](https://about.gitlab.com/handbook/product/ux/ux-research/usability-testing/#usability-at-gitlab) | | -| [Design standards](https://internal-handbook.gitlab.io/handbook/product/ai-strategy/ai-integration-effort/ux_maturity/#design-standards) adherence
How compliant is the solution with our design standards? | Should adhere to ([PJs](https://design.gitlab.com/), [Design](https://docs.gitlab.com/ee/development/contributing/design.html#checklist)) | | +| [Problem validation](https://about.gitlab.com/handbook/product/ai/ux-maturity/#validation-problem-validation)
How well do we understand the problem? | [Mix of evidence and assumptions](https://about.gitlab.com/handbook/product/ai/ux-maturity/#questions-to-ask) | | +| [Solution validation](https://about.gitlab.com/handbook/product/ai/ux-maturity/#validation-solution-validation)
How usable is the solution? | [Usability testing](https://about.gitlab.com/handbook/product/ux/ux-scorecards/#option-b-perform-a-formative-evaluation) and [Heuristic evaluation](https://about.gitlab.com/handbook/product/ux/ux-scorecards/#option-a-conduct-a-heuristic-evaluation), Avg. task pass rate >80%, Grade B | | +| [Improve](https://about.gitlab.com/handbook/product/ai/ux-maturity/#build-improve)
How successful is the solution? | Quality goals set by the team are reached. | | +| [Design standards](https://about.gitlab.com/handbook/product/ai/ux-maturity/#design-standards) adherence
How compliant is the solution with our design standards? | Should adhere to ([Pajamas](https://design.gitlab.com/), [checklist](https://docs.gitlab.com/ee/development/contributing/design.html#checklist)) | | # [Generally Available](https://docs.gitlab.com/ee/policy/alpha-beta-support.html#generally-available-ga) +You can use `only` and `except` to control when to add jobs to pipelines. + +- Use `only` to define when a job runs. +- Use `except` to define when a job **does not** run. + +See [specify when jobs run with `only` and `except`](../jobs/job_control.md#specify-when-jobs-run-with-only-and-except) +for more details and examples. + +#### `only:refs` / `except:refs` + +NOTE: +`only:refs` and `except:refs` are deprecated and not being actively developed. These keywords +are still usable to ensure backwards compatibility, but could be scheduled for removal +in a future milestone. To use refs, regular expressions, or variables to control +when to add jobs to pipelines, use [`rules:if`](#rulesif) instead. + +You can use the `only:refs` and `except:refs` keywords to control when to add jobs to a +pipeline based on branch names or pipeline types. + +**Keyword type**: Job keyword. You can use it only as part of a job. + +**Possible inputs**: An array including any number of: + +- Branch names, for example `main` or `my-feature-branch`. +- [Regular expressions](../jobs/job_control.md#only--except-regex-syntax) + that match against branch names, for example `/^feature-.*/`. +- The following keywords: + + | **Value** | **Description** | + | -------------------------|-----------------| + | `api` | For pipelines triggered by the [pipelines API](../../api/pipelines.md#create-a-new-pipeline). | + | `branches` | When the Git reference for a pipeline is a branch. | + | `chat` | For pipelines created by using a [GitLab ChatOps](../chatops/index.md) command. | + | `external` | When you use CI services other than GitLab. | + | `external_pull_requests` | When an external pull request on GitHub is created or updated (See [Pipelines for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests)). | + | `merge_requests` | For pipelines created when a merge request is created or updated. Enables [merge request pipelines](../pipelines/merge_request_pipelines.md), [merged results pipelines](../pipelines/merged_results_pipelines.md), and [merge trains](../pipelines/merge_trains.md). | + | `pipelines` | For [multi-project pipelines](../pipelines/downstream_pipelines.md#multi-project-pipelines) created by [using the API with `CI_JOB_TOKEN`](../pipelines/downstream_pipelines.md#trigger-a-multi-project-pipeline-by-using-the-api), or the [`trigger`](#trigger) keyword. | + | `pushes` | For pipelines triggered by a `git push` event, including for branches and tags. | + | `schedules` | For [scheduled pipelines](../pipelines/schedules.md). | + | `tags` | When the Git reference for a pipeline is a tag. | + | `triggers` | For pipelines created by using a [trigger token](../triggers/index.md#configure-cicd-jobs-to-run-in-triggered-pipelines). | + | `web` | For pipelines created by selecting **Run pipeline** in the GitLab UI, from the project's **Build > Pipelines** section. | + +**Example of `only:refs` and `except:refs`**: + +```yaml +job1: + script: echo + only: + - main + - /^issue-.*$/ + - merge_requests + +job2: + script: echo + except: + - main + - /^stable-branch.*$/ + - schedules +``` + +**Additional details**: + +- Scheduled pipelines run on specific branches, so jobs configured with `only: branches` + run on scheduled pipelines too. Add `except: schedules` to prevent jobs with `only: branches` + from running on scheduled pipelines. +- `only` or `except` used without any other keywords are equivalent to `only: refs` + or `except: refs`. For example, the following two jobs configurations have the same + behavior: + + ```yaml + job1: + script: echo + only: + - branches + + job2: + script: echo + only: + refs: + - branches + ``` + +- If a job does not use `only`, `except`, or [`rules`](#rules), then `only` is set to `branches` + and `tags` by default. + + For example, `job1` and `job2` are equivalent: + + ```yaml + job1: + script: echo "test" + + job2: + script: echo "test" + only: + - branches + - tags + ``` + +#### `only:variables` / `except:variables` + +NOTE: +`only:variables` and `except:variables` are deprecated and not being actively developed. +These keywords are still usable to ensure backwards compatibility, but could be scheduled +for removal in a future milestone. To use refs, regular expressions, or variables +to control when to add jobs to pipelines, use [`rules:if`](#rulesif) instead. + +You can use the `only:variables` or `except:variables` keywords to control when to add jobs +to a pipeline, based on the status of [CI/CD variables](../variables/index.md). + +**Keyword type**: Job keyword. You can use it only as part of a job. + +**Possible inputs**: + +- An array of [CI/CD variable expressions](../jobs/job_control.md#cicd-variable-expressions). + +**Example of `only:variables`**: + +```yaml +deploy: + script: cap staging deploy + only: + variables: + - $RELEASE == "staging" + - $STAGING +``` + +**Related topics**: + +- [`only:variables` and `except:variables` examples](../jobs/job_control.md#only-variables--except-variables-examples). + +#### `only:changes` / `except:changes` + +`only:variables` and `except:variables` + +NOTE: +`only:changes` and `except:changes` are deprecated and not being actively developed. +These keywords are still usable to ensure backwards compatibility, but could be scheduled +for removal in a future milestone. To use changed files to control when to add a job to a pipeline, +use [`rules:changes`](#ruleschanges) instead. + +Use the `changes` keyword with `only` to run a job, or with `except` to skip a job, +when a Git push event modifies a file. + +Use `changes` in pipelines with the following refs: + +- `branches` +- `external_pull_requests` +- `merge_requests` (see additional details about [using `only:changes` with merge request pipelines](../jobs/job_control.md#use-onlychanges-with-merge-request-pipelines)) + +**Keyword type**: Job keyword. You can use it only as part of a job. + +**Possible inputs**: An array including any number of: + +- Paths to files. +- Wildcard paths for single directories, for example `path/to/directory/*`, or a directory + and all its subdirectories, for example `path/to/directory/**/*`. +- Wildcard [glob](https://en.wikipedia.org/wiki/Glob_(programming)) paths for all + files with the same extension or multiple extensions, for example `*.md` or `path/to/directory/*.{rb,py,sh}`. + See the [Ruby `fnmatch` documentation](https://docs.ruby-lang.org/en/master/File.html#method-c-fnmatch) + for the supported syntax list. +- Wildcard paths to files in the root directory, or all directories, wrapped in double quotes. + For example `"*.json"` or `"**/*.json"`. + +**Example of `only:changes`**: + +```yaml +docker build: + script: docker build -t my-image:$CI_COMMIT_REF_SLUG . + only: + refs: + - branches + changes: + - Dockerfile + - docker/scripts/* + - dockerfiles/**/* + - more_scripts/*.{rb,py,sh} + - "**/*.json" +``` + +**Additional details**: + +- `changes` resolves to `true` if any of the matching files are changed (an `OR` operation). +- If you use refs other than `branches`, `external_pull_requests`, or `merge_requests`, + `changes` can't determine if a given file is new or old and always returns `true`. +- If you use `only: changes` with other refs, jobs ignore the changes and always run. +- If you use `except: changes` with other refs, jobs ignore the changes and never run. + +**Related topics**: + +- [`only: changes` and `except: changes` examples](../jobs/job_control.md#onlychanges--exceptchanges-examples). +- If you use `changes` with [only allow merge requests to be merged if the pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#require-a-successful-pipeline-for-merge), + you should [also use `only:merge_requests`](../jobs/job_control.md#use-onlychanges-with-merge-request-pipelines). +- [Jobs or pipelines can run unexpectedly when using `only: changes`](../jobs/job_control.md#jobs-or-pipelines-run-unexpectedly-when-using-changes). + +#### `only:kubernetes` / `except:kubernetes` + +NOTE: +`only:kubernetes` and `except:kubernetes` are deprecated and not being actively developed. +These keywords are still usable to ensure backwards compatibility, but could be scheduled +for removal in a future milestone. To control if jobs are added to the pipeline when +the Kubernetes service is active in the project, use [`rules:if`](#rulesif) with the +[`CI_KUBERNETES_ACTIVE`](../variables/predefined_variables.md) predefined CI/CD variable instead. + +Use `only:kubernetes` or `except:kubernetes` to control if jobs are added to the pipeline +when the Kubernetes service is active in the project. + +**Keyword type**: Job-specific. You can use it only as part of a job. + +**Possible inputs**: + +- The `kubernetes` strategy accepts only the `active` keyword. + +**Example of `only:kubernetes`**: + +```yaml +deploy: + only: + kubernetes: active +``` + +In this example, the `deploy` job runs only when the Kubernetes service is active +in the project. diff --git a/doc/development/database/multiple_databases.md b/doc/development/database/multiple_databases.md index 79e1d3c0578..c8c696c4e88 100644 --- a/doc/development/database/multiple_databases.md +++ b/doc/development/database/multiple_databases.md @@ -49,6 +49,8 @@ The usage of schema enforces the base class to be used: ### Guidelines on choosing between `gitlab_main_cell` and `gitlab_main_clusterwide` schema +Depending on the use case, your feature may be [cell-local or clusterwide](../../architecture/blueprints/cells/index.md#how-do-i-decide-whether-to-move-my-feature-to-the-cluster-cell-or-organization-level) and hence the tables used for the feature should also use the appropriate schema. + When you choose the appropriate schema for tables, consider the following guidelines as part of the [Cells](../../architecture/blueprints/cells/index.md) architecture: - Default to `gitlab_main_cell`: We expect most tables to be assigned to the `gitlab_main_cell` schema by default. Choose this schema if the data in the table is related to `projects` or `namespaces`. diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md index 56b592ef019..fe21f0db1c7 100644 --- a/doc/operations/feature_flags.md +++ b/doc/operations/feature_flags.md @@ -24,8 +24,7 @@ To contribute to the development of the GitLab product, view ## How it works -GitLab uses [Unleash](https://github.com/Unleash/unleash), a feature -toggle service. +GitLab offers an [Unleash](https://github.com/Unleash/unleash)-compatible API for feature flags. By enabling or disabling a flag in GitLab, your application can determine which features to enable or disable. @@ -76,10 +75,9 @@ is 200. For GitLab SaaS, the maximum number is determined by [tier](https://abou You can apply a feature flag strategy across multiple environments, without defining the strategy multiple times. -GitLab feature flags use [Unleash](https://docs.getunleash.io/) as the feature flag -engine. In Unleash, there are [strategies](https://docs.getunleash.io/reference/activation-strategies) -for granular feature flag controls. GitLab feature flags can have multiple strategies, -and the supported strategies are: +GitLab feature flags are based on [Unleash](https://docs.getunleash.io/). In Unleash, there are +[strategies](https://docs.getunleash.io/reference/activation-strategies) for granular feature +flag controls. GitLab feature flags can have multiple strategies, and the supported strategies are: - [All users](#all-users) - [Percent of Users](#percent-of-users) diff --git a/doc/user/clusters/agent/user_access.md b/doc/user/clusters/agent/user_access.md index 21dc249b1d1..a1e98a2db76 100644 --- a/doc/user/clusters/agent/user_access.md +++ b/doc/user/clusters/agent/user_access.md @@ -151,15 +151,66 @@ Prerequisite: - You have an agent configured with the `user_access` entry. -To grant Kubernetes API access: +### Configure local access with the GitLab CLI (recommended) + +You can use the [GitLab CLI `glab`](../../../editor_extensions/gitlab_cli/index.md) to create or update +a Kubernetes configuration file to access the agent Kubernetes API. + +Use `glab cluster agent` commands to manage cluster connections: + +1. View a list of all the agents associated with your project: + +```shell +glab cluster agent list --repo '/' + +# If your current working directory is the Git repository of the project with the agent, you can omit the --repo option: +glab cluster agent list +``` + +1. Use the numerical agent ID presented in the first column of the output to update your `kubeconfig`: + +```shell +glab cluster agent update-kubeconfig --repo '/' --agent '' --use-context +``` + +1. Verify the update with `kubectl` or your preferred Kubernetes tooling: + +```shell +kubectl get nodes +``` + +The `update-kubeconfig` command sets `glab cluster agent get-token` as a +[credential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins) +for Kubernetes tools to retrieve a token. The `get-token` command creates and +returns a personal access token that is valid until the end of the current day. +Kubernetes tools cache the token until it expires, the API returns an authorization error, or the process exits. Expect all subsequent calls to your Kubernetes tooling to create a new token. + +The `glab cluster agent update-kubeconfig` command supports a number of command line flags. You can view all supported flags with `glab cluster agent update-kubeconfig --help`. + +Some examples: + +```shell +# When the current working directory is the Git repository where the agent is registered the --repo / -R flag can be omitted +glab cluster agent update-kubeconfig --agent '' + +# When the --use-context option is specified the `current-context` of the kubeconfig file is changed to the agent context +glab cluster agent update-kubeconfig --agent '' --use-context + +# The --kubeconfig flag can be used to specify an alternative kubeconfig path +glab cluster agent update-kubeconfig --agent '' --kubeconfig ~/gitlab.kubeconfig +``` + +### Configure local access manually using a personal access token + +You can configure access to a Kubernetes cluster using a long-lived personal access token following these steps: 1. On the left sidebar, select **Search or go to** and find your project. 1. Select **Operate > Kubernetes clusters** and retrieve the numerical ID of the agent you want to access. You need the ID to construct the full API token. 1. Create a [personal access token](../../profile/personal_access_tokens.md) with the `k8s_proxy` scope. You need the access token to construct the full API token. -1. Construct `kube config` entries to access the cluster: - 1. Make sure that the proper `kube config` is selected. +1. Construct `kubeconfig` entries to access the cluster: + 1. Make sure that the proper `kubeconfig` is selected. For example, you can set the `KUBECONFIG` environment variable. - 1. Add the GitLab KAS proxy cluster to the `kube config`: + 1. Add the GitLab KAS proxy cluster to the `kubeconfig`: ```shell kubectl config set-cluster --server "https://kas.gitlab.com/k8s-proxy" diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md index 444afd3442b..70af800b180 100644 --- a/doc/user/group/saml_sso/index.md +++ b/doc/user/group/saml_sso/index.md @@ -54,7 +54,8 @@ To set up SSO with Azure as your identity provider: 1. You should set the following attributes: - **Unique User Identifier (Name identifier)** to `user.objectID`. - **nameid-format** to `persistent`. For more information, see how to [manage user SAML identity](#manage-user-saml-identity). - - **Additional claims** to [supported attributes](#user-attributes). + - **email** to `user.mail` or similar. + - **Additional claims** to [supported attributes](#configure-assertions). 1. Make sure the identity provider is set to have provider-initiated calls to link existing GitLab accounts. @@ -98,7 +99,7 @@ To set up Google Workspace as your identity provider: - For **Last name**: `last_name`. - For **Name ID format**: `EMAIL`. - For **NameID**: `Basic Information > Primary email`. - For more information, see [manage user SAML identity](#manage-user-saml-identity). + For more information, see [supported attributes](#configure-assertions). 1. Make sure the identity provider is set to have provider-initiated calls to link existing GitLab accounts. @@ -134,6 +135,8 @@ To set up SSO with Okta as your identity provider: 1. Set these values: - For **Application username (NameID)**: **Custom** `user.getInternalProperty("id")`. - For **Name ID Format**: `Persistent`. For more information, see [manage user SAML identity](#manage-user-saml-identity). + - For **email**: `user.email` or similar. + - For additional **Attribute Statements**, see [supported attributes](#configure-assertions). 1. Make sure the identity provider is set to have provider-initiated calls to link existing GitLab accounts. @@ -170,10 +173,28 @@ To set up OneLogin as your identity provider: | **Identity provider single sign-on URL** | **SAML 2.0 Endpoint** | 1. For **NameID**, use `OneLogin ID`. For more information, see [manage user SAML identity](#manage-user-saml-identity). - +1. Configure [required and supported attributes](#configure-assertions). 1. Make sure the identity provider is set to have provider-initiated calls to link existing GitLab accounts. +### Configure assertions + +At minimum, you must configure the following assertions: + +1. [NameID](#manage-user-saml-identity). +1. Email. + +Optionally, you can pass user information to GitLab as attributes in the SAML assertion. + +- The user's email address can be an **email** or **mail** attribute. +- The username can be either a **username** or **nickname** attribute. You should specify only + one of these. + +For more information, see the [attributes available for self-managed GitLab instances](../../../integration/saml.md#configure-assertions). + +NOTE: +Attribute names starting with phrases such as `http://schemas.microsoft.com/ws/2008/06/identity/claims/` are not supported. For more information on configuring required attribute names in the SAML identity provider's settings, see [example group SAML and SCIM configurations](../../../user/group/saml_sso/example_saml_config.md). + ### Use metadata To configure some identity providers, you need a GitLab metadata URL. @@ -253,19 +274,6 @@ When a user tries to sign in with Group SSO, GitLab attempts to find or create a - Create a new account with another email address. - Sign-in to their existing account to link the SAML identity. -### User attributes - -You can pass user information to GitLab as attributes in the SAML assertion. - -- The user's email address can be an **email** or **mail** attribute. -- The username can be either a **username** or **nickname** attribute. You should specify only - one of these. - -For more information, see the [attributes available for self-managed GitLab instances](../../../integration/saml.md#configure-assertions). - -NOTE: -Attribute names starting with phrases such as `http://schemas.microsoft.com/ws/2008/06/identity/claims/` are not supported. For more information on configuring required attribute names in the SAML identity provider's settings, see [example group SAML and SCIM configurations](../../../user/group/saml_sso/example_saml_config.md). - ### Link SAML to your existing GitLab.com account > **Remember me** checkbox [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/121569) in GitLab 15.7. diff --git a/doc/user/packages/generic_packages/index.md b/doc/user/packages/generic_packages/index.md index 938093f2a27..1416dcde14f 100644 --- a/doc/user/packages/generic_packages/index.md +++ b/doc/user/packages/generic_packages/index.md @@ -33,7 +33,7 @@ Prerequisites: - You must [authenticate with the API](../../../api/rest/index.md#authentication). If authenticating with a deploy token, it must be configured with the `write_package_registry` scope. If authenticating with a personal access token or project access token, it must be - configured with the `api` scope. + configured with the `api` scope. Project access tokens must have at least the Developer role. - You must call this API endpoint serially when attempting to upload multiple files under the same package name and version. Attempts to concurrently upload multiple files into a new package name and version may face partial failures with @@ -142,7 +142,9 @@ If multiple packages have the same name, version, and filename, then the most re Prerequisites: -- You need to [authenticate with the API](../../../api/rest/index.md#authentication). If authenticating with a deploy token, it must be configured with the `read_package_registry` and/or `write_package_registry` scope. +- You need to [authenticate with the API](../../../api/rest/index.md#authentication). + - If authenticating with a deploy token, it must be configured with the `read_package_registry` and/or `write_package_registry` scope. + - Project access tokens require the `read_api` scope and at least the `Reporter` role. ```plaintext GET /projects/:id/packages/generic/:package_name/:package_version/:file_name diff --git a/doc/user/project/integrations/gitlab_slack_application.md b/doc/user/project/integrations/gitlab_slack_application.md index 6f70305ce8b..67a6916c3b6 100644 --- a/doc/user/project/integrations/gitlab_slack_application.md +++ b/doc/user/project/integrations/gitlab_slack_application.md @@ -74,7 +74,7 @@ You can use slash commands to run common GitLab operations. Replace `` - You must authorize your Slack user on GitLab.com when you run your first slash command. - You can [create a shorter project alias](#create-a-project-alias-for-slash-commands) for slash commands. -**For [Slack slash commands](slack_slash_commands.md) on self-managed GitLab, [Mattermost slash commands](mattermost_slash_commands.md), and [ChatOps](../../../ci/chatops/index.md)**, replace `/gitlab` with the slash command trigger name configured for your integration. +**For [Slack slash commands](slack_slash_commands.md) on self-managed GitLab and [Mattermost slash commands](mattermost_slash_commands.md), replace `/gitlab` with the slash command trigger name configured for your integration. The following slash commands are available: diff --git a/lib/api/entities/commit_signature.rb b/lib/api/entities/commit_signature.rb index 9c30c3c59ea..cdd63df77f0 100644 --- a/lib/api/entities/commit_signature.rb +++ b/lib/api/entities/commit_signature.rb @@ -6,27 +6,24 @@ module API expose :signature_type, documentation: { type: 'string', example: 'PGP' } expose :signature, merge: true do |commit, options| - if commit.signature.is_a?(::CommitSignatures::GpgSignature) || commit.raw_commit_from_rugged? + case commit.signature + when ::CommitSignatures::GpgSignature ::API::Entities::GpgCommitSignature.represent commit_signature(commit), options - elsif commit.signature.is_a?(::CommitSignatures::X509CommitSignature) + when ::CommitSignatures::X509CommitSignature ::API::Entities::X509Signature.represent commit.signature, options - elsif commit.signature.is_a?(::CommitSignatures::SshSignature) + when ::CommitSignatures::SshSignature ::API::Entities::SshSignature.represent(commit.signature, options) end end - expose :commit_source, documentation: { type: 'string', example: 'gitaly' } do |commit, _| - commit.raw_commit_from_rugged? ? "rugged" : "gitaly" + expose :commit_source, documentation: { type: 'string', example: 'gitaly' } do |_commit, _| + "gitaly" end private def commit_signature(commit) - if commit.raw_commit_from_rugged? - commit.gpg_commit.signature - else - commit.signature - end + commit.signature end end end diff --git a/lib/api/entities/group.rb b/lib/api/entities/group.rb index d18a29ce4d4..1a1765c2e0a 100644 --- a/lib/api/entities/group.rb +++ b/lib/api/entities/group.rb @@ -10,7 +10,8 @@ module API expose :project_creation_level_str, as: :project_creation_level expose :auto_devops_enabled expose :subgroup_creation_level_str, as: :subgroup_creation_level - expose :emails_disabled + expose(:emails_disabled, documentation: { type: 'boolean' }) { |group, options| group.emails_disabled? } + expose :emails_enabled, documentation: { type: 'boolean' } expose :mentions_disabled expose :lfs_enabled?, as: :lfs_enabled expose :default_branch_protection diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb index f7802938d8b..fbe13bfe8f7 100644 --- a/lib/api/helpers/groups_helpers.rb +++ b/lib/api/helpers/groups_helpers.rb @@ -18,7 +18,8 @@ module API optional :project_creation_level, type: String, values: ::Gitlab::Access.project_creation_string_values, desc: 'Determine if developers can create projects in the group', as: :project_creation_level_str optional :auto_devops_enabled, type: Boolean, desc: 'Default to Auto DevOps pipeline for all projects within this group' optional :subgroup_creation_level, type: String, values: ::Gitlab::Access.subgroup_creation_string_values, desc: 'Allowed to create subgroups', as: :subgroup_creation_level_str - optional :emails_disabled, type: Boolean, desc: 'Disable email notifications' + optional :emails_disabled, type: Boolean, desc: '_(Deprecated)_ Disable email notifications. Use: emails_enabled' + optional :emails_enabled, type: Boolean, desc: 'Enable email notifications' optional :mentions_disabled, type: Boolean, desc: 'Disable a group from getting mentioned' optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group' optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access' diff --git a/lib/gitlab/config_checker/puma_rugged_checker.rb b/lib/gitlab/config_checker/puma_rugged_checker.rb deleted file mode 100644 index 82c59f3328b..00000000000 --- a/lib/gitlab/config_checker/puma_rugged_checker.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module ConfigChecker - module PumaRuggedChecker - extend self - extend Gitlab::Git::RuggedImpl::UseRugged - - def check - notices = [] - - if running_puma_with_multiple_threads? && rugged_enabled_through_feature_flag? - link_start = '' - link_end = '' - notices << { - type: 'warning', - message: _('Puma is running with a thread count above 1 and the Rugged '\ - 'service is enabled. This may decrease performance in some environments. '\ - 'See our %{link_start}documentation%{link_end} '\ - 'for details of this issue.') % { link_start: link_start, link_end: link_end } - } - end - - notices - end - end - end -end diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb index ae90291c0a3..3744c81f51d 100644 --- a/lib/gitlab/git/blob.rb +++ b/lib/gitlab/git/blob.rb @@ -230,5 +230,3 @@ module Gitlab end end end - -Gitlab::Git::Blob.singleton_class.prepend Gitlab::Git::RuggedImpl::Blob::ClassMethods diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 571dde6fcfc..1086ea45a7a 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -5,7 +5,6 @@ module Gitlab module Git class Commit include Gitlab::EncodingHelper - prepend Gitlab::Git::RuggedImpl::Commit extend Gitlab::Git::WrapsGitalyErrors include Gitlab::Utils::StrongMemoize @@ -502,5 +501,3 @@ module Gitlab end end end - -Gitlab::Git::Commit.singleton_class.prepend Gitlab::Git::RuggedImpl::Commit::ClassMethods diff --git a/lib/gitlab/git/ref.rb b/lib/gitlab/git/ref.rb index 4a09f866db4..205dd5be35a 100644 --- a/lib/gitlab/git/ref.rb +++ b/lib/gitlab/git/ref.rb @@ -4,7 +4,6 @@ module Gitlab module Git class Ref include Gitlab::EncodingHelper - include Gitlab::Git::RuggedImpl::Ref # Branch or tag name # without "refs/tags|heads" prefix diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index a98cf95edf4..db6e6b4d00b 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -11,7 +11,6 @@ module Gitlab include Gitlab::Git::WrapsGitalyErrors include Gitlab::EncodingHelper include Gitlab::Utils::StrongMemoize - prepend Gitlab::Git::RuggedImpl::Repository SEARCH_CONTEXT_LINES = 3 REV_LIST_COMMIT_LIMIT = 2_000 diff --git a/lib/gitlab/git/rugged_impl/blob.rb b/lib/gitlab/git/rugged_impl/blob.rb deleted file mode 100644 index dc869ff5279..00000000000 --- a/lib/gitlab/git/rugged_impl/blob.rb +++ /dev/null @@ -1,107 +0,0 @@ -# frozen_string_literal: true - -# NOTE: This code is legacy. Do not add/modify code here unless you have -# discussed with the Gitaly team. See -# https://docs.gitlab.com/ee/development/gitaly.html#legacy-rugged-code -# for more details. - -module Gitlab - module Git - module RuggedImpl - module Blob - module ClassMethods - extend ::Gitlab::Utils::Override - include Gitlab::Git::RuggedImpl::UseRugged - - override :tree_entry - def tree_entry(repository, sha, path, limit) - if use_rugged?(repository, :rugged_tree_entry) - execute_rugged_call(:rugged_tree_entry, repository, sha, path, limit) - else - super - end - end - - private - - def rugged_tree_entry(repository, sha, path, limit) - return unless path - - # Strip any leading / characters from the path - path = path.sub(%r{\A/*}, '') - - rugged_commit = repository.lookup(sha) - root_tree = rugged_commit.tree - - blob_entry = find_entry_by_path(repository, root_tree.oid, *path.split('/')) - - return unless blob_entry - - if blob_entry[:type] == :commit - submodule_blob(blob_entry, path, sha) - else - blob = repository.lookup(blob_entry[:oid]) - - if blob - new( - id: blob.oid, - name: blob_entry[:name], - size: blob.size, - # Rugged::Blob#content is expensive; don't call it if we don't have to. - data: limit == 0 ? '' : blob.content(limit), - mode: blob_entry[:filemode].to_s(8), - path: path, - commit_id: sha, - binary: blob.binary? - ) - end - end - rescue Rugged::ReferenceError - nil - end - - # Recursive search of blob id by path - # - # Ex. - # blog/ # oid: 1a - # app/ # oid: 2a - # models/ # oid: 3a - # file.rb # oid: 4a - # - # - # Blob.find_entry_by_path(repo, '1a', 'blog', 'app', 'file.rb') # => '4a' - # - def find_entry_by_path(repository, root_id, *path_parts) - root_tree = repository.lookup(root_id) - - entry = root_tree.find do |entry| - entry[:name] == path_parts[0] - end - - return unless entry - - if path_parts.size > 1 - return unless entry[:type] == :tree - - path_parts.shift - find_entry_by_path(repository, entry[:oid], *path_parts) - else - [:blob, :commit].include?(entry[:type]) ? entry : nil - end - end - - def submodule_blob(blob_entry, path, sha) - new( - id: blob_entry[:oid], - name: blob_entry[:name], - size: 0, - data: '', - path: path, - commit_id: sha - ) - end - end - end - end - end -end diff --git a/lib/gitlab/git/rugged_impl/commit.rb b/lib/gitlab/git/rugged_impl/commit.rb deleted file mode 100644 index cf547414b0d..00000000000 --- a/lib/gitlab/git/rugged_impl/commit.rb +++ /dev/null @@ -1,115 +0,0 @@ -# frozen_string_literal: true - -# NOTE: This code is legacy. Do not add/modify code here unless you have -# discussed with the Gitaly team. See -# https://docs.gitlab.com/ee/development/gitaly.html#legacy-rugged-code -# for more details. - -# rubocop:disable Gitlab/ModuleWithInstanceVariables -module Gitlab - module Git - module RuggedImpl - module Commit - module ClassMethods - extend ::Gitlab::Utils::Override - include Gitlab::Git::RuggedImpl::UseRugged - - def rugged_find(repo, commit_id) - obj = repo.rev_parse_target(commit_id) - - obj.is_a?(::Rugged::Commit) ? obj : nil - rescue ::Rugged::Error - nil - end - - # This needs to return an array of Gitlab::Git:Commit objects - # instead of Rugged::Commit objects to ensure upstream models - # operate on a consistent interface. Unlike - # Gitlab::Git::Commit.find, Gitlab::Git::Commit.batch_by_oid - # doesn't attempt to decorate the result. - def rugged_batch_by_oid(repo, oids) - oids.map { |oid| rugged_find(repo, oid) } - .compact - .map { |commit| decorate(repo, commit) } - # Match Gitaly's list_commits_by_oid behavior - rescue ::Gitlab::Git::Repository::NoRepository - [] - end - - override :find_commit - def find_commit(repo, commit_id) - if use_rugged?(repo, :rugged_find_commit) - execute_rugged_call(:rugged_find, repo, commit_id) - else - super - end - end - - override :batch_by_oid - def batch_by_oid(repo, oids) - if use_rugged?(repo, :rugged_list_commits_by_oid) - execute_rugged_call(:rugged_batch_by_oid, repo, oids) - else - super - end - end - end - - extend ::Gitlab::Utils::Override - include Gitlab::Git::RuggedImpl::UseRugged - - override :init_commit - def init_commit(raw_commit) - case raw_commit - when ::Rugged::Commit - init_from_rugged(raw_commit) - else - super - end - end - - override :commit_tree_entry - def commit_tree_entry(path) - if use_rugged?(@repository, :rugged_commit_tree_entry) - execute_rugged_call(:rugged_tree_entry, path) - else - super - end - end - - # Is this the same as Blob.find_entry_by_path ? - def rugged_tree_entry(path) - rugged_commit.tree.path(path) - rescue Rugged::TreeError - nil - end - - def rugged_commit - @rugged_commit ||= if raw_commit.is_a?(Rugged::Commit) - raw_commit - else - @repository.rev_parse_target(id) - end - end - - def init_from_rugged(commit) - author = commit.author - committer = commit.committer - - @raw_commit = commit - @id = commit.oid - @message = commit.message - @authored_date = author[:time] - @committed_date = committer[:time] - @author_name = author[:name] - @author_email = author[:email] - @committer_name = committer[:name] - @committer_email = committer[:email] - @parent_ids = commit.parents.map(&:oid) - @trailers = Hash[commit.trailers] - end - end - end - end -end -# rubocop:enable Gitlab/ModuleWithInstanceVariables diff --git a/lib/gitlab/git/rugged_impl/ref.rb b/lib/gitlab/git/rugged_impl/ref.rb deleted file mode 100644 index b553e82dc47..00000000000 --- a/lib/gitlab/git/rugged_impl/ref.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -# NOTE: This code is legacy. Do not add/modify code here unless you have -# discussed with the Gitaly team. See -# https://docs.gitlab.com/ee/development/gitaly.html#legacy-rugged-code -# for more details. - -module Gitlab - module Git - module RuggedImpl - module Ref - def self.dereference_object(object) - object = object.target while object.is_a?(::Rugged::Tag::Annotation) - - object - end - end - end - end -end diff --git a/lib/gitlab/git/rugged_impl/repository.rb b/lib/gitlab/git/rugged_impl/repository.rb deleted file mode 100644 index cd4eefa158e..00000000000 --- a/lib/gitlab/git/rugged_impl/repository.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -# NOTE: This code is legacy. Do not add/modify code here unless you have -# discussed with the Gitaly team. See -# https://docs.gitlab.com/ee/development/gitaly.html#legacy-rugged-code -# for more details. - -# rubocop:disable Gitlab/ModuleWithInstanceVariables -module Gitlab - module Git - module RuggedImpl - module Repository - extend ::Gitlab::Utils::Override - include Gitlab::Git::RuggedImpl::UseRugged - - FEATURE_FLAGS = %i[rugged_find_commit rugged_tree_entries rugged_tree_entry rugged_commit_is_ancestor rugged_commit_tree_entry rugged_list_commits_by_oid].freeze - - def alternate_object_directories - relative_object_directories.map { |d| File.join(path, d) } - end - - ALLOWED_OBJECT_RELATIVE_DIRECTORIES_VARIABLES = %w[ - GIT_OBJECT_DIRECTORY_RELATIVE - GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE - ].freeze - - def relative_object_directories - Gitlab::Git::HookEnv.all(gl_repository).values_at(*ALLOWED_OBJECT_RELATIVE_DIRECTORIES_VARIABLES).flatten.compact - end - - def rugged - @rugged ||= ::Rugged::Repository.new(path, alternates: alternate_object_directories) - rescue ::Rugged::RepositoryError, ::Rugged::OSError - raise ::Gitlab::Git::Repository::NoRepository, 'no repository for such path' - end - - def cleanup - @rugged&.close - end - - # Return the object that +revspec+ points to. If +revspec+ is an - # annotated tag, then return the tag's target instead. - def rev_parse_target(revspec) - obj = rugged.rev_parse(revspec) - Ref.dereference_object(obj) - end - - override :ancestor? - def ancestor?(from, to) - if use_rugged?(self, :rugged_commit_is_ancestor) - execute_rugged_call(:rugged_is_ancestor?, from, to) - else - super - end - end - - def rugged_is_ancestor?(ancestor_id, descendant_id) - return false if ancestor_id.nil? || descendant_id.nil? - - rugged_merge_base(ancestor_id, descendant_id) == ancestor_id - rescue Rugged::OdbError - false - end - - def rugged_merge_base(from, to) - rugged.merge_base(from, to) - rescue Rugged::ReferenceError - nil - end - - # Lookup for rugged object by oid or ref name - def lookup(oid_or_ref_name) - rev_parse_target(oid_or_ref_name) - end - end - end - end -end -# rubocop:enable Gitlab/ModuleWithInstanceVariables diff --git a/lib/gitlab/git/rugged_impl/tree.rb b/lib/gitlab/git/rugged_impl/tree.rb deleted file mode 100644 index bc3ff01e1e2..00000000000 --- a/lib/gitlab/git/rugged_impl/tree.rb +++ /dev/null @@ -1,147 +0,0 @@ -# frozen_string_literal: true - -# NOTE: This code is legacy. Do not add/modify code here unless you have -# discussed with the Gitaly team. See -# https://docs.gitlab.com/ee/development/gitaly.html#legacy-rugged-code -# for more details. - -module Gitlab - module Git - module RuggedImpl - module Tree - module ClassMethods - extend ::Gitlab::Utils::Override - include Gitlab::Git::RuggedImpl::UseRugged - - TREE_SORT_ORDER = { tree: 0, blob: 1, commit: 2 }.freeze - - override :tree_entries - def tree_entries(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, pagination_params = nil) - if use_rugged?(repository, :rugged_tree_entries) - entries = execute_rugged_call( - :tree_entries_with_flat_path_from_rugged, repository, sha, path, recursive, skip_flat_paths) - - if pagination_params - paginated_response(entries, pagination_params[:limit], pagination_params[:page_token].to_s) - else - [entries, nil] - end - else - super - end - end - - # Rugged version of TreePagination in Go: https://gitlab.com/gitlab-org/gitaly/-/merge_requests/3611 - def paginated_response(entries, limit, token) - total_entries = entries.count - - return [[], nil] if limit == 0 || limit.blank? - - entries = Gitlab::Utils.stable_sort_by(entries) { |x| TREE_SORT_ORDER[x.type] } - - if token.blank? - index = 0 - else - index = entries.index { |entry| entry.id == token } - - raise Gitlab::Git::CommandError, "could not find starting OID: #{token}" if index.nil? - - index += 1 - end - - return [entries[index..], nil] if limit < 0 - - last_index = index + limit - result = entries[index...last_index] - - if last_index < total_entries - cursor = Gitaly::PaginationCursor.new(next_cursor: result.last.id) - end - - [result, cursor] - end - - def tree_entries_with_flat_path_from_rugged(repository, sha, path, recursive, skip_flat_paths) - tree_entries_from_rugged(repository, sha, path, recursive).tap do |entries| - # This was an optimization to reduce N+1 queries for Gitaly - # (https://gitlab.com/gitlab-org/gitaly/issues/530). - rugged_populate_flat_path(repository, sha, path, entries) unless skip_flat_paths - end - end - - def tree_entries_from_rugged(repository, sha, path, recursive) - current_path_entries = get_tree_entries_from_rugged(repository, sha, path) - ordered_entries = [] - - current_path_entries.each do |entry| - ordered_entries << entry - - if recursive && entry.dir? - ordered_entries.concat(tree_entries_from_rugged(repository, sha, entry.path, true)) - end - end - - ordered_entries - end - - def rugged_populate_flat_path(repository, sha, path, entries) - entries.each do |entry| - entry.flat_path = entry.path - - next unless entry.dir? - - entry.flat_path = - if path - File.join(path, rugged_flatten_tree(repository, sha, entry, path)) - else - rugged_flatten_tree(repository, sha, entry, path) - end - end - end - - # Returns the relative path of the first subdir that doesn't have only one directory descendant - def rugged_flatten_tree(repository, sha, tree, root_path) - subtree = tree_entries_from_rugged(repository, sha, tree.path, false) - - if subtree.count == 1 && subtree.first.dir? - File.join(tree.name, rugged_flatten_tree(repository, sha, subtree.first, root_path)) - else - tree.name - end - end - - def get_tree_entries_from_rugged(repository, sha, path) - commit = repository.lookup(sha) - root_tree = commit.tree - - tree = if path - id = find_id_by_path(repository, root_tree.oid, path) - if id - repository.lookup(id) - else - [] - end - else - root_tree - end - - tree.map do |entry| - current_path = path ? File.join(path, entry[:name]) : entry[:name] - - new( - id: entry[:oid], - name: entry[:name], - type: entry[:type], - mode: entry[:filemode].to_s(8), - path: current_path, - commit_id: sha - ) - end - rescue Rugged::ReferenceError - [] - end - end - end - end - end -end diff --git a/lib/gitlab/git/rugged_impl/use_rugged.rb b/lib/gitlab/git/rugged_impl/use_rugged.rb deleted file mode 100644 index 57cced97d02..00000000000 --- a/lib/gitlab/git/rugged_impl/use_rugged.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Git - module RuggedImpl - module UseRugged - def use_rugged?(_, _) - false - end - - def execute_rugged_call(method_name, *args) - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - start = Gitlab::Metrics::System.monotonic_time - - result = send(method_name, *args) # rubocop:disable GitlabSecurity/PublicSend - - duration = Gitlab::Metrics::System.monotonic_time - start - - if Gitlab::RuggedInstrumentation.active? - Gitlab::RuggedInstrumentation.increment_query_count - Gitlab::RuggedInstrumentation.add_query_time(duration) - - Gitlab::RuggedInstrumentation.add_call_details( - feature: method_name, - args: args, - duration: duration, - backtrace: Gitlab::BacktraceCleaner.clean_backtrace(caller)) - end - - result - end - end - - def running_puma_with_multiple_threads? - return false unless Gitlab::Runtime.puma? - - ::Puma.respond_to?(:cli_config) && ::Puma.cli_config.options[:max_threads] > 1 - end - - def rugged_feature_keys - Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS - end - - def rugged_enabled_through_feature_flag? - false - end - end - end - end -end diff --git a/lib/gitlab/git/tree.rb b/lib/gitlab/git/tree.rb index 6e97e412b91..4747ab55c63 100644 --- a/lib/gitlab/git/tree.rb +++ b/lib/gitlab/git/tree.rb @@ -12,9 +12,6 @@ module Gitlab class << self # Get list of tree objects # for repository based on commit sha and path - # Uses rugged for raw objects - # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/320 def where( repository, sha, path = nil, recursive = false, skip_flat_paths = true, rescue_not_found = true, pagination_params = nil) @@ -110,5 +107,3 @@ module Gitlab end end end - -Gitlab::Git::Tree.singleton_class.prepend Gitlab::Git::RuggedImpl::Tree::ClassMethods diff --git a/lib/gitlab/gitaly_client/storage_settings.rb b/lib/gitlab/gitaly_client/storage_settings.rb index 4cc0269673f..adf0c811274 100644 --- a/lib/gitlab/gitaly_client/storage_settings.rb +++ b/lib/gitlab/gitaly_client/storage_settings.rb @@ -31,19 +31,11 @@ module Gitlab end def self.disk_access_denied? - return false if rugged_enabled? - !temporarily_allowed?(ALLOW_KEY) rescue StandardError false # Err on the side of caution, don't break gitlab for people end - def self.rugged_enabled? - Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS.any? do |flag| - Feature.enabled?(flag) - end - end - def initialize(storage) raise InvalidConfigurationError, "expected a Hash, got a #{storage.class.name}" unless storage.is_a?(Hash) raise InvalidConfigurationError, INVALID_STORAGE_MESSAGE unless storage.has_key?('path') diff --git a/lib/tasks/gitlab/features.rake b/lib/tasks/gitlab/features.rake deleted file mode 100644 index e44328e0de1..00000000000 --- a/lib/tasks/gitlab/features.rake +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -namespace :gitlab do - namespace :features do - desc 'GitLab | Features | Enable direct Git access via Rugged for NFS' - task enable_rugged: :environment do - set_rugged_feature_flags(true) - puts 'All Rugged feature flags were enabled.' - end - - task disable_rugged: :environment do - set_rugged_feature_flags(false) - puts 'All Rugged feature flags were disabled.' - end - - task unset_rugged: :environment do - set_rugged_feature_flags(nil) - puts 'All Rugged feature flags were unset.' - end - end - - def set_rugged_feature_flags(status) - Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS.each do |flag| - case status - when nil - Feature.remove(flag) - when true - Feature.enable(flag) - when false - Feature.disable(flag) - end - end - end -end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9f16738dcaa..a54d6bf92b5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -38905,9 +38905,6 @@ msgstr "" msgid "Pull requests from fork are not supported" msgstr "" -msgid "Puma is running with a thread count above 1 and the Rugged service is enabled. This may decrease performance in some environments. See our %{link_start}documentation%{link_end} for details of this issue." -msgstr "" - msgid "PumbleIntegration|Send notifications about project events to Pumble." msgstr "" diff --git a/spec/controllers/profiles/notifications_controller_spec.rb b/spec/controllers/profiles/notifications_controller_spec.rb index 22c0a62a6a1..ef49eb911ba 100644 --- a/spec/controllers/profiles/notifications_controller_spec.rb +++ b/spec/controllers/profiles/notifications_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Profiles::NotificationsController do +RSpec.describe Profiles::NotificationsController, feature_category: :team_planning do let(:user) do create(:user) do |user| user.emails.create!(email: 'original@example.com', confirmed_at: Time.current) diff --git a/spec/features/boards/multiple_boards_spec.rb b/spec/features/boards/multiple_boards_spec.rb index 9d59d3dd02a..e9d34c6f87f 100644 --- a/spec/features/boards/multiple_boards_spec.rb +++ b/spec/features/boards/multiple_boards_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Multiple Issue Boards', :js, feature_category: :team_planning do - let_it_be(:user) { create(:user, :no_super_sidebar) } + let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public) } let_it_be(:planning) { create(:label, project: project, name: 'Planning') } let_it_be(:board) { create(:board, name: 'board1', project: project) } diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index a248a2b471a..0437e5df6e9 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -329,7 +329,7 @@ RSpec.describe 'Edit group settings', feature_category: :groups_and_projects do end def updated_emails_disabled? - group.reload.clear_memoization(:emails_disabled_memoized) + group.reload.clear_memoization(:emails_enabled_memoized) group.emails_disabled? end end diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index 8450322945c..cf18f3cb4e5 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -276,7 +276,7 @@ RSpec.describe 'Group show page', feature_category: :groups_and_projects do end it 'is disabled if emails are disabled' do - group.update!(emails_disabled: true) + group.update!(emails_enabled: false) visit path diff --git a/spec/features/merge_request/user_sees_merge_request_file_tree_sidebar_spec.rb b/spec/features/merge_request/user_sees_merge_request_file_tree_sidebar_spec.rb index c385def6762..8caa13c6297 100644 --- a/spec/features/merge_request/user_sees_merge_request_file_tree_sidebar_spec.rb +++ b/spec/features/merge_request/user_sees_merge_request_file_tree_sidebar_spec.rb @@ -15,48 +15,56 @@ RSpec.describe 'Merge request > User sees merge request file tree sidebar', :js, sign_in(user) visit diffs_project_merge_request_path(project, merge_request) wait_for_requests - scroll_into_view end it 'sees file tree sidebar' do expect(page).to have_selector('.file-row[role=button]') end - # TODO: fix this test - # For some reason the browser in CI doesn't update the file tree sidebar when review bar is shown - # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118378#note_1403906356 - # - # it 'has last entry visible with discussions enabled' do - # add_diff_line_draft_comment('foo', find('.line_holder', match: :first)) - # scroll_into_view - # scroll_to_end - # button = find_all('.file-row[role=button]').last - # expect(button.obscured?).to be_falsy - # end - - shared_examples 'shows last visible file in sidebar' do - it 'shows last file' do - scroll_to_end + shared_examples 'last entry clickable' do + specify do + sidebar_scroller.execute_script('this.scrollBy(0,99999)') button = find_all('.file-row[role=button]').last title = button.find('[data-testid=file-row-name-container]')[:title] + expect(button.obscured?).to be_falsy button.click expect(page).to have_selector(".file-title-name[title*=\"#{title}\"]") end end - it_behaves_like 'shows last visible file in sidebar' + it_behaves_like 'last entry clickable' + + context 'when has started a review' do + before do + add_diff_line_draft_comment('foo', find('.line_holder', match: :first)) + # wait for review bar to appear + find_by_testid('review_bar_component') + # wait for sidebar to adjust + sleep(1) + end + + it_behaves_like 'last entry clickable' + + context 'when scrolled into full view' do + before do + sidebar.execute_script("this.scrollIntoView({ block: 'end' })") + end + + it_behaves_like 'last entry clickable' + end + end context 'when viewing using file-by-file mode' do let(:user) { create(:user, view_diffs_file_by_file: true) } - it_behaves_like 'shows last visible file in sidebar' - end + it_behaves_like 'last entry clickable' - def scroll_into_view - sidebar.execute_script("this.scrollIntoView({ block: 'end' })") - end + context 'when navigating to the next file' do + before do + click_link 'Next' + end - def scroll_to_end - sidebar_scroller.execute_script('this.scrollBy(0,99999)') + it_behaves_like 'last entry clickable' + end end end diff --git a/spec/features/profiles/user_visits_profile_account_page_spec.rb b/spec/features/profiles/user_visits_profile_account_page_spec.rb deleted file mode 100644 index 8569cefd1f4..00000000000 --- a/spec/features/profiles/user_visits_profile_account_page_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User visits the profile account page', feature_category: :user_profile do - let(:user) { create(:user, :no_super_sidebar) } - - before do - sign_in(user) - - visit(profile_account_path) - end - - it 'shows correct menu item' do - expect(page).to have_active_navigation('Account') - end -end diff --git a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb index f92b8e2e751..c081f4a3ec9 100644 --- a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb +++ b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb @@ -3,19 +3,7 @@ require 'spec_helper' RSpec.describe 'User visits the authentication log', feature_category: :user_profile do - let(:user) { create(:user, :no_super_sidebar) } - - context 'when user signed in' do - before do - sign_in(user) - end - - it 'shows correct menu item' do - visit(audit_log_profile_path) - - expect(page).to have_active_navigation('Authentication Log') - end - end + let(:user) { create(:user) } context 'when user has activity' do before do diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb index 4da1a7ba81a..033d69d29b9 100644 --- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb +++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe 'User visits the profile preferences page', :js, feature_category: :user_profile do include ListboxHelpers - let(:user) { create(:user, :no_super_sidebar) } + let(:user) { create(:user) } before do sign_in(user) @@ -13,10 +13,6 @@ RSpec.describe 'User visits the profile preferences page', :js, feature_category visit(profile_preferences_path) end - it 'shows correct menu item' do - expect(page).to have_active_navigation('Preferences') - end - describe 'User changes their syntax highlighting theme', :js do it 'updates their preference' do choose 'user_color_scheme_id_5' @@ -44,7 +40,7 @@ RSpec.describe 'User visits the profile preferences page', :js, feature_category wait_for_requests - find('#logo').click + find('[data-track-label="gitlab_logo_link"]').click expect(page).to have_content("You don't have starred projects yet") expect(page).to have_current_path starred_dashboard_projects_path, ignore_query: true diff --git a/spec/features/profiles/user_visits_profile_spec.rb b/spec/features/profiles/user_visits_profile_spec.rb index 821c3d5ef2b..37a19ecadb8 100644 --- a/spec/features/profiles/user_visits_profile_spec.rb +++ b/spec/features/profiles/user_visits_profile_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'User visits their profile', feature_category: :user_profile do - let_it_be_with_refind(:user) { create(:user, :no_super_sidebar) } + let_it_be_with_refind(:user) { create(:user) } before do stub_feature_flags(profile_tabs_vue: false) @@ -11,12 +11,6 @@ RSpec.describe 'User visits their profile', feature_category: :user_profile do sign_in(user) end - it 'shows correct menu item' do - visit(profile_path) - - expect(page).to have_active_navigation('Profile') - end - it 'shows profile info' do visit(profile_path) @@ -59,7 +53,7 @@ RSpec.describe 'User visits their profile', feature_category: :user_profile do expect(page).to have_content user.username end - page.within ".content" do + within_testid('super-sidebar') do click_link link end diff --git a/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb b/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb deleted file mode 100644 index 728fe1a3172..00000000000 --- a/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User visits the profile SSH keys page', feature_category: :user_profile do - let(:user) { create(:user, :no_super_sidebar) } - - before do - sign_in(user) - - visit(profile_keys_path) - end - - it 'shows correct menu item' do - expect(page).to have_active_navigation('SSH Keys') - end -end diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb index b7b2093d78a..a000c9e1da8 100644 --- a/spec/features/projects/user_uses_shortcuts_spec.rb +++ b/spec/features/projects/user_uses_shortcuts_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_projects do - let_it_be(:user) { create(:user, :no_super_sidebar) } + let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository, namespace: user.namespace) } before do @@ -21,14 +21,14 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('o') - expect(page).to have_active_navigation(project.name) + expect(page).to have_active_sub_navigation(project.name) end it 'redirects to the activity page' do find('body').native.send_key('g') find('body').native.send_key('v') - expect(page).to have_active_navigation('Project') + expect(page).to have_active_navigation('Manage') expect(page).to have_active_sub_navigation('Activity') end end @@ -38,31 +38,39 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('f') - expect(page).to have_active_navigation('Repository') - expect(page).to have_active_sub_navigation('Files') + expect(page).to have_active_navigation('Code') + expect(page).to have_active_sub_navigation('Repository') end - it 'redirects to the repository commits page' do - find('body').native.send_key('g') - find('body').native.send_key('c') + context 'when hitting the commits controller' do + # Hitting the commits controller with the super sidebar enabled seems to trigger more SQL + # queries, exceeding the 100 limit. We need to increase the limit a bit for these tests to pass. + before do + allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(110) + end - expect(page).to have_active_navigation('Repository') - expect(page).to have_active_sub_navigation('Commits') + it 'redirects to the repository commits page' do + find('body').native.send_key('g') + find('body').native.send_key('c') + + expect(page).to have_active_navigation('Code') + expect(page).to have_active_sub_navigation('Commits') + end end it 'redirects to the repository graph page' do find('body').native.send_key('g') find('body').native.send_key('n') - expect(page).to have_active_navigation('Repository') - expect(page).to have_active_sub_navigation('Graph') + expect(page).to have_active_navigation('Code') + expect(page).to have_active_sub_navigation('Repository graph') end it 'redirects to the repository charts page' do find('body').native.send_key('g') find('body').native.send_key('d') - expect(page).to have_active_navigation(_('Analytics')) + expect(page).to have_active_navigation(_('Analyze')) expect(page).to have_active_sub_navigation(_('Repository')) end end @@ -72,16 +80,16 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('i') - expect(page).to have_active_navigation('Issues') - expect(page).to have_active_sub_navigation('List') + expect(page).to have_active_navigation('Pinned') + expect(page).to have_active_sub_navigation('Issues') end it 'redirects to the issue board page' do find('body').native.send_key('g') find('body').native.send_key('b') - expect(page).to have_active_navigation('Issues') - expect(page).to have_active_sub_navigation('Board') + expect(page).to have_active_navigation('Plan') + expect(page).to have_active_sub_navigation('Issue boards') end it 'redirects to the new issue page' do @@ -97,7 +105,8 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('m') - expect(page).to have_active_navigation('Merge requests') + expect(page).to have_active_navigation('Pinned') + expect(page).to have_active_sub_navigation('Merge requests') end end @@ -106,7 +115,7 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('p') - expect(page).to have_active_navigation('CI/CD') + expect(page).to have_active_navigation('Build') expect(page).to have_active_sub_navigation('Pipelines') end @@ -114,7 +123,7 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('j') - expect(page).to have_active_navigation('CI/CD') + expect(page).to have_active_navigation('Build') expect(page).to have_active_sub_navigation('Jobs') end end @@ -124,7 +133,7 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('e') - expect(page).to have_active_navigation('Deployments') + expect(page).to have_active_navigation('Operate') expect(page).to have_active_sub_navigation('Environments') end end @@ -134,7 +143,7 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('k') - expect(page).to have_active_navigation('Infrastructure') + expect(page).to have_active_navigation('Operate') expect(page).to have_active_sub_navigation('Kubernetes') end end @@ -144,7 +153,8 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('s') - expect(page).to have_active_navigation('Snippets') + expect(page).to have_active_navigation('Code') + expect(page).to have_active_sub_navigation('Snippets') end end @@ -153,7 +163,8 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project find('body').native.send_key('g') find('body').native.send_key('w') - expect(page).to have_active_navigation('Wiki') + expect(page).to have_active_navigation('Plan') + expect(page).to have_active_sub_navigation('Wiki') end end end diff --git a/spec/features/user_sees_active_nav_items_spec.rb b/spec/features/user_sees_active_nav_items_spec.rb new file mode 100644 index 00000000000..966b8491374 --- /dev/null +++ b/spec/features/user_sees_active_nav_items_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User sees correct active nav items in the super sidebar', :js, feature_category: :value_stream_management do + let_it_be(:current_user) { create(:user) } + + before do + sign_in(current_user) + end + + describe 'profile pages' do + context 'when visiting profile page' do + before do + visit profile_path + end + + it 'renders the side navigation with the correct submenu set as active' do + expect(page).to have_active_sub_navigation('Profile') + end + end + + context 'when visiting preferences page' do + before do + visit profile_preferences_path + end + + it 'renders the side navigation with the correct submenu set as active' do + expect(page).to have_active_sub_navigation('Preferences') + end + end + + context 'when visiting authentication logs' do + before do + visit audit_log_profile_path + end + + it 'renders the side navigation with the correct submenu set as active' do + expect(page).to have_active_sub_navigation('Authentication Log') + end + end + + context 'when visiting SSH keys page' do + before do + visit profile_keys_path + end + + it 'renders the side navigation with the correct submenu set as active' do + expect(page).to have_active_sub_navigation('SSH Keys') + end + end + + context 'when visiting account page' do + before do + visit profile_account_path + end + + it 'renders the side navigation with the correct submenu set as active' do + expect(page).to have_active_sub_navigation('Account') + end + end + end +end diff --git a/spec/finders/user_group_notification_settings_finder_spec.rb b/spec/finders/user_group_notification_settings_finder_spec.rb index ac59a42d813..83d0d343c04 100644 --- a/spec/finders/user_group_notification_settings_finder_spec.rb +++ b/spec/finders/user_group_notification_settings_finder_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe UserGroupNotificationSettingsFinder do +RSpec.describe UserGroupNotificationSettingsFinder, feature_category: :team_planning do let_it_be(:user) { create(:user) } subject { described_class.new(user, Group.where(id: groups.map(&:id))).execute } @@ -127,38 +127,38 @@ RSpec.describe UserGroupNotificationSettingsFinder do expect(result.count).to eq(3) end - end - end - context 'preloading `emails_disabled`' do - let_it_be(:root_group) { create(:group) } - let_it_be(:sub_group) { create(:group, parent: root_group) } - let_it_be(:sub_sub_group) { create(:group, parent: sub_group) } + context 'preloading `emails_enabled`' do + let_it_be(:root_group) { create(:group) } + let_it_be(:sub_group) { create(:group, parent: root_group) } + let_it_be(:sub_sub_group) { create(:group, parent: sub_group) } - let_it_be(:another_root_group) { create(:group) } - let_it_be(:sub_group_with_emails_disabled) { create(:group, emails_disabled: true, parent: another_root_group) } - let_it_be(:another_sub_sub_group) { create(:group, parent: sub_group_with_emails_disabled) } + let_it_be(:another_root_group) { create(:group) } + let_it_be(:sub_group_with_emails_disabled) { create(:group, emails_enabled: false, parent: another_root_group) } + let_it_be(:another_sub_sub_group) { create(:group, parent: sub_group_with_emails_disabled) } - let_it_be(:root_group_with_emails_disabled) { create(:group, emails_disabled: true) } - let_it_be(:group) { create(:group, parent: root_group_with_emails_disabled) } + let_it_be(:root_group_with_emails_disabled) { create(:group, emails_enabled: false) } + let_it_be(:group) { create(:group, parent: root_group_with_emails_disabled) } - let(:groups) { Group.where(id: [sub_sub_group, another_sub_sub_group, group]) } + let(:groups) { Group.where(id: [sub_sub_group, another_sub_sub_group, group]) } - before do - described_class.new(user, groups).execute - end + before do + described_class.new(user, groups).execute + end - it 'preloads the `group.emails_disabled` method' do - recorder = ActiveRecord::QueryRecorder.new do - groups.each(&:emails_disabled?) - end + it 'preloads the `group.emails_enabled` method' do + recorder = ActiveRecord::QueryRecorder.new do + groups.each(&:emails_enabled?) + end - expect(recorder.count).to eq(0) - end + expect(recorder.count).to eq(0) + end - it 'preloads the `group.emails_disabled` method correctly' do - groups.each do |group| - expect(group.emails_disabled?).to eq(Group.find(group.id).emails_disabled?) # compare the memoized and the freshly loaded value + it 'preloads the `group.emails_enabled` method correctly' do + groups.each do |group| + expect(group.emails_enabled?).to eq(Group.find(group.id).emails_enabled?) # compare the memoized and the freshly loaded value + end + end end end end diff --git a/spec/frontend/repository/components/commit_info_spec.js b/spec/frontend/repository/components/commit_info_spec.js index 34e941aa858..468aaf3dc1c 100644 --- a/spec/frontend/repository/components/commit_info_spec.js +++ b/spec/frontend/repository/components/commit_info_spec.js @@ -35,6 +35,7 @@ describe('Repository last commit component', () => { expect(findUserLink().exists()).toBe(true); expect(findUserAvatarLink().exists()).toBe(true); + expect(findUserAvatarLink().props('imgAlt')).toBe("Test authorName's avatar"); }); it('hides author component when author does not exist', () => { diff --git a/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js b/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js index 72d9f699821..1376133ec37 100644 --- a/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js +++ b/spec/frontend/vue_shared/components/entity_select/entity_select_spec.js @@ -71,7 +71,7 @@ describe('EntitySelect', () => { fetchItemsMock = jest.fn().mockImplementation(() => ({ items: [itemMock], totalPages: 1 })); }); - describe('GlCollapsableListbox props', () => { + describe('GlCollapsibleListbox props', () => { beforeEach(() => { createComponent(); }); @@ -81,7 +81,7 @@ describe('EntitySelect', () => { ${'block'} | ${block} ${'toggleClass'} | ${toggleClass} ${'headerText'} | ${headerText} - `('passes the $prop prop to GlCollapsableListbox', ({ prop, expectedValue }) => { + `('passes the $prop prop to GlCollapsibleListbox', ({ prop, expectedValue }) => { expect(findListbox().props(prop)).toBe(expectedValue); }); }); diff --git a/spec/frontend/vue_shared/components/list_selector/group_item_spec.js b/spec/frontend/vue_shared/components/list_selector/group_item_spec.js new file mode 100644 index 00000000000..b59e4c734c1 --- /dev/null +++ b/spec/frontend/vue_shared/components/list_selector/group_item_spec.js @@ -0,0 +1,55 @@ +import { GlAvatar } from '@gitlab/ui'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import GroupItem from '~/vue_shared/components/list_selector/group_item.vue'; + +describe('GroupItem spec', () => { + let wrapper; + + const MOCK_GROUP = { fullName: 'Group 1', name: 'group1', avatarUrl: 'some/avatar.jpg' }; + + const createComponent = (props) => { + wrapper = mountExtended(GroupItem, { + propsData: { + data: MOCK_GROUP, + ...props, + }, + }); + }; + + const findAvatar = () => wrapper.findComponent(GlAvatar); + const findDeleteButton = () => wrapper.findByRole('button', { fullName: 'Delete Group 1' }); + + beforeEach(() => createComponent()); + + it('renders an Avatar component', () => { + expect(findAvatar().props('size')).toBe(32); + expect(findAvatar().attributes()).toMatchObject({ + src: MOCK_GROUP.avatarUrl, + alt: MOCK_GROUP.fullName, + }); + }); + + it('renders a fullName and name', () => { + expect(wrapper.text()).toContain('Group 1'); + expect(wrapper.text()).toContain('@group1'); + }); + + it('does not render a delete button by default', () => { + expect(findDeleteButton().exists()).toBe(false); + }); + + describe('Delete button', () => { + beforeEach(() => createComponent({ canDelete: true })); + + it('renders a delete button', () => { + expect(findDeleteButton().exists()).toBe(true); + expect(findDeleteButton().props('icon')).toBe('remove'); + }); + + it('emits a delete event if the delete button is clicked', () => { + findDeleteButton().trigger('click'); + + expect(wrapper.emitted('delete')).toEqual([[MOCK_GROUP.name]]); + }); + }); +}); diff --git a/spec/frontend/vue_shared/components/list_selector/index_spec.js b/spec/frontend/vue_shared/components/list_selector/index_spec.js index 96074519857..4222a28afe8 100644 --- a/spec/frontend/vue_shared/components/list_selector/index_spec.js +++ b/spec/frontend/vue_shared/components/list_selector/index_spec.js @@ -3,11 +3,13 @@ import VueApollo from 'vue-apollo'; import { GlCard, GlIcon, GlCollapsibleListbox, GlSearchBoxByType } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import ListSelector from '~/vue_shared/components/list_selector/index.vue'; -import User from '~/vue_shared/components/list_selector/user.vue'; +import UserItem from '~/vue_shared/components/list_selector/user_item.vue'; +import GroupItem from '~/vue_shared/components/list_selector/group_item.vue'; import usersAutocompleteQuery from '~/graphql_shared/queries/users_autocomplete.query.graphql'; +import groupsAutocompleteQuery from '~/graphql_shared/queries/groups_autocomplete.query.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { USERS_RESPONSE_MOCK } from './mock_data'; +import { USERS_RESPONSE_MOCK, GROUPS_RESPONSE_MOCK } from './mock_data'; Vue.use(VueApollo); @@ -15,21 +17,31 @@ describe('List Selector spec', () => { let wrapper; let fakeApollo; - const MOCK_PROPS = { + const USERS_MOCK_PROPS = { title: 'Users', projectPath: 'some/project/path', type: 'users', }; - const usersAutocompleteQuerySuccess = jest.fn().mockResolvedValue(USERS_RESPONSE_MOCK); + const GROUPS_MOCK_PROPS = { + title: 'Groups', + projectPath: 'some/project/path', + type: 'groups', + }; - const createComponent = async (props) => { - fakeApollo = createMockApollo([[usersAutocompleteQuery, usersAutocompleteQuerySuccess]]); + const usersAutocompleteQuerySuccess = jest.fn().mockResolvedValue(USERS_RESPONSE_MOCK); + const groupsAutocompleteQuerySuccess = jest.fn().mockResolvedValue(GROUPS_RESPONSE_MOCK); + + const createComponent = async ( + props, + query = usersAutocompleteQuery, + queryResponse = usersAutocompleteQuerySuccess, + ) => { + fakeApollo = createMockApollo([[query, queryResponse]]); wrapper = mountExtended(ListSelector, { apolloProvider: fakeApollo, propsData: { - ...MOCK_PROPS, ...props, }, }); @@ -38,21 +50,23 @@ describe('List Selector spec', () => { }; const findCard = () => wrapper.findComponent(GlCard); - const findTitle = () => wrapper.findByText(MOCK_PROPS.title); + const findTitle = () => findCard().find('[data-testid="list-selector-title"]'); const findIcon = () => wrapper.findComponent(GlIcon); const findListBox = () => wrapper.findComponent(GlCollapsibleListbox); const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); - const findAllUserComponents = () => wrapper.findAllComponents(User); + const findAllUserComponents = () => wrapper.findAllComponents(UserItem); + const findAllGroupComponents = () => wrapper.findAllComponents(GroupItem); describe('Users type', () => { - beforeEach(() => createComponent({ type: 'users' })); + beforeEach(() => createComponent(USERS_MOCK_PROPS)); it('renders a Card component', () => { expect(findCard().exists()).toBe(true); }); - it('renders a title', () => { + it('renders a correct title', () => { expect(findTitle().exists()).toBe(true); + expect(findTitle().text()).toContain('Users'); }); it('renders the correct icon', () => { @@ -81,7 +95,7 @@ describe('List Selector spec', () => { it('calls query with correct variables when Search box receives an input', () => { expect(usersAutocompleteQuerySuccess).toHaveBeenCalledWith({ - fullPath: MOCK_PROPS.projectPath, + fullPath: USERS_MOCK_PROPS.projectPath, isProject: true, search, }); @@ -108,11 +122,11 @@ describe('List Selector spec', () => { describe('selected items', () => { const selectedUser = { username: 'root' }; const selectedItems = [selectedUser]; - beforeEach(() => createComponent({ selectedItems })); + beforeEach(() => createComponent({ ...USERS_MOCK_PROPS, selectedItems })); it('renders a heading with the total selected items', () => { - expect(findCard().text()).toContain('Users'); - expect(findCard().text()).toContain('1'); + expect(findTitle().text()).toContain('Users'); + expect(findTitle().text()).toContain('1'); }); it('renders a user component for each selected item', () => { @@ -131,4 +145,85 @@ describe('List Selector spec', () => { }); }); }); + + describe('Groups type', () => { + beforeEach(() => + createComponent(GROUPS_MOCK_PROPS, groupsAutocompleteQuery, groupsAutocompleteQuerySuccess), + ); + + it('renders a correct title', () => { + expect(findTitle().exists()).toBe(true); + expect(findTitle().text()).toContain('Groups'); + }); + + it('renders the correct icon', () => { + expect(findIcon().props('name')).toBe('group'); + }); + + it('does not call query when search box has not received an input', () => { + expect(groupsAutocompleteQuerySuccess).not.toHaveBeenCalled(); + expect(findAllGroupComponents().length).toBe(0); + }); + + describe('searching', () => { + const searchResponse = GROUPS_RESPONSE_MOCK.data.groups.nodes; + const search = 'foo'; + + const emitSearchInput = async () => { + findSearchBox().vm.$emit('input', search); + await waitForPromises(); + }; + + beforeEach(() => emitSearchInput()); + + it('calls query with correct variables when Search box receives an input', () => { + expect(groupsAutocompleteQuerySuccess).toHaveBeenCalledWith({ + search, + }); + }); + + it('renders a List box component with the correct props', () => { + expect(findListBox().props()).toMatchObject({ multiple: true, items: searchResponse }); + }); + + it('renders a group component for each search result', () => { + expect(findAllGroupComponents().length).toBe(searchResponse.length); + }); + + it('emits an event when a search result is selected', () => { + const firstSearchResult = searchResponse[0]; + findAllGroupComponents().at(0).vm.$emit('select', firstSearchResult.name); + + expect(wrapper.emitted('select')).toEqual([ + [{ ...firstSearchResult, text: 'Flightjs', value: 'Flightjs' }], + ]); + }); + }); + + describe('selected items', () => { + const selectedGroup = { name: 'Flightjs' }; + const selectedItems = [selectedGroup]; + beforeEach(() => createComponent({ ...GROUPS_MOCK_PROPS, selectedItems })); + + it('renders a heading with the total selected items', () => { + expect(findTitle().text()).toContain('Groups'); + expect(findTitle().text()).toContain('1'); + }); + + it('renders a group component for each selected item', () => { + expect(findAllGroupComponents().length).toBe(selectedItems.length); + expect(findAllGroupComponents().at(0).props()).toMatchObject({ + data: selectedGroup, + canDelete: true, + }); + }); + + it('emits a delete event when a delete event is emitted from the group component', () => { + const name = 'Flightjs'; + findAllGroupComponents().at(0).vm.$emit('delete', name); + + expect(wrapper.emitted('delete')).toEqual([[name]]); + }); + }); + }); }); diff --git a/spec/frontend/vue_shared/components/list_selector/mock_data.js b/spec/frontend/vue_shared/components/list_selector/mock_data.js index ce5d209a938..25ecac9632b 100644 --- a/spec/frontend/vue_shared/components/list_selector/mock_data.js +++ b/spec/frontend/vue_shared/components/list_selector/mock_data.js @@ -23,3 +23,27 @@ export const USERS_RESPONSE_MOCK = { }, }, }; + +export const GROUPS_RESPONSE_MOCK = { + data: { + groups: { + nodes: [ + { + id: 'gid://gitlab/Group/33', + name: 'Flightjs', + fullName: 'Flightjs', + avatarUrl: null, + __typename: 'Group', + }, + { + id: 'gid://gitlab/Group/34', + name: 'Flight 2', + fullName: 'Flight2', + avatarUrl: null, + __typename: 'Group', + }, + ], + __typename: 'GroupConnection', + }, + }, +}; diff --git a/spec/frontend/vue_shared/components/list_selector/user_spec.js b/spec/frontend/vue_shared/components/list_selector/user_item_spec.js similarity index 90% rename from spec/frontend/vue_shared/components/list_selector/user_spec.js rename to spec/frontend/vue_shared/components/list_selector/user_item_spec.js index 5ce21f6672b..d84a29c67e0 100644 --- a/spec/frontend/vue_shared/components/list_selector/user_spec.js +++ b/spec/frontend/vue_shared/components/list_selector/user_item_spec.js @@ -1,14 +1,14 @@ import { GlAvatar } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; -import User from '~/vue_shared/components/list_selector/user.vue'; +import UserItem from '~/vue_shared/components/list_selector/user_item.vue'; -describe('User spec', () => { +describe('UserItem spec', () => { let wrapper; const MOCK_USER = { name: 'Admin', username: 'root', avatarUrl: 'some/avatar.jpg' }; const createComponent = (props) => { - wrapper = mountExtended(User, { + wrapper = mountExtended(UserItem, { propsData: { data: MOCK_USER, ...props, diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 0db15541b99..f5cadfc2761 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -288,13 +288,13 @@ RSpec.describe GroupsHelper, feature_category: :groups_and_projects do end it 'returns false if parent group is disabling emails' do - allow(group).to receive(:emails_disabled?).and_return(true) + allow(group).to receive(:emails_enabled?).and_return(false) expect(helper.can_disable_group_emails?(subgroup)).to be_falsey end it 'returns true if parent group is not disabling emails' do - allow(group).to receive(:emails_disabled?).and_return(false) + allow(group).to receive(:emails_enabled?).and_return(true) expect(helper.can_disable_group_emails?(subgroup)).to be_truthy end diff --git a/spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb b/spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb deleted file mode 100644 index afee3c5536e..00000000000 --- a/spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::ConfigChecker::PumaRuggedChecker do - describe '#check' do - subject { described_class.check } - - context 'application is not puma' do - before do - allow(Gitlab::Runtime).to receive(:puma?).and_return(false) - end - - it { is_expected.to be_empty } - end - - context 'application is puma' do - let(:notice_multi_threaded_puma_with_rugged) do - { - type: 'warning', - message: 'Puma is running with a thread count above 1 and the Rugged '\ - 'service is enabled. This may decrease performance in some environments. '\ - 'See our documentation '\ - 'for details of this issue.' - } - end - - before do - allow(Gitlab::Runtime).to receive(:puma?).and_return(true) - allow(described_class).to receive(:running_puma_with_multiple_threads?).and_return(multithreaded_puma) - allow(described_class).to receive(:rugged_enabled_through_feature_flag?).and_return(rugged_enabled) - end - - context 'not multithreaded_puma and rugged API enabled' do - let(:multithreaded_puma) { false } - let(:rugged_enabled) { true } - - it { is_expected.to be_empty } - end - - context 'not multithreaded_puma and rugged API is not enabled' do - let(:multithreaded_puma) { false } - let(:rugged_enabled) { false } - - it { is_expected.to be_empty } - end - - context 'multithreaded_puma and rugged API is not enabled' do - let(:multithreaded_puma) { true } - let(:rugged_enabled) { false } - - it { is_expected.to be_empty } - end - - context 'multithreaded_puma and rugged API is enabled' do - let(:multithreaded_puma) { true } - let(:rugged_enabled) { true } - - it 'report multi_threaded_puma_with_rugged notices' do - is_expected.to contain_exactly(notice_multi_threaded_puma_with_rugged) - end - end - end - end -end diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 5bb4b84835d..59cf87ddc7e 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -154,18 +154,6 @@ RSpec.describe Gitlab::Git::Blob do it_behaves_like '.find' end - describe '.find with Rugged enabled', :enable_rugged do - it 'calls out to the Rugged implementation' do - allow_next_instance_of(Rugged) do |instance| - allow(instance).to receive(:rev_parse).with(TestEnv::BRANCH_SHA['master']).and_call_original - end - - described_class.find(repository, TestEnv::BRANCH_SHA['master'], 'files/images/6049019_460s.jpg') - end - - it_behaves_like '.find' - end - describe '.raw' do let(:raw_blob) { described_class.raw(repository, SeedRepo::RubyBlob::ID) } let(:bad_blob) { described_class.raw(repository, SeedRepo::BigCommit::ID) } diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 5c4be1003c3..d8d62ac9670 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -160,18 +160,6 @@ RSpec.describe Gitlab::Git::Commit, feature_category: :source_code_management do it_behaves_like '.find' end - describe '.find with Rugged enabled', :enable_rugged do - it 'calls out to the Rugged implementation' do - allow_next_instance_of(Rugged) do |instance| - allow(instance).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original - end - - described_class.find(repository, SeedRepo::Commit::ID) - end - - it_behaves_like '.find' - end - describe '.last_for_path' do context 'no path' do subject { described_class.last_for_path(repository, 'master') } @@ -459,18 +447,6 @@ RSpec.describe Gitlab::Git::Commit, feature_category: :source_code_management do end end - describe '.batch_by_oid with Rugged enabled', :enable_rugged do - it_behaves_like '.batch_by_oid' - - it 'calls out to the Rugged implementation' do - allow_next_instance_of(Rugged) do |instance| - allow(instance).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original - end - - described_class.batch_by_oid(repository, [SeedRepo::Commit::ID]) - end - end - describe '.extract_signature_lazily' do subject { described_class.extract_signature_lazily(repository, commit_id).itself } diff --git a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb deleted file mode 100644 index d5a0ab3d5e0..00000000000 --- a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb +++ /dev/null @@ -1,116 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::Git::RuggedImpl::UseRugged, feature_category: :gitaly do - let(:project) { create(:project, :repository) } - let(:repository) { project.repository } - let(:feature_flag_name) { wrapper.rugged_feature_keys.first } - - subject(:wrapper) do - klazz = Class.new do - include Gitlab::Git::RuggedImpl::UseRugged - - def rugged_test(ref, test_number); end - end - - klazz.new - end - - describe '#execute_rugged_call', :request_store do - let(:args) { ['refs/heads/master', 1] } - - before do - allow(Gitlab::PerformanceBar).to receive(:enabled_for_request?).and_return(true) - end - - it 'instruments Rugged call' do - expect(subject).to receive(:rugged_test).with(args) - - subject.execute_rugged_call(:rugged_test, args) - - expect(Gitlab::RuggedInstrumentation.query_count).to eq(1) - expect(Gitlab::RuggedInstrumentation.list_call_details.count).to eq(1) - end - end - - describe '#use_rugged?' do - it 'returns false' do - expect(subject.use_rugged?(repository, feature_flag_name)).to be false - end - end - - describe '#running_puma_with_multiple_threads?' do - context 'when using Puma' do - before do - stub_const('::Puma', double('puma constant')) - allow(Gitlab::Runtime).to receive(:puma?).and_return(true) - end - - it "returns false when Puma doesn't support the cli_config method" do - allow(::Puma).to receive(:respond_to?).with(:cli_config).and_return(false) - - expect(subject.running_puma_with_multiple_threads?).to be_falsey - end - - it 'returns false for single thread Puma' do - allow(::Puma).to receive_message_chain(:cli_config, :options).and_return(max_threads: 1) - - expect(subject.running_puma_with_multiple_threads?).to be false - end - - it 'returns true for multi-threaded Puma' do - allow(::Puma).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2) - - expect(subject.running_puma_with_multiple_threads?).to be true - end - end - - context 'when not using Puma' do - before do - allow(Gitlab::Runtime).to receive(:puma?).and_return(false) - end - - it 'returns false' do - expect(subject.running_puma_with_multiple_threads?).to be false - end - end - end - - describe '#rugged_enabled_through_feature_flag?' do - subject { wrapper.send(:rugged_enabled_through_feature_flag?) } - - before do - allow(Feature).to receive(:enabled?).with(:feature_key_1).and_return(true) - allow(Feature).to receive(:enabled?).with(:feature_key_2).and_return(true) - allow(Feature).to receive(:enabled?).with(:feature_key_3).and_return(false) - allow(Feature).to receive(:enabled?).with(:feature_key_4).and_return(false) - - stub_const('Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS', feature_keys) - end - - context 'no feature keys given' do - let(:feature_keys) { [] } - - it { is_expected.to be_falsey } - end - - context 'all features are enabled' do - let(:feature_keys) { [:feature_key_1, :feature_key_2] } - - it { is_expected.to be_falsey } - end - - context 'all features are not enabled' do - let(:feature_keys) { [:feature_key_3, :feature_key_4] } - - it { is_expected.to be_falsey } - end - - context 'some feature is enabled' do - let(:feature_keys) { [:feature_key_4, :feature_key_2] } - - it { is_expected.to be_falsey } - end - end -end diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb index 9675e48a77f..090f9af2620 100644 --- a/spec/lib/gitlab/git/tree_spec.rb +++ b/spec/lib/gitlab/git/tree_spec.rb @@ -192,122 +192,4 @@ RSpec.describe Gitlab::Git::Tree, feature_category: :source_code_management do end end end - - describe '.where with Rugged enabled', :enable_rugged do - it 'does not call to the Rugged implementation' do - allow_next_instance_of(Rugged) do |instance| - allow(instance).not_to receive(:lookup) - end - - described_class.where(repository, SeedRepo::Commit::ID, 'files', false, false) - end - - it_behaves_like 'repo' do - describe 'Pagination' do - context 'with restrictive limit' do - let(:pagination_params) { { limit: 3, page_token: nil } } - - it 'returns limited paginated list of tree objects' do - expect(entries.count).to eq(3) - expect(cursor.next_cursor).to be_present - end - end - - context 'when limit is equal to number of entries' do - let(:entries_count) { entries.count } - - it 'returns all entries with a cursor' do - result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: entries_count, page_token: nil }) - - expect(cursor).to eq(Gitaly::PaginationCursor.new) - expect(result.entries.count).to eq(entries_count) - end - end - - context 'when limit is 0' do - let(:pagination_params) { { limit: 0, page_token: nil } } - - it 'returns empty result' do - expect(entries).to eq([]) - expect(cursor).to be_nil - end - end - - context 'when limit is missing' do - let(:pagination_params) { { limit: nil, page_token: nil } } - - it 'returns all entries' do - expect(entries.count).to be < 20 - expect(cursor).to eq(Gitaly::PaginationCursor.new) - end - end - - context 'when limit is negative' do - let(:entries_count) { entries.count } - - it 'returns all entries' do - result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: -1, page_token: nil }) - - expect(result.count).to eq(entries_count) - expect(cursor).to eq(Gitaly::PaginationCursor.new) - end - - context 'when token is provided' do - let(:pagination_params) { { limit: 1000, page_token: nil } } - let(:token) { entries.second.id } - - it 'returns all entries after token' do - result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: -1, page_token: token }) - - expect(result.count).to eq(entries.count - 2) - expect(cursor).to eq(Gitaly::PaginationCursor.new) - end - end - end - - context 'when token does not exist' do - let(:pagination_params) { { limit: 5, page_token: 'aabbccdd' } } - - it 'raises a command error' do - expect { entries }.to raise_error(Gitlab::Git::CommandError, /could not find starting OID: aabbccdd/) - end - end - - context 'when limit is bigger than number of entries' do - let(:pagination_params) { { limit: 1000, page_token: nil } } - - it 'returns only available entries' do - expect(entries.count).to be < 20 - expect(cursor).to eq(Gitaly::PaginationCursor.new) - end - end - - it 'returns all tree entries in specific order during cursor pagination' do - collected_entries = [] - token = nil - - expected_entries = entries - - loop do - result, cursor = Gitlab::Git::Tree.where(repository, sha, path, recursive, skip_flat_paths, rescue_not_found, { limit: 5, page_token: token }) - - collected_entries += result.entries - token = cursor&.next_cursor - - break if token.blank? - end - - expect(collected_entries.map(&:path)).to match_array(expected_entries.map(&:path)) - - expected_order = [ - collected_entries.select(&:dir?).map(&:path), - collected_entries.select(&:file?).map(&:path), - collected_entries.select(&:submodule?).map(&:path) - ].flatten - - expect(collected_entries.map(&:path)).to eq(expected_order) - end - end - end - end end diff --git a/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb b/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb index 0c4c8de52ae..7252f7d6afb 100644 --- a/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb +++ b/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::GitalyClient::StorageSettings do +RSpec.describe Gitlab::GitalyClient::StorageSettings, feature_category: :gitaly do describe "#initialize" do context 'when the storage contains no path' do it 'raises an error' do @@ -62,16 +62,16 @@ RSpec.describe Gitlab::GitalyClient::StorageSettings do end describe '.disk_access_denied?' do - context 'when Rugged is enabled', :enable_rugged do - it 'returns false' do - expect(described_class.disk_access_denied?).to be_falsey - end - end + subject { described_class.disk_access_denied? } - context 'when Rugged is disabled' do - it 'returns true' do - expect(described_class.disk_access_denied?).to be_truthy + it { is_expected.to be_truthy } + + context 'in case of an exception' do + before do + allow(described_class).to receive(:temporarily_allowed?).and_raise('boom') end + + it { is_expected.to be_falsey } end end end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index f9885d9081e..e873a59b54a 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -707,16 +707,6 @@ eos it_behaves_like "#uri_type" end - describe '#uri_type with Rugged enabled', :enable_rugged do - it 'calls out to the Rugged implementation' do - allow_any_instance_of(Rugged::Tree).to receive(:path).with('files/html').and_call_original - - commit.uri_type('files/html') - end - - it_behaves_like '#uri_type' - end - describe '.diff_max_files' do subject(:diff_max_files) { described_class.diff_max_files } diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 0ae4b35af7a..37b4a9011f4 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -2930,18 +2930,21 @@ RSpec.describe Group, feature_category: :groups_and_projects do end describe '.ids_with_disabled_email' do - let_it_be(:parent_1) { create(:group, emails_disabled: true) } + let_it_be(:parent_1) { create(:group) } let_it_be(:child_1) { create(:group, parent: parent_1) } - let_it_be(:parent_2) { create(:group, emails_disabled: false) } + let_it_be(:parent_2) { create(:group) } let_it_be(:child_2) { create(:group, parent: parent_2) } - let_it_be(:other_group) { create(:group, emails_disabled: false) } + let_it_be(:other_group) { create(:group) } shared_examples 'returns namespaces with disabled email' do subject(:group_ids_where_email_is_disabled) { described_class.ids_with_disabled_email([child_1, child_2, other_group]) } - it { is_expected.to eq(Set.new([child_1.id])) } + it do + parent_1.update_attribute(:emails_enabled, false) + is_expected.to eq(Set.new([child_1.id])) + end end it_behaves_like 'returns namespaces with disabled email' diff --git a/spec/models/namespace_setting_spec.rb b/spec/models/namespace_setting_spec.rb index e9822d97447..c7449e047b0 100644 --- a/spec/models/namespace_setting_spec.rb +++ b/spec/models/namespace_setting_spec.rb @@ -216,36 +216,6 @@ RSpec.describe NamespaceSetting, feature_category: :groups_and_projects, type: : end end - describe '#emails_enabled?' do - context 'when a group has no parent' - let(:settings) { create(:namespace_settings, emails_enabled: true) } - let(:grandparent) { create(:group) } - let(:parent) { create(:group, parent: grandparent) } - let(:group) { create(:group, parent: parent, namespace_settings: settings) } - - context 'when the groups setting is changed' do - it 'returns false when the attribute is false' do - group.update_attribute(:emails_disabled, true) - - expect(group.emails_enabled?).to be_falsey - end - end - - context 'when a group has a parent' do - it 'returns true when no parent has disabled emails' do - expect(group.emails_enabled?).to be_truthy - end - - context 'when ancestor emails are disabled' do - it 'returns false' do - grandparent.update_attribute(:emails_disabled, true) - - expect(group.emails_enabled?).to be_falsey - end - end - end - end - context 'when a group has parent groups' do let(:grandparent) { create(:group, namespace_settings: settings) } let(:parent) { create(:group, parent: grandparent) } @@ -269,6 +239,58 @@ RSpec.describe NamespaceSetting, feature_category: :groups_and_projects, type: : end end + describe '#emails_enabled?' do + context 'when a group has no parent' + let(:settings) { create(:namespace_settings, emails_enabled: true) } + let(:grandparent) { create(:group) } + let(:parent) { create(:group, parent: grandparent) } + let(:group) { create(:group, parent: parent, namespace_settings: settings) } + + context 'when the groups setting is changed' do + it 'returns false when the attribute is false' do + group.update_attribute(:emails_enabled, false) + + expect(group.emails_enabled?).to be_falsey + end + end + + context 'when a group has a parent' do + it 'returns true when no parent has disabled emails' do + expect(group.emails_enabled?).to be_truthy + end + + context 'when ancestor emails are disabled' do + it 'returns false' do + grandparent.update_attribute(:emails_enabled, false) + + expect(group.emails_enabled?).to be_falsey + end + end + end + + context 'when a group has parent groups' do + let(:grandparent) { create(:group, namespace_settings: settings) } + let(:parent) { create(:group, parent: grandparent) } + let!(:group) { create(:group, parent: parent) } + + context "when a parent group has emails disabled" do + let(:settings) { create(:namespace_settings, emails_enabled: false) } + + it 'returns false' do + expect(group.emails_enabled?).to be_falsey + end + end + + context 'when all parent groups have emails enabled' do + let(:settings) { create(:namespace_settings, emails_enabled: true) } + + it 'returns true' do + expect(group.emails_enabled?).to be_truthy + end + end + end + end + context 'runner registration settings' do shared_context 'with runner registration settings changing in hierarchy' do context 'when there are no parents' do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 9974aac3c6c..a460e47a0e5 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -1863,20 +1863,22 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do describe '#emails_disabled?' do context 'when not a subgroup' do + let(:group) { create(:group) } + it 'returns false' do - group = create(:group, emails_disabled: false) + group.update_attribute(:emails_enabled, true) expect(group.emails_disabled?).to be_falsey end it 'returns true' do - group = create(:group, emails_disabled: true) + group.update_attribute(:emails_enabled, false) expect(group.emails_disabled?).to be_truthy end it 'does not query the db when there is no parent group' do - group = create(:group, emails_disabled: true) + group.update_attribute(:emails_enabled, false) expect { group.emails_disabled? }.not_to exceed_query_limit(0) end @@ -1903,7 +1905,8 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do describe '#emails_enabled?' do context 'without a persisted namespace_setting object' do - let(:group) { build(:group, emails_disabled: false) } + let(:group_settings) { create(:namespace_settings) } + let(:group) { build(:group, emails_disabled: false, namespace_settings: group_settings) } it "is the opposite of emails_disabled" do expect(group.emails_enabled?).to be_truthy diff --git a/spec/models/notification_recipient_spec.rb b/spec/models/notification_recipient_spec.rb index 2275bea4c7f..f19c0a68f87 100644 --- a/spec/models/notification_recipient_spec.rb +++ b/spec/models/notification_recipient_spec.rb @@ -14,7 +14,7 @@ RSpec.describe NotificationRecipient, feature_category: :team_planning do context 'when emails are disabled' do it 'returns false if group disabled' do - expect(project.namespace).to receive(:emails_disabled?).and_return(true) + expect(project.namespace).to receive(:emails_enabled?).and_return(false) expect(recipient).to receive(:emails_disabled?).and_call_original expect(recipient.notifiable?).to eq false end @@ -28,7 +28,7 @@ RSpec.describe NotificationRecipient, feature_category: :team_planning do context 'when emails are enabled' do it 'returns true if group enabled' do - expect(project.namespace).to receive(:emails_disabled?).and_return(false) + expect(project.namespace).to receive(:emails_enabled?).and_return(true) expect(recipient).to receive(:emails_disabled?).and_call_original expect(recipient.notifiable?).to eq true end diff --git a/spec/models/project_setting_spec.rb b/spec/models/project_setting_spec.rb index 719e51018ac..8ad232b7e0c 100644 --- a/spec/models/project_setting_spec.rb +++ b/spec/models/project_setting_spec.rb @@ -214,7 +214,7 @@ RSpec.describe ProjectSetting, type: :model, feature_category: :groups_and_proje context 'when emails are enabled in parent group' do before do - allow(project.namespace).to receive(:emails_disabled?).and_return(false) + allow(project.namespace).to receive(:emails_enabled?).and_return(true) end it 'returns true' do diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index dfef955ccd5..606c4ea05b9 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -3001,10 +3001,6 @@ RSpec.describe Repository, feature_category: :source_code_management do it_behaves_like '#tree' - describe '#tree? with Rugged enabled', :enable_rugged do - it_behaves_like '#tree' - end - describe '#size' do context 'with a non-existing repository' do it 'returns 0' do @@ -3216,16 +3212,6 @@ RSpec.describe Repository, feature_category: :source_code_management do end end - describe '#ancestor? with Rugged enabled', :enable_rugged do - it 'calls out to the Rugged implementation' do - allow_any_instance_of(Rugged).to receive(:merge_base).with(repository.commit.id, Gitlab::Git::BLANK_SHA).and_call_original - - repository.ancestor?(repository.commit.id, Gitlab::Git::BLANK_SHA) - end - - it_behaves_like '#ancestor?' - end - describe '#archive_metadata' do let(:ref) { 'master' } let(:storage_path) { '/tmp' } diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index c3a7dbdcdbb..6a112918288 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -2426,16 +2426,6 @@ RSpec.describe API::Commits, feature_category: :source_code_management do expect(json_response['x509_certificate']['x509_issuer']['crl_url']).to eq(commit.signature.x509_certificate.x509_issuer.crl_url) expect(json_response['commit_source']).to eq('gitaly') end - - context 'with Rugged enabled', :enable_rugged do - it 'returns correct JSON' do - get api(route, current_user) - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['signature_type']).to eq('X509') - expect(json_response['commit_source']).to eq('gitaly') - end - end end context 'with ssh signed commit' do diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 662e11f7cfb..ee1f3deab50 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -572,7 +572,8 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do expect(json_response['require_two_factor_authentication']).to eq(group1.require_two_factor_authentication) expect(json_response['two_factor_grace_period']).to eq(group1.two_factor_grace_period) expect(json_response['auto_devops_enabled']).to eq(group1.auto_devops_enabled) - expect(json_response['emails_disabled']).to eq(group1.emails_disabled) + expect(json_response['emails_disabled']).to eq(group1.emails_disabled?) + expect(json_response['emails_enabled']).to eq(group1.emails_enabled?) expect(json_response['mentions_disabled']).to eq(group1.mentions_disabled) expect(json_response['project_creation_level']).to eq('maintainer') expect(json_response['subgroup_creation_level']).to eq('maintainer') @@ -895,7 +896,8 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do expect(json_response['require_two_factor_authentication']).to eq(false) expect(json_response['two_factor_grace_period']).to eq(48) expect(json_response['auto_devops_enabled']).to eq(nil) - expect(json_response['emails_disabled']).to eq(nil) + expect(json_response['emails_disabled']).to eq(false) + expect(json_response['emails_enabled']).to eq(true) expect(json_response['mentions_disabled']).to eq(nil) expect(json_response['project_creation_level']).to eq("noone") expect(json_response['subgroup_creation_level']).to eq("maintainer") diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d08f0f2e2ba..2dd4e92eee9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -301,13 +301,6 @@ RSpec.configure do |config| # https://gitlab.com/gitlab-org/gitlab/-/issues/385453 stub_feature_flags(vscode_web_ide: false) - enable_rugged = example.metadata[:enable_rugged].present? - - # Disable Rugged features by default - Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS.each do |flag| - stub_feature_flags(flag => enable_rugged) - end - # Disable `main_branch_over_master` as we migrate # from `master` to `main` accross our codebase. # It's done in order to preserve the concistency in tests @@ -335,8 +328,6 @@ RSpec.configure do |config| stub_feature_flags(clickhouse_data_collection: false) stub_feature_flags(vite: false) - - allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged) else unstub_all_feature_flags end @@ -393,11 +384,6 @@ RSpec.configure do |config| ::Gitlab::SafeRequestStore.ensure_request_store { example.run } end - config.around(:example, :enable_rugged) do |example| - # Skip tests that need rugged when using praefect DB. - example.run unless GitalySetup.praefect_with_db? - end - config.around(:example, :yaml_processor_feature_flag_corectness) do |example| ::Gitlab::Ci::YamlProcessor::FeatureFlags.ensure_correct_usage do example.run diff --git a/spec/support/helpers/gitaly_setup.rb b/spec/support/helpers/gitaly_setup.rb index 06390406efc..f263b3b44ce 100644 --- a/spec/support/helpers/gitaly_setup.rb +++ b/spec/support/helpers/gitaly_setup.rb @@ -72,7 +72,9 @@ module GitalySetup end def repos_path(storage = REPOS_STORAGE) - Gitlab.config.repositories.storages[REPOS_STORAGE].legacy_disk_path + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab.config.repositories.storages[REPOS_STORAGE].legacy_disk_path + end end def service_cmd(service, toml = nil) diff --git a/spec/support/matchers/navigation_matcher.rb b/spec/support/matchers/navigation_matcher.rb index a0beecbfb2c..400c2fe7436 100644 --- a/spec/support/matchers/navigation_matcher.rb +++ b/spec/support/matchers/navigation_matcher.rb @@ -1,14 +1,20 @@ # frozen_string_literal: true +# These matches look for selectors within the Vue navigation sidebar. +# They should therefore be used in feature specs with the Js driver enabled. + RSpec::Matchers.define :have_active_navigation do |expected| match do |page| - expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1) - expect(page.find('.sidebar-top-level-items > li.active')).to have_content(expected) + within_testid('super-sidebar') do + expect(page).to have_selector('button[aria-expanded="true"]', text: expected) + end end end RSpec::Matchers.define :have_active_sub_navigation do |expected| match do |page| - expect(page).to have_css('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)', text: expected) + within_testid('super-sidebar') do + expect(page).to have_selector('[aria-current="page"]', text: expected) + end end end diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index 9308d49c18a..b36f67be55e 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -3782,11 +3782,9 @@ - './spec/features/profiles/user_manages_emails_spec.rb' - './spec/features/profiles/user_search_settings_spec.rb' - './spec/features/profiles/user_visits_notifications_tab_spec.rb' -- './spec/features/profiles/user_visits_profile_account_page_spec.rb' - './spec/features/profiles/user_visits_profile_authentication_log_spec.rb' - './spec/features/profiles/user_visits_profile_preferences_page_spec.rb' - './spec/features/profiles/user_visits_profile_spec.rb' -- './spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb' - './spec/features/project_group_variables_spec.rb' - './spec/features/projects/active_tabs_spec.rb' - './spec/features/projects/activity/rss_spec.rb' @@ -5809,7 +5807,6 @@ - './spec/lib/gitlab/composer/version_index_spec.rb' - './spec/lib/gitlab/conan_token_spec.rb' - './spec/lib/gitlab/config_checker/external_database_checker_spec.rb' -- './spec/lib/gitlab/config_checker/puma_rugged_checker_spec.rb' - './spec/lib/gitlab/config/entry/attributable_spec.rb' - './spec/lib/gitlab/config/entry/boolean_spec.rb' - './spec/lib/gitlab/config/entry/composable_array_spec.rb' @@ -6216,7 +6213,6 @@ - './spec/lib/gitlab/git/remote_mirror_spec.rb' - './spec/lib/gitlab/git/repository_cleaner_spec.rb' - './spec/lib/gitlab/git/repository_spec.rb' -- './spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb' - './spec/lib/gitlab/git_spec.rb' - './spec/lib/gitlab/git/tag_spec.rb' - './spec/lib/gitlab/git/tree_spec.rb' diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb index c86fcf5ae20..dde9498eb2c 100644 --- a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb +++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb @@ -174,6 +174,8 @@ RSpec.shared_examples 'multiple issue boards' do end def assert_boards_nav_active - expect(find('.nav-sidebar .active .active')).to have_selector('a', text: 'Boards') + within_testid('super-sidebar') do + expect(page).to have_selector('[aria-current="page"]', text: 'Issue boards') + end end end diff --git a/spec/support/shared_examples/services/notification_service_shared_examples.rb b/spec/support/shared_examples/services/notification_service_shared_examples.rb index df1ae67a590..c53872ca4bc 100644 --- a/spec/support/shared_examples/services/notification_service_shared_examples.rb +++ b/spec/support/shared_examples/services/notification_service_shared_examples.rb @@ -45,7 +45,7 @@ RSpec.shared_examples 'group emails are disabled' do before do reset_delivered_emails! - target_group.clear_memoization(:emails_disabled_memoized) + target_group.clear_memoization(:emails_enabled_memoized) end it 'sends no emails with group emails disabled' do