From 08608c8e9e9821858dd2f452a3c9ebfb945ab69f Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 6 Dec 2023 09:12:47 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../ci/package-and-test/main.gitlab-ci.yml | 1 + .../components/constants.js | 2 - .../continuous_vulnerability_scan.vue | 133 ---------------- .../components/feature_card.vue | 7 - .../security_configuration/index.js | 2 - .../projects/pipelines_controller.rb | 11 ++ .../project_features_compatibility.rb | 4 + app/models/concerns/routable.rb | 33 ++-- app/models/project.rb | 2 +- app/models/project_feature.rb | 2 + app/views/profiles/show.html.haml | 2 +- ...re_model_registry_access_level_updated.yml | 9 ++ ...endency_scanning_on_advisory_ingestion.yml | 8 - .../optimize_where_full_path_in.yml | 8 + .../pipeline_stage_set_last_modified.yml | 8 + config/sidekiq_queues.yml | 2 - ...y_ci_finished_builds_started_at_default.rb | 15 ++ ..._ci_finished_builds_finished_at_default.rb | 15 ++ ...id_ci_finished_builds_started_at_values.rb | 14 ++ ...egistry_access_level_to_project_feature.rb | 16 ++ db/schema_migrations/20231130195635 | 1 + db/structure.sql | 3 +- .../audit_event_types.md | 1 + .../documentation/styleguide/index.md | 2 - doc/user/permissions.md | 1 + doc/user/project/members/index.md | 1 + lib/api/helpers.rb | 4 + .../import_export/project/import_export.yml | 2 + locale/gitlab.pot | 14 +- qa/Gemfile | 4 +- qa/Gemfile.lock | 8 +- rubocop/cop/gitlab/feature_available_usage.rb | 1 + spec/factories/projects.rb | 1 + .../continuous_vulnerability_scan_spec.js | 132 ---------------- .../components/feature_card_spec.js | 18 --- .../design_management/delete_spec.rb | 69 ++++----- spec/graphql/resolvers/group_resolver_spec.rb | 2 +- .../resolvers/project_resolver_spec.rb | 2 +- .../references/alert_reference_filter_spec.rb | 10 +- .../commit_reference_filter_spec.rb | 14 +- .../references/label_reference_filter_spec.rb | 12 +- .../milestone_reference_filter_spec.rb | 2 +- .../project_reference_filter_spec.rb | 2 +- .../filter/references/reference_cache_spec.rb | 12 +- .../snippet_reference_filter_spec.rb | 10 +- .../import_export/safe_model_attributes.yml | 1 + spec/models/concerns/routable_spec.rb | 143 +++++++++++++----- spec/models/project_feature_spec.rb | 1 + spec/models/project_spec.rb | 1 + .../merge_requests/set_assignees_spec.rb | 4 +- spec/requests/api/project_attributes.yml | 1 + .../projects/pipelines_controller_spec.rb | 52 +++++++ 52 files changed, 395 insertions(+), 430 deletions(-) delete mode 100644 app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue create mode 100644 config/audit_events/types/project_feature_model_registry_access_level_updated.yml delete mode 100644 config/feature_flags/development/global_dependency_scanning_on_advisory_ingestion.yml create mode 100644 config/feature_flags/development/optimize_where_full_path_in.yml create mode 100644 config/feature_flags/development/pipeline_stage_set_last_modified.yml create mode 100644 db/click_house/migrate/20231205104100_modify_ci_finished_builds_started_at_default.rb create mode 100644 db/click_house/migrate/20231205104101_modify_ci_finished_builds_finished_at_default.rb create mode 100644 db/click_house/migrate/20231205112200_fix_invalid_ci_finished_builds_started_at_values.rb create mode 100644 db/migrate/20231130195635_add_model_registry_access_level_to_project_feature.rb create mode 100644 db/schema_migrations/20231130195635 delete mode 100644 spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml index d897ed90204..dbf88683a19 100644 --- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml +++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml @@ -359,6 +359,7 @@ oauth: variables: QA_SCENARIO: Test::Integration::OAuth rules: + - when: manual - !reference [.rules:test:qa-default-branch, rules] - if: $QA_SUITES =~ /Test::Integration::OAuth/ - !reference [.rules:test:manual, rules] diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js index da213b0ed43..fd713a7a504 100644 --- a/app/assets/javascripts/security_configuration/components/constants.js +++ b/app/assets/javascripts/security_configuration/components/constants.js @@ -1,6 +1,5 @@ import { helpPagePath } from '~/helpers/help_page_helper'; import { __, s__ } from '~/locale'; -import ContinuousVulnerabilityScan from '~/security_configuration/components/continuous_vulnerability_scan.vue'; import { REPORT_TYPE_SAST, @@ -211,7 +210,6 @@ export const securityFeatures = [ configurationHelpPath: DEPENDENCY_SCANNING_CONFIG_HELP_PATH, type: REPORT_TYPE_DEPENDENCY_SCANNING, anchor: 'dependency-scanning', - slotComponent: ContinuousVulnerabilityScan, }, { name: CONTAINER_SCANNING_NAME, diff --git a/app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue b/app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue deleted file mode 100644 index df648f665c7..00000000000 --- a/app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue +++ /dev/null @@ -1,133 +0,0 @@ - - - diff --git a/app/assets/javascripts/security_configuration/components/feature_card.vue b/app/assets/javascripts/security_configuration/components/feature_card.vue index 395bdad5dcc..2100da78219 100644 --- a/app/assets/javascripts/security_configuration/components/feature_card.vue +++ b/app/assets/javascripts/security_configuration/components/feature_card.vue @@ -73,9 +73,6 @@ export default { hasSecondary() { return Boolean(this.feature.secondary); }, - hasSlotComponent() { - return Boolean(this.feature.slotComponent); - }, // This condition is a temporary hack to not display any wrong information // until this BE Bug is fixed: https://gitlab.com/gitlab-org/gitlab/-/issues/350307. // More Information: https://gitlab.com/gitlab-org/gitlab/-/issues/350307#note_825447417 @@ -221,9 +218,5 @@ export default { {{ $options.i18n.configurationGuide }} - -
- -
diff --git a/app/assets/javascripts/security_configuration/index.js b/app/assets/javascripts/security_configuration/index.js index 4b498091134..aa3c9c87622 100644 --- a/app/assets/javascripts/security_configuration/index.js +++ b/app/assets/javascripts/security_configuration/index.js @@ -26,7 +26,6 @@ export const initSecurityConfiguration = (el) => { autoDevopsHelpPagePath, autoDevopsPath, vulnerabilityTrainingDocsPath, - continuousVulnerabilityScansEnabled, } = el.dataset; const { augmentedSecurityFeatures } = augmentFeatures( @@ -44,7 +43,6 @@ export const initSecurityConfiguration = (el) => { autoDevopsHelpPagePath, autoDevopsPath, vulnerabilityTrainingDocsPath, - continuousVulnerabilityScansEnabled, }, render(createElement) { return createElement(SecurityConfigurationApp, { diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index cd2db2dad2c..7df902d8bec 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -166,6 +166,8 @@ class Projects::PipelinesController < Projects::ApplicationController @stage = pipeline.stage(params[:stage]) return not_found unless @stage + return unless stage_stale? + render json: StageSerializer .new(project: @project, current_user: @current_user) .represent(@stage, details: true, retried: params[:retried]) @@ -263,6 +265,15 @@ class Projects::PipelinesController < Projects::ApplicationController redirect_to url_for(safe_params.except(:scope).merge(status: safe_params[:scope])), status: :moved_permanently end + def stage_stale? + return true if Feature.disabled?(:pipeline_stage_set_last_modified, @current_user) + + last_modified = [@stage.updated_at.utc, @stage.statuses.maximum(:updated_at)].max + + expires_in 24.hours + stale?(last_modified: last_modified, etag: @stage) + end + # rubocop: disable CodeReuse/ActiveRecord def pipeline return @pipeline if defined?(@pipeline) diff --git a/app/models/concerns/project_features_compatibility.rb b/app/models/concerns/project_features_compatibility.rb index c70100c03c8..1d687b29b02 100644 --- a/app/models/concerns/project_features_compatibility.rb +++ b/app/models/concerns/project_features_compatibility.rb @@ -118,6 +118,10 @@ module ProjectFeaturesCompatibility write_feature_attribute_string(:model_experiments_access_level, value) end + def model_registry_access_level=(value) + write_feature_attribute_string(:model_registry_access_level, value) + end + # TODO: Remove this method after we drop support for project create/edit APIs to set the # container_registry_enabled attribute. They can instead set the container_registry_access_level # attribute. diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb index 4c16ba18823..242194be440 100644 --- a/app/models/concerns/routable.rb +++ b/app/models/concerns/routable.rb @@ -94,16 +94,31 @@ module Routable "(LOWER(routes.path) = LOWER(#{connection.quote(path)}))" end - route = - if use_includes - includes(:route).references(:routes) - else - joins(:route) - end + if Feature.enabled?(:optimize_where_full_path_in, Feature.current_request) + route_scope = all + source_type_condition = { source_type: route_scope.klass.base_class } - route - .where(wheres.join(' OR ')) - .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046") + routes_matching_condition = Route.where(source_type_condition).where(wheres.join(' OR ')) + + result = route_scope.where(id: routes_matching_condition.pluck(:source_id)) + + if use_includes + result.preload(:route) + else + result + end + else + route = + if use_includes + includes(:route).references(:routes) + else + joins(:route) + end + + route + .where(wheres.join(' OR ')) + .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046") + end end end diff --git a/app/models/project.rb b/app/models/project.rb index 29afe9de722..bb421fc7dc6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -499,7 +499,7 @@ class Project < ApplicationRecord accepts_nested_attributes_for :prometheus_integration, update_only: true accepts_nested_attributes_for :alerting_setting, update_only: true - delegate :merge_requests_access_level, :forking_access_level, :issues_access_level, :wiki_access_level, :snippets_access_level, :builds_access_level, :repository_access_level, :package_registry_access_level, :pages_access_level, :metrics_dashboard_access_level, :analytics_access_level, :operations_access_level, :security_and_compliance_access_level, :container_registry_access_level, :environments_access_level, :feature_flags_access_level, :monitor_access_level, :releases_access_level, :infrastructure_access_level, :model_experiments_access_level, to: :project_feature, allow_nil: true + delegate :merge_requests_access_level, :forking_access_level, :issues_access_level, :wiki_access_level, :snippets_access_level, :builds_access_level, :repository_access_level, :package_registry_access_level, :pages_access_level, :metrics_dashboard_access_level, :analytics_access_level, :operations_access_level, :security_and_compliance_access_level, :container_registry_access_level, :environments_access_level, :feature_flags_access_level, :monitor_access_level, :releases_access_level, :infrastructure_access_level, :model_experiments_access_level, :model_registry_access_level, to: :project_feature, allow_nil: true delegate :name, to: :owner, allow_nil: true, prefix: true delegate :jira_dvcs_server_last_sync_at, to: :feature_usage delegate :last_pipeline, to: :commit, allow_nil: true diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 36f1e09b2ba..c8287628716 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -27,6 +27,7 @@ class ProjectFeature < ApplicationRecord releases infrastructure model_experiments + model_registry ].freeze EXPORTABLE_FEATURES = (FEATURES - [:security_and_compliance, :pages]).freeze @@ -81,6 +82,7 @@ class ProjectFeature < ApplicationRecord attribute :feature_flags_access_level, default: ENABLED attribute :environments_access_level, default: ENABLED attribute :model_experiments_access_level, default: ENABLED + attribute :model_registry_access_level, default: ENABLED attribute :package_registry_access_level, default: -> do if ::Gitlab.config.packages.enabled diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index d60c5c41f43..609db11d139 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -127,7 +127,7 @@ = f.text_field :mastodon, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: "@robin@example.com" .form-group.gl-form-group - = f.label :website_url, s_('Profiles|Website url') + = f.label :website_url, s_('Profiles|Website URL') = f.text_field :website_url, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: s_("Profiles|https://website.com") .form-group.gl-form-group = f.label :location, s_('Profiles|Location') diff --git a/config/audit_events/types/project_feature_model_registry_access_level_updated.yml b/config/audit_events/types/project_feature_model_registry_access_level_updated.yml new file mode 100644 index 00000000000..2be827cfcad --- /dev/null +++ b/config/audit_events/types/project_feature_model_registry_access_level_updated.yml @@ -0,0 +1,9 @@ +--- +name: project_feature_model_registry_access_level_updated +description: Model registry access level was updated +introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/412734 +introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138399 +feature_category: mlops +milestone: '16.7' +saved_to_database: true +streamed: true diff --git a/config/feature_flags/development/global_dependency_scanning_on_advisory_ingestion.yml b/config/feature_flags/development/global_dependency_scanning_on_advisory_ingestion.yml deleted file mode 100644 index fbede45e665..00000000000 --- a/config/feature_flags/development/global_dependency_scanning_on_advisory_ingestion.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: global_dependency_scanning_on_advisory_ingestion -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135581 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427424 -milestone: '16.6' -type: development -group: group::composition analysis -default_enabled: true diff --git a/config/feature_flags/development/optimize_where_full_path_in.yml b/config/feature_flags/development/optimize_where_full_path_in.yml new file mode 100644 index 00000000000..a47b703a958 --- /dev/null +++ b/config/feature_flags/development/optimize_where_full_path_in.yml @@ -0,0 +1,8 @@ +--- +name: optimize_where_full_path_in +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137886 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/432863 +milestone: '16.7' +type: development +group: group::tenant scale +default_enabled: false diff --git a/config/feature_flags/development/pipeline_stage_set_last_modified.yml b/config/feature_flags/development/pipeline_stage_set_last_modified.yml new file mode 100644 index 00000000000..55790f7a447 --- /dev/null +++ b/config/feature_flags/development/pipeline_stage_set_last_modified.yml @@ -0,0 +1,8 @@ +--- +name: pipeline_stage_set_last_modified +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138499 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433359 +milestone: '16.7' +type: development +group: group::global search +default_enabled: false diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 88115fab689..77503814158 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -511,8 +511,6 @@ - 1 - - package_cleanup - 1 -- - package_metadata_advisory_scan - - 1 - - package_metadata_global_advisory_scan - 1 - - package_repositories diff --git a/db/click_house/migrate/20231205104100_modify_ci_finished_builds_started_at_default.rb b/db/click_house/migrate/20231205104100_modify_ci_finished_builds_started_at_default.rb new file mode 100644 index 00000000000..00c8c825015 --- /dev/null +++ b/db/click_house/migrate/20231205104100_modify_ci_finished_builds_started_at_default.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ModifyCiFinishedBuildsStartedAtDefault < ClickHouse::Migration + def up + execute <<~SQL + ALTER TABLE ci_finished_builds MODIFY COLUMN started_at DEFAULT COALESCE(finished_at, 0) + SQL + end + + def down + execute <<~SQL + ALTER TABLE ci_finished_builds MODIFY COLUMN started_at DEFAULT now() + SQL + end +end diff --git a/db/click_house/migrate/20231205104101_modify_ci_finished_builds_finished_at_default.rb b/db/click_house/migrate/20231205104101_modify_ci_finished_builds_finished_at_default.rb new file mode 100644 index 00000000000..6ea4b158536 --- /dev/null +++ b/db/click_house/migrate/20231205104101_modify_ci_finished_builds_finished_at_default.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ModifyCiFinishedBuildsFinishedAtDefault < ClickHouse::Migration + def up + execute <<~SQL + ALTER TABLE ci_finished_builds MODIFY COLUMN finished_at DEFAULT 0 + SQL + end + + def down + execute <<~SQL + ALTER TABLE ci_finished_builds MODIFY COLUMN finished_at DEFAULT now() + SQL + end +end diff --git a/db/click_house/migrate/20231205112200_fix_invalid_ci_finished_builds_started_at_values.rb b/db/click_house/migrate/20231205112200_fix_invalid_ci_finished_builds_started_at_values.rb new file mode 100644 index 00000000000..28a63490793 --- /dev/null +++ b/db/click_house/migrate/20231205112200_fix_invalid_ci_finished_builds_started_at_values.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class FixInvalidCiFinishedBuildsStartedAtValues < ClickHouse::Migration + def up + # Fix existing records to have the new default + execute <<~SQL + ALTER TABLE ci_finished_builds UPDATE started_at = finished_at WHERE started_at > finished_at + SQL + end + + def down + # no-op as there is no way to retrieve old data + end +end diff --git a/db/migrate/20231130195635_add_model_registry_access_level_to_project_feature.rb b/db/migrate/20231130195635_add_model_registry_access_level_to_project_feature.rb new file mode 100644 index 00000000000..95675a1f82a --- /dev/null +++ b/db/migrate/20231130195635_add_model_registry_access_level_to_project_feature.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class AddModelRegistryAccessLevelToProjectFeature < Gitlab::Database::Migration[2.2] + OPERATIONS_DEFAULT_VALUE = 20 + + enable_lock_retries! + milestone '16.7' + + def change + add_column :project_features, + :model_registry_access_level, + :integer, + null: false, + default: OPERATIONS_DEFAULT_VALUE + end +end diff --git a/db/schema_migrations/20231130195635 b/db/schema_migrations/20231130195635 new file mode 100644 index 00000000000..5e8d8232feb --- /dev/null +++ b/db/schema_migrations/20231130195635 @@ -0,0 +1 @@ +5c9d89f5d5401d6a7082d5790cb12ee610a0a06138cf3608534a09685c812ea8 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index c64a5a234c4..3596bb114ca 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -21881,7 +21881,8 @@ CREATE TABLE project_features ( feature_flags_access_level integer DEFAULT 20 NOT NULL, environments_access_level integer DEFAULT 20 NOT NULL, releases_access_level integer DEFAULT 20 NOT NULL, - model_experiments_access_level integer DEFAULT 20 NOT NULL + model_experiments_access_level integer DEFAULT 20 NOT NULL, + model_registry_access_level integer DEFAULT 20 NOT NULL ); CREATE SEQUENCE project_features_id_seq diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md index fa89074ad53..cc396a6345c 100644 --- a/doc/administration/audit_event_streaming/audit_event_types.md +++ b/doc/administration/audit_event_streaming/audit_event_types.md @@ -313,6 +313,7 @@ Audit event types belong to the following product categories. | Name | Description | Saved to database | Streamed | Introduced in | |:-----|:------------|:------------------|:---------|:--------------| | [`project_feature_model_experiments_access_level_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121027) | Model experiments access level was updated| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/412384) | +| [`project_feature_model_registry_access_level_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138399) | Model registry access level was updated| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.7](https://gitlab.com/gitlab-org/gitlab/-/issues/412734) | ### Not categorized diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md index 6109d4d603d..3a3dbc8c50d 100644 --- a/doc/development/documentation/styleguide/index.md +++ b/doc/development/documentation/styleguide/index.md @@ -218,8 +218,6 @@ Use sentence case for topic titles. For example: When referring to specific user interface text, like a button label or menu item, use the same capitalization that's displayed in the user interface. -Standards for this content are listed in the [Pajamas Design System Content section](https://design.gitlab.com/content/punctuation/) -and typically match what's mentioned in this Documentation Style Guide. If you think the user interface text contains style mistakes, create an issue or an MR to propose a change to the user interface text. diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 6b1ffee85c0..87ac456d8c3 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -406,6 +406,7 @@ The following table lists group permissions available for each role: | Manage group runners | | | | | ✓ | | [Migrate groups](group/import/index.md) | | | | | ✓ | | Manage [subscriptions, and purchase storage and compute minutes](../subscriptions/gitlab_com/index.md) | | | | | ✓ | +| Manage group-level custom roles | | | | | ✓ | diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md index 0c191ca1b14..f242a2d891b 100644 --- a/doc/user/project/members/index.md +++ b/doc/user/project/members/index.md @@ -116,6 +116,7 @@ to perform actions. Prerequisites: - You must have the Owner or Maintainer role. +- [Group membership lock](../../group/access_and_permissions.md#prevent-members-from-being-added-to-projects-in-a-group) must be disabled. To add a user to a project: diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 7c57666b843..f5dcbc07704 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -378,6 +378,10 @@ module API authorize! :admin_group, user_group end + def authorize_admin_member_role! + authorize! :admin_member_role, user_group + end + def authorize_read_builds! authorize! :read_build, user_project end diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml index 6f3601e9a21..e38930ed548 100644 --- a/lib/gitlab/import_export/project/import_export.yml +++ b/lib/gitlab/import_export/project/import_export.yml @@ -318,6 +318,7 @@ included_attributes: - :releases_access_level - :infrastructure_access_level - :model_experiments_access_level + - :model_registry_access_level prometheus_metrics: - :created_at - :updated_at @@ -738,6 +739,7 @@ included_attributes: - :releases_access_level - :infrastructure_access_level - :model_experiments_access_level + - :model_registry_access_level - :auto_devops_deploy_strategy - :auto_devops_enabled - :container_registry_enabled diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 2b91923b9f4..8cf0c45c7a7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -9441,18 +9441,6 @@ msgstr "" msgid "CVE|Why Request a CVE ID?" msgstr "" -msgid "CVS|By enabling this feature, you accept the %{linkStart}Testing Terms of Use%{linkEnd}" -msgstr "" - -msgid "CVS|Continuous Vulnerability Scan" -msgstr "" - -msgid "CVS|Detect vulnerabilities outside a pipeline as new data is added to the GitLab Advisory Database." -msgstr "" - -msgid "CVS|Toggle CVS" -msgstr "" - msgid "Cadence is not automated" msgstr "" @@ -37150,7 +37138,7 @@ msgstr "" msgid "Profiles|Using emoji in names seems fun, but please try to set a status message instead" msgstr "" -msgid "Profiles|Website url" +msgid "Profiles|Website URL" msgstr "" msgid "Profiles|Who you represent or work for." diff --git a/qa/Gemfile b/qa/Gemfile index 47b6c7daf39..33f50c30139 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' -gem 'gitlab-qa', '~> 12', '>= 12.5.1', require: 'gitlab/qa' +gem 'gitlab-qa', '~> 13', require: 'gitlab/qa' gem 'gitlab_quality-test_tooling', '~> 1.8.1', require: false gem 'gitlab-utils', path: '../gems/gitlab-utils' gem 'activesupport', '~> 7.0.8' # This should stay in sync with the root's Gemfile @@ -26,7 +26,7 @@ gem 'rspec-parameterized', '~> 1.0.0' gem 'octokit', '~> 8.0.0' gem "faraday-retry", "~> 2.2" gem 'zeitwerk', '~> 2.6', '>= 2.6.12' -gem 'influxdb-client', '~> 2.9' +gem 'influxdb-client', '~> 3.0' gem 'terminal-table', '~> 3.0.2', require: false gem 'slack-notifier', '~> 2.4', require: false gem 'fog-google', '~> 1.19', require: false diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index f8083fcfd22..e79bfeff4ef 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -123,7 +123,7 @@ GEM gitlab (4.19.0) httparty (~> 0.20) terminal-table (>= 1.5.1) - gitlab-qa (12.5.1) + gitlab-qa (13.0.0) activesupport (>= 6.1, < 7.1) gitlab (~> 4.19) http (~> 5.0) @@ -189,7 +189,7 @@ GEM httpclient (2.8.3) i18n (1.12.0) concurrent-ruby (~> 1.0) - influxdb-client (2.9.0) + influxdb-client (3.0.0) jwt (2.5.0) knapsack (4.0.0) rake @@ -363,10 +363,10 @@ DEPENDENCIES faraday-retry (~> 2.2) fog-core (= 2.1.0) fog-google (~> 1.19) - gitlab-qa (~> 12, >= 12.5.1) + gitlab-qa (~> 13) gitlab-utils! gitlab_quality-test_tooling (~> 1.8.1) - influxdb-client (~> 2.9) + influxdb-client (~> 3.0) knapsack (~> 4.0) nokogiri (~> 1.15, >= 1.15.5) octokit (~> 8.0.0) diff --git a/rubocop/cop/gitlab/feature_available_usage.rb b/rubocop/cop/gitlab/feature_available_usage.rb index 307ff7ea6f6..0b1c4367eae 100644 --- a/rubocop/cop/gitlab/feature_available_usage.rb +++ b/rubocop/cop/gitlab/feature_available_usage.rb @@ -29,6 +29,7 @@ module RuboCop releases infrastructure model_experiments + model_registry ].freeze EE_FEATURES = %i[requirements].freeze ALL_FEATURES = (FEATURES + EE_FEATURES).freeze diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index a1d56194ba5..82fdeea9557 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -43,6 +43,7 @@ FactoryBot.define do releases_access_level { ProjectFeature::ENABLED } infrastructure_access_level { ProjectFeature::ENABLED } model_experiments_access_level { ProjectFeature::ENABLED } + model_registry_access_level { ProjectFeature::ENABLED } # we can't assign the delegated `#ci_cd_settings` attributes directly, as the # `#ci_cd_settings` relation needs to be created first diff --git a/spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js b/spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js deleted file mode 100644 index c395c91d880..00000000000 --- a/spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js +++ /dev/null @@ -1,132 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { GlBadge, GlToggle } from '@gitlab/ui'; -import VueApollo from 'vue-apollo'; -import Vue from 'vue'; -import ProjectSetContinuousVulnerabilityScanning from '~/security_configuration/graphql/project_set_continuous_vulnerability_scanning.graphql'; -import ContinuousVulnerabilityScan from '~/security_configuration/components/continuous_vulnerability_scan.vue'; -import createMockApollo from 'helpers/mock_apollo_helper'; - -Vue.use(VueApollo); - -const setCVSMockResponse = { - data: { - projectSetContinuousVulnerabilityScanning: { - continuousVulnerabilityScanningEnabled: true, - errors: [], - }, - }, -}; - -const defaultProvide = { - continuousVulnerabilityScansEnabled: true, - projectFullPath: 'project/full/path', -}; - -describe('ContinuousVulnerabilityScan', () => { - let wrapper; - let apolloProvider; - let requestHandlers; - - const createComponent = (options) => { - requestHandlers = { - setCVSMutationHandler: jest.fn().mockResolvedValue(setCVSMockResponse), - }; - - apolloProvider = createMockApollo([ - [ProjectSetContinuousVulnerabilityScanning, requestHandlers.setCVSMutationHandler], - ]); - - wrapper = shallowMount(ContinuousVulnerabilityScan, { - propsData: { - feature: { - available: true, - configured: true, - }, - }, - provide: { - glFeatures: { - dependencyScanningOnAdvisoryIngestion: true, - globalDependencyScanningOnAdvisoryIngestion: false, - }, - ...defaultProvide, - }, - apolloProvider, - ...options, - }); - }; - - beforeEach(() => { - createComponent(); - }); - - afterEach(() => { - apolloProvider = null; - }); - - const findBadge = () => wrapper.findComponent(GlBadge); - const findToggle = () => wrapper.findComponent(GlToggle); - - it('renders the component', () => { - expect(wrapper.exists()).toBe(true); - }); - - it('renders the correct title', () => { - expect(wrapper.text()).toContain('Continuous Vulnerability Scan'); - }); - - it('renders the badge and toggle component with correct values', () => { - expect(findBadge().exists()).toBe(true); - expect(findBadge().text()).toBe('Experiment'); - - expect(findToggle().exists()).toBe(true); - expect(findToggle().props('value')).toBe(defaultProvide.continuousVulnerabilityScansEnabled); - }); - - it('should disable toggle when feature is not configured', () => { - createComponent({ - propsData: { - feature: { - available: true, - configured: false, - }, - }, - }); - expect(findToggle().props('disabled')).toBe(true); - }); - - it('calls mutation on toggle change with correct payload', () => { - findToggle().vm.$emit('change', true); - - expect(requestHandlers.setCVSMutationHandler).toHaveBeenCalledWith({ - input: { - projectPath: 'project/full/path', - enable: true, - }, - }); - }); - - describe('when feature flag is disabled', () => { - it.each` - dependencyScanningOnAdvisoryIngestion | globalDependencyScanningOnAdvisoryIngestion - ${false} | ${false} - ${true} | ${true} - ${false} | ${true} - `( - 'when dependencyScanningOnAdvisoryIngestion: `$dependencyScanningOnAdvisoryIngestion` and globalDependencyScanningOnAdvisoryIngestion: `$globalDependencyScanningOnAdvisoryIngestion` should not render toggle and badge', - ({ dependencyScanningOnAdvisoryIngestion, globalDependencyScanningOnAdvisoryIngestion }) => { - createComponent({ - provide: { - glFeatures: { - dependencyScanningOnAdvisoryIngestion, - globalDependencyScanningOnAdvisoryIngestion, - }, - ...defaultProvide, - }, - }); - - expect(findToggle().exists()).toBe(false); - expect(findBadge().exists()).toBe(false); - }, - ); - }); -}); diff --git a/spec/frontend/security_configuration/components/feature_card_spec.js b/spec/frontend/security_configuration/components/feature_card_spec.js index c715d01dd58..983a66a7fd3 100644 --- a/spec/frontend/security_configuration/components/feature_card_spec.js +++ b/spec/frontend/security_configuration/components/feature_card_spec.js @@ -1,6 +1,5 @@ import { GlIcon } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; -import Vue from 'vue'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { securityFeatures } from '~/security_configuration/components/constants'; import FeatureCard from '~/security_configuration/components/feature_card.vue'; @@ -14,10 +13,6 @@ import { import { manageViaMRErrorMessage } from '../constants'; import { makeFeature } from './utils'; -const MockComponent = Vue.component('MockComponent', { - render: (createElement) => createElement('span'), -}); - describe('FeatureCard component', () => { let feature; let wrapper; @@ -394,17 +389,4 @@ describe('FeatureCard component', () => { }); }); }); - - describe('when a slot component is passed', () => { - beforeEach(() => { - feature = makeFeature({ - slotComponent: MockComponent, - }); - createComponent({ feature }); - }); - - it('renders the component properly', () => { - expect(wrapper.findComponent(MockComponent).exists()).toBe(true); - }); - }); }); diff --git a/spec/graphql/mutations/design_management/delete_spec.rb b/spec/graphql/mutations/design_management/delete_spec.rb index 1b78529fbc7..7f499301543 100644 --- a/spec/graphql/mutations/design_management/delete_spec.rb +++ b/spec/graphql/mutations/design_management/delete_spec.rb @@ -86,46 +86,47 @@ RSpec.describe Mutations::DesignManagement::Delete do end end - it 'runs no more than 31 queries' do + it 'runs no more than 34 queries' do allow(Gitlab::Tracking).to receive(:event) # rubocop:disable RSpec/ExpectGitlabTracking filenames.each(&:present?) # ignore setup - # Queries: as of 2022-09-08 + # Queries: as of 2022-12-01 # ------------- - # 01. routing query - # 02. policy query: find namespace by type and id - # 03. policy query: find namespace by id - # 04. policy query: project.project_feature - # 05,06. project.authorizations for user (same query twice) - # 07. find issue by iid - # 08. find project by id - # 09. find namespace by id - # 10. find group namespace by id - # 11. policy query: find namespace by id (same query as 3) - # 12. project.authorizations for user (same query as 5) - # 13. find user by id - # 14. project.project_features (same query as 3) - # 15. project.authorizations for user (same query as 5) - # 16. current designs by filename and issue - # 17, 18 project.authorizations for user (same query as 5) - # 19. find design_management_repository for project - # 20. find route by id and source_type + # 01. for routes to find routes.source_id of projects matching paths + # 02. Find projects with the above source id. + # 03. preload routes of the above projects + # 04. policy query: find namespace by type and id + # 05. policy query: namespace_bans + # 06. policy query: project.project_feature + # 07,08. project.authorizations for user (same query twice) + # 09. find issue by iid + # 10. find project by id + # 11. find namespace by id + # 12. policy query: find namespace by type and id (same query as 4) + # 13. project.authorizations for user (same query as 7) + # 14. find user by id + # 15. project.project_features (same query as 6) + # 16. project.authorizations for user (same query as 7) + # 17. current designs by filename and issue + # 18, 19 project.authorizations for user (same query as 7) + # 20. find design_management_repository for project + # 21. find route by source_id and source_type # ------------- our queries are below: - # 21. start transaction - # 22. create version with sha and issue - # 23. create design-version links - # 24. validate version.actions.present? - # 25. validate version.sha is unique - # 26. validate version.issue.present? - # 27. leave transaction - # 28. find project by id (same query as 8) - # 29. find namespace by id (same query as 9) - # 30. find project by id (same query as 8) - # 31. find project by id (same query as 8) - # 32. create event - # 33. find plan for standard context + # 22. start transaction + # 23. create version with sha and issue + # 24. create design-version links + # 25. validate version.actions.present? + # 26. validate version.sha is unique + # 27. validate version.issue.present? + # 28. leave transaction + # 29. find project by id (same query as 10) + # 30. find namespace by id (same query as 11) + # 31. find project by id (same query as 10) + # 32. find project by id (same query as 10) + # 33. create event + # 34. find plan for standard context # - expect { run_mutation }.not_to exceed_query_limit(33) + expect { run_mutation }.not_to exceed_query_limit(34) end end diff --git a/spec/graphql/resolvers/group_resolver_spec.rb b/spec/graphql/resolvers/group_resolver_spec.rb index ed406d14772..c04961b4804 100644 --- a/spec/graphql/resolvers/group_resolver_spec.rb +++ b/spec/graphql/resolvers/group_resolver_spec.rb @@ -12,7 +12,7 @@ RSpec.describe Resolvers::GroupResolver do it 'batch-resolves groups by full path' do paths = [group1.full_path, group2.full_path] - result = batch_sync(max_queries: 1) do + result = batch_sync(max_queries: 3) do paths.map { |path| resolve_group(path) } end diff --git a/spec/graphql/resolvers/project_resolver_spec.rb b/spec/graphql/resolvers/project_resolver_spec.rb index dec9d4701e1..03febc75d3f 100644 --- a/spec/graphql/resolvers/project_resolver_spec.rb +++ b/spec/graphql/resolvers/project_resolver_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Resolvers::ProjectResolver do it 'batch-resolves projects by full path' do paths = [project1.full_path, project2.full_path] - result = batch_sync(max_queries: 1) do + result = batch_sync(max_queries: 3) do paths.map { |path| resolve_project(path) } end diff --git a/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb b/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb index 9723e9b39f1..9a2e68aaae0 100644 --- a/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb @@ -240,9 +240,15 @@ RSpec.describe Banzai::Filter::References::AlertReferenceFilter, feature_categor # Since we're not batching alert queries across projects, # we have to account for that. - # 1 for both projects, 1 for alerts in each project == 3 + # 1 for routes to find routes.source_id of projects matching paths + # 1 for projects belonging to the above routes + # 1 for preloading routes of the projects + # 1 for loading the namespaces associated to the project + # 1 for loading the routes associated with the namespace + # 1x2 for alerts in each project + # Total == 7 # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/330359 - max_count += 2 + max_count += 6 expect do reference_filter(markdown) diff --git a/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb index 6e0f9eda0e2..35a3f20f7b7 100644 --- a/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb @@ -287,12 +287,18 @@ RSpec.describe Banzai::Filter::References::CommitReferenceFilter, feature_catego reference_filter(markdown) end.count - markdown = "#{commit_reference} 8b95f2f1 8b95f2f2 8b95f2f3 #{commit2_reference} #{commit3_reference}" + expect(max_count).to eq 0 + + markdown = "#{commit_reference} 8b95f2f1 8b95f2f2 8b95f2f3 #{commit2_reference} #{commit3_reference}" # Commits are not DB entries, they are on the project itself. - # So adding commits from two more projects to the markdown should - # only increase by 1 query - max_count += 1 + # 1 for for routes to find routes.source_id of projects matching paths + # 1 for projects belonging to the above routes + # 1 for preloading routes of the projects + # 1 for loading the namespaces associated to the project + # 1 for loading the routes associated with the namespace + # Total = 5 + max_count += 5 expect do reference_filter(markdown) diff --git a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb index a4587b70dfa..81b08a4c516 100644 --- a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb @@ -747,10 +747,16 @@ RSpec.describe Banzai::Filter::References::LabelReferenceFilter, feature_categor # Since we're not batching label queries across projects/groups, # queries increase when a new project/group is added. # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/330359 - # first reference to already loaded project (1), - # second reference requires project and namespace (2), and label (1) + # 1 for for routes to find routes.source_id of projects matching paths + # 1 for projects belonging to the above routes + # 1 for preloading routes of the projects + # 1 for loading the namespaces associated to the project + # 1 for loading the routes associated with the namespace + # 1 for the group + # 1x2 for labels + # Total == 8 markdown = "#{project_reference} #{group2_reference}" - max_count = control_count + 3 + max_count = control_count + 7 expect do reference_filter(markdown) diff --git a/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb index 1fa62d70b72..e778f07227c 100644 --- a/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb @@ -522,7 +522,7 @@ RSpec.describe Banzai::Filter::References::MilestoneReferenceFilter, feature_cat # queries increase when a new project/group is added. # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/330359 markdown = "#{project_reference} #{group2_reference}" - control_count += 5 + control_count += 9 expect do reference_filter(markdown) diff --git a/spec/lib/banzai/filter/references/project_reference_filter_spec.rb b/spec/lib/banzai/filter/references/project_reference_filter_spec.rb index 9433862ac8a..c55fff78756 100644 --- a/spec/lib/banzai/filter/references/project_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/project_reference_filter_spec.rb @@ -119,7 +119,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter, feature_categ reference_filter(markdown) end.count - expect(max_count).to eq 1 + expect(max_count).to eq 2 markdown = "#{normal_project_reference} #{invalidate_reference(normal_project_reference)} #{group_project_reference} #{nested_project_reference}" diff --git a/spec/lib/banzai/filter/references/reference_cache_spec.rb b/spec/lib/banzai/filter/references/reference_cache_spec.rb index 577e4471433..04877931610 100644 --- a/spec/lib/banzai/filter/references/reference_cache_spec.rb +++ b/spec/lib/banzai/filter/references/reference_cache_spec.rb @@ -79,8 +79,16 @@ RSpec.describe Banzai::Filter::References::ReferenceCache, feature_category: :te expect(control_count).to eq 3 # Since this is an issue filter that is not batching issue queries # across projects, we have to account for that. - # 1 for original issue, 2 for second route/project, 1 for other issue - max_count = control_count + 4 + # 1 for for routes to find routes.source_id of projects matching paths + # 1 for projects belonging to the above routes + # 1 for preloading routes of the projects + # 1 for loading the namespaces associated to the project + # 1 for loading the routes associated with the namespace + # 1x2 for issues + # 1x2 for groups + # 1x2 for work_item_types + # Total = 11 + max_count = control_count + 8 expect do cache.load_references_per_parent(filter.nodes) diff --git a/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb index b196d85ba8a..00eac7262f4 100644 --- a/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb @@ -239,9 +239,15 @@ RSpec.describe Banzai::Filter::References::SnippetReferenceFilter, feature_categ # Since we're not batching snippet queries across projects, # we have to account for that. - # 1 for both projects, 1 for snippets in each project == 3 + # 1 for for routes to find routes.source_id of projects matching paths + # 1 for projects belonging to the above routes + # 1 for preloading routes of the projects + # 1 for loading the namespaces associated to the project + # 1 for loading the routes associated with the namespace + # 1x2 for snippets in each project == 2 + # Total = 7 # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/330359 - max_count = control_count + 2 + max_count = control_count + 6 expect do reference_filter(markdown) diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index e0efa1bfd38..3efa33d8879 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -706,6 +706,7 @@ ProjectFeature: - monitor_access_level - infrastructure_access_level - model_experiments_access_level +- model_registry_access_level - created_at - updated_at ProtectedBranch::MergeAccessLevel: diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index 7e324812b97..e71392f7bbc 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.shared_examples 'routable resource' do - shared_examples_for '.find_by_full_path' do |has_cross_join: false| + shared_examples_for '.find_by_full_path' do it 'finds records by their full path' do expect(described_class.find_by_full_path(record.full_path)).to eq(record) expect(described_class.find_by_full_path(record.full_path.upcase)).to eq(record) @@ -46,22 +46,98 @@ RSpec.shared_examples 'routable resource' do end end - if has_cross_join - it 'has a cross-join' do - expect(Gitlab::Database).to receive(:allow_cross_joins_across_databases) + it 'does not have cross-join' do + expect(Gitlab::Database).not_to receive(:allow_cross_joins_across_databases) - described_class.find_by_full_path(record.full_path) - end - else - it 'does not have cross-join' do - expect(Gitlab::Database).not_to receive(:allow_cross_joins_across_databases) - - described_class.find_by_full_path(record.full_path) - end + described_class.find_by_full_path(record.full_path) end end it_behaves_like '.find_by_full_path', :aggregate_failures + + shared_examples_for '.where_full_path_in' do + context 'without any paths' do + it 'returns an empty relation' do + expect(described_class.where_full_path_in([])).to eq([]) + end + end + + context 'without any valid paths' do + it 'returns an empty relation' do + expect(described_class.where_full_path_in(%w[unknown])).to eq([]) + end + end + + context 'with valid paths' do + it 'returns the entities matching the paths' do + result = described_class.where_full_path_in([record.full_path, record_2.full_path]) + + expect(result).to contain_exactly(record, record_2) + end + + it 'returns entities regardless of the casing of paths' do + result = described_class.where_full_path_in([record.full_path.upcase, record_2.full_path.upcase]) + + expect(result).to contain_exactly(record, record_2) + end + end + + context 'on the usage of `use_includes` parameter' do + let_it_be(:klass) { record.class.to_s.downcase } + let_it_be(:record_3) { create(:"#{klass}") } + let_it_be(:record_4) { create(:"#{klass}") } + + context 'when use_includes: true' do + it 'includes route information when loading records' do + control_count = ActiveRecord::QueryRecorder.new do + described_class.where_full_path_in([record.full_path, record_2.full_path], use_includes: true) + .map(&:route) + end + + expect do + described_class.where_full_path_in( + [ + record.full_path, + record_2.full_path, + record_3.full_path, + record_4.full_path + ], use_includes: true) + .map(&:route) + end.to issue_same_number_of_queries_as(control_count) + end + end + + context 'when use_includes: false' do + it 'does not include route information when loading records' do + control_count = ActiveRecord::QueryRecorder.new do + described_class.where_full_path_in([record.full_path, record_2.full_path], use_includes: false) + .map(&:route) + end + + expect do + described_class.where_full_path_in( + [ + record.full_path, + record_2.full_path, + record_3.full_path, + record_4.full_path + ], use_includes: false) + .map(&:route) + end.not_to issue_same_number_of_queries_as(control_count) + end + end + end + end + + it_behaves_like '.where_full_path_in', :aggregate_failures + + context 'when the `optimize_where_full_path_in` feature flag is turned OFF' do + before do + stub_feature_flags(optimize_where_full_path_in: false) + end + + it_behaves_like '.where_full_path_in', :aggregate_failures + end end RSpec.shared_examples 'routable resource with parent' do @@ -105,10 +181,12 @@ RSpec.describe Group, 'Routable', :with_clean_rails_cache, feature_category: :gr it_behaves_like 'routable resource' do let_it_be(:record) { group } + let_it_be(:record_2) { nested_group } end it_behaves_like 'routable resource with parent' do let_it_be(:record) { nested_group } + let_it_be(:record_2) { group } end describe 'Validations' do @@ -169,34 +247,6 @@ RSpec.describe Group, 'Routable', :with_clean_rails_cache, feature_category: :gr expect(group.route.namespace).to eq(group) end - describe '.where_full_path_in' do - context 'without any paths' do - it 'returns an empty relation' do - expect(described_class.where_full_path_in([])).to eq([]) - end - end - - context 'without any valid paths' do - it 'returns an empty relation' do - expect(described_class.where_full_path_in(%w[unknown])).to eq([]) - end - end - - context 'with valid paths' do - it 'returns the projects matching the paths' do - result = described_class.where_full_path_in([group.to_param, nested_group.to_param]) - - expect(result).to contain_exactly(group, nested_group) - end - - it 'returns projects regardless of the casing of paths' do - result = described_class.where_full_path_in([group.to_param.upcase, nested_group.to_param.upcase]) - - expect(result).to contain_exactly(group, nested_group) - end - end - end - describe '#parent_loaded?' do before do group.parent = create(:group) @@ -232,9 +282,11 @@ end RSpec.describe Project, 'Routable', :with_clean_rails_cache, feature_category: :groups_and_projects do let_it_be(:namespace) { create(:namespace) } let_it_be(:project) { create(:project, namespace: namespace) } + let_it_be(:project_2) { create(:project) } it_behaves_like 'routable resource with parent' do let_it_be(:record) { project } + let_it_be(:record_2) { project_2 } end it 'creates route with namespace referencing project namespace' do @@ -252,6 +304,17 @@ RSpec.describe Project, 'Routable', :with_clean_rails_cache, feature_category: : expect(record).to be_nil end end + + describe '.where_full_path_in' do + it 'does not return records if the sources are different, but the IDs match' do + group = create(:group, id: 1992) + project = create(:project, id: 1992) + + records = described_class.where(id: project.id).where_full_path_in([group.full_path]) + + expect(records).to be_empty + end + end end RSpec.describe Namespaces::ProjectNamespace, 'Routable', :with_clean_rails_cache, feature_category: :groups_and_projects do diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index c0a78ff2f53..149b0d4df8c 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -31,6 +31,7 @@ RSpec.describe ProjectFeature, feature_category: :groups_and_projects do specify { expect(subject.package_registry_access_level).to eq(ProjectFeature::ENABLED) } specify { expect(subject.container_registry_access_level).to eq(ProjectFeature::ENABLED) } specify { expect(subject.model_experiments_access_level).to eq(ProjectFeature::ENABLED) } + specify { expect(subject.model_registry_access_level).to eq(ProjectFeature::ENABLED) } end describe 'PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 53c2373c08b..dcd2e634ce3 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1128,6 +1128,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr it { is_expected.to delegate_method(:container_registry_access_level).to(:project_feature) } it { is_expected.to delegate_method(:environments_access_level).to(:project_feature) } it { is_expected.to delegate_method(:model_experiments_access_level).to(:project_feature) } + it { is_expected.to delegate_method(:model_registry_access_level).to(:project_feature) } it { is_expected.to delegate_method(:feature_flags_access_level).to(:project_feature) } it { is_expected.to delegate_method(:releases_access_level).to(:project_feature) } it { is_expected.to delegate_method(:infrastructure_access_level).to(:project_feature) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb index cb7bac771b3..1bd239ecd87 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb @@ -127,7 +127,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled, featur context 'when passing append as true' do let(:mode) { Types::MutationOperationModeEnum.enum[:append] } let(:input) { { assignee_usernames: [assignee2.username], operation_mode: mode } } - let(:db_query_limit) { 23 } + let(:db_query_limit) { 25 } before do # In CE, APPEND is a NOOP as you can't have multiple assignees @@ -147,7 +147,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled, featur end context 'when passing remove as true' do - let(:db_query_limit) { 31 } + let(:db_query_limit) { 33 } let(:mode) { Types::MutationOperationModeEnum.enum[:remove] } let(:input) { { assignee_usernames: [assignee.username], operation_mode: mode } } let(:expected_result) { [] } diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml index bab5bd2b6ac..ab03df84cd5 100644 --- a/spec/requests/api/project_attributes.yml +++ b/spec/requests/api/project_attributes.yml @@ -133,6 +133,7 @@ project_feature: - project_id - updated_at - operations_access_level + - model_registry_access_level computed_attributes: - issues_enabled - jobs_enabled diff --git a/spec/requests/projects/pipelines_controller_spec.rb b/spec/requests/projects/pipelines_controller_spec.rb index 7bdb66755db..e5d96631df6 100644 --- a/spec/requests/projects/pipelines_controller_spec.rb +++ b/spec/requests/projects/pipelines_controller_spec.rb @@ -75,6 +75,58 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte expect(response).to have_gitlab_http_status(:ok) end + context 'when pipeline_stage_set_last_modified is disabled' do + before do + stub_feature_flags(pipeline_stage_set_last_modified: false) + end + + it 'does not set Last-Modified' do + create(:ci_build, :retried, :failed, pipeline: pipeline, stage: 'build') + + request_build_stage + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Last-Modified']).to be_nil + expect(response.headers['Cache-Control']).to eq('max-age=0, private, must-revalidate') + end + end + + context 'when pipeline_stage_set_last_modified is enabled' do + before do + stub_feature_flags(pipeline_stage_set_last_modified: true) + stage.statuses.update_all(updated_at: status_timestamp) + end + + let(:last_modified) { DateTime.parse(response.headers['Last-Modified']).utc } + let(:cache_control) { response.headers['Cache-Control'] } + + context 'when status.updated_at is before stage.updated' do + let(:stage) { pipeline.stage('build') } + let(:status_timestamp) { stage.updated_at - 10.minutes } + + it 'sets correct Last-Modified of stage.updated_at' do + request_build_stage + + expect(response).to have_gitlab_http_status(:ok) + expect(last_modified).to be_within(1.second).of stage.updated_at + expect(cache_control).to eq('max-age=86400, private') + end + end + + context 'when status.updated_at is after stage.updated' do + let(:stage) { pipeline.stage('build') } + let(:status_timestamp) { stage.updated_at + 10.minutes } + + it 'sets correct Last-Modified of max(status.updated_at)' do + request_build_stage + + expect(response).to have_gitlab_http_status(:ok) + expect(last_modified).to be_within(1.second).of status_timestamp + expect(cache_control).to eq('max-age=86400, private') + end + end + end + context 'with retried builds' do it 'does not execute N+1 queries' do create(:ci_build, :retried, :failed, pipeline: pipeline, stage: 'build')