summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-28 09:09:23 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-28 09:09:23 +0000
commitdba63244c19187d32f1f998403555f1893f5abdb (patch)
treed07f5aa931f280617456f80c5c139789598290cf /app
parent66d107f9394f719c63cb30f53d62b5b5db888e4b (diff)
downloadgitlab-ce-dba63244c19187d32f1f998403555f1893f5abdb.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue4
-rw-r--r--app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue2
-rw-r--r--app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue2
-rw-r--r--app/assets/javascripts/blob/components/blob_header.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_card_inner.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue1
-rw-r--r--app/assets/javascripts/branches/components/delete_branch_modal.vue4
-rw-r--r--app/assets/javascripts/branches/components/delete_merged_branches.vue2
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue2
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue2
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue6
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_header.vue6
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue6
-rw-r--r--app/assets/javascripts/ci/runner/components/stat/runner_stats.vue2
-rw-r--r--app/assets/javascripts/content_editor/components/formatting_toolbar.vue2
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue2
-rw-r--r--app/assets/javascripts/emoji/components/emoji_group.vue2
-rw-r--r--app/assets/javascripts/feature_flags/components/strategy.vue2
-rw-r--r--app/assets/javascripts/groups/components/empty_states/subgroups_and_projects_empty_state.vue2
-rw-r--r--app/assets/javascripts/groups/components/group_item.vue4
-rw-r--r--app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue2
-rw-r--r--app/controllers/projects/ml/experiments_controller.rb2
-rw-r--r--app/events/packages/package_created_event.rb23
-rw-r--r--app/models/ml/candidate.rb40
-rw-r--r--app/models/packages/package.rb14
-rw-r--r--app/workers/all_queues.yml9
-rw-r--r--app/workers/ml/experiment_tracking/associate_ml_candidate_to_package_worker.rb28
27 files changed, 130 insertions, 45 deletions
diff --git a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
index 3082897af76..09ca815975f 100644
--- a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
+++ b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
@@ -127,7 +127,7 @@ export default {
data-testid="vsa-metrics-group"
>
<h4 class="gl-my-0">{{ group.title }}</h4>
- <div class="gl-display-flex gl-flex-wrap">
+ <div class="gl-display-flex gl-flex-wrap-wrap">
<metric-tile
v-for="metric in group.data"
:key="metric.identifier"
@@ -142,7 +142,7 @@ export default {
</div>
</div>
</div>
- <div v-else class="gl-display-flex gl-flex-wrap gl-mb-7">
+ <div v-else class="gl-display-flex gl-flex-wrap-wrap gl-mb-7">
<metric-tile
v-for="metric in metrics"
:key="metric.identifier"
diff --git a/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue b/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue
index 907b68e6ffc..38422956995 100644
--- a/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue
+++ b/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue
@@ -123,7 +123,7 @@ export default {
/>
</gl-form-group>
- <div class="gl-display-flex gl-flex-wrap">
+ <div class="gl-display-flex gl-flex-wrap-wrap">
<gl-button
type="submit"
class="gl-sm-mr-3 gl-w-full gl-sm-w-auto"
diff --git a/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue b/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue
index 9cf41750efe..d2a962c8551 100644
--- a/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue
+++ b/app/assets/javascripts/authentication/two_factor_auth/components/recovery_codes.vue
@@ -127,7 +127,7 @@ export default {
</li>
</ul>
</gl-card>
- <div class="gl-my-n2 gl-mx-n2 gl-display-flex gl-flex-wrap">
+ <div class="gl-my-n2 gl-mx-n2 gl-display-flex gl-flex-wrap-wrap">
<div class="gl-p-2">
<clipboard-button
:title="$options.i18n.copyButton"
diff --git a/app/assets/javascripts/blob/components/blob_header.vue b/app/assets/javascripts/blob/components/blob_header.vue
index 4e47aa99fd8..883d4edea0f 100644
--- a/app/assets/javascripts/blob/components/blob_header.vue
+++ b/app/assets/javascripts/blob/components/blob_header.vue
@@ -97,7 +97,7 @@ export default {
</blob-filepath>
</div>
- <div class="gl-display-flex gl-flex-wrap file-actions">
+ <div class="gl-display-flex gl-flex-wrap-wrap file-actions">
<viewer-switcher v-if="showViewerSwitcher" v-model="viewer" :doc-icon="blobSwitcherDocIcon" />
<slot name="actions"></slot>
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index befd04c29ae..f1b8abaf0f5 100644
--- a/app/assets/javascripts/boards/components/board_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -251,7 +251,7 @@ export default {
</h4>
<slot></slot>
</div>
- <div v-if="showLabelFooter" class="board-card-labels gl-mt-2 gl-display-flex gl-flex-wrap">
+ <div v-if="showLabelFooter" class="board-card-labels gl-mt-2 gl-display-flex gl-flex-wrap-wrap">
<template v-for="label in orderedLabels">
<gl-label
:key="label.id"
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index a50bbf7fd7e..5f082066ad4 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -419,7 +419,6 @@ export default {
v-if="loadingMore"
size="sm"
:label="$options.i18n.loadingMoreboardItems"
- data-testid="count-loading-icon"
/>
<span v-if="showingAllItems">{{ showingAllItemsText }}</span>
<span v-else>{{ paginatedIssueText }}</span>
diff --git a/app/assets/javascripts/branches/components/delete_branch_modal.vue b/app/assets/javascripts/branches/components/delete_branch_modal.vue
index d5631337cec..df082488b39 100644
--- a/app/assets/javascripts/branches/components/delete_branch_modal.vue
+++ b/app/assets/javascripts/branches/components/delete_branch_modal.vue
@@ -173,7 +173,9 @@ export default {
</form>
<template #modal-footer>
- <div class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap gl-m-0">
+ <div
+ class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap-wrap gl-m-0"
+ >
<gl-button data-testid="delete-branch-cancel-button" @click="closeModal">
{{ $options.i18n.cancelButtonText }}
</gl-button>
diff --git a/app/assets/javascripts/branches/components/delete_merged_branches.vue b/app/assets/javascripts/branches/components/delete_merged_branches.vue
index 70974f2e725..3393fb5c014 100644
--- a/app/assets/javascripts/branches/components/delete_merged_branches.vue
+++ b/app/assets/javascripts/branches/components/delete_merged_branches.vue
@@ -150,7 +150,7 @@ export default {
<template #modal-footer>
<div
- class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap gl-m-0 gl-mr-3"
+ class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap-wrap gl-m-0 gl-mr-3"
>
<gl-button data-testid="delete-merged-branches-cancel-button" @click="closeModal">
{{ $options.i18n.cancelButtonText }}
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
index 84fa8eae64a..a0651841397 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_modal.vue
@@ -461,7 +461,7 @@ export default {
@dismiss="dismissTip"
>
<div
- class="gl-display-flex gl-flex-direction-row gl-flex-wrap gl-md-flex-wrap-nowrap gl-gap-3"
+ class="gl-display-flex gl-flex-direction-row gl-flex-wrap-wrap gl-md-flex-wrap-nowrap gl-gap-3"
>
<div>
<p>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
index 7368d1a3a91..2a710f6ee0b 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
@@ -52,7 +52,7 @@ export default {
};
</script>
<template>
- <div class="gl-mb-4 gl-display-flex gl-flex-wrap gl-gap-3">
+ <div class="gl-mb-4 gl-display-flex gl-flex-wrap-wrap gl-gap-3">
<gl-button
v-if="showFileTreeToggle"
id="file-tree-toggle"
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue
index 372f04075ab..7dc3eb035ae 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue
@@ -134,7 +134,9 @@ export default {
</script>
<template>
- <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-wrap">
+ <div
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-wrap-wrap"
+ >
<template v-if="showLoadingState">
<div>
<gl-loading-icon class="gl-mr-auto gl-display-inline-block" size="sm" />
@@ -171,7 +173,7 @@ export default {
</gl-sprintf>
</span>
</div>
- <div class="gl-display-flex gl-flex-wrap">
+ <div class="gl-display-flex gl-flex-wrap-wrap">
<pipeline-editor-mini-graph :pipeline="pipeline" v-on="$listeners" />
<gl-button
class="gl-ml-3"
diff --git a/app/assets/javascripts/ci/runner/components/runner_header.vue b/app/assets/javascripts/ci/runner/components/runner_header.vue
index 874c234ca4c..954369455dc 100644
--- a/app/assets/javascripts/ci/runner/components/runner_header.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_header.vue
@@ -38,9 +38,9 @@ export default {
</script>
<template>
<div
- class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-gap-3 gl-flex-wrap gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-gap-3 gl-flex-wrap-wrap gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
>
- <div class="gl-display-flex gl-align-items-flex-start gl-gap-3 gl-flex-wrap">
+ <div class="gl-display-flex gl-align-items-flex-start gl-gap-3 gl-flex-wrap-wrap">
<runner-status-badge :runner="runner" />
<runner-type-badge v-if="runner" :type="runner.runnerType" />
<span>
@@ -65,6 +65,6 @@ export default {
</template>
</span>
</div>
- <div class="gl-display-flex gl-gap-3 gl-flex-wrap"><slot name="actions"></slot></div>
+ <div class="gl-display-flex gl-gap-3 gl-flex-wrap-wrap"><slot name="actions"></slot></div>
</div>
</template>
diff --git a/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue b/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue
index 273226141d2..b562bc9029e 100644
--- a/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue
@@ -57,7 +57,7 @@ export default {
<div class="gl-mt-3 gl-mb-6">
<label>{{ s__('Runners|Operating systems') }}</label>
- <div class="gl-display-flex gl-flex-wrap gl-gap-5">
+ <div class="gl-display-flex gl-flex-wrap-wrap gl-gap-5">
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<runner-platforms-radio v-model="model" :value="$options.LINUX_PLATFORM">
Linux
@@ -74,7 +74,7 @@ export default {
<div class="gl-mt-3 gl-mb-6">
<label>{{ s__('Runners|Cloud templates') }}</label>
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
- <div class="gl-display-flex gl-flex-wrap gl-gap-5">
+ <div class="gl-display-flex gl-flex-wrap-wrap gl-gap-5">
<runner-platforms-radio
v-model="model"
:image="$options.AWS_LOGO_URL"
@@ -88,7 +88,7 @@ export default {
<div class="gl-mt-3 gl-mb-6">
<label>{{ s__('Runners|Containers') }}</label>
- <div class="gl-display-flex gl-flex-wrap gl-gap-5">
+ <div class="gl-display-flex gl-flex-wrap-wrap gl-gap-5">
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<runner-platforms-radio :image="$options.DOCKER_LOGO_URL">
<gl-link :href="$options.DOCKER_HELP_URL" target="_blank">
diff --git a/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue b/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
index e0a6f4b1e67..37f13c630b6 100644
--- a/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
+++ b/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
@@ -83,7 +83,7 @@ export default {
</script>
<template>
<runner-count #default="{ count }" :scope="scope" :variables="variables">
- <div v-if="count" class="gl-display-flex gl-flex-wrap gl-py-6">
+ <div v-if="count" class="gl-display-flex gl-flex-wrap-wrap gl-py-6">
<runner-single-stat
v-for="stat in stats"
:key="stat.key"
diff --git a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue
index a5be63fa89f..30914611047 100644
--- a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue
+++ b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue
@@ -30,7 +30,7 @@ export default {
<gl-tabs content-class="gl-display-none">
<gl-tab title-link-class="gl-py-4 gl-px-3" :title="__('Write')" />
<template #tabs-end>
- <div class="gl-ml-auto gl-py-2 gl-display-flex gl-flex-wrap gl-align-items-end">
+ <div class="gl-ml-auto gl-py-2 gl-display-flex gl-flex-wrap-wrap gl-align-items-end">
<toolbar-text-style-dropdown
data-testid="text-styles"
@execute="trackToolbarControlExecution"
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index ab003fb2879..2b98c7b708c 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -368,7 +368,7 @@ export default {
data-testid="design-toolbar-wrapper"
>
<div
- class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full gl-flex-wrap gl-gap-3"
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full gl-flex-wrap-wrap gl-gap-3"
>
<div class="gl-display-flex gl-align-items-center">
<span class="gl-font-weight-bold gl-mr-3">{{ s__('DesignManagement|Designs') }}</span>
diff --git a/app/assets/javascripts/emoji/components/emoji_group.vue b/app/assets/javascripts/emoji/components/emoji_group.vue
index bbac6866636..b0e879fae43 100644
--- a/app/assets/javascripts/emoji/components/emoji_group.vue
+++ b/app/assets/javascripts/emoji/components/emoji_group.vue
@@ -24,7 +24,7 @@ export default {
<!-- eslint-disable-next-line vue/no-deprecated-functional-template -->
<template functional>
- <div class="gl-display-flex gl-flex-wrap gl-mb-2">
+ <div class="gl-display-flex gl-flex-wrap-wrap gl-mb-2">
<template v-if="props.renderGroup">
<button
v-for="emoji in props.emojis"
diff --git a/app/assets/javascripts/feature_flags/components/strategy.vue b/app/assets/javascripts/feature_flags/components/strategy.vue
index 1d7a79f926a..76a68624a63 100644
--- a/app/assets/javascripts/feature_flags/components/strategy.vue
+++ b/app/assets/javascripts/feature_flags/components/strategy.vue
@@ -186,7 +186,7 @@ export default {
<span v-if="appliesToAllEnvironments" class="text-secondary gl-mt-3 mt-md-0 ml-md-3">
{{ $options.i18n.allEnvironments }}
</span>
- <div v-else class="gl-display-flex gl-align-items-center gl-flex-wrap">
+ <div v-else class="gl-display-flex gl-align-items-center gl-flex-wrap-wrap">
<gl-token
v-for="environment in filteredEnvironments"
:key="environment.id"
diff --git a/app/assets/javascripts/groups/components/empty_states/subgroups_and_projects_empty_state.vue b/app/assets/javascripts/groups/components/empty_states/subgroups_and_projects_empty_state.vue
index 955cb1ca63e..763abaebebb 100644
--- a/app/assets/javascripts/groups/components/empty_states/subgroups_and_projects_empty_state.vue
+++ b/app/assets/javascripts/groups/components/empty_states/subgroups_and_projects_empty_state.vue
@@ -52,7 +52,7 @@ export default {
<template>
<div v-if="canCreateSubgroups || canCreateProjects" class="gl-mt-5">
- <div class="gl-display-flex gl-mx-n3 gl-my-n3 gl-flex-wrap">
+ <div class="gl-display-flex gl-mx-n3 gl-my-n3 gl-flex-wrap-wrap">
<div v-if="canCreateSubgroups" class="gl-p-3 gl-w-full gl-sm-w-half">
<gl-link :href="newSubgroupPath" :class="$options.linkClasses">
<div class="svg-content gl-w-15 gl-flex-shrink-0 gl-mr-5">
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index d9781ef9c84..399a2039582 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -190,7 +190,7 @@ export default {
<div class="group-text-container d-flex flex-fill align-items-center">
<div class="group-text flex-grow-1 flex-shrink-1">
<div
- class="gl-display-flex gl-align-items-center gl-flex-wrap title namespace-title gl-font-weight-bold gl-mr-3"
+ class="gl-display-flex gl-align-items-center gl-flex-wrap-wrap title namespace-title gl-font-weight-bold gl-mr-3"
>
<a
v-gl-tooltip.bottom
@@ -259,7 +259,7 @@ export default {
<gl-badge variant="warning">{{ __('pending deletion') }}</gl-badge>
</div>
<div
- class="metadata gl-display-flex gl-flex-grow-1 gl-flex-shrink-0 gl-flex-wrap justify-content-md-between"
+ class="metadata gl-display-flex gl-flex-grow-1 gl-flex-shrink-0 gl-flex-wrap-wrap justify-content-md-between"
>
<item-stats
:item="group"
diff --git a/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue b/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
index aaa37f145aa..ac59da6d6d3 100644
--- a/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
+++ b/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
@@ -135,7 +135,7 @@ export default {
<template v-if="hasIncompatibleRepos">
<slot name="incompatible-repos-warning"></slot>
</template>
- <div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap gl-mb-5">
+ <div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap-wrap gl-mb-5">
<gl-button
variant="confirm"
:loading="isImportingAnyRepo"
diff --git a/app/controllers/projects/ml/experiments_controller.rb b/app/controllers/projects/ml/experiments_controller.rb
index 4f393b47f63..be333fff6e8 100644
--- a/app/controllers/projects/ml/experiments_controller.rb
+++ b/app/controllers/projects/ml/experiments_controller.rb
@@ -32,7 +32,7 @@ module Projects
.execute
.keyset_paginate(cursor: params[:cursor], per_page: MAX_CANDIDATES_PER_PAGE)
- @candidates = paginator.records.each(&:artifact_lazy)
+ @candidates = paginator.records
@page_info = page_info(paginator)
end
diff --git a/app/events/packages/package_created_event.rb b/app/events/packages/package_created_event.rb
new file mode 100644
index 00000000000..5818a1ad19f
--- /dev/null
+++ b/app/events/packages/package_created_event.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Packages
+ class PackageCreatedEvent < ::Gitlab::EventStore::Event
+ def schema
+ {
+ 'type' => 'object',
+ 'properties' => {
+ 'project_id' => { 'type' => 'integer' },
+ 'name' => { 'type' => 'string' },
+ 'version' => { 'type' => %w[string null] },
+ 'package_type' => { 'type' => 'string', 'enum' => ::Packages::Package.package_types.keys },
+ 'id' => { 'type' => 'integer' }
+ },
+ 'required' => %w[project_id id name package_type]
+ }
+ end
+
+ def generic?
+ data[:package_type] == 'generic'
+ end
+ end
+end
diff --git a/app/models/ml/candidate.rb b/app/models/ml/candidate.rb
index cf83ab08665..02da09e6b51 100644
--- a/app/models/ml/candidate.rb
+++ b/app/models/ml/candidate.rb
@@ -15,6 +15,7 @@ module Ml
belongs_to :experiment, class_name: 'Ml::Experiment'
belongs_to :user
+ belongs_to :package, class_name: 'Packages::Package'
has_many :metrics, class_name: 'Ml::CandidateMetric'
has_many :params, class_name: 'Ml::CandidateParam'
has_many :metadata, class_name: 'Ml::CandidateMetadata'
@@ -22,7 +23,7 @@ module Ml
attribute :eid, default: -> { SecureRandom.uuid }
- scope :including_relationships, -> { includes(:latest_metrics, :params, :user) }
+ scope :including_relationships, -> { includes(:latest_metrics, :params, :user, :package) }
scope :by_name, ->(name) { where("ml_candidates.name LIKE ?", "%#{sanitize_sql_like(name)}%") } # rubocop:disable GitlabSecurity/SqlInjection
scope :order_by_metric, ->(metric, direction) do
subquery = Ml::CandidateMetric.latest.where(name: metric)
@@ -50,6 +51,8 @@ module Ml
delegate :project_id, :project, to: :experiment
+ alias_attribute :artifact, :package
+
# Remove alias after https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115401
alias_attribute :iid, :eid
@@ -57,21 +60,6 @@ module Ml
"/#{package_name}/#{package_version}/"
end
- def artifact
- artifact_lazy&.itself
- end
-
- def artifact_lazy
- BatchLoader.for(id).batch do |candidate_ids, loader|
- Packages::Package
- .joins("INNER JOIN ml_candidates ON packages_packages.name=(concat('#{PACKAGE_PREFIX}', ml_candidates.id))")
- .where(ml_candidates: { id: candidate_ids })
- .find_each do |package|
- loader.call(package.name.delete_prefix(PACKAGE_PREFIX).to_i, package)
- end
- end
- end
-
def package_name
"#{PACKAGE_PREFIX}#{id}"
end
@@ -86,6 +74,26 @@ module Ml
joins(:experiment).find_by(experiment: { project_id: project_id }, eid: iid)
end
+
+ def candidate_id_for_package(package_name)
+ return unless package_name.starts_with?(PACKAGE_PREFIX)
+
+ id = package_name.delete_prefix(PACKAGE_PREFIX)
+
+ return unless numeric?(id)
+
+ id.to_i
+ end
+
+ def find_from_package_name(package_name)
+ find_by_id(candidate_id_for_package(package_name))
+ end
+
+ private
+
+ def numeric?(value)
+ value.match?(/\A\d+\z/)
+ end
end
end
end
diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb
index 970538b45e7..2e497dfdcbb 100644
--- a/app/models/packages/package.rb
+++ b/app/models/packages/package.rb
@@ -31,6 +31,8 @@ class Packages::Package < ApplicationRecord
belongs_to :project
belongs_to :creator, class_name: 'User'
+ after_create_commit :publish_creation_event, if: :generic?
+
# package_files must be destroyed by ruby code in order to properly remove carrierwave uploads and update project statistics
has_many :package_files, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# TODO: put the installable default scope on the :package_files association once the dependent: :destroy is removed
@@ -353,6 +355,18 @@ class Packages::Package < ApplicationRecord
end
end
+ def publish_creation_event
+ ::Gitlab::EventStore.publish(
+ ::Packages::PackageCreatedEvent.new(data: {
+ project_id: project_id,
+ id: id,
+ name: name,
+ version: version,
+ package_type: package_type
+ })
+ )
+ end
+
private
def composer_tag_version?
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 1624538152e..a5dc5e9cc0e 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -2919,6 +2919,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: ml_experiment_tracking_associate_ml_candidate_to_package
+ :worker_name: Ml::ExperimentTracking::AssociateMlCandidateToPackageWorker
+ :feature_category: :mlops
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: namespaces_process_sync_events
:worker_name: Namespaces::ProcessSyncEventsWorker
:feature_category: :pods
diff --git a/app/workers/ml/experiment_tracking/associate_ml_candidate_to_package_worker.rb b/app/workers/ml/experiment_tracking/associate_ml_candidate_to_package_worker.rb
new file mode 100644
index 00000000000..d7e9f4b4b98
--- /dev/null
+++ b/app/workers/ml/experiment_tracking/associate_ml_candidate_to_package_worker.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Ml
+ module ExperimentTracking
+ class AssociateMlCandidateToPackageWorker
+ include Gitlab::EventStore::Subscriber
+
+ data_consistency :always
+ feature_category :mlops
+ urgency :low
+ idempotent!
+
+ def handle_event(event)
+ candidate = Ml::Candidate.find_from_package_name(event.data[:name])
+ package = Packages::Package.find_by_id(event.data[:id])
+
+ return unless candidate && package
+
+ candidate.package = package
+ candidate.save!
+ end
+
+ def self.handles_event?(event)
+ event.generic? && Ml::Candidate.candidate_id_for_package(event.data[:name]).present?
+ end
+ end
+ end
+end