From 447f884dc07d39c8a7a4da1365250cd98c2863cf Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 7 Jun 2024 12:23:52 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- Gemfile.checksum | 2 +- Gemfile.lock | 2 +- .../import_groups/components/import_table.vue | 18 +++++++ .../model_registry/apps/index_ml_models.vue | 5 ++ .../ml/model_registry/apps/show_ml_model.vue | 5 ++ .../apps/show_ml_model_version.vue | 5 ++ .../components/import_artifact_zone.vue | 8 +++- .../components/model_create.vue | 14 ++++-- .../components/model_version_create.vue | 4 +- .../model_registry/services/upload_model.js | 21 +++++++- .../super_sidebar/components/user_bar.vue | 2 +- app/helpers/preferences_helper.rb | 2 +- .../projects/ml/model_registry_helper.rb | 13 +++-- app/views/dashboard/issues.html.haml | 4 +- ...ll_project_relation_exports_project_id.yml | 9 ++++ ...ll_terraform_state_versions_project_id.yml | 9 ++++ db/docs/project_relation_exports.yml | 1 + db/docs/terraform_state_versions.yml | 4 +- ..._project_id_to_project_relation_exports.rb | 9 ++++ ..._project_id_to_terraform_state_versions.rb | 9 ++++ ..._project_relation_exports_on_project_id.rb | 16 +++++++ ..._project_relation_exports_project_id_fk.rb | 16 +++++++ ...ect_relation_exports_project_id_trigger.rb | 25 ++++++++++ ...ill_project_relation_exports_project_id.rb | 40 ++++++++++++++++ ..._terraform_state_versions_on_project_id.rb | 16 +++++++ ..._terraform_state_versions_project_id_fk.rb | 16 +++++++ ...aform_state_versions_project_id_trigger.rb | 25 ++++++++++ ...ill_terraform_state_versions_project_id.rb | 40 ++++++++++++++++ db/schema_migrations/20240605113246 | 1 + db/schema_migrations/20240605113247 | 1 + db/schema_migrations/20240605113248 | 1 + db/schema_migrations/20240605113249 | 1 + db/schema_migrations/20240605113250 | 1 + db/schema_migrations/20240605132806 | 1 + db/schema_migrations/20240605132807 | 1 + db/schema_migrations/20240605132808 | 1 + db/schema_migrations/20240605132809 | 1 + db/schema_migrations/20240605132810 | 1 + db/structure.sql | 48 +++++++++++++++++++ doc/administration/auth/oidc.md | 4 +- .../settings/import_and_export_settings.md | 8 +++- doc/api/bulk_imports.md | 6 ++- doc/api/graphql/reference/index.md | 5 +- doc/api/oauth2.md | 2 +- doc/development/rails_update.md | 6 ++- .../import/direct_transfer_migrations.md | 4 ++ doc/user/group/import/index.md | 8 +++- doc/user/project/issues/managing_issues.md | 2 +- ...ill_project_relation_exports_project_id.rb | 10 ++++ ...ill_terraform_state_versions_project_id.rb | 10 ++++ locale/gitlab.pot | 23 +++++++-- .../dashboard/issuables_counter_spec.rb | 2 +- spec/features/dashboard/shortcuts_spec.rb | 2 +- .../apps/index_ml_models_spec.js | 1 + .../model_registry/apps/show_ml_model_spec.js | 1 + .../apps/show_ml_model_version_spec.js | 1 + .../components/import_artifact_zone_spec.js | 9 ++++ .../components/model_create_spec.js | 31 ++++++++++-- .../components/model_detail_spec.js | 1 + .../components/model_version_create_spec.js | 28 +++++++++-- .../components/model_version_detail_spec.js | 1 + .../services/upload_model_spec.js | 14 +++++- .../super_sidebar/components/user_bar_spec.js | 2 +- spec/helpers/preferences_helper_spec.rb | 2 +- .../projects/ml/model_registry_helper_spec.rb | 3 ++ ...roject_relation_exports_project_id_spec.rb | 15 ++++++ ...erraform_state_versions_project_id_spec.rb | 15 ++++++ ...roject_relation_exports_project_id_spec.rb | 33 +++++++++++++ ...erraform_state_versions_project_id_spec.rb | 33 +++++++++++++ spec/rails_autoload.rb | 23 +++++++-- .../features/work_items_shared_examples.rb | 8 ++-- workhorse/testdata/localhost.crt | 44 ++++++++--------- 72 files changed, 675 insertions(+), 80 deletions(-) create mode 100644 db/docs/batched_background_migrations/backfill_project_relation_exports_project_id.yml create mode 100644 db/docs/batched_background_migrations/backfill_terraform_state_versions_project_id.yml create mode 100644 db/migrate/20240605113246_add_project_id_to_project_relation_exports.rb create mode 100644 db/migrate/20240605132806_add_project_id_to_terraform_state_versions.rb create mode 100644 db/post_migrate/20240605113247_index_project_relation_exports_on_project_id.rb create mode 100644 db/post_migrate/20240605113248_add_project_relation_exports_project_id_fk.rb create mode 100644 db/post_migrate/20240605113249_add_project_relation_exports_project_id_trigger.rb create mode 100644 db/post_migrate/20240605113250_queue_backfill_project_relation_exports_project_id.rb create mode 100644 db/post_migrate/20240605132807_index_terraform_state_versions_on_project_id.rb create mode 100644 db/post_migrate/20240605132808_add_terraform_state_versions_project_id_fk.rb create mode 100644 db/post_migrate/20240605132809_add_terraform_state_versions_project_id_trigger.rb create mode 100644 db/post_migrate/20240605132810_queue_backfill_terraform_state_versions_project_id.rb create mode 100644 db/schema_migrations/20240605113246 create mode 100644 db/schema_migrations/20240605113247 create mode 100644 db/schema_migrations/20240605113248 create mode 100644 db/schema_migrations/20240605113249 create mode 100644 db/schema_migrations/20240605113250 create mode 100644 db/schema_migrations/20240605132806 create mode 100644 db/schema_migrations/20240605132807 create mode 100644 db/schema_migrations/20240605132808 create mode 100644 db/schema_migrations/20240605132809 create mode 100644 db/schema_migrations/20240605132810 create mode 100644 lib/gitlab/background_migration/backfill_project_relation_exports_project_id.rb create mode 100644 lib/gitlab/background_migration/backfill_terraform_state_versions_project_id.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_project_relation_exports_project_id_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_terraform_state_versions_project_id_spec.rb create mode 100644 spec/migrations/20240605113250_queue_backfill_project_relation_exports_project_id_spec.rb create mode 100644 spec/migrations/20240605132810_queue_backfill_terraform_state_versions_project_id_spec.rb diff --git a/Gemfile.checksum b/Gemfile.checksum index 588ac56255b..759d4d8ee61 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -220,7 +220,7 @@ {"name":"gitlab-glfm-markdown","version":"0.0.17","platform":"x86_64-darwin","checksum":"50e0f4865ef7c455426c7c058fc10ff9c8366482d48a63d6f6693b38c4a49c1c"}, {"name":"gitlab-glfm-markdown","version":"0.0.17","platform":"x86_64-linux","checksum":"cc877ff8ceb3aa8a331fdb8991592e35897823e0f77ba9e4b2b65082c665089b"}, {"name":"gitlab-labkit","version":"0.36.0","platform":"ruby","checksum":"35f21d1c3870ed0c9b8321e25d0b0b0b5021805a5d0525d1eb0fde6b103af981"}, -{"name":"gitlab-license","version":"2.4.0","platform":"ruby","checksum":"fd238fb1e605a6b9250d4eb1744434ffd131f18d50a3be32f613c883f7635e20"}, +{"name":"gitlab-license","version":"2.5.0","platform":"ruby","checksum":"4c166c469c2ad17876ca43188a4ccebe3feb0726c4c1770047f8dcef96573f4d"}, {"name":"gitlab-mail_room","version":"0.0.25","platform":"ruby","checksum":"223ce7c3c0797b6015eaa37147884e6ddc7be9a7ee90a424358c96bc18613b1a"}, {"name":"gitlab-markup","version":"1.9.0","platform":"ruby","checksum":"7eda045a08ec2d110084252fa13a8c9eac8bdac0e302035ca7db4b82bcbd7ed4"}, {"name":"gitlab-net-dns","version":"0.9.2","platform":"ruby","checksum":"f726d978479d43810819f12a45c0906d775a07e34df111bbe693fffbbef3059d"}, diff --git a/Gemfile.lock b/Gemfile.lock index a298d719530..ba040213e67 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -712,7 +712,7 @@ GEM opentracing (~> 0.4) pg_query (>= 4.2.3, < 6.0) redis (> 3.0.0, < 6.0.0) - gitlab-license (2.4.0) + gitlab-license (2.5.0) gitlab-mail_room (0.0.25) jwt (>= 2.0) net-imap (>= 0.2.1) diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue index f60f242e56d..46fc6153b38 100644 --- a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue +++ b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue @@ -637,6 +637,7 @@ export default { gitlabLogo: window.gon.gitlab_logo, PAGE_SIZES, permissionsHelpPath: helpPagePath('user/permissions', { anchor: 'group-members-permissions' }), + betaFeatureHelpPath: helpPagePath('policy/experiment-beta-support', { anchor: 'beta-features' }), popoverOptions: { title: __('What is listed here?') }, i18n, LOCAL_STORAGE_KEY: 'gl-bulk-imports-status-page-size-v1', @@ -802,6 +803,23 @@ export default { data-testid="import-projects-warning" /> + + + + + + + { this.resetFile(); this.alert = { message: this.$options.i18n.successfulUpload, variant: 'success' }; diff --git a/app/assets/javascripts/ml/model_registry/components/model_create.vue b/app/assets/javascripts/ml/model_registry/components/model_create.vue index 33825891a18..a7514f14cfb 100644 --- a/app/assets/javascripts/ml/model_registry/components/model_create.vue +++ b/app/assets/javascripts/ml/model_registry/components/model_create.vue @@ -28,7 +28,7 @@ export default { GlFormTextarea, ImportArtifactZone: () => import('./import_artifact_zone.vue'), }, - inject: ['projectPath'], + inject: ['projectPath', 'maxAllowedFileSize'], props: { createModelVisible: { type: Boolean, @@ -106,6 +106,7 @@ export default { importPath, file: this.selectedFile.file, subfolder: this.selectedFile.subfolder, + maxAllowedFileSize: this.maxAllowedFileSize, }); const { showPath } = this.versionData.mlModelVersionCreate.modelVersion._links; @@ -118,7 +119,6 @@ export default { } catch (error) { Sentry.captureException(error); this.errorMessage = error; - this.selectedFile = emptyArtifactFile; this.showModal(); } }, @@ -258,9 +258,13 @@ export default { - {{ - errorMessage - }} + {{ errorMessage }} diff --git a/app/assets/javascripts/ml/model_registry/components/model_version_create.vue b/app/assets/javascripts/ml/model_registry/components/model_version_create.vue index 778bbf0f358..764580539c0 100644 --- a/app/assets/javascripts/ml/model_registry/components/model_version_create.vue +++ b/app/assets/javascripts/ml/model_registry/components/model_version_create.vue @@ -27,7 +27,7 @@ export default { GlFormTextarea, ImportArtifactZone: () => import('./import_artifact_zone.vue'), }, - inject: ['projectPath'], + inject: ['projectPath', 'maxAllowedFileSize'], props: { modelGid: { type: String, @@ -78,6 +78,7 @@ export default { importPath, file: this.selectedFile.file, subfolder: this.selectedFile.subfolder, + maxAllowedFileSize: this.maxAllowedFileSize, }); const { showPath } = this.versionData.mlModelVersionCreate.modelVersion._links; visitUrl(showPath); @@ -85,7 +86,6 @@ export default { } catch (error) { Sentry.captureException(error); this.errorMessage = error; - this.selectedFile = emptyArtifactFile; this.showModal(); } }, diff --git a/app/assets/javascripts/ml/model_registry/services/upload_model.js b/app/assets/javascripts/ml/model_registry/services/upload_model.js index dfd37dba294..3ddc02d3297 100644 --- a/app/assets/javascripts/ml/model_registry/services/upload_model.js +++ b/app/assets/javascripts/ml/model_registry/services/upload_model.js @@ -1,11 +1,30 @@ import axios from '~/lib/utils/axios_utils'; +import { numberToHumanSize } from '~/lib/utils/number_utils'; import { contentTypeMultipartFormData } from '~/lib/utils/headers'; import { joinPaths } from '~/lib/utils/url_utility'; +import { s__, sprintf } from '~/locale'; -export const uploadModel = ({ importPath, file, subfolder }) => { +export const uploadModel = ({ importPath, file, subfolder, maxAllowedFileSize }) => { if (!file) { return Promise.resolve(); } + if (!maxAllowedFileSize) { + return Promise.resolve(s__('Mlmodelregistry|Provide the max allowed file size')); + } + + if (file.size > maxAllowedFileSize) { + const errorMessage = sprintf( + s__( + 'MlModelRegistry|File "%{name}" is %{size}. It is larger than max allowed size of %{maxAllowedFileSize}', + ), + { + name: file.name, + size: numberToHumanSize(file.size), + maxAllowedFileSize: numberToHumanSize(maxAllowedFileSize), + }, + ); + return Promise.reject(new Error(errorMessage)); + } const formData = new FormData(); const importUrl = joinPaths(importPath, subfolder, encodeURIComponent(file.name)); diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue index af405812711..9ea9412a3f5 100644 --- a/app/assets/javascripts/super_sidebar/components/user_bar.vue +++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue @@ -44,7 +44,7 @@ export default { import(/* webpackChunkName: 'organization_switcher' */ './organization_switcher.vue'), }, i18n: { - issues: __('Issues'), + issues: __('Assigned issues'), mergeRequests: __('Merge requests'), searchKbdHelp: sprintf( s__('GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search'), diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index 45cbe909a27..4398dcbe742 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -36,7 +36,7 @@ module PreferencesHelper followed_user_activity: _("Followed Users' Activity"), groups: _("Your Groups"), todos: _("Your To-Do List"), - issues: _("Assigned Issues"), + issues: _("Assigned issues"), merge_requests: _("Assigned merge requests"), operations: _("Operations Dashboard") }.with_indifferent_access.freeze diff --git a/app/helpers/projects/ml/model_registry_helper.rb b/app/helpers/projects/ml/model_registry_helper.rb index f98f3411036..ea45d177003 100644 --- a/app/helpers/projects/ml/model_registry_helper.rb +++ b/app/helpers/projects/ml/model_registry_helper.rb @@ -10,7 +10,8 @@ module Projects projectPath: project.full_path, create_model_path: new_project_ml_model_path(project), can_write_model_registry: can_write_model_registry?(user, project), - mlflow_tracking_url: mlflow_tracking_url(project) + mlflow_tracking_url: mlflow_tracking_url(project), + max_allowed_file_size: max_allowed_file_size(project) } to_json(data) @@ -25,7 +26,8 @@ module Projects can_write_model_registry: can_write_model_registry?(user, project), mlflow_tracking_url: mlflow_tracking_url(project), model_id: model.id, - model_name: model.name + model_name: model.name, + max_allowed_file_size: max_allowed_file_size(project) } to_json(data) @@ -42,7 +44,8 @@ module Projects version_name: model_version.version, can_write_model_registry: can_write_model_registry?(user, project), import_path: model_version_artifact_import_path(project.id, model_version.id), - model_path: project_ml_model_path(project, model_version.model) + model_path: project_ml_model_path(project, model_version.model), + max_allowed_file_size: max_allowed_file_size(project) } to_json(data) @@ -62,6 +65,10 @@ module Projects user&.can?(:write_model_registry, project) end + def max_allowed_file_size(project) + project.actual_limits.ml_model_max_file_size + end + def to_json(data) Gitlab::Json.generate(data.deep_transform_keys { |k| k.to_s.camelize(:lower) }) end diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index cae3d58abac..8bf7e7ad970 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -1,4 +1,4 @@ -- page_title _("Issues") +- page_title _("Assigned issues") - @breadcrumb_link = issues_dashboard_path(assignee_username: current_user.username) - add_page_specific_style 'page_bundles/issuable_list' - add_page_specific_style 'page_bundles/dashboard' @@ -9,7 +9,7 @@ = render_if_exists 'shared/dashboard/saml_reauth_notice', groups_requiring_saml_reauth: user_groups_requiring_reauth -= render ::Layouts::PageHeadingComponent.new(_('Issues')) do |c| += render ::Layouts::PageHeadingComponent.new(_('Assigned issues')) do |c| - c.with_actions do = render 'shared/new_project_item_vue_select' diff --git a/db/docs/batched_background_migrations/backfill_project_relation_exports_project_id.yml b/db/docs/batched_background_migrations/backfill_project_relation_exports_project_id.yml new file mode 100644 index 00000000000..b65ea819b1d --- /dev/null +++ b/db/docs/batched_background_migrations/backfill_project_relation_exports_project_id.yml @@ -0,0 +1,9 @@ +--- +migration_job_name: BackfillProjectRelationExportsProjectId +description: Backfills sharding key `project_relation_exports.project_id` from `project_export_jobs`. +feature_category: importers +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155429 +milestone: '17.1' +queued_migration_version: 20240605113250 +finalize_after: '2024-07-22' +finalized_by: # version of the migration that finalized this BBM diff --git a/db/docs/batched_background_migrations/backfill_terraform_state_versions_project_id.yml b/db/docs/batched_background_migrations/backfill_terraform_state_versions_project_id.yml new file mode 100644 index 00000000000..a3f27a08aa7 --- /dev/null +++ b/db/docs/batched_background_migrations/backfill_terraform_state_versions_project_id.yml @@ -0,0 +1,9 @@ +--- +migration_job_name: BackfillTerraformStateVersionsProjectId +description: Backfills sharding key `terraform_state_versions.project_id` from `terraform_states`. +feature_category: infrastructure_as_code +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155438 +milestone: '17.1' +queued_migration_version: 20240605132810 +finalize_after: '2024-07-22' +finalized_by: # version of the migration that finalized this BBM diff --git a/db/docs/project_relation_exports.yml b/db/docs/project_relation_exports.yml index 9f7c8fb03d4..0e994abdd6c 100644 --- a/db/docs/project_relation_exports.yml +++ b/db/docs/project_relation_exports.yml @@ -19,3 +19,4 @@ desired_sharding_key: table: project_export_jobs sharding_key: project_id belongs_to: project_export_job +desired_sharding_key_migration_job_name: BackfillProjectRelationExportsProjectId diff --git a/db/docs/terraform_state_versions.yml b/db/docs/terraform_state_versions.yml index dbcf459ccfc..e9863e2c1cb 100644 --- a/db/docs/terraform_state_versions.yml +++ b/db/docs/terraform_state_versions.yml @@ -4,7 +4,8 @@ classes: - Terraform::StateVersion feature_categories: - infrastructure_as_code -description: Represents a Terraform state file at a point in time, with a corresponding file stored in object storage +description: Represents a Terraform state file at a point in time, with a corresponding + file stored in object storage introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35211 milestone: '13.4' gitlab_schema: gitlab_main_cell @@ -19,3 +20,4 @@ desired_sharding_key: table: terraform_states sharding_key: project_id belongs_to: terraform_state +desired_sharding_key_migration_job_name: BackfillTerraformStateVersionsProjectId diff --git a/db/migrate/20240605113246_add_project_id_to_project_relation_exports.rb b/db/migrate/20240605113246_add_project_id_to_project_relation_exports.rb new file mode 100644 index 00000000000..a5e3a41ac05 --- /dev/null +++ b/db/migrate/20240605113246_add_project_id_to_project_relation_exports.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddProjectIdToProjectRelationExports < Gitlab::Database::Migration[2.2] + milestone '17.1' + + def change + add_column :project_relation_exports, :project_id, :bigint + end +end diff --git a/db/migrate/20240605132806_add_project_id_to_terraform_state_versions.rb b/db/migrate/20240605132806_add_project_id_to_terraform_state_versions.rb new file mode 100644 index 00000000000..6fa7cb03206 --- /dev/null +++ b/db/migrate/20240605132806_add_project_id_to_terraform_state_versions.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddProjectIdToTerraformStateVersions < Gitlab::Database::Migration[2.2] + milestone '17.1' + + def change + add_column :terraform_state_versions, :project_id, :bigint + end +end diff --git a/db/post_migrate/20240605113247_index_project_relation_exports_on_project_id.rb b/db/post_migrate/20240605113247_index_project_relation_exports_on_project_id.rb new file mode 100644 index 00000000000..57d9884470e --- /dev/null +++ b/db/post_migrate/20240605113247_index_project_relation_exports_on_project_id.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class IndexProjectRelationExportsOnProjectId < Gitlab::Database::Migration[2.2] + milestone '17.1' + disable_ddl_transaction! + + INDEX_NAME = 'index_project_relation_exports_on_project_id' + + def up + add_concurrent_index :project_relation_exports, :project_id, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :project_relation_exports, INDEX_NAME + end +end diff --git a/db/post_migrate/20240605113248_add_project_relation_exports_project_id_fk.rb b/db/post_migrate/20240605113248_add_project_relation_exports_project_id_fk.rb new file mode 100644 index 00000000000..4556fb7b44f --- /dev/null +++ b/db/post_migrate/20240605113248_add_project_relation_exports_project_id_fk.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class AddProjectRelationExportsProjectIdFk < Gitlab::Database::Migration[2.2] + milestone '17.1' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :project_relation_exports, :projects, column: :project_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :project_relation_exports, column: :project_id + end + end +end diff --git a/db/post_migrate/20240605113249_add_project_relation_exports_project_id_trigger.rb b/db/post_migrate/20240605113249_add_project_relation_exports_project_id_trigger.rb new file mode 100644 index 00000000000..f4484447cf5 --- /dev/null +++ b/db/post_migrate/20240605113249_add_project_relation_exports_project_id_trigger.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddProjectRelationExportsProjectIdTrigger < Gitlab::Database::Migration[2.2] + milestone '17.1' + + def up + install_sharding_key_assignment_trigger( + table: :project_relation_exports, + sharding_key: :project_id, + parent_table: :project_export_jobs, + parent_sharding_key: :project_id, + foreign_key: :project_export_job_id + ) + end + + def down + remove_sharding_key_assignment_trigger( + table: :project_relation_exports, + sharding_key: :project_id, + parent_table: :project_export_jobs, + parent_sharding_key: :project_id, + foreign_key: :project_export_job_id + ) + end +end diff --git a/db/post_migrate/20240605113250_queue_backfill_project_relation_exports_project_id.rb b/db/post_migrate/20240605113250_queue_backfill_project_relation_exports_project_id.rb new file mode 100644 index 00000000000..5b55e292dbf --- /dev/null +++ b/db/post_migrate/20240605113250_queue_backfill_project_relation_exports_project_id.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class QueueBackfillProjectRelationExportsProjectId < Gitlab::Database::Migration[2.2] + milestone '17.1' + restrict_gitlab_migration gitlab_schema: :gitlab_main_cell + + MIGRATION = "BackfillProjectRelationExportsProjectId" + DELAY_INTERVAL = 2.minutes + BATCH_SIZE = 1000 + SUB_BATCH_SIZE = 100 + + def up + queue_batched_background_migration( + MIGRATION, + :project_relation_exports, + :id, + :project_id, + :project_export_jobs, + :project_id, + :project_export_job_id, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration( + MIGRATION, + :project_relation_exports, + :id, + [ + :project_id, + :project_export_jobs, + :project_id, + :project_export_job_id + ] + ) + end +end diff --git a/db/post_migrate/20240605132807_index_terraform_state_versions_on_project_id.rb b/db/post_migrate/20240605132807_index_terraform_state_versions_on_project_id.rb new file mode 100644 index 00000000000..4f65707ecc7 --- /dev/null +++ b/db/post_migrate/20240605132807_index_terraform_state_versions_on_project_id.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class IndexTerraformStateVersionsOnProjectId < Gitlab::Database::Migration[2.2] + milestone '17.1' + disable_ddl_transaction! + + INDEX_NAME = 'index_terraform_state_versions_on_project_id' + + def up + add_concurrent_index :terraform_state_versions, :project_id, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :terraform_state_versions, INDEX_NAME + end +end diff --git a/db/post_migrate/20240605132808_add_terraform_state_versions_project_id_fk.rb b/db/post_migrate/20240605132808_add_terraform_state_versions_project_id_fk.rb new file mode 100644 index 00000000000..c705c155de4 --- /dev/null +++ b/db/post_migrate/20240605132808_add_terraform_state_versions_project_id_fk.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class AddTerraformStateVersionsProjectIdFk < Gitlab::Database::Migration[2.2] + milestone '17.1' + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :terraform_state_versions, :projects, column: :project_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :terraform_state_versions, column: :project_id + end + end +end diff --git a/db/post_migrate/20240605132809_add_terraform_state_versions_project_id_trigger.rb b/db/post_migrate/20240605132809_add_terraform_state_versions_project_id_trigger.rb new file mode 100644 index 00000000000..071994aff5a --- /dev/null +++ b/db/post_migrate/20240605132809_add_terraform_state_versions_project_id_trigger.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddTerraformStateVersionsProjectIdTrigger < Gitlab::Database::Migration[2.2] + milestone '17.1' + + def up + install_sharding_key_assignment_trigger( + table: :terraform_state_versions, + sharding_key: :project_id, + parent_table: :terraform_states, + parent_sharding_key: :project_id, + foreign_key: :terraform_state_id + ) + end + + def down + remove_sharding_key_assignment_trigger( + table: :terraform_state_versions, + sharding_key: :project_id, + parent_table: :terraform_states, + parent_sharding_key: :project_id, + foreign_key: :terraform_state_id + ) + end +end diff --git a/db/post_migrate/20240605132810_queue_backfill_terraform_state_versions_project_id.rb b/db/post_migrate/20240605132810_queue_backfill_terraform_state_versions_project_id.rb new file mode 100644 index 00000000000..5acf58c9b0b --- /dev/null +++ b/db/post_migrate/20240605132810_queue_backfill_terraform_state_versions_project_id.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class QueueBackfillTerraformStateVersionsProjectId < Gitlab::Database::Migration[2.2] + milestone '17.1' + restrict_gitlab_migration gitlab_schema: :gitlab_main_cell + + MIGRATION = "BackfillTerraformStateVersionsProjectId" + DELAY_INTERVAL = 2.minutes + BATCH_SIZE = 1000 + SUB_BATCH_SIZE = 100 + + def up + queue_batched_background_migration( + MIGRATION, + :terraform_state_versions, + :id, + :project_id, + :terraform_states, + :project_id, + :terraform_state_id, + job_interval: DELAY_INTERVAL, + batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + delete_batched_background_migration( + MIGRATION, + :terraform_state_versions, + :id, + [ + :project_id, + :terraform_states, + :project_id, + :terraform_state_id + ] + ) + end +end diff --git a/db/schema_migrations/20240605113246 b/db/schema_migrations/20240605113246 new file mode 100644 index 00000000000..8322e1f1b67 --- /dev/null +++ b/db/schema_migrations/20240605113246 @@ -0,0 +1 @@ +0633b0f78ffa5b7550bb6c08df4d1992d137e703fad7be7dfbeb8f1947043b28 \ No newline at end of file diff --git a/db/schema_migrations/20240605113247 b/db/schema_migrations/20240605113247 new file mode 100644 index 00000000000..febf70fb544 --- /dev/null +++ b/db/schema_migrations/20240605113247 @@ -0,0 +1 @@ +e437a04b396cc520e4efdfba802a6fa019ebe42ef56556f6456c96c957017dfc \ No newline at end of file diff --git a/db/schema_migrations/20240605113248 b/db/schema_migrations/20240605113248 new file mode 100644 index 00000000000..b38dbd43802 --- /dev/null +++ b/db/schema_migrations/20240605113248 @@ -0,0 +1 @@ +01772232031f3546e17b11e863114eb97908f657d9525136c5810cc1254ae14c \ No newline at end of file diff --git a/db/schema_migrations/20240605113249 b/db/schema_migrations/20240605113249 new file mode 100644 index 00000000000..c8bf95c0c29 --- /dev/null +++ b/db/schema_migrations/20240605113249 @@ -0,0 +1 @@ +cbbdfc5caaa00e2fc0b458a6a8e555ed033f066d85f7a363726fdb66ff4aad8f \ No newline at end of file diff --git a/db/schema_migrations/20240605113250 b/db/schema_migrations/20240605113250 new file mode 100644 index 00000000000..1998b175aca --- /dev/null +++ b/db/schema_migrations/20240605113250 @@ -0,0 +1 @@ +333432f11538c10e77ac8f73bf0b364c3230999ff718d7e25b7e0df33c372e56 \ No newline at end of file diff --git a/db/schema_migrations/20240605132806 b/db/schema_migrations/20240605132806 new file mode 100644 index 00000000000..8d44133edee --- /dev/null +++ b/db/schema_migrations/20240605132806 @@ -0,0 +1 @@ +48616de4dab655eb5a01da5f7b8149c3d5ca66c64cdccea86468a3b6a9e83237 \ No newline at end of file diff --git a/db/schema_migrations/20240605132807 b/db/schema_migrations/20240605132807 new file mode 100644 index 00000000000..12d876ada6a --- /dev/null +++ b/db/schema_migrations/20240605132807 @@ -0,0 +1 @@ +63ab2d580707d4a7095ccdfcbd636b701708b5b415284112084446b21ee35807 \ No newline at end of file diff --git a/db/schema_migrations/20240605132808 b/db/schema_migrations/20240605132808 new file mode 100644 index 00000000000..54914dc23ee --- /dev/null +++ b/db/schema_migrations/20240605132808 @@ -0,0 +1 @@ +8e168eb75e5ab533b51be54c9df72249fc166f1d0fc3f1f396c87058c4116501 \ No newline at end of file diff --git a/db/schema_migrations/20240605132809 b/db/schema_migrations/20240605132809 new file mode 100644 index 00000000000..99346006c8a --- /dev/null +++ b/db/schema_migrations/20240605132809 @@ -0,0 +1 @@ +0e2504f0165fbeb417a7a5ff3650f0cb9aa151ff9f72e5c773659e4c3f4075c5 \ No newline at end of file diff --git a/db/schema_migrations/20240605132810 b/db/schema_migrations/20240605132810 new file mode 100644 index 00000000000..bb5bac4f808 --- /dev/null +++ b/db/schema_migrations/20240605132810 @@ -0,0 +1 @@ +c4eaba0dc0a28d090b3d79f49752ad929d0ed89ca4cfb422c6f15087ba81e31a \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index effddaa342d..5c9376fcb3b 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1153,6 +1153,22 @@ RETURN NEW; END $$; +CREATE FUNCTION trigger_b2612138515d() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN +IF NEW."project_id" IS NULL THEN + SELECT "project_id" + INTO NEW."project_id" + FROM "project_export_jobs" + WHERE "project_export_jobs"."id" = NEW."project_export_job_id"; +END IF; + +RETURN NEW; + +END +$$; + CREATE FUNCTION trigger_b4520c29ea74() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -1233,6 +1249,22 @@ RETURN NEW; END $$; +CREATE FUNCTION trigger_d4487a75bd44() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN +IF NEW."project_id" IS NULL THEN + SELECT "project_id" + INTO NEW."project_id" + FROM "terraform_states" + WHERE "terraform_states"."id" = NEW."terraform_state_id"; +END IF; + +RETURN NEW; + +END +$$; + CREATE FUNCTION trigger_dbdd61a66a91() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -15146,6 +15178,7 @@ CREATE TABLE project_relation_exports ( relation text NOT NULL, jid text, export_error text, + project_id bigint, CONSTRAINT check_15e644d856 CHECK ((char_length(jid) <= 255)), CONSTRAINT check_4b5880b795 CHECK ((char_length(relation) <= 255)), CONSTRAINT check_dbd1cf73d0 CHECK ((char_length(export_error) <= 300)) @@ -17367,6 +17400,7 @@ CREATE TABLE terraform_state_versions ( ci_build_id bigint, verification_started_at timestamp with time zone, verification_state smallint DEFAULT 0 NOT NULL, + project_id bigint, CONSTRAINT check_0824bb7bbd CHECK ((char_length(file) <= 255)), CONSTRAINT tf_state_versions_verification_failure_text_limit CHECK ((char_length(verification_failure) <= 255)) ); @@ -27609,6 +27643,8 @@ CREATE INDEX index_project_pages_metadata_on_project_id_and_deployed_is_true ON CREATE INDEX index_project_relation_export_upload_id ON project_relation_export_uploads USING btree (project_relation_export_id); +CREATE INDEX index_project_relation_exports_on_project_id ON project_relation_exports USING btree (project_id); + CREATE UNIQUE INDEX index_project_repositories_on_disk_path ON project_repositories USING btree (disk_path); CREATE UNIQUE INDEX index_project_repositories_on_project_id ON project_repositories USING btree (project_id); @@ -28241,6 +28277,8 @@ CREATE INDEX index_terraform_state_versions_on_ci_build_id ON terraform_state_ve CREATE INDEX index_terraform_state_versions_on_created_by_user_id ON terraform_state_versions USING btree (created_by_user_id); +CREATE INDEX index_terraform_state_versions_on_project_id ON terraform_state_versions USING btree (project_id); + CREATE UNIQUE INDEX index_terraform_state_versions_on_state_id_and_version ON terraform_state_versions USING btree (terraform_state_id, version); CREATE INDEX index_terraform_state_versions_on_verification_state ON terraform_state_versions USING btree (verification_state); @@ -30663,6 +30701,8 @@ CREATE TRIGGER trigger_a1bc7c70cbdf BEFORE INSERT OR UPDATE ON vulnerability_use CREATE TRIGGER trigger_a253cb3cacdf BEFORE INSERT OR UPDATE ON dora_daily_metrics FOR EACH ROW EXECUTE FUNCTION trigger_a253cb3cacdf(); +CREATE TRIGGER trigger_b2612138515d BEFORE INSERT OR UPDATE ON project_relation_exports FOR EACH ROW EXECUTE FUNCTION trigger_b2612138515d(); + CREATE TRIGGER trigger_b4520c29ea74 BEFORE INSERT OR UPDATE ON approval_merge_request_rule_sources FOR EACH ROW EXECUTE FUNCTION trigger_b4520c29ea74(); CREATE TRIGGER trigger_c17a166692a2 BEFORE INSERT OR UPDATE ON audit_events_streaming_headers FOR EACH ROW EXECUTE FUNCTION trigger_c17a166692a2(); @@ -30675,6 +30715,8 @@ CREATE TRIGGER trigger_c9090feed334 BEFORE INSERT OR UPDATE ON boards_epic_lists CREATE TRIGGER trigger_catalog_resource_sync_event_on_project_update AFTER UPDATE ON projects FOR EACH ROW WHEN ((((old.name)::text IS DISTINCT FROM (new.name)::text) OR (old.description IS DISTINCT FROM new.description) OR (old.visibility_level IS DISTINCT FROM new.visibility_level))) EXECUTE FUNCTION insert_catalog_resource_sync_event(); +CREATE TRIGGER trigger_d4487a75bd44 BEFORE INSERT OR UPDATE ON terraform_state_versions FOR EACH ROW EXECUTE FUNCTION trigger_d4487a75bd44(); + CREATE TRIGGER trigger_dbdd61a66a91 BEFORE INSERT OR UPDATE ON agent_activity_events FOR EACH ROW EXECUTE FUNCTION trigger_dbdd61a66a91(); CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace(); @@ -30859,6 +30901,9 @@ ALTER TABLE ONLY scan_result_policy_violations ALTER TABLE ONLY incident_management_timeline_events ADD CONSTRAINT fk_1800597ef9 FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE SET NULL; +ALTER TABLE ONLY terraform_state_versions + ADD CONSTRAINT fk_180cde327a FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + ALTER TABLE ONLY project_features ADD CONSTRAINT fk_18513d9b92 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; @@ -31312,6 +31357,9 @@ ALTER TABLE ONLY users ALTER TABLE ONLY analytics_devops_adoption_snapshots ADD CONSTRAINT fk_78c9eac821 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; +ALTER TABLE ONLY project_relation_exports + ADD CONSTRAINT fk_7a4d3d5c0f FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + ALTER TABLE ONLY lists ADD CONSTRAINT fk_7a5553d60f FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE; diff --git a/doc/administration/auth/oidc.md b/doc/administration/auth/oidc.md index c2896f1be26..6f7e01fbcd2 100644 --- a/doc/administration/auth/oidc.md +++ b/doc/administration/auth/oidc.md @@ -295,7 +295,7 @@ gitlab_rails['omniauth_providers'] = [ name: "azure_oauth2", label: "Azure OIDC", # optional label for login button, defaults to "Openid Connect" args: { - name: "azure_activedirectory_v2", + name: "azure_oauth2", strategy_class: "OmniAuth::Strategies::OpenIDConnect", scope: ["openid", "profile", "email"], response_type: "code", @@ -319,7 +319,7 @@ gitlab_rails['omniauth_providers'] = [ ```ruby gitlab_rails['omniauth_providers'] = [ { - name: "azure_oauth2", + name: "azure_activedirectory_v2", label: "Azure OIDC", # optional label for login button, defaults to "Openid Connect" args: { name: "azure_activedirectory_v2", diff --git a/doc/administration/settings/import_and_export_settings.md b/doc/administration/settings/import_and_export_settings.md index 247fc47c9ae..be47f1047fa 100644 --- a/doc/administration/settings/import_and_export_settings.md +++ b/doc/administration/settings/import_and_export_settings.md @@ -39,12 +39,18 @@ To enable the export of ## Enable migration of groups and projects by direct transfer +DETAILS: +**Status:** Beta + > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383268) in GitLab 15.8. -> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/461326) in GitLab 17.1. WARNING: In GitLab 16.1 and earlier, you should **not** use direct transfer with [scheduled scan execution policies](../../user/application_security/policies/scan-execution-policies.md). If using direct transfer, first upgrade to GitLab 16.2 and ensure security policy bots are enabled in the projects you are enforcing. +WARNING: +This feature is in [beta](../../policy/experiment-beta-support.md#beta) and subject to change without notice. +This feature is not ready for production use. + Migration of groups and projects by direct transfer is disabled by default. To enable migration of groups and projects by direct transfer: diff --git a/doc/api/bulk_imports.md b/doc/api/bulk_imports.md index 3e23449f44e..69f086a9253 100644 --- a/doc/api/bulk_imports.md +++ b/doc/api/bulk_imports.md @@ -15,6 +15,10 @@ DETAILS: With the group migration by direct transfer API, you can start and view the progress of migrations initiated with [group migration by direct transfer](../user/group/import/index.md). +WARNING: +Migrating projects with this API is in [beta](../policy/experiment-beta-support.md#beta). This feature is not +ready for production use. + ## Prerequisites For information on prerequisites for group migration by direct transfer API, see @@ -27,7 +31,7 @@ prerequisites for [migrating groups by direct transfer](../user/group/import/dir Use this endpoint to start a new group or project migration. Specify: - `entities[group_entity]` to migrate a group. -- `entities[project_entity]` to migrate a project. +- `entities[project_entity]` to migrate a project. (**Status:** Beta) ```plaintext POST /bulk_imports diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index f3490b641e3..2ea9ed6e235 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -906,7 +906,7 @@ Returns [`[CiRunnerUsage!]`](#cirunnerusage). | Name | Type | Description | | ---- | ---- | ----------- | | `fromDate` | [`Date`](#date) | Start of the requested date frame. Defaults to the start of the previous calendar month. | -| `fullPath` | [`ID`](#id) | Filter jobs by the full path of the group or project they belong to. For example, `gitlab-org` or `gitlab-org/gitlab`. Available only to admins, group maintainers (when a group is specified), or project maintainers (when a project is specified). Limited to runners from 5000 child projects. | +| `fullPath` | [`ID`](#id) | Filter jobs by the full path of the group or project they belong to. For example, `gitlab-org` or `gitlab-org/gitlab`. Available only to administrators and users with the Maintainer role for the group (when a group is specified), or project (when a project is specified). Limited to runners from 5000 child projects. | | `runnerType` | [`CiRunnerType`](#cirunnertype) | Filter runners by the type. | | `runnersLimit` | [`Int`](#int) | Maximum number of runners to return. Other runners will be aggregated to a `runner: null` entry. Defaults to 5 if unspecified. Maximum of 500. | | `toDate` | [`Date`](#date) | End of the requested date frame. Defaults to the end of the previous calendar month. | @@ -926,7 +926,7 @@ Returns [`[CiRunnerUsageByProject!]`](#cirunnerusagebyproject). | Name | Type | Description | | ---- | ---- | ----------- | | `fromDate` | [`Date`](#date) | Start of the requested date frame. Defaults to the start of the previous calendar month. | -| `fullPath` | [`ID`](#id) | Filter jobs based on the full path of the group or project they belong to. For example, `gitlab-org` or `gitlab-org/gitlab`. Available only to admins, group maintainers (when a group is specified), or project maintainers (when a project is specified). Limited to runners from 5000 child projects. | +| `fullPath` | [`ID`](#id) | Filter jobs based on the full path of the group or project they belong to. For example, `gitlab-org` or `gitlab-org/gitlab`. Available only to administrators and users with the Maintainer role for the group (when a group is specified), or project (when a project is specified). Limited to runners from 5000 child projects. | | `projectsLimit` | [`Int`](#int) | Maximum number of projects to return. Other projects will be aggregated to a `project: null` entry. Defaults to 5 if unspecified. Maximum of 500. | | `runnerType` | [`CiRunnerType`](#cirunnertype) | Filter jobs by the type of runner that executed them. | | `toDate` | [`Date`](#date) | End of the requested date frame. Defaults to the end of the previous calendar month. | @@ -8064,6 +8064,7 @@ Input type: `RunnersExportUsageInput` | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `fromDate` | [`ISO8601Date`](#iso8601date) | UTC start date of the period to report on. Defaults to the start of last full month. | +| `fullPath` | [`ID`](#id) | Filter jobs by the full path of the group or project they belong to. For example, `gitlab-org` or `gitlab-org/gitlab`. Available only to administrators and users with the Maintainer role for the group (when a group is specified), or project (when a project is specified). Limited to runners from 5000 child projects. | | `maxProjectCount` | [`Int`](#int) | Maximum number of projects to return. All other runner usage will be attributed to an `` entry. Defaults to 1000 projects. | | `runnerType` | [`CiRunnerType`](#cirunnertype) | Scope of the runners to include in the report. | | `toDate` | [`ISO8601Date`](#iso8601date) | UTC end date of the period to report on. " \ "Defaults to the end of the month specified by `fromDate`. | diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md index 10dbfdad88e..2483a1344ff 100644 --- a/doc/api/oauth2.md +++ b/doc/api/oauth2.md @@ -106,7 +106,7 @@ Before starting the flow, generate the `STATE`, the `CODE_VERIFIER` and the `COD - The `CODE_VERIFIER` is a random string, between 43 and 128 characters in length, which use the characters `A-Z`, `a-z`, `0-9`, `-`, `.`, `_`, and `~`. - The `CODE_CHALLENGE` is an URL-safe base64-encoded string of the SHA256 hash of the - `CODE_VERIFIER` + `CODE_VERIFIER`. - The SHA256 hash must be in binary format before encoding. - In Ruby, you can set that up with `Base64.urlsafe_encode64(Digest::SHA256.digest(CODE_VERIFIER), padding: false)`. - For reference, a `CODE_VERIFIER` string of `ks02i3jdikdo2k0dkfodf3m39rjfjsdk0wk349rj3jrhf` when hashed diff --git a/doc/development/rails_update.md b/doc/development/rails_update.md index d00a1681e76..277af8d4092 100644 --- a/doc/development/rails_update.md +++ b/doc/development/rails_update.md @@ -18,10 +18,12 @@ We strive to run GitLab using the latest Rails releases to benefit from performa 1. Check the [Upgrading Ruby on Rails](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html) guide and prepare the application for the upcoming changes. 1. Update the `rails` gem version in `Gemfile`. -1. Run `bundle update rails`. -1. Run the update task `rake rails:update`. +1. Run `bundle update --conservative rails`. +1. For major and minor version updates, run `bin/rails app:update` and check if any of the suggested changes should be applied. 1. Update the `activesupport` version in `qa/Gemfile`. 1. Run `bundle update --conservative activesupport` in the `qa` folder. +1. Update the `activerecord_version` version in `vendor/gems/attr_encrypted/attr_encrypted.gemspec`. +1. Run `bundle update --conservative activerecord` in the `vendor/gems/attr_encrypted` folder. 1. Resolve any Bundler conflicts. 1. Ensure that `@rails/ujs` and `@rails/actioncable` npm packages match the new rails version in [`package.json`](https://gitlab.com/gitlab-org/gitlab/blob/master/package.json). 1. Run `yarn patch-package @rails/ujs` after updating this to ensure our local patch file version matches. diff --git a/doc/user/group/import/direct_transfer_migrations.md b/doc/user/group/import/direct_transfer_migrations.md index 6e4809ce39c..1b613e6c4e0 100644 --- a/doc/user/group/import/direct_transfer_migrations.md +++ b/doc/user/group/import/direct_transfer_migrations.md @@ -114,6 +114,10 @@ role. 1. The **Status** column shows the import status of each group. If you leave the page open, it updates in real-time. 1. After a group has been imported, select its GitLab path to open its GitLab URL. +WARNING: +Importing groups with projects is in [beta](../../../policy/experiment-beta-support.md#beta). This feature is not +ready for production use. + ## Group import history > - **Partially completed** status [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/394727) in GitLab 16.7. diff --git a/doc/user/group/import/index.md b/doc/user/group/import/index.md index 577ccfb78e9..9aa11a86e3c 100644 --- a/doc/user/group/import/index.md +++ b/doc/user/group/import/index.md @@ -43,13 +43,19 @@ Migrating groups by direct transfer copies the groups from one place to another. - The subgroup of any existing top-level group. - Another GitLab instance, including GitLab.com. - In the [API](../../../api/bulk_imports.md), copy top-level groups and subgroups to these locations. -- Copy groups with projects or without projects. +- Copy groups with projects (in [beta](../../../policy/experiment-beta-support.md#beta) and not ready for production + use) or without projects. Copying projects with groups is available: + - On GitLab.com by default. Not all group and project resources are copied. See list of copied resources below: - [Migrated group items](migrated_items.md#migrated-group-items). - [Migrated project items](migrated_items.md#migrated-project-items). +WARNING: +Importing groups with projects is in [beta](../../../policy/experiment-beta-support.md#beta). This feature is not +ready for production use. + We invite you to leave your feedback about migrating by direct transfer in [the feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/284495). diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md index debea3edb65..f801ff04fb0 100644 --- a/doc/user/project/issues/managing_issues.md +++ b/doc/user/project/issues/managing_issues.md @@ -460,7 +460,7 @@ To view all issues assigned to you: Or: - To use a [keyboard shortcut](../../shortcuts.md), press Shift + i. -- On the left sidebar, at the top, select **Issues** (**{issues}**). +- On the left sidebar, at the top, select **Assigned issues** (**{issues}**). ## Filter the list of issues diff --git a/lib/gitlab/background_migration/backfill_project_relation_exports_project_id.rb b/lib/gitlab/background_migration/backfill_project_relation_exports_project_id.rb new file mode 100644 index 00000000000..94171f1ae76 --- /dev/null +++ b/lib/gitlab/background_migration/backfill_project_relation_exports_project_id.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + class BackfillProjectRelationExportsProjectId < BackfillDesiredShardingKeyJob + operation_name :backfill_project_relation_exports_project_id + feature_category :importers + end + end +end diff --git a/lib/gitlab/background_migration/backfill_terraform_state_versions_project_id.rb b/lib/gitlab/background_migration/backfill_terraform_state_versions_project_id.rb new file mode 100644 index 00000000000..17e34af40ec --- /dev/null +++ b/lib/gitlab/background_migration/backfill_terraform_state_versions_project_id.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + class BackfillTerraformStateVersionsProjectId < BackfillDesiredShardingKeyJob + operation_name :backfill_terraform_state_versions_project_id + feature_category :infrastructure_as_code + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9b8903c2db7..2bfd33347f1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7151,7 +7151,7 @@ msgstr "" msgid "Assigned %{reviewer_users_sentence} as %{reviewer_text}." msgstr "" -msgid "Assigned Issues" +msgid "Assigned issues" msgstr "" msgid "Assigned merge requests" @@ -9671,6 +9671,9 @@ msgstr "" msgid "BulkImport|Import without projects" msgstr "" +msgid "BulkImport|Importing projects is a %{docsLinkStart}Beta%{docsLinkEnd} feature." +msgstr "" + msgid "BulkImport|Importing the group failed." msgstr "" @@ -33297,6 +33300,9 @@ msgstr "" msgid "MlModelRegistry|Failed to load model with error: %{message}" msgstr "" +msgid "MlModelRegistry|File \"%{name}\" is %{size}. It is larger than max allowed size of %{maxAllowedFileSize}" +msgstr "" + msgid "MlModelRegistry|For example 1.0.0" msgstr "" @@ -33422,6 +33428,9 @@ msgid_plural "MlModelRegistry|ยท %d versions" msgstr[0] "" msgstr[1] "" +msgid "Mlmodelregistry|Provide the max allowed file size" +msgstr "" + msgid "Mock an external CI integration." msgstr "" @@ -60846,6 +60855,15 @@ msgstr "" msgid "Your CI runner usage CSV export containing the top %{exported_objects} has been added to this email as an attachment." msgstr "" +msgid "Your CI runner usage CSV export containing the top %{exported_objects} in the \"%{full_path}\" group has been added to this email as an attachment." +msgstr "" + +msgid "Your CI runner usage CSV export for the \"%{full_path}\" project has been added to this email as an attachment." +msgstr "" + +msgid "Your CI runner usage CSV export of the top %{exported_objects} has been added to this email as an attachment." +msgstr "" + msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details." msgstr "" @@ -60858,9 +60876,6 @@ msgstr "" msgid "Your CSV export of %{exported_objects} from project %{project_name} (%{project_url}) has been added to this email as an attachment." msgstr "" -msgid "Your CSV export of the top %{exported_objects} has been added to this email as an attachment." -msgstr "" - msgid "Your CSV export request has succeeded. The result will be emailed to %{email}." msgstr "" diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb index d34f8cb3e18..4035c9e2f20 100644 --- a/spec/features/dashboard/issuables_counter_spec.rb +++ b/spec/features/dashboard/issuables_counter_spec.rb @@ -55,7 +55,7 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching, expect(dashboard_count).to have_content(count) within_testid('super-sidebar') do - expect(page).to have_link("Issues #{count}") + expect(page).to have_link("Assigned issues #{count}") end end diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index ccd7224a9be..239999da3c7 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -16,7 +16,7 @@ RSpec.describe 'Dashboard shortcuts', :js, feature_category: :shared do it 'navigate to tabs' do find('body').send_keys([:shift, 'I']) - check_page_title('Issues') + check_page_title('Assigned issues') find('body').send_keys([:shift, 'M']) diff --git a/spec/frontend/ml/model_registry/apps/index_ml_models_spec.js b/spec/frontend/ml/model_registry/apps/index_ml_models_spec.js index 10c3f6d1dd1..e9cb3865e90 100644 --- a/spec/frontend/ml/model_registry/apps/index_ml_models_spec.js +++ b/spec/frontend/ml/model_registry/apps/index_ml_models_spec.js @@ -21,6 +21,7 @@ Vue.use(VueApollo); const defaultProps = { projectPath: 'path/to/project', canWriteModelRegistry: false, + maxAllowedFileSize: 99999, }; describe('ml/model_registry/apps/index_ml_models', () => { diff --git a/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js b/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js index a380914f770..21e01d9405a 100644 --- a/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js +++ b/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js @@ -89,6 +89,7 @@ describe('ml/model_registry/apps/show_ml_model', () => { indexModelsPath: 'index/path', mlflowTrackingUrl: 'path/to/tracking', canWriteModelRegistry, + maxAllowedFileSize: 99999, }, stubs: { GlTab, DeleteModel, LoadOrErrorOrShow }, }); diff --git a/spec/frontend/ml/model_registry/apps/show_ml_model_version_spec.js b/spec/frontend/ml/model_registry/apps/show_ml_model_version_spec.js index cd2b0095215..7e0afa9ae95 100644 --- a/spec/frontend/ml/model_registry/apps/show_ml_model_version_spec.js +++ b/spec/frontend/ml/model_registry/apps/show_ml_model_version_spec.js @@ -60,6 +60,7 @@ describe('ml/model_registry/apps/show_model_version.vue', () => { canWriteModelRegistry: true, importPath: 'path/to/import', modelPath: 'path/to/model', + maxAllowedFileSize: 99999, }, apolloProvider, stubs: { diff --git a/spec/frontend/ml/model_registry/components/import_artifact_zone_spec.js b/spec/frontend/ml/model_registry/components/import_artifact_zone_spec.js index 9374920e9d9..0dd29b3b55b 100644 --- a/spec/frontend/ml/model_registry/components/import_artifact_zone_spec.js +++ b/spec/frontend/ml/model_registry/components/import_artifact_zone_spec.js @@ -13,6 +13,8 @@ jest.mock('~/ml/model_registry/services/upload_model', () => ({ describe('ImportArtifactZone', () => { let wrapper; + const provide = { maxAllowedFileSize: 99999 }; + const file = { name: 'file.txt', size: 1024 }; const initialProps = { path: 'some/path', @@ -32,6 +34,7 @@ describe('ImportArtifactZone', () => { propsData: { ...initialProps, }, + provide, }); }); @@ -71,6 +74,7 @@ describe('ImportArtifactZone', () => { }, importPath: 'some/path', subfolder: '', + maxAllowedFileSize: 99999, }); }); @@ -96,6 +100,7 @@ describe('ImportArtifactZone', () => { propsData: { ...initialProps, }, + provide, stubs: { GlFormInputGroup, }, @@ -128,6 +133,7 @@ describe('ImportArtifactZone', () => { }, importPath: 'some/path', subfolder: 'action', + maxAllowedFileSize: 99999, }); }); }); @@ -138,6 +144,7 @@ describe('ImportArtifactZone', () => { propsData: { ...initialProps, }, + provide, }); }); @@ -169,6 +176,7 @@ describe('ImportArtifactZone', () => { ...initialProps, submitOnSelect: false, }, + provide, }); }); @@ -188,6 +196,7 @@ describe('ImportArtifactZone', () => { ...initialProps, path: null, }, + provide, }); }); diff --git a/spec/frontend/ml/model_registry/components/model_create_spec.js b/spec/frontend/ml/model_registry/components/model_create_spec.js index 3b769df4dae..b13ebb3b084 100644 --- a/spec/frontend/ml/model_registry/components/model_create_spec.js +++ b/spec/frontend/ml/model_registry/components/model_create_spec.js @@ -1,11 +1,12 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; -import { GlAlert, GlModal } from '@gitlab/ui'; +import { GlModal } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import * as Sentry from '~/sentry/sentry_browser_wrapper'; import { visitUrl } from '~/lib/utils/url_utility'; import ModelCreate from '~/ml/model_registry/components/model_create.vue'; import ImportArtifactZone from '~/ml/model_registry/components/import_artifact_zone.vue'; +import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue'; import { uploadModel } from '~/ml/model_registry/services/upload_model'; import createModelMutation from '~/ml/model_registry/graphql/mutations/create_model.mutation.graphql'; import createModelVersionMutation from '~/ml/model_registry/graphql/mutations/create_model_version.mutation.graphql'; @@ -29,6 +30,8 @@ describe('ModelCreate', () => { let wrapper; let apolloProvider; + const file = { name: 'file.txt', size: 1024 }; + beforeEach(() => { jest.spyOn(Sentry, 'captureException').mockImplementation(); }); @@ -54,8 +57,12 @@ describe('ModelCreate', () => { }, provide: { projectPath: 'some/project', + maxAllowedFileSize: 99999, }, apolloProvider, + stubs: { + ImportArtifactZone, + }, }); }; @@ -65,8 +72,9 @@ describe('ModelCreate', () => { const findDescriptionInput = () => wrapper.findByTestId('descriptionId'); const findVersionDescriptionInput = () => wrapper.findByTestId('versionDescriptionId'); const findImportArtifactZone = () => wrapper.findComponent(ImportArtifactZone); + const zone = () => wrapper.findComponent(UploadDropzone); const findGlModal = () => wrapper.findComponent(GlModal); - const findGlAlert = () => wrapper.findComponent(GlAlert); + const findGlAlert = () => wrapper.findByTestId('modal-create-alert'); const submitForm = async () => { findGlModal().vm.$emit('primary', new Event('primary')); await waitForPromises(); @@ -181,6 +189,8 @@ describe('ModelCreate', () => { findVersionInput().vm.$emit('input', '1.0.0'); findDescriptionInput().vm.$emit('input', 'My model description'); findVersionDescriptionInput().vm.$emit('input', 'My version description'); + await Vue.nextTick(); + zone().vm.$emit('change', file); jest.spyOn(apolloProvider.defaultClient, 'mutate'); await submitForm(); @@ -215,9 +225,10 @@ describe('ModelCreate', () => { it('Uploads a file mutation upon confirm', () => { expect(uploadModel).toHaveBeenCalledWith({ - file: null, + file, importPath: '/api/v4/projects/1/packages/ml_models/1/files/', subfolder: '', + maxAllowedFileSize: 99999, }); }); @@ -256,6 +267,8 @@ describe('ModelCreate', () => { findNameInput().vm.$emit('input', 'gpt-alice-1'); findVersionInput().vm.$emit('input', '1.0.0'); findVersionDescriptionInput().vm.$emit('input', 'My version description'); + await Vue.nextTick(); + zone().vm.$emit('change', file); await submitForm(); }); @@ -304,6 +317,8 @@ describe('ModelCreate', () => { findVersionInput().vm.$emit('input', '1.0.0'); findDescriptionInput().vm.$emit('input', 'My model description'); findVersionDescriptionInput().vm.$emit('input', 'My version description'); + await Vue.nextTick(); + zone().vm.$emit('change', file); uploadModel.mockRejectedValueOnce('Artifact import error.'); await submitForm(); }); @@ -313,6 +328,16 @@ describe('ModelCreate', () => { await submitForm(); // retry submit expect(visitUrl).toHaveBeenCalledWith('/some/project/-/ml/models/1/versions/1'); }); + + it('Uploads a file mutation upon confirm', async () => { + await submitForm(); // retry submit + expect(uploadModel).toHaveBeenCalledWith({ + file, + importPath: '/api/v4/projects/1/packages/ml_models/1/files/', + subfolder: '', + maxAllowedFileSize: 99999, + }); + }); }); describe('Failed flow without version', () => { diff --git a/spec/frontend/ml/model_registry/components/model_detail_spec.js b/spec/frontend/ml/model_registry/components/model_detail_spec.js index 2c3c59241fc..ad51626a15f 100644 --- a/spec/frontend/ml/model_registry/components/model_detail_spec.js +++ b/spec/frontend/ml/model_registry/components/model_detail_spec.js @@ -11,6 +11,7 @@ let wrapper; const createWrapper = (modelProp = model) => { wrapper = shallowMountExtended(ModelDetail, { propsData: { model: modelProp }, + provide: { maxAllowedFileSize: 99999 }, stubs: { GlTab }, }); }; diff --git a/spec/frontend/ml/model_registry/components/model_version_create_spec.js b/spec/frontend/ml/model_registry/components/model_version_create_spec.js index 6ab37352ac9..7045e8be81d 100644 --- a/spec/frontend/ml/model_registry/components/model_version_create_spec.js +++ b/spec/frontend/ml/model_registry/components/model_version_create_spec.js @@ -6,6 +6,7 @@ import * as Sentry from '~/sentry/sentry_browser_wrapper'; import { visitUrl } from '~/lib/utils/url_utility'; import ModelVersionCreate from '~/ml/model_registry/components/model_version_create.vue'; import ImportArtifactZone from '~/ml/model_registry/components/import_artifact_zone.vue'; +import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue'; import { uploadModel } from '~/ml/model_registry/services/upload_model'; import createModelVersionMutation from '~/ml/model_registry/graphql/mutations/create_model_version.mutation.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; @@ -28,6 +29,8 @@ describe('ModelVersionCreate', () => { let wrapper; let apolloProvider; + const file = { name: 'file.txt', size: 1024 }; + beforeEach(() => { jest.spyOn(Sentry, 'captureException').mockImplementation(); }); @@ -45,11 +48,15 @@ describe('ModelVersionCreate', () => { wrapper = shallowMountExtended(ModelVersionCreate, { provide: { projectPath: 'some/project', + maxAllowedFileSize: 99999, }, propsData: { modelGid: 'gid://gitlab/Ml::Model/1', }, apolloProvider, + stubs: { + UploadDropzone, + }, }); }; @@ -57,6 +64,7 @@ describe('ModelVersionCreate', () => { const findVersionInput = () => wrapper.findByTestId('versionId'); const findDescriptionInput = () => wrapper.findByTestId('descriptionId'); const findImportArtifactZone = () => wrapper.findComponent(ImportArtifactZone); + const zone = () => wrapper.findComponent(UploadDropzone); const findGlModal = () => wrapper.findComponent(GlModal); const findGlAlert = () => wrapper.findComponent(GlAlert); const submitForm = async () => { @@ -128,6 +136,7 @@ describe('ModelVersionCreate', () => { createWrapper(); findVersionInput().vm.$emit('input', '1.0.0'); findDescriptionInput().vm.$emit('input', 'My model version description'); + zone().vm.$emit('change', file); jest.spyOn(apolloProvider.defaultClient, 'mutate'); await submitForm(); @@ -149,11 +158,13 @@ describe('ModelVersionCreate', () => { it('Uploads a file mutation upon confirm', () => { expect(uploadModel).toHaveBeenCalledWith({ - file: null, + file, importPath: '/api/v4/projects/1/packages/ml_models/1/files/', subfolder: '', + maxAllowedFileSize: 99999, }); }); + it('Visits the model versions page upon successful create mutation', async () => { createWrapper(); @@ -194,18 +205,29 @@ describe('ModelVersionCreate', () => { describe('Failed flow with file upload retried', () => { beforeEach(async () => { createWrapper(); + findVersionInput().vm.$emit('input', '1.0.0'); + zone().vm.$emit('change', file); uploadModel.mockRejectedValueOnce('Artifact import error.'); await submitForm(); }); it('Visits the model versions page upon successful create mutation', async () => { - expect(findGlAlert().text()).toBe('Artifact import error.'); - await submitForm(); expect(visitUrl).toHaveBeenCalledWith('/some/project/-/ml/models/1/versions/1'); }); + + it('Uploads the model upon retry', async () => { + await submitForm(); + + expect(uploadModel).toHaveBeenCalledWith({ + file, + importPath: '/api/v4/projects/1/packages/ml_models/1/files/', + subfolder: '', + maxAllowedFileSize: 99999, + }); + }); }); }); }); diff --git a/spec/frontend/ml/model_registry/components/model_version_detail_spec.js b/spec/frontend/ml/model_registry/components/model_version_detail_spec.js index 3225ffba3aa..7e3a1d1591e 100644 --- a/spec/frontend/ml/model_registry/components/model_version_detail_spec.js +++ b/spec/frontend/ml/model_registry/components/model_version_detail_spec.js @@ -35,6 +35,7 @@ const createWrapper = (modelVersion = modelVersionWithCandidate, props = {}, pro projectPath: 'path/to/project', canWriteModelRegistry: true, importPath: 'path/to/import', + maxAllowedFileSize: 99999, ...provide, }, }); diff --git a/spec/frontend/ml/model_registry/services/upload_model_spec.js b/spec/frontend/ml/model_registry/services/upload_model_spec.js index 096b56ebf46..e3173643325 100644 --- a/spec/frontend/ml/model_registry/services/upload_model_spec.js +++ b/spec/frontend/ml/model_registry/services/upload_model_spec.js @@ -4,6 +4,8 @@ import { uploadModel } from '~/ml/model_registry/services/upload_model'; describe('uploadModel', () => { const importPath = 'some/path'; const file = { name: 'file.txt', size: 1024 }; + const largeFile = { name: 'file.txt', size: 2024 }; + const maxAllowedFileSize = 2000; let axiosMock; beforeEach(() => { @@ -18,7 +20,7 @@ describe('uploadModel', () => { it('should upload a file to the specified import path', async () => { const filePath = `${importPath}/${encodeURIComponent(file.name)}`; - await uploadModel({ importPath, file }); + await uploadModel({ importPath, file, maxAllowedFileSize }); expect(axiosMock).toHaveBeenCalledTimes(1); expect(axiosMock).toHaveBeenCalledWith(filePath, expect.any(FormData), { @@ -32,7 +34,7 @@ describe('uploadModel', () => { const subfolder = 'action'; const filePath = `${importPath}/action/${encodeURIComponent(file.name)}`; - await uploadModel({ importPath, file, subfolder }); + await uploadModel({ importPath, file, subfolder, maxAllowedFileSize }); expect(axiosMock).toHaveBeenCalledTimes(1); expect(axiosMock).toHaveBeenCalledWith(filePath, expect.any(FormData), { @@ -47,4 +49,12 @@ describe('uploadModel', () => { expect(axiosMock).not.toHaveBeenCalled(); }); + + it('should raise an error for large files', async () => { + await expect( + uploadModel({ importPath: 'some/path', file: largeFile, maxAllowedFileSize }), + ).rejects.toThrow( + new Error('File "file.txt" is 1.98 KiB. It is larger than max allowed size of 1.95 KiB'), + ); + }); }); diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js index 5909ee663cb..a56bedb619c 100644 --- a/spec/frontend/super_sidebar/components/user_bar_spec.js +++ b/spec/frontend/super_sidebar/components/user_bar_spec.js @@ -106,7 +106,7 @@ describe('UserBar component', () => { const isuesCounter = findIssuesCounter(); expect(isuesCounter.props('count')).toBe(userCounts.assigned_issues); expect(isuesCounter.props('href')).toBe(mockSidebarData.issues_dashboard_path); - expect(isuesCounter.props('label')).toBe(__('Issues')); + expect(isuesCounter.props('label')).toBe(__('Assigned issues')); expect(isuesCounter.attributes('data-track-action')).toBe('click_link'); expect(isuesCounter.attributes('data-track-label')).toBe('issues_link'); expect(isuesCounter.attributes('data-track-property')).toBe('nav_core_menu'); diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index 5306b86d08f..9f584971bfd 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -36,7 +36,7 @@ RSpec.describe PreferencesHelper do { text: "Followed Users' Activity", value: 'followed_user_activity' }, { text: "Your Groups", value: 'groups' }, { text: "Your To-Do List", value: 'todos' }, - { text: "Assigned Issues", value: 'issues' }, + { text: "Assigned issues", value: 'issues' }, { text: "Assigned merge requests", value: 'merge_requests' } ] end diff --git a/spec/helpers/projects/ml/model_registry_helper_spec.rb b/spec/helpers/projects/ml/model_registry_helper_spec.rb index e3021cf3707..41f4f7dfa43 100644 --- a/spec/helpers/projects/ml/model_registry_helper_spec.rb +++ b/spec/helpers/projects/ml/model_registry_helper_spec.rb @@ -17,6 +17,7 @@ RSpec.describe Projects::Ml::ModelRegistryHelper, feature_category: :mlops do 'projectPath' => project.full_path, 'createModelPath' => "/#{project.full_path}/-/ml/models/new", 'canWriteModelRegistry' => true, + 'maxAllowedFileSize' => 10737418240, 'mlflowTrackingUrl' => "http://localhost/api/v4/projects/#{project.id}/ml/mlflow/" }) end @@ -47,6 +48,7 @@ RSpec.describe Projects::Ml::ModelRegistryHelper, feature_category: :mlops do 'projectPath' => project.full_path, 'indexModelsPath' => "/#{project.full_path}/-/ml/models", 'canWriteModelRegistry' => true, + 'maxAllowedFileSize' => 10737418240, 'mlflowTrackingUrl' => "http://localhost/api/v4/projects/#{project.id}/ml/mlflow/", 'modelId' => model.id, 'modelName' => 'cool_model' @@ -86,6 +88,7 @@ RSpec.describe Projects::Ml::ModelRegistryHelper, feature_category: :mlops do "modelName" => model_version.name, "versionName" => model_version.version, "canWriteModelRegistry" => true, + 'maxAllowedFileSize' => 10737418240, "importPath" => "/api/v4/projects/#{project.id}/packages/ml_models/#{model_version.id}/files/", "modelPath" => "/#{project.full_path}/-/ml/models/1" }) diff --git a/spec/lib/gitlab/background_migration/backfill_project_relation_exports_project_id_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_relation_exports_project_id_spec.rb new file mode 100644 index 00000000000..afc0f17999b --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_project_relation_exports_project_id_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillProjectRelationExportsProjectId, + feature_category: :importers, + schema: 20240605113246 do + include_examples 'desired sharding key backfill job' do + let(:batch_table) { :project_relation_exports } + let(:backfill_column) { :project_id } + let(:backfill_via_table) { :project_export_jobs } + let(:backfill_via_column) { :project_id } + let(:backfill_via_foreign_key) { :project_export_job_id } + end +end diff --git a/spec/lib/gitlab/background_migration/backfill_terraform_state_versions_project_id_spec.rb b/spec/lib/gitlab/background_migration/backfill_terraform_state_versions_project_id_spec.rb new file mode 100644 index 00000000000..bdeb56dcb5e --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_terraform_state_versions_project_id_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillTerraformStateVersionsProjectId, + feature_category: :infrastructure_as_code, + schema: 20240605132806 do + include_examples 'desired sharding key backfill job' do + let(:batch_table) { :terraform_state_versions } + let(:backfill_column) { :project_id } + let(:backfill_via_table) { :terraform_states } + let(:backfill_via_column) { :project_id } + let(:backfill_via_foreign_key) { :terraform_state_id } + end +end diff --git a/spec/migrations/20240605113250_queue_backfill_project_relation_exports_project_id_spec.rb b/spec/migrations/20240605113250_queue_backfill_project_relation_exports_project_id_spec.rb new file mode 100644 index 00000000000..e48be5a2249 --- /dev/null +++ b/spec/migrations/20240605113250_queue_backfill_project_relation_exports_project_id_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillProjectRelationExportsProjectId, feature_category: :importers do + let!(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :project_relation_exports, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE, + gitlab_schema: :gitlab_main_cell, + job_arguments: [ + :project_id, + :project_export_jobs, + :project_id, + :project_export_job_id + ] + ) + } + end + end +end diff --git a/spec/migrations/20240605132810_queue_backfill_terraform_state_versions_project_id_spec.rb b/spec/migrations/20240605132810_queue_backfill_terraform_state_versions_project_id_spec.rb new file mode 100644 index 00000000000..dce3aea7d7e --- /dev/null +++ b/spec/migrations/20240605132810_queue_backfill_terraform_state_versions_project_id_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillTerraformStateVersionsProjectId, feature_category: :infrastructure_as_code do + let!(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :terraform_state_versions, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE, + gitlab_schema: :gitlab_main_cell, + job_arguments: [ + :project_id, + :terraform_states, + :project_id, + :terraform_state_id + ] + ) + } + end + end +end diff --git a/spec/rails_autoload.rb b/spec/rails_autoload.rb index d3518acf8b2..865b6790260 100644 --- a/spec/rails_autoload.rb +++ b/spec/rails_autoload.rb @@ -48,9 +48,22 @@ require_relative '../config/initializers/0_inject_enterprise_edition_module' require_relative '../config/initializers_before_autoloader/000_inflections' require_relative '../config/initializers_before_autoloader/004_zeitwerk' -Rails.autoloaders.each do |autoloader| - autoloader.push_dir('lib') - autoloader.push_dir('ee/lib') if Gitlab.ee? - autoloader.push_dir('jh/lib') if Gitlab.jh? - autoloader.setup +# We wrap this bit of logic in a module to avoid polluting the global namespace with a local variable and methods +module AutoloadersSetup + def self.dir_already_autoloaded?(autoloaded_dirs, dir) + autoloaded_dirs.any? { File.expand_path(dir, __dir__) } + end + + def self.setup_autoloaders + autoloaded_dirs = [] # NOTE: can't use Rails.autoloaders.each_with_object, it doesn't work, so we need a local var. + Rails.autoloaders.each do |autoloader| + autoloader.push_dir('lib') unless dir_already_autoloaded?(autoloaded_dirs, "../lib") + autoloader.push_dir('ee/lib') if Gitlab.ee? && !dir_already_autoloaded?(autoloaded_dirs, "../ee/lib") + autoloader.push_dir('jh/lib') if Gitlab.jh? && !dir_already_autoloaded?(autoloaded_dirs, "../jh/lib") + autoloader.setup + autoloaded_dirs += autoloader.dirs + end + end end + +AutoloadersSetup.setup_autoloaders diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb index 025b721ff9b..8de581f1b2d 100644 --- a/spec/support/shared_examples/features/work_items_shared_examples.rb +++ b/spec/support/shared_examples/features/work_items_shared_examples.rb @@ -735,13 +735,13 @@ RSpec.shared_examples 'work items time tracking' do click_button '3d' expect(page).to have_css 'h2', text: 'Time tracking report' - expect(page).to have_text '1d Sidney Jones1 First summary' - expect(page).to have_text '2d Sidney Jones1 Second summary' + expect(page).to have_text "1d #{user.name} First summary" + expect(page).to have_text "2d #{user.name} Second summary" click_button 'Delete time spent', match: :first - expect(page).to have_text '1d Sidney Jones1 First summary' - expect(page).not_to have_text '2d Sidney Jones1 Second summary' + expect(page).to have_text "1d #{user.name} First summary" + expect(page).not_to have_text "2d #{user.name} Second summary" click_button 'Close' diff --git a/workhorse/testdata/localhost.crt b/workhorse/testdata/localhost.crt index bee60e42e00..eea46eb34f4 100644 --- a/workhorse/testdata/localhost.crt +++ b/workhorse/testdata/localhost.crt @@ -1,27 +1,21 @@ -----BEGIN CERTIFICATE----- -MIIEjjCCAvagAwIBAgIQC2au+A/aGQ2Z21O0wVoEwjANBgkqhkiG9w0BAQsFADCB -pTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMT0wOwYDVQQLDDRpZ29y -ZHJvemRvdkBJZ29ycy1NYWNCb29rLVByby0yLmxvY2FsIChJZ29yIERyb3pkb3Yp -MUQwQgYDVQQDDDtta2NlcnQgaWdvcmRyb3pkb3ZASWdvcnMtTWFjQm9vay1Qcm8t -Mi5sb2NhbCAoSWdvciBEcm96ZG92KTAeFw0yMjAzMDcwNDMxMjRaFw0yNDA2MDcw -NDMxMjRaMGgxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0 -ZTE9MDsGA1UECww0aWdvcmRyb3pkb3ZASWdvcnMtTWFjQm9vay1Qcm8tMi5sb2Nh -bCAoSWdvciBEcm96ZG92KTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AMJ8ofGdcnenVRtNGViF4oxPv+CCFA6D2nfsjkJG8kmO6WW7VlbhJYxCMAuyFF1F -b2UI2rrTFL8Aeq1KxeQzdrb3cpCquVH/UQ00G4ply28XVPRdbIyLQvOThMEeLL6v -6gb4edL5oZmo/vWhdQxv0NGt282PAEt+bjnbdl28on8WVzmsw/m0nZ2BVWke+oUM -krfsbyFaZj7aW8w0dNeK25ANy/Ldx55ENRDquphwYHDnpFOQpkHo5nPuoms5j2Sf -GW3u3hgeFhRrFjqDstU3OKdA4AdHntDjl0gHm35w1m8PXiql/3EpkEMMx5ixQAqM -cMZ7VVzy0HIjqsjdJZpzjx8CAwEAAaN2MHQwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud -JQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFKTVZ2JsYLGJOP+UX0AwGO/81Kab -MCwGA1UdEQQlMCOCCWxvY2FsaG9zdIcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATAN -BgkqhkiG9w0BAQsFAAOCAYEAkGntoogSlhukGqTNbTXN9T/gXLtx9afWlgcBEafF -MYQoJ1DOwXoYCQkMsxE0xWUyLDTpvjzfKkkyQwWzTwcYqRHOKafKYVSvENU5oaDY -c2nk32SfkcF6bqJ50uBlFMEvKFExU1U+YSJhuEH/iqT9sSd52uwmnB0TJhSOc3J/ -1ZapKM2G71ezi8OyizwlwDJAwQ37CqrYS2slVO6Cy8zJ1l/ZsZ+kxRb+ME0LREI0 -J/rFTo9A6iyuXeBQ2jiRUrC6pmmbUQbVSjROx4RSmWoI/58/VnuZBY9P62OAOgUv -pukfAbh3SUjN5++m4Py7WjP/y+L2ILPOFtxTY+CQPWQ5Hbff8iMB4NNfutdU1wSS -CzXT1zWbU12kXod80wkMqWvNb3yU5spqXV6WYhOHiDIyqpPIqp5/i93Ck3Hd6/BQ -DYlNOQsVHdSjWzNw9UubjpatiFqMK4hvJZE0haoLlmfDeZeqWk9oAuuCibLJGPg4 -TQri+lKgi0e76ynUr1zP1xUR +MIIDfDCCAmSgAwIBAgIUa/KdQW7BbWxtDFUBbRpFxEvR2wUwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA2MDcwOTI2MjlaFw0zMjA4 +MjQwOTI2MjlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDCfKHxnXJ3p1UbTRlYheKMT7/gghQOg9p37I5CRvJJ +jullu1ZW4SWMQjALshRdRW9lCNq60xS/AHqtSsXkM3a293KQqrlR/1ENNBuKZctv +F1T0XWyMi0Lzk4TBHiy+r+oG+HnS+aGZqP71oXUMb9DRrdvNjwBLfm4523ZdvKJ/ +Flc5rMP5tJ2dgVVpHvqFDJK37G8hWmY+2lvMNHTXituQDcvy3ceeRDUQ6rqYcGBw +56RTkKZB6OZz7qJrOY9knxlt7t4YHhYUaxY6g7LVNzinQOAHR57Q45dIB5t+cNZv +D14qpf9xKZBDDMeYsUAKjHDGe1Vc8tByI6rI3SWac48fAgMBAAGjZDBiMB0GA1Ud +DgQWBBQBEdAtdWtE9gHf3Dq1I02pE2gQGDAfBgNVHSMEGDAWgBQBEdAtdWtE9gHf +3Dq1I02pE2gQGDAPBgNVHRMBAf8EBTADAQH/MA8GA1UdEQQIMAaHBH8AAAEwDQYJ +KoZIhvcNAQELBQADggEBAGJeDycH50Olfcrm+nr8eOSMTf4Ehq2QRDZabFClp2sy +HHGfqqbCtrBFpshI+T04H10ncUEM6GQR/iQ4+dWR3LppZWc4bQAIE4145n4jsEP1 +xwYgiSGRwx3Blzb6RlkTwHmaJpEw9mOSHMkt/0syicvgrPb/dEPrO26IhBhY3Me3 +H1tpGYQQW6fXx8nJNHrVmzlp9Be0N71wNBocD2nnmaHf8+m9CF7kQ28zXrawC5lz +JRafQi4fxUQC01cGoJmva1wa9xr4LItVp6PcOowohh3x5mmtySYxYi9DVgHJRmci +6ANK7CUbCaAydlv4EX3sz3YMEe35+e1n3I19wkHWqBA= -----END CERTIFICATE-----