Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
66b78786e8
commit
447f884dc0
|
|
@ -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"},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span class="gl-ml-3">
|
||||
<gl-icon name="information-o" :size="12" class="gl-text-blue-600" />
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
'BulkImport|Importing projects is a %{docsLinkStart}Beta%{docsLinkEnd} feature.',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #docsLink="{ content }"
|
||||
><gl-link :href="$options.betaFeatureHelpPath" target="_blank">{{
|
||||
content
|
||||
}}</gl-link></template
|
||||
>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
</div>
|
||||
<gl-table
|
||||
ref="table"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export default {
|
|||
return {
|
||||
mlflowTrackingUrl: this.mlflowTrackingUrl,
|
||||
projectPath: this.projectPath,
|
||||
maxAllowedFileSize: this.maxAllowedFileSize,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
|
@ -47,6 +48,10 @@ export default {
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
maxAllowedFileSize: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
models: {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ export default {
|
|||
mlflowTrackingUrl: this.mlflowTrackingUrl,
|
||||
projectPath: this.projectPath,
|
||||
canWriteModelRegistry: this.canWriteModelRegistry,
|
||||
maxAllowedFileSize: this.maxAllowedFileSize,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
|
@ -96,6 +97,10 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
maxAllowedFileSize: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
model: {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export default {
|
|||
canWriteModelRegistry: this.canWriteModelRegistry,
|
||||
importPath: this.importPath,
|
||||
versionName: this.versionName,
|
||||
maxAllowedFileSize: this.maxAllowedFileSize,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
|
@ -61,6 +62,10 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
maxAllowedFileSize: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
modelWithModelVersion: {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export default {
|
|||
GlInputGroupText,
|
||||
UploadDropzone,
|
||||
},
|
||||
inject: ['maxAllowedFileSize'],
|
||||
props: {
|
||||
path: {
|
||||
type: String,
|
||||
|
|
@ -65,7 +66,12 @@ export default {
|
|||
},
|
||||
submitRequest(importPath) {
|
||||
this.loading = true;
|
||||
uploadModel({ importPath, file: this.file, subfolder: this.subfolder })
|
||||
uploadModel({
|
||||
importPath,
|
||||
file: this.file,
|
||||
subfolder: this.subfolder,
|
||||
maxAllowedFileSize: this.maxAllowedFileSize,
|
||||
})
|
||||
.then(() => {
|
||||
this.resetFile();
|
||||
this.alert = { message: this.$options.i18n.successfulUpload, variant: 'success' };
|
||||
|
|
|
|||
|
|
@ -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 {
|
|||
</gl-form-group>
|
||||
</gl-form>
|
||||
|
||||
<gl-alert v-if="errorMessage" variant="danger" @dismiss="hideAlert">{{
|
||||
errorMessage
|
||||
}}</gl-alert>
|
||||
<gl-alert
|
||||
v-if="errorMessage"
|
||||
data-testid="modal-create-alert"
|
||||
variant="danger"
|
||||
@dismiss="hideAlert"
|
||||
>{{ errorMessage }}</gl-alert
|
||||
>
|
||||
</gl-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
0633b0f78ffa5b7550bb6c08df4d1992d137e703fad7be7dfbeb8f1947043b28
|
||||
|
|
@ -0,0 +1 @@
|
|||
e437a04b396cc520e4efdfba802a6fa019ebe42ef56556f6456c96c957017dfc
|
||||
|
|
@ -0,0 +1 @@
|
|||
01772232031f3546e17b11e863114eb97908f657d9525136c5810cc1254ae14c
|
||||
|
|
@ -0,0 +1 @@
|
|||
cbbdfc5caaa00e2fc0b458a6a8e555ed033f066d85f7a363726fdb66ff4aad8f
|
||||
|
|
@ -0,0 +1 @@
|
|||
333432f11538c10e77ac8f73bf0b364c3230999ff718d7e25b7e0df33c372e56
|
||||
|
|
@ -0,0 +1 @@
|
|||
48616de4dab655eb5a01da5f7b8149c3d5ca66c64cdccea86468a3b6a9e83237
|
||||
|
|
@ -0,0 +1 @@
|
|||
63ab2d580707d4a7095ccdfcbd636b701708b5b415284112084446b21ee35807
|
||||
|
|
@ -0,0 +1 @@
|
|||
8e168eb75e5ab533b51be54c9df72249fc166f1d0fc3f1f396c87058c4116501
|
||||
|
|
@ -0,0 +1 @@
|
|||
0e2504f0165fbeb417a7a5ff3650f0cb9aa151ff9f72e5c773659e4c3f4075c5
|
||||
|
|
@ -0,0 +1 @@
|
|||
c4eaba0dc0a28d090b3d79f49752ad929d0ed89ca4cfb422c6f15087ba81e31a
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -906,7 +906,7 @@ Returns [`[CiRunnerUsage!]`](#cirunnerusage).
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="queryrunnerusagefromdate"></a>`fromDate` | [`Date`](#date) | Start of the requested date frame. Defaults to the start of the previous calendar month. |
|
||||
| <a id="queryrunnerusagefullpath"></a>`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. |
|
||||
| <a id="queryrunnerusagefullpath"></a>`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. |
|
||||
| <a id="queryrunnerusagerunnertype"></a>`runnerType` | [`CiRunnerType`](#cirunnertype) | Filter runners by the type. |
|
||||
| <a id="queryrunnerusagerunnerslimit"></a>`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. |
|
||||
| <a id="queryrunnerusagetodate"></a>`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 |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="queryrunnerusagebyprojectfromdate"></a>`fromDate` | [`Date`](#date) | Start of the requested date frame. Defaults to the start of the previous calendar month. |
|
||||
| <a id="queryrunnerusagebyprojectfullpath"></a>`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. |
|
||||
| <a id="queryrunnerusagebyprojectfullpath"></a>`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. |
|
||||
| <a id="queryrunnerusagebyprojectprojectslimit"></a>`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. |
|
||||
| <a id="queryrunnerusagebyprojectrunnertype"></a>`runnerType` | [`CiRunnerType`](#cirunnertype) | Filter jobs by the type of runner that executed them. |
|
||||
| <a id="queryrunnerusagebyprojecttodate"></a>`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`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationrunnersexportusageclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationrunnersexportusagefromdate"></a>`fromDate` | [`ISO8601Date`](#iso8601date) | UTC start date of the period to report on. Defaults to the start of last full month. |
|
||||
| <a id="mutationrunnersexportusagefullpath"></a>`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. |
|
||||
| <a id="mutationrunnersexportusagemaxprojectcount"></a>`maxProjectCount` | [`Int`](#int) | Maximum number of projects to return. All other runner usage will be attributed to an `<Other projects>` entry. Defaults to 1000 projects. |
|
||||
| <a id="mutationrunnersexportusagerunnertype"></a>`runnerType` | [`CiRunnerType`](#cirunnertype) | Scope of the runners to include in the report. |
|
||||
| <a id="mutationrunnersexportusagetodate"></a>`toDate` | [`ISO8601Date`](#iso8601date) | UTC end date of the period to report on. " \ "Defaults to the end of the month specified by `fromDate`. |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ To view all issues assigned to you:
|
|||
Or:
|
||||
|
||||
- To use a [keyboard shortcut](../../shortcuts.md), press <kbd>Shift</kbd> + <kbd>i</kbd>.
|
||||
- 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ let wrapper;
|
|||
const createWrapper = (modelProp = model) => {
|
||||
wrapper = shallowMountExtended(ModelDetail, {
|
||||
propsData: { model: modelProp },
|
||||
provide: { maxAllowedFileSize: 99999 },
|
||||
stubs: { GlTab },
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ const createWrapper = (modelVersion = modelVersionWithCandidate, props = {}, pro
|
|||
projectPath: 'path/to/project',
|
||||
canWriteModelRegistry: true,
|
||||
importPath: 'path/to/import',
|
||||
maxAllowedFileSize: 99999,
|
||||
...provide,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
|
|
@ -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-----
|
||||
|
|
|
|||
Loading…
Reference in New Issue