diff options
46 files changed, 231 insertions, 136 deletions
diff --git a/.rubocop_todo/lint/redundant_cop_disable_directive.yml b/.rubocop_todo/lint/redundant_cop_disable_directive.yml index eaaf0562d9e..bbc9aecf637 100644 --- a/.rubocop_todo/lint/redundant_cop_disable_directive.yml +++ b/.rubocop_todo/lint/redundant_cop_disable_directive.yml @@ -241,7 +241,6 @@ Lint/RedundantCopDisableDirective: - 'spec/components/previews/pajamas/banner_component_preview.rb' - 'spec/controllers/concerns/preferred_language_switcher_spec.rb' - 'spec/controllers/profiles/two_factor_auths_controller_spec.rb' - - 'spec/finders/personal_access_tokens_finder_spec.rb' - 'spec/frontend/fixtures/merge_requests.rb' - 'spec/graphql/mutations/clusters/agent_tokens/create_spec.rb' - 'spec/graphql/mutations/clusters/agents/create_spec.rb' diff --git a/.rubocop_todo/rspec/feature_category.yml b/.rubocop_todo/rspec/feature_category.yml index 6a06ffef089..7f806aebbf5 100644 --- a/.rubocop_todo/rspec/feature_category.yml +++ b/.rubocop_todo/rspec/feature_category.yml @@ -1841,7 +1841,6 @@ RSpec/FeatureCategory: - 'spec/finders/packages/pypi/packages_finder_spec.rb' - 'spec/finders/packages/tags_finder_spec.rb' - 'spec/finders/pending_todos_finder_spec.rb' - - 'spec/finders/personal_access_tokens_finder_spec.rb' - 'spec/finders/personal_projects_finder_spec.rb' - 'spec/finders/projects/export_job_finder_spec.rb' - 'spec/finders/projects/groups_finder_spec.rb' diff --git a/app/assets/javascripts/ci/common/pipelines_table.vue b/app/assets/javascripts/ci/common/pipelines_table.vue index 1efde90015e..d63d2d1713e 100644 --- a/app/assets/javascripts/ci/common/pipelines_table.vue +++ b/app/assets/javascripts/ci/common/pipelines_table.vue @@ -130,8 +130,7 @@ export default { return cleanLeadingSeparator(item.project.full_path); }, failedJobsCount(pipeline) { - // Remove `pipeline?.failed_builds?.length` when we remove `ci_fix_performance_pipelines_json_endpoint`. - return pipeline?.failed_builds_count || pipeline?.failed_builds?.length || 0; + return pipeline?.failed_builds_count || 0; }, onRefreshPipelinesTable() { this.$emit('refresh-pipelines-table'); diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 1fe312269e5..a9e15c0bd90 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -159,7 +159,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo .represent( @pipelines, preload: true, - disable_failed_builds: ::Feature.enabled?(:ci_fix_performance_pipelines_json_endpoint, @project) + disable_failed_builds: true ), count: { all: @pipelines.count diff --git a/app/models/concerns/repository_storage_movable.rb b/app/models/concerns/repository_storage_movable.rb index 77edabb9706..89bdef1ccc6 100644 --- a/app/models/concerns/repository_storage_movable.rb +++ b/app/models/concerns/repository_storage_movable.rb @@ -6,6 +6,9 @@ module RepositoryStorageMovable included do scope :order_created_at_desc, -> { order(created_at: :desc) } + scope :scheduled_or_started, -> do + where(state: [state_machine.states[:scheduled].value, state_machine.states[:started].value]) + end validates :container, presence: true validates :state, presence: true diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb index ffb08e10f1f..7a80ad33d68 100644 --- a/app/models/project_snippet.rb +++ b/app/models/project_snippet.rb @@ -5,4 +5,6 @@ class ProjectSnippet < Snippet validates :project, presence: true validates :secret, inclusion: { in: [false] } + + scope :by_project, ->(project) { where(project: project) } end diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 78b0c0849e3..3e075fdaa9e 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -77,6 +77,7 @@ class Snippet < ApplicationRecord scope :inc_relations_for_view, -> { includes(author: :status) } scope :inc_statistics, -> { includes(:statistics) } scope :with_statistics, -> { joins(:statistics) } + scope :with_repository_storage_moves, -> { joins(:repository_storage_moves) } scope :inc_projects_namespace_route, -> { includes(project: [:route, :namespace]) } scope :without_created_by_banned_user, -> do diff --git a/app/models/user.rb b/app/models/user.rb index 7177f1981eb..d0aca79a57c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -800,9 +800,9 @@ class User < MainClusterwide::ApplicationRecord order = <<~SQL CASE - WHEN LOWER(users.name) = :query THEN 0 + WHEN LOWER(users.public_email) = :query THEN 0 WHEN LOWER(users.username) = :query THEN 1 - WHEN LOWER(users.public_email) = :query THEN 2 + WHEN LOWER(users.name) = :query THEN 2 ELSE 3 END SQL diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index a2a2f9d2800..8c86646ba5c 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -18,6 +18,15 @@ module Projects return false unless can?(current_user, :remove_project, project) project.update_attribute(:pending_delete, true) + + # There is a possibility of active repository move processes for + # project and snippets. An attempt to delete the project at the same time + # can lead to race condition and an inconsistent state. + # + # This validation stops the project delete process if it detects active + # repository move schedules for it. + validate_active_repositories_move! + # Flush the cache for both repositories. This has to be done _before_ # removing the physical repositories as some expiration code depends on # Git data (e.g. a list of branch names). @@ -50,6 +59,16 @@ module Projects private + def validate_active_repositories_move! + if project.repository_storage_moves.scheduled_or_started.exists? + raise_error(s_("DeleteProject|Couldn't remove the project. A project repository storage move is in progress. Try again when it's complete.")) + end + + if ::ProjectSnippet.by_project(project).with_repository_storage_moves.merge(::Snippets::RepositoryStorageMove.scheduled_or_started).exists? + raise_error(s_("DeleteProject|Couldn't remove the project. A related snippet repository storage move is in progress. Try again when it's complete.")) + end + end + def trash_project_repositories! unless remove_repository(project.repository) raise_error(s_('DeleteProject|Failed to remove project repository. Please try again or contact administrator.')) diff --git a/app/views/projects/pages/_access.html.haml b/app/views/projects/pages/_access.html.haml index 6eab31075d4..1e18e528665 100644 --- a/app/views/projects/pages/_access.html.haml +++ b/app/views/projects/pages/_access.html.haml @@ -1,7 +1,7 @@ - if @project.pages_deployed? - pages_url = build_pages_url(@project, with_unique_domain: true) - = render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5', data: { qa_selector: 'access_page_container' } }, footer_options: { class: 'gl-alert-warning' }) do |c| + = render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5', data: { testid: 'access-page-container' } }, footer_options: { class: 'gl-alert-warning' }) do |c| - c.with_header do = s_('GitLabPages|Access pages') - c.with_body do diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index 9c1f4c8643f..4fda5379876 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -17,9 +17,8 @@ - page_description(_("%{count} %{scope} for term '%{term}'") % { count: @search_results.formatted_count(@scope), scope: @scope, term: @search_term }) - page_card_attributes("Namespace" => @group&.full_path, "Project" => @project&.full_path) -.page-title-holder.gl-display-flex.gl-flex-wrap.gl-justify-content-space-between - %h1.page-title.gl-font-size-h-display.gl-mr-5= _('Search') - = render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' } +.gl-display-flex.gl-flex-wrap.gl-justify-content-end.gl-pt-6.gl-pb-5 + = render_if_exists 'search/form_elasticsearch' #js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "default-branch-name": @project&.default_branch } } .results.gl-lg-display-flex.gl-mt-0 diff --git a/config/feature_flags/development/ci_fix_performance_pipelines_json_endpoint.yml b/config/feature_flags/development/ci_fix_performance_pipelines_json_endpoint.yml deleted file mode 100644 index 069d0349181..00000000000 --- a/config/feature_flags/development/ci_fix_performance_pipelines_json_endpoint.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: ci_fix_performance_pipelines_json_endpoint -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132990 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427255 -milestone: '16.5' -type: development -group: group::pipeline authoring -default_enabled: false diff --git a/db/post_migrate/20231103132849_add_state_index_for_snippet_repository_storage_move.rb b/db/post_migrate/20231103132849_add_state_index_for_snippet_repository_storage_move.rb new file mode 100644 index 00000000000..3270a60acd8 --- /dev/null +++ b/db/post_migrate/20231103132849_add_state_index_for_snippet_repository_storage_move.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddStateIndexForSnippetRepositoryStorageMove < Gitlab::Database::Migration[2.2] + disable_ddl_transaction! + milestone '16.6' + + INDEX_NAME = 'index_snippet_repository_storage_moves_on_state' + + def up + # State 2 = scheduled and 3 = started + add_concurrent_index :snippet_repository_storage_moves, :state, where: 'state IN (2, 3)', name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :snippet_repository_storage_moves, INDEX_NAME + end +end diff --git a/db/schema_migrations/20231103132849 b/db/schema_migrations/20231103132849 new file mode 100644 index 00000000000..4ac9f938f32 --- /dev/null +++ b/db/schema_migrations/20231103132849 @@ -0,0 +1 @@ +42c514c8e4addaa7836538741d5080c16e4db330507a037abfb149907c37a6a7
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index bc15823a408..3b4dd0300a1 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -34359,6 +34359,8 @@ CREATE INDEX index_snippet_repositories_verification_state ON snippet_repositori CREATE INDEX index_snippet_repository_storage_moves_on_snippet_id ON snippet_repository_storage_moves USING btree (snippet_id); +CREATE INDEX index_snippet_repository_storage_moves_on_state ON snippet_repository_storage_moves USING btree (state) WHERE (state = ANY (ARRAY[2, 3])); + CREATE UNIQUE INDEX index_snippet_user_mentions_on_note_id ON snippet_user_mentions USING btree (note_id) WHERE (note_id IS NOT NULL); CREATE INDEX index_snippets_on_author_id ON snippets USING btree (author_id); diff --git a/doc/administration/dedicated/index.md b/doc/administration/dedicated/index.md index a517823c0cc..83105e7b557 100644 --- a/doc/administration/dedicated/index.md +++ b/doc/administration/dedicated/index.md @@ -38,7 +38,7 @@ After you first sign in to Switchboard, you must update your password and set up The following stages guide you through a series of four steps to provide the information required to create your GitLab Dedicated tenant. 1. Confirm account details: Confirm key attributes of your GitLab Dedicated account: - - Reference architecture: Corresponds with the number of users you provided to your account team when beginning the onboarding process. For more information, see [reference architectures](../../administration/reference_architectures/index.md). + - Reference architecture: Corresponds with the number of users you provided to your account team when beginning the onboarding process. For more information, see [reference architectures](../../subscriptions/gitlab_dedicated/index.md#availability-and-scalability). - Total repository storage size: Corresponds with the storage size you provided to your account team when beginning the onboarding process. - If you need to make changes to these attributes, [submit a support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650). 1. Tenant configuration: Provides the minimum required information needed to create your GitLab Dedicated tenant: diff --git a/doc/api/group_iterations.md b/doc/api/group_iterations.md index a2e23e29d89..b8cb1b7e053 100644 --- a/doc/api/group_iterations.md +++ b/doc/api/group_iterations.md @@ -16,6 +16,10 @@ There's a separate [project iterations API](iterations.md) page. Returns a list of group iterations. +Iterations created by **Enable automatic scheduling** in +[Iteration cadences](../user/group/iterations/index.md#iteration-cadences) return `null` for +the `title` and `description` fields. + ```plaintext GET /groups/:id/iterations GET /groups/:id/iterations?state=opened diff --git a/doc/api/iterations.md b/doc/api/iterations.md index 364cca9c977..ef718fffe0a 100644 --- a/doc/api/iterations.md +++ b/doc/api/iterations.md @@ -18,6 +18,10 @@ As of GitLab 13.5, we don't have project-level iterations, but you can use this Returns a list of project iterations. +Iterations created by **Enable automatic scheduling** in +[Iteration cadences](../user/group/iterations/index.md#iteration-cadences) return `null` for +the `title` and `description` fields. + ```plaintext GET /projects/:id/iterations GET /projects/:id/iterations?state=opened diff --git a/doc/development/testing_guide/end_to_end/capybara_to_chemlab_migration_guide.md b/doc/development/testing_guide/end_to_end/capybara_to_chemlab_migration_guide.md index 7bac76c88e8..025f998c0c9 100644 --- a/doc/development/testing_guide/end_to_end/capybara_to_chemlab_migration_guide.md +++ b/doc/development/testing_guide/end_to_end/capybara_to_chemlab_migration_guide.md @@ -35,44 +35,6 @@ Given the view: | ------ | ----- | | ![before](img/gl-capybara_V13_12.png) | ![after](img/gl-chemlab_V13_12.png) | -<!-- -```ruby -# frozen_string_literal: true - -module QA - module Page - class Form < Page::Base - view '_form.html' do - element :first_name - element :last_name - element :company_name - element :user_name - element :password - element :continue - end - end - end -end -``` -```ruby -# frozen_string_literal: true - -module QA - module Page - class Form < Chemlab::Page - text_field :first_name - text_field :last_name - text_field :company_name - text_field :user_name - text_field :password - - button :continue - end - end -end -``` ---> - ## Key Differences ### Page Library Design vs Page Object Design diff --git a/doc/integration/kerberos.md b/doc/integration/kerberos.md index 77d70010aa5..a01d31421ec 100644 --- a/doc/integration/kerberos.md +++ b/doc/integration/kerberos.md @@ -4,7 +4,7 @@ group: Authentication info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" --- -# Use Kerberos as an OAuth 2.0 authentication provider **(PREMIUM SELF)** +# Use Kerberos as an OAuth 2.0 authentication provider **(FREE SELF)** GitLab can integrate with [Kerberos](https://web.mit.edu/kerberos/) as an authentication mechanism. diff --git a/doc/solutions/index.md b/doc/solutions/index.md new file mode 100644 index 00000000000..bf165eadeea --- /dev/null +++ b/doc/solutions/index.md @@ -0,0 +1,15 @@ +--- +stage: Solutions Architecture +group: Solutions Architecture +info: This file is owned by the Solutions Architecture team. +--- + +# Solutions architecture + +As with all extensible platforms, GitLab has many features that can be creatively combined together with third party functionality to create solutions that address the specific people, process, and technology challenges of the organizations that use it. Reference solutions and implementations can also be crafted at a more general level so that they can be adopted and customized by customers with similar needs to the reference solution. + +This documentation is the home for solutions GitLab wishes to share with customers. + +## Relationship to documentation + +While information in this section gives valuable and qualified guidance on ways to solve problems by using the GitLab platform, the product documentation is the authoritative reference for product features and functions. diff --git a/doc/subscriptions/gitlab_dedicated/index.md b/doc/subscriptions/gitlab_dedicated/index.md index d07979cfda5..07abfb223ef 100644 --- a/doc/subscriptions/gitlab_dedicated/index.md +++ b/doc/subscriptions/gitlab_dedicated/index.md @@ -23,7 +23,10 @@ GitLab Dedicated allows you to select the cloud region where your data will be s ### Availability and scalability -GitLab Dedicated leverages the GitLab [Cloud Native Hybrid reference architectures](../../administration/reference_architectures/index.md#cloud-native-hybrid) with high availability enabled. When [onboarding](../../administration/dedicated/index.md#onboarding-to-gitlab-dedicated-using-switchboard), GitLab will match you to the closest reference architecture size based on your number of users. Learn about the [current Service Level Objective](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/#current-service-level-objective). +GitLab Dedicated leverages modified versions of the GitLab [Cloud Native Hybrid reference architectures](../../administration/reference_architectures/index.md#cloud-native-hybrid) with high availability enabled. When [onboarding](../../administration/dedicated/index.md#onboarding-to-gitlab-dedicated-using-switchboard), GitLab will match you to the closest reference architecture size based on your number of users. Learn about the [current Service Level Objective](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/#current-service-level-objective). + +NOTE: +The published [reference architectures](../../administration/reference_architectures/index.md) act as a starting point in defining the cloud resources deployed inside GitLab Dedicated environments, but they are not comprehensive. GitLab Dedicated leverages additional Cloud Provider services beyond what's included in the standard reference architectures for enhanced security and stability of the environment. Therefore, GitLab Dedicated costs differ from standard reference architecture costs. #### Disaster Recovery diff --git a/doc/tutorials/left_sidebar/index.md b/doc/tutorials/left_sidebar/index.md index 55e3b1dc30d..be631a20d50 100644 --- a/doc/tutorials/left_sidebar/index.md +++ b/doc/tutorials/left_sidebar/index.md @@ -12,12 +12,12 @@ Follow this tutorial to learn how to use the new left sidebar to navigate the UI ## Enable the new left sidebar -To view the new sidebar: +From 16.0 through 16.5, you can turn the new sidebar on and off: 1. On the left sidebar, select your avatar. -1. Turn on the **New navigation** toggle. +1. Change the **New navigation** toggle. -To turn off this sidebar, return to your avatar and turn off the toggle. +Return to your avatar to change the setting. ## Layout of the left sidebar diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md index ac0c0dd8629..43defb29fd5 100644 --- a/doc/user/packages/npm_registry/index.md +++ b/doc/user/packages/npm_registry/index.md @@ -269,7 +269,7 @@ npm deprecate @scope/package "" ### Package forwarding to npmjs.com -When an npm package is not found in the Package Registry, the request is forwarded to [npmjs.com](https://www.npmjs.com/). +When an npm package is not found in the Package Registry, the request is forwarded to [npmjs.com](https://www.npmjs.com/). The forward is performed by sending an HTTP redirect back to the requesting client. Administrators can disable this behavior in the [Continuous Integration settings](../../admin_area/settings/continuous_integration.md). diff --git a/doc/user/project/index.md b/doc/user/project/index.md index b60d87adbd3..9ee1e33ecdd 100644 --- a/doc/user/project/index.md +++ b/doc/user/project/index.md @@ -143,19 +143,24 @@ To push your repository and create a project: 1. Push with SSH or HTTPS: - To push with SSH: - ```shell - git push --set-upstream git@gitlab.example.com:namespace/myproject.git master - ``` + ```shell + # Use this version if your project uses the standard port 22 + $ git push --set-upstream git@gitlab.example.com:namespace/myproject.git main + + # Use this version if your project requires a non-standard port number + $ git push --set-upstream ssh://git@gitlab.example.com:00/namespace/myproject.git main + ``` - To push with HTTPS: - ```shell - git push --set-upstream https://gitlab.example.com/namespace/myproject.git master - ``` + ```shell + git push --set-upstream https://gitlab.example.com/namespace/myproject.git master + ``` - For `gitlab.example.com`, use the domain name of the machine that hosts your Git repository. - For `namespace`, use the name of your [namespace](../namespace/index.md). - For `myproject`, use the name of your project. + - If specifying a port, change `00` to your project's required port number. - Optional. To export existing repository tags, append the `--tags` flag to your `git push` command. 1. Optional. To configure the remote: diff --git a/generator_templates/post_deployment_migration/post_deployment_migration/migration.rb.tt b/generator_templates/post_deployment_migration/post_deployment_migration/migration.rb.tt index dbce7eb201e..005b1e9c5e9 100644 --- a/generator_templates/post_deployment_migration/post_deployment_migration/migration.rb.tt +++ b/generator_templates/post_deployment_migration/post_deployment_migration/migration.rb.tt @@ -23,6 +23,7 @@ class <%= migration_class_name %> < Gitlab::Database::Migration[<%= Gitlab::Data # Add dependent 'batched_background_migrations.queued_migration_version' values. # DEPENDENT_BATCHED_BACKGROUND_MIGRATIONS = [] + milestone '<%= Gitlab.current_milestone %>' def up end diff --git a/lib/generators/batched_background_migration/templates/queue_batched_background_migration.template b/lib/generators/batched_background_migration/templates/queue_batched_background_migration.template index 886a3bd3116..df4c5382749 100644 --- a/lib/generators/batched_background_migration/templates/queue_batched_background_migration.template +++ b/lib/generators/batched_background_migration/templates/queue_batched_background_migration.template @@ -6,6 +6,8 @@ # Update below commented lines with appropriate values. class <%= migration_class_name %> < Gitlab::Database::Migration[<%= Gitlab::Database::Migration.current_version %>] + milestone '<%= Gitlab.current_milestone %>' + MIGRATION = "<%= class_name %>" # DELAY_INTERVAL = 2.minutes # BATCH_SIZE = <%= Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers::BATCH_SIZE %> diff --git a/lib/tasks/gitlab/tw/codeowners.rake b/lib/tasks/gitlab/tw/codeowners.rake index 36ed611a0c2..7415e6c920c 100644 --- a/lib/tasks/gitlab/tw/codeowners.rake +++ b/lib/tasks/gitlab/tw/codeowners.rake @@ -76,6 +76,7 @@ namespace :tw do CodeOwnerRule.new('Runner', '@fneill'), CodeOwnerRule.new('Runner SaaS', '@fneill'), CodeOwnerRule.new('Security Policies', '@rdickenson'), + CodeOwnerRule.new('Solutions Architecture', '@jfullam @brianwald @Darwinjs'), CodeOwnerRule.new('Source Code', '@msedlakjakubowski'), CodeOwnerRule.new('Static Analysis', '@rdickenson'), CodeOwnerRule.new('Style Guide', '@sselhorn'), diff --git a/locale/gitlab.pot b/locale/gitlab.pot index afdc179ece9..0eeb0f73bba 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -16176,6 +16176,12 @@ msgstr "" msgid "Delete video" msgstr "" +msgid "DeleteProject|Couldn't remove the project. A project repository storage move is in progress. Try again when it's complete." +msgstr "" + +msgid "DeleteProject|Couldn't remove the project. A related snippet repository storage move is in progress. Try again when it's complete." +msgstr "" + msgid "DeleteProject|Failed to remove design repository. Please try again or contact administrator." msgstr "" @@ -28038,6 +28044,11 @@ msgstr "" msgid "Learn more: %{url}" msgstr "" +msgid "LearnGitLab|%d task to go" +msgid_plural "LearnGitLab|%d tasks to go" +msgstr[0] "" +msgstr[1] "" + msgid "LearnGitLab|%{percentage}%{percentSymbol} completed" msgstr "" @@ -28146,6 +28157,9 @@ msgstr "" msgid "LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:" msgstr "" +msgid "LearnGitLab|You completed all tasks!" +msgstr "" + msgid "LearnGitLab|Your team is growing! You've successfully invited new team members to the %{projectName} project." msgstr "" @@ -53114,15 +53128,15 @@ msgstr "" msgid "VulnerabilityManagement|An unverified non-confirmed finding" msgstr "" -msgid "VulnerabilityManagement|Change status" -msgstr "" - msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}." msgstr "" msgid "VulnerabilityManagement|Create Jira issue" msgstr "" +msgid "VulnerabilityManagement|Dismiss as..." +msgstr "" + msgid "VulnerabilityManagement|Enter a name" msgstr "" diff --git a/package.json b/package.json index ce3c2819411..e697cc0e95c 100644 --- a/package.json +++ b/package.json @@ -59,11 +59,10 @@ "@gitlab/favicon-overlay": "2.0.0", "@gitlab/fonts": "^1.3.0", "@gitlab/svgs": "3.69.0", - "@gitlab/ui": "67.5.2", + "@gitlab/ui": "68.0.0", "@gitlab/visual-review-tools": "1.7.3", "@gitlab/web-ide": "0.0.1-dev-20231004090414", "@mattiasbuelens/web-streams-adapter": "^0.1.0", - "@popperjs/core": "^2.11.2", "@rails/actioncable": "7.0.8", "@rails/ujs": "7.0.8", "@snowplow/browser-plugin-client-hints": "^3.9.0", diff --git a/qa/qa/page/project/settings/pages.rb b/qa/qa/page/project/settings/pages.rb index c5b8560ba9a..64990dc2991 100644 --- a/qa/qa/page/project/settings/pages.rb +++ b/qa/qa/page/project/settings/pages.rb @@ -8,11 +8,11 @@ module QA include QA::Page::Settings::Common view 'app/views/projects/pages/_access.html.haml' do - element :access_page_container + element 'access-page-container' end def go_to_access_page - within_element(:access_page_container) do + within_element('access-page-container') do find('a').click page.driver.browser.switch_to.window(page.driver.browser.window_handles.last) end diff --git a/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb index 582270c7940..579b6e43533 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb @@ -40,7 +40,7 @@ module QA end Page::Project::Menu.perform(&:go_to_pages_settings) - Page::Project::Deployments::Pages.perform(&:go_to_access_page) + Page::Project::Settings::Pages.perform(&:go_to_access_page) Support::Waiter.wait_until( sleep_interval: 2, diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb index 8381642cd4d..1ab47f6fd59 100644 --- a/spec/features/search/user_uses_header_search_field_spec.rb +++ b/spec/features/search/user_uses_header_search_field_spec.rb @@ -31,12 +31,6 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat submit_search('gitlab') end - it 'renders page title' do - page.within('.page-title') do - expect(page).to have_content('Search') - end - end - it 'renders breadcrumbs' do page.within('.breadcrumbs') do expect(page).to have_content('Search') diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb index d91b2c8f599..d7cc72fe8ed 100644 --- a/spec/finders/personal_access_tokens_finder_spec.rb +++ b/spec/finders/personal_access_tokens_finder_spec.rb @@ -2,16 +2,16 @@ require 'spec_helper' -RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do +RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode, feature_category: :system_access do using RSpec::Parameterized::TableSyntax describe '#execute' do - let(:admin) { create(:admin) } - let(:user) { create(:user) } - let(:other_user) { create(:user) } - let(:project_bot) { create(:user, :project_bot) } + let_it_be(:admin) { create(:admin) } + let_it_be(:user) { create(:user) } + let_it_be(:other_user) { create(:user) } + let_it_be(:project_bot) { create(:user, :project_bot) } - let!(:tokens) do + let_it_be(:tokens) do { active: create(:personal_access_token, user: user, name: 'my_pat_1'), active_other: create(:personal_access_token, user: other_user, name: 'my_pat_2'), @@ -24,6 +24,8 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do } end + let(:tokens_keys) { tokens.keys } + let(:params) { {} } let(:current_user) { admin } @@ -89,7 +91,7 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by user' do where(:by_user, :expected_tokens) do - nil | tokens.keys + nil | ref(:tokens_keys) ref(:user) | [:active, :expired, :revoked, :active_impersonation, :expired_impersonation, :revoked_impersonation] ref(:other_user) | [:active_other] ref(:admin) | [] @@ -106,7 +108,7 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by users' do where(:by_users, :expected_tokens) do - nil | tokens.keys + nil | ref(:tokens_keys) lazy { [user] } | [:active, :expired, :revoked, :active_impersonation, :expired_impersonation, :revoked_impersonation] lazy { [other_user] } | [:active_other] lazy { [user, other_user] } | [:active, :active_other, :expired, :revoked, :active_impersonation, :expired_impersonation, :revoked_impersonation] @@ -124,10 +126,10 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by impersonation' do where(:by_impersonation, :expected_tokens) do - nil | tokens.keys + nil | ref(:tokens_keys) true | [:active_impersonation, :expired_impersonation, :revoked_impersonation] false | [:active, :active_other, :expired, :revoked, :bot] - 'other' | tokens.keys + 'other' | ref(:tokens_keys) end with_them do @@ -141,10 +143,10 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by state' do where(:by_state, :expected_tokens) do - nil | tokens.keys + nil | ref(:tokens_keys) 'active' | [:active, :active_other, :active_impersonation, :bot] 'inactive' | [:expired, :revoked, :expired_impersonation, :revoked_impersonation] - 'other' | tokens.keys + 'other' | ref(:tokens_keys) end with_them do @@ -158,9 +160,9 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by owner type' do where(:by_owner_type, :expected_tokens) do - nil | tokens.keys + nil | ref(:tokens_keys) 'human' | [:active, :active_other, :expired, :revoked, :active_impersonation, :expired_impersonation, :revoked_impersonation] - 'other' | tokens.keys + 'other' | ref(:tokens_keys) end with_them do @@ -197,7 +199,7 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do where(:by_created_before, :expected_tokens) do 6.days.ago | [] 2.days.ago | [:active_other] - 2.days.from_now | tokens.keys + 2.days.from_now | ref(:tokens_keys) end with_them do @@ -211,7 +213,7 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by created after' do where(:by_created_after, :expected_tokens) do - 6.days.ago | tokens.keys + 6.days.ago | ref(:tokens_keys) 2.days.ago | [:active, :expired, :revoked, :active_impersonation, :expired_impersonation, :revoked_impersonation, :bot] 2.days.from_now | [] end @@ -236,7 +238,7 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do where(:by_last_used_before, :expected_tokens) do 6.days.ago | [] 2.days.ago | [:active_other] - 2.days.from_now | tokens.keys + 2.days.from_now | ref(:tokens_keys) end with_them do @@ -250,7 +252,7 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by last used after' do where(:by_last_used_after, :expected_tokens) do - 6.days.ago | tokens.keys + 6.days.ago | ref(:tokens_keys) 2.days.ago | [:active, :expired, :revoked, :active_impersonation, :expired_impersonation, :revoked_impersonation, :bot] 2.days.from_now | [] end @@ -267,7 +269,7 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'by search' do where(:by_search, :expected_tokens) do - nil | tokens.keys + nil | ref(:tokens_keys) 'my_pat' | [:active, :active_other] 'other' | [] end @@ -283,10 +285,10 @@ RSpec.describe PersonalAccessTokensFinder, :enable_admin_mode do describe 'sort' do where(:sort, :expected_tokens) do - nil | tokens.keys + nil | ref(:tokens_keys) 'id_asc' | [:active, :active_other, :expired, :revoked, :active_impersonation, :expired_impersonation, :revoked_impersonation, :bot] 'id_desc' | [:bot, :revoked_impersonation, :expired_impersonation, :active_impersonation, :revoked, :expired, :active_other, :active] - 'other' | tokens.keys + 'other' | ref(:tokens_keys) end with_them do diff --git a/spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb b/spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb index 2d48b83be4c..893cf976074 100644 --- a/spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb +++ b/spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb @@ -14,6 +14,7 @@ RSpec.describe BatchedBackgroundMigration::BatchedBackgroundMigrationGenerator, before do prepare_destination + allow(Gitlab).to receive(:current_milestone).and_return('16.6') end after do diff --git a/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt b/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt index 84a3593b4e3..36f7885b591 100644 --- a/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt +++ b/spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt @@ -6,6 +6,8 @@ # Update below commented lines with appropriate values. class QueueMyBatchedMigration < Gitlab::Database::Migration[2.2] + milestone '16.6' + MIGRATION = "MyBatchedMigration" # DELAY_INTERVAL = 2.minutes # BATCH_SIZE = 1000 diff --git a/spec/lib/gitlab/other_markup_spec.rb b/spec/lib/gitlab/other_markup_spec.rb index cdeaed6d368..266cb75a8ac 100644 --- a/spec/lib/gitlab/other_markup_spec.rb +++ b/spec/lib/gitlab/other_markup_spec.rb @@ -122,7 +122,9 @@ RSpec.describe Gitlab::OtherMarkup, feature_category: :wiki do test_text = '<A' + ('A' * 54773) expect do - Timeout.timeout(3.seconds) { RedCloth.new(test_text, [:sanitize_html]).to_html } + Timeout.timeout(Gitlab::OtherMarkup::RENDER_TIMEOUT.seconds) do + RedCloth.new(test_text, [:sanitize_html]).to_html + end end.not_to raise_error end end diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb index 3d1c87771f3..5ce9499c420 100644 --- a/spec/models/project_snippet_spec.rb +++ b/spec/models/project_snippet_spec.rb @@ -2,11 +2,24 @@ require 'spec_helper' -RSpec.describe ProjectSnippet do +RSpec.describe ProjectSnippet, feature_category: :source_code_management do describe "Associations" do it { is_expected.to belong_to(:project) } end + describe 'scopes' do + describe '.by_project' do + subject { described_class.by_project(project) } + + let_it_be(:project) { create(:project) } + let_it_be(:snippet1) { create(:project_snippet, project: project) } + let_it_be(:snippet2) { create(:project_snippet, project: build(:project)) } + let_it_be(:snippet3) { create(:personal_snippet) } + + it { is_expected.to contain_exactly(snippet1) } + end + end + describe "Validation" do it { is_expected.to validate_presence_of(:project) } it { is_expected.to validate_inclusion_of(:secret).in_array([false]) } diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 7eb1d9fda7b..ff1c5959cb0 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Snippet do +RSpec.describe Snippet, feature_category: :source_code_management do include FakeBlobHelpers describe 'modules' do @@ -26,6 +26,22 @@ RSpec.describe Snippet do it { is_expected.to have_many(:repository_storage_moves).class_name('Snippets::RepositoryStorageMove').inverse_of(:container) } end + describe 'scopes' do + describe '.with_repository_storage_moves' do + subject { described_class.with_repository_storage_moves } + + let_it_be(:snippet) { create(:project_snippet) } + + it { is_expected.to be_empty } + + context 'when associated repository storage move exists' do + let!(:snippet_repository_storage_move) { create(:snippet_repository_storage_move, container: snippet) } + + it { is_expected.to match_array([snippet]) } + end + end + end + describe 'validation' do it { is_expected.to validate_presence_of(:author) } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index cff98cdb9fb..1c4b0fafc94 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -3280,6 +3280,9 @@ RSpec.describe User, feature_category: :user_profile do end describe 'username matching' do + let_it_be(:named_john) { create(:user, name: 'John', username: 'abcd') } + let_it_be(:username_john) { create(:user, name: 'John Doe', username: 'john') } + it 'returns users with a matching username' do expect(described_class.search(user.username)).to eq([user, user2]) end @@ -3300,6 +3303,10 @@ RSpec.describe User, feature_category: :user_profile do expect(described_class.search(user2.username.upcase)).to eq([user2]) end + it 'returns users with an exact matching username first' do + expect(described_class.search('John')).to eq([username_john, named_john]) + end + it 'returns users with a exact matching username shorter than 3 chars' do expect(described_class.search(user3.username)).to eq([user3]) end diff --git a/spec/requests/projects/merge_requests_controller_spec.rb b/spec/requests/projects/merge_requests_controller_spec.rb index 4af8f4fac7f..1033a51cd80 100644 --- a/spec/requests/projects/merge_requests_controller_spec.rb +++ b/spec/requests/projects/merge_requests_controller_spec.rb @@ -187,21 +187,6 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :source_code expect(response).to have_gitlab_http_status(:ok) expect(Gitlab::Json.parse(response.body)['count']['all']).to eq(2) end - - context 'when the FF ci_fix_performance_pipelines_json_endpoint is disabled' do - before do - stub_feature_flags(ci_fix_performance_pipelines_json_endpoint: false) - end - - it 'returns the failed builds' do - get pipelines_project_merge_request_path(project, merge_request, format: :json) - - expect(response).to have_gitlab_http_status(:ok) - expect(Gitlab::Json.parse(response.body)['pipelines'].size).to eq(1) - expect(Gitlab::Json.parse(response.body)['pipelines'][0]['failed_builds_count']).to eq(2) - expect(Gitlab::Json.parse(response.body)['pipelines'][0]['failed_builds'].size).to eq(2) - end - end end private diff --git a/spec/serializers/ci/pipeline_entity_spec.rb b/spec/serializers/ci/pipeline_entity_spec.rb index 0fd9a12440f..e4ac8488c8c 100644 --- a/spec/serializers/ci/pipeline_entity_spec.rb +++ b/spec/serializers/ci/pipeline_entity_spec.rb @@ -256,7 +256,6 @@ RSpec.describe Ci::PipelineEntity, feature_category: :continuous_integration do project.add_maintainer(user) end - # Remove with `ci_fix_performance_pipelines_json_endpoint`. context 'when disable_failed_builds is true' do let(:options) { { disable_failed_builds: true } } diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 0210e101e5f..a0064eadf13 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -472,6 +472,31 @@ RSpec.describe Projects::DestroyService, :aggregate_failures, :event_store_publi end end + context 'with related storage move records' do + context 'when project has active repository storage move records' do + let!(:project_repository_storage_move) { create(:project_repository_storage_move, :scheduled, container: project) } + + it 'does not delete the project' do + expect(destroy_project(project, user)).to be_falsey + + expect(project.delete_error).to eq "Couldn't remove the project. A project repository storage move is in progress. Try again when it's complete." + expect(project.pending_delete).to be_falsey + end + end + + context 'when project has active snippet storage move records' do + let(:project_snippet) { create(:project_snippet, project: project) } + let!(:snippet_repository_storage_move) { create(:snippet_repository_storage_move, :started, container: project_snippet) } + + it 'does not delete the project' do + expect(destroy_project(project, user)).to be_falsey + + expect(project.delete_error).to eq "Couldn't remove the project. A related snippet repository storage move is in progress. Try again when it's complete." + expect(project.pending_delete).to be_falsey + end + end + end + context 'repository removal' do describe '.trash_project_repositories!' do let(:trash_project_repositories!) { described_class.new(project, user, {}).send(:trash_project_repositories!) } diff --git a/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb b/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb index a9a13ddcd60..bb382ec511c 100644 --- a/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb +++ b/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb @@ -5,6 +5,19 @@ RSpec.shared_examples 'handles repository moves' do it { is_expected.to belong_to(:container) } end + describe 'scopes' do + describe '.scheduled_or_started' do + subject { described_class.scheduled_or_started } + + let!(:initial) { create(repository_storage_factory_key, state: 1) } + let!(:scheduled) { create(repository_storage_factory_key, state: 2) } + let!(:started) { create(repository_storage_factory_key, state: 3) } + let!(:finished) { create(repository_storage_factory_key, state: 4) } + + it { is_expected.to contain_exactly(scheduled, started) } + end + end + describe 'validations' do it { is_expected.to validate_presence_of(:container) } it { is_expected.to validate_presence_of(:state) } diff --git a/spec/views/search/show.html.haml_spec.rb b/spec/views/search/show.html.haml_spec.rb index 0158a9049b9..e6d2ef02c9a 100644 --- a/spec/views/search/show.html.haml_spec.rb +++ b/spec/views/search/show.html.haml_spec.rb @@ -29,13 +29,6 @@ RSpec.describe 'search/show', feature_category: :global_search do end context 'when the search page is opened' do - it 'displays the title' do - render - - expect(rendered).to have_selector('h1.page-title', text: 'Search') - expect(rendered).not_to have_selector('h1.page-title code') - end - it 'does not render the results partial' do render diff --git a/yarn.lock b/yarn.lock index ee37317309a..6c025818d9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1274,10 +1274,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.69.0.tgz#bf76b8ffbe72a783807761a38abe8aaedcfe8c12" integrity sha512-Zu8Fcjhi3Bk26jZOptcD5F4SHWC7/KuAe00NULViCeswKdoda1k19B+9oCSbsbxY7vMoFuD20kiCJdBCpxb3HA== -"@gitlab/ui@67.5.2": - version "67.5.2" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-67.5.2.tgz#9a8d6008353b7250c1686a2a20fcae6630c97213" - integrity sha512-Qtkh9AEHjPrST/rl4SeY7Wh/ZB68GQO9jjM4Jll+3JicX3prg55uuFd4PATcq71DbXyIySZuDI/DrltgkhWByw== +"@gitlab/ui@68.0.0": + version "68.0.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-68.0.0.tgz#06228d889a1a49215b0d715b4b3dd7e583a39ff2" + integrity sha512-El0BEBqil9hqsLSHl0AuhSikYaeNcg3M6adKti/lkKn0KbTKSl48CsJy/sObQY0khuu70+OoQFeuF85KwWnxEw== dependencies: "@floating-ui/dom" "1.2.9" bootstrap-vue "2.23.1" @@ -1846,7 +1846,7 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== -"@popperjs/core@^2.11.2", "@popperjs/core@^2.9.0": +"@popperjs/core@^2.9.0": version "2.11.5" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== |