Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-11-23 18:13:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-11-23 18:13:51 +0300
commit61cb988554d7d554f0e9727fc73acc9acba5ea8f (patch)
tree49e910dd011e4b07476726f31e77b20a7efe1ccb /app
parente1a5a2f484427b549a200c2443da0c1987f6743a (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue12
-rw-r--r--app/assets/javascripts/ci/catalog/components/list/catalog_list_skeleton_loader.vue14
-rw-r--r--app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue19
-rw-r--r--app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue4
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue83
-rw-r--r--app/assets/javascripts/work_items/components/work_item_sticky_header.vue142
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss2
-rw-r--r--app/finders/events_finder.rb1
-rw-r--r--app/finders/members_finder.rb9
-rw-r--r--app/models/ci/build_need.rb12
-rw-r--r--app/models/ci/build_report_result.rb6
-rw-r--r--app/models/ci/build_runner_session.rb6
-rw-r--r--app/models/ci/build_trace_metadata.rb6
-rw-r--r--app/models/ci/job_annotation.rb6
-rw-r--r--app/models/ci/pending_build.rb6
-rw-r--r--app/models/ci/running_build.rb5
-rw-r--r--app/models/ci/sources/pipeline.rb2
-rw-r--r--app/models/ci/unit_test_failure.rb6
-rw-r--r--app/models/event.rb4
-rw-r--r--app/models/ml/model.rb4
-rw-r--r--app/models/vulnerability.rb2
-rw-r--r--app/services/jira_import/users_mapper_service.rb1
-rw-r--r--app/services/ml/destroy_model_service.rb19
24 files changed, 264 insertions, 112 deletions
diff --git a/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue b/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue
index ff2dcd4393a..0b14a8e81a5 100644
--- a/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue
+++ b/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue
@@ -1,6 +1,7 @@
<script>
import { GlAvatar, GlAvatarLink, GlBadge } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import CiResourceAbout from './ci_resource_about.vue';
import CiResourceHeaderSkeletonLoader from './ci_resource_header_skeleton_loader.vue';
@@ -47,9 +48,6 @@ export default {
entityId() {
return getIdFromGraphQLId(this.resource.id);
},
- fullPath() {
- return `${this.rootNamespace.fullPath}/${this.rootNamespace.name}`;
- },
hasLatestVersion() {
return this.latestVersion?.tagName;
},
@@ -59,12 +57,12 @@ export default {
latestVersion() {
return this.resource.latestVersion;
},
- rootNamespace() {
- return this.resource.rootNamespace;
- },
versionBadgeText() {
return this.latestVersion.tagName;
},
+ webPath() {
+ return cleanLeadingSeparator(this.resource?.webPath);
+ },
},
};
</script>
@@ -86,7 +84,7 @@ export default {
class="gl-display-flex gl-flex-direction-column gl-align-items-flex-start gl-justify-content-center"
>
<div class="gl-font-sm gl-text-secondary">
- {{ fullPath }}
+ {{ webPath }}
</div>
<span class="gl-display-flex">
<div class="gl-font-lg gl-font-weight-bold">{{ resource.name }}</div>
diff --git a/app/assets/javascripts/ci/catalog/components/list/catalog_list_skeleton_loader.vue b/app/assets/javascripts/ci/catalog/components/list/catalog_list_skeleton_loader.vue
index 3722b8e6c59..5de71fa1fc5 100644
--- a/app/assets/javascripts/ci/catalog/components/list/catalog_list_skeleton_loader.vue
+++ b/app/assets/javascripts/ci/catalog/components/list/catalog_list_skeleton_loader.vue
@@ -37,21 +37,19 @@ export default {
>
<!-- Catalog project avatar -->
<rect x="0" y="0" width="48" height="48" rx="4" ry="4" />
- <!-- namespace path -->
- <rect x="60" y="4" width="400" height="16" rx="2" ry="2" />
+ <!-- resource path -->
+ <rect x="60" y="0" width="200" height="10" rx="2" ry="2" />
+ <!-- resource name -->
+ <rect x="60" y="14" width="400" height="16" rx="2" ry="2" />
<!-- Project description -->
- <rect x="60" y="30" width="500" height="12" rx="2" ry="2" />
+ <rect x="60" y="34" width="500" height="12" rx="2" ry="2" />
<!-- Release date line -->
<rect :x="coordinates.releaseDateX" y="30" width="200" height="12" rx="2" ry="2" />
<!-- Favorites -->
- <rect :x="coordinates.statsX" y="4" width="16" height="16" rx="2" ry="2" />
- <rect :x="coordinates.statsX + 18" y="7" width="18" height="10" rx="2" ry="2" />
-
- <!-- Forks -->
<rect :x="coordinates.statsX + 50" y="4" width="16" height="16" rx="2" ry="2" />
- <rect :x="coordinates.statsX + 68" y="7" width="18" height="10" rx="2" ry="2" />
+ <rect :x="coordinates.statsX + 70" y="7" width="18" height="10" rx="2" ry="2" />
</gl-skeleton-loader>
</div>
</template>
diff --git a/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue b/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue
index 5bbf11e541f..504d3d38275 100644
--- a/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue
+++ b/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue
@@ -3,6 +3,7 @@ import { GlAvatar, GlBadge, GlIcon, GlLink, GlSprintf, GlTooltipDirective } from
import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { formatDate, getTimeago } from '~/lib/utils/datetime_utility';
+import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
import { CI_RESOURCE_DETAILS_PAGE_NAME } from '../../router/constants';
export default {
@@ -45,6 +46,9 @@ export default {
starCount() {
return this.resource?.starCount || 0;
},
+ starIcon() {
+ return this.starCount > 0 ? 'star' : 'star-o';
+ },
hasReleasedVersion() {
return Boolean(this.latestVersion?.releasedAt);
},
@@ -57,12 +61,12 @@ export default {
releasedAt() {
return getTimeago().format(this.latestVersion?.releasedAt);
},
- resourcePath() {
- return `${this.resource.rootNamespace?.name} / ${this.resource.rootNamespace?.fullPath} / `;
- },
tagName() {
return this.latestVersion?.tagName || this.$options.i18n.unreleased;
},
+ webPath() {
+ return cleanLeadingSeparator(this.resource?.webPath);
+ },
},
methods: {
navigateToDetailsPage(e) {
@@ -98,20 +102,21 @@ export default {
@click="navigateToDetailsPage"
/>
<div class="gl-display-flex gl-flex-direction-column gl-flex-grow-1">
- <div class="gl-display-flex gl-flex-wrap gl-gap-2 gl-mb-2">
+ <span class="gl-font-sm gl-mb-1">{{ webPath }}</span>
+ <div class="gl-display-flex gl-flex-wrap gl-gap-2 gl-mb-1">
<gl-link
class="gl-text-gray-900! gl-mr-1"
:href="detailsPageHref"
data-testid="ci-resource-link"
@click="navigateToDetailsPage"
>
- {{ resourcePath }} <b> {{ resource.name }}</b>
+ <b> {{ resource.name }}</b>
</gl-link>
<div class="gl-display-flex gl-flex-grow-1 gl-md-justify-content-space-between">
- <gl-badge size="sm">{{ tagName }}</gl-badge>
+ <gl-badge size="sm" class="gl-h-5 gl-align-self-center">{{ tagName }}</gl-badge>
<span class="gl-display-flex gl-align-items-center gl-ml-5">
<span class="gl--flex-center" data-testid="stats-favorites">
- <gl-icon name="star" :size="14" class="gl-mr-1" />
+ <gl-icon :name="starIcon" :size="14" class="gl-mr-2" />
<span class="gl-mr-3">{{ starCount }}</span>
</span>
</span>
diff --git a/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql b/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql
index a86db4c1b03..0dc16e3492d 100644
--- a/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql
+++ b/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql
@@ -15,10 +15,5 @@ fragment CatalogResourceFields on CiCatalogResource {
webUrl
}
}
- rootNamespace {
- id
- fullPath
- name
- }
webPath
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
index 55ae390216d..d2c1c914028 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
@@ -22,14 +22,14 @@ export default {
variables() {
return this.mergeRequestQueryVariables;
},
- update: (data) => data.project.mergeRequest.userPermissions,
+ update: (data) => data.project?.mergeRequest.userPermissions || {},
},
state: {
query: conflictsStateQuery,
variables() {
return this.mergeRequestQueryVariables;
},
- update: (data) => data.project.mergeRequest,
+ update: (data) => data.project?.mergeRequest || {},
},
},
props: {
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index 45d3aa564a5..2440fc7d433 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -3,12 +3,10 @@ import { isEmpty } from 'lodash';
import {
GlAlert,
GlSkeletonLoader,
- GlLoadingIcon,
GlIcon,
GlButton,
GlTooltipDirective,
GlEmptyState,
- GlIntersectionObserver,
} from '@gitlab/ui';
import noAccessSvg from '@gitlab/svgs/dist/illustrations/analytics/no-access.svg?raw';
import { s__ } from '~/locale';
@@ -17,7 +15,6 @@ import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { isLoggedIn } from '~/lib/utils/common_utils';
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
-import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
import { WORKSPACE_PROJECT } from '~/issues/constants';
import {
i18n,
@@ -52,6 +49,7 @@ import WorkItemDetailModal from './work_item_detail_modal.vue';
import WorkItemAwardEmoji from './work_item_award_emoji.vue';
import WorkItemRelationships from './work_item_relationships/work_item_relationships.vue';
import WorkItemTypeIcon from './work_item_type_icon.vue';
+import WorkItemStickyHeader from './work_item_sticky_header.vue';
export default {
i18n,
@@ -62,7 +60,6 @@ export default {
components: {
GlAlert,
GlButton,
- GlLoadingIcon,
GlSkeletonLoader,
GlIcon,
GlEmptyState,
@@ -78,9 +75,8 @@ export default {
WorkItemNotes,
WorkItemDetailModal,
AbuseCategorySelector,
- GlIntersectionObserver,
- ConfidentialityBadge,
WorkItemRelationships,
+ WorkItemStickyHeader,
},
mixins: [glFeatureFlagMixin()],
inject: ['fullPath', 'isGroup', 'reportAbusePath'],
@@ -235,7 +231,7 @@ export default {
return this.isWidgetPresent(WIDGET_TYPE_CURRENT_USER_TODOS);
},
showWorkItemCurrentUserTodos() {
- return this.$options.isLoggedIn && this.workItemCurrentUserTodos;
+ return Boolean(this.$options.isLoggedIn && this.workItemCurrentUserTodos);
},
currentUserTodos() {
return this.workItemCurrentUserTodos?.currentUserTodos?.nodes;
@@ -537,62 +533,25 @@ export default {
:update-in-progress="updateInProgress"
/>
</div>
- <gl-intersection-observer
+ <work-item-sticky-header
v-if="showIntersectionObserver"
- @appear="hideStickyHeader"
- @disappear="showStickyHeader"
- >
- <transition name="issuable-header-slide">
- <div
- v-if="isStickyHeaderShowing"
- class="issue-sticky-header gl-fixed gl-bg-white gl-border-b gl-z-index-3 gl-py-2"
- data-testid="work-item-sticky-header"
- >
- <div
- class="gl-align-items-center gl-mx-auto gl-px-5 gl-display-flex gl-max-w-container-xl"
- >
- <span class="gl-text-truncate gl-font-weight-bold gl-pr-3 gl-mr-auto">
- {{ workItem.title }}
- </span>
- <gl-loading-icon v-if="updateInProgress" class="gl-mr-3" />
- <confidentiality-badge
- v-if="workItem.confidential"
- class="gl-mr-3"
- :issuable-type="workItemType"
- :workspace-type="$options.WORKSPACE_PROJECT"
- />
- <work-item-todos
- v-if="showWorkItemCurrentUserTodos"
- :work-item-id="workItem.id"
- :work-item-iid="workItemIid"
- :work-item-fullpath="projectFullPath"
- :current-user-todos="currentUserTodos"
- @error="updateError = $event"
- />
- <work-item-actions
- :full-path="fullPath"
- :work-item-id="workItem.id"
- :subscribed-to-notifications="workItemNotificationsSubscribed"
- :work-item-type="workItemType"
- :work-item-type-id="workItemTypeId"
- :can-delete="canDelete"
- :can-update="canUpdate"
- :is-confidential="workItem.confidential"
- :is-parent-confidential="parentWorkItemConfidentiality"
- :work-item-reference="workItem.reference"
- :work-item-create-note-email="workItem.createNoteEmail"
- :is-modal="isModal"
- @deleteWorkItem="
- $emit('deleteWorkItem', { workItemType, workItemId: workItem.id })
- "
- @toggleWorkItemConfidentiality="toggleConfidentiality"
- @error="updateError = $event"
- @promotedToObjective="$emit('promotedToObjective', workItemIid)"
- />
- </div>
- </div>
- </transition>
- </gl-intersection-observer>
+ :current-user-todos="currentUserTodos"
+ :show-work-item-current-user-todos="showWorkItemCurrentUserTodos"
+ :parent-work-item-confidentiality="parentWorkItemConfidentiality"
+ :update-in-progress="updateInProgress"
+ :full-path="fullPath"
+ :is-modal="isModal"
+ :work-item="workItem"
+ :is-sticky-header-showing="isStickyHeaderShowing"
+ :work-item-parent-id="workItemParentId"
+ :work-item-notifications-subscribed="workItemNotificationsSubscribed"
+ @hideStickyHeader="hideStickyHeader"
+ @showStickyHeader="showStickyHeader"
+ @deleteWorkItem="$emit('deleteWorkItem', { workItemType, workItemId: workItem.id })"
+ @toggleWorkItemConfidentiality="toggleConfidentiality"
+ @error="updateError = $event"
+ @promotedToObjective="$emit('promotedToObjective', workItemIid)"
+ />
<div
data-testid="work-item-overview"
:class="{ 'work-item-overview': workItemsMvc2Enabled }"
diff --git a/app/assets/javascripts/work_items/components/work_item_sticky_header.vue b/app/assets/javascripts/work_items/components/work_item_sticky_header.vue
new file mode 100644
index 00000000000..ec6d2c21748
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/work_item_sticky_header.vue
@@ -0,0 +1,142 @@
+<script>
+import { GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui';
+import { WORKSPACE_PROJECT } from '~/issues/constants';
+import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
+import WorkItemActions from './work_item_actions.vue';
+import WorkItemTodos from './work_item_todos.vue';
+
+export default {
+ components: {
+ GlIntersectionObserver,
+ GlLoadingIcon,
+ WorkItemActions,
+ WorkItemTodos,
+ ConfidentialityBadge,
+ },
+ props: {
+ workItem: {
+ type: Object,
+ required: true,
+ },
+ fullPath: {
+ type: String,
+ required: true,
+ },
+ isStickyHeaderShowing: {
+ type: Boolean,
+ required: true,
+ },
+ workItemNotificationsSubscribed: {
+ type: Boolean,
+ required: true,
+ },
+ workItemParentId: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ updateInProgress: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ parentWorkItemConfidentiality: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ showWorkItemCurrentUserTodos: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ currentUserTodos: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ computed: {
+ canUpdate() {
+ return this.workItem.userPermissions?.updateWorkItem;
+ },
+ canDelete() {
+ return this.workItem.userPermissions?.deleteWorkItem;
+ },
+ workItemType() {
+ return this.workItem.workItemType?.name;
+ },
+ workItemTypeId() {
+ return this.workItem.workItemType?.id;
+ },
+ projectFullPath() {
+ return this.workItem.namespace?.fullPath;
+ },
+ },
+ WORKSPACE_PROJECT,
+};
+</script>
+
+<template>
+ <gl-intersection-observer
+ @appear="$emit('hideStickyHeader')"
+ @disappear="$emit('showStickyHeader')"
+ >
+ <transition name="issuable-header-slide">
+ <div
+ v-if="isStickyHeaderShowing"
+ class="issue-sticky-header gl-fixed gl-bg-white gl-border-b gl-z-index-3 gl-py-2"
+ data-testid="work-item-sticky-header"
+ >
+ <div
+ class="gl-align-items-center gl-mx-auto gl-px-5 gl-display-flex gl-max-w-container-xl gl-gap-3"
+ >
+ <span class="gl-text-truncate gl-font-weight-bold gl-pr-3 gl-mr-auto">
+ {{ workItem.title }}
+ </span>
+ <gl-loading-icon v-if="updateInProgress" />
+ <confidentiality-badge
+ v-if="workItem.confidential"
+ :issuable-type="workItemType"
+ :workspace-type="$options.WORKSPACE_PROJECT"
+ />
+ <work-item-todos
+ v-if="showWorkItemCurrentUserTodos"
+ :work-item-id="workItem.id"
+ :work-item-iid="workItem.iid"
+ :work-item-fullpath="projectFullPath"
+ :current-user-todos="currentUserTodos"
+ @error="$emit('error')"
+ />
+ <work-item-actions
+ :full-path="fullPath"
+ :work-item-id="workItem.id"
+ :subscribed-to-notifications="workItemNotificationsSubscribed"
+ :work-item-type="workItemType"
+ :work-item-type-id="workItemTypeId"
+ :can-delete="canDelete"
+ :can-update="canUpdate"
+ :is-confidential="workItem.confidential"
+ :is-parent-confidential="parentWorkItemConfidentiality"
+ :work-item-reference="workItem.reference"
+ :work-item-create-note-email="workItem.createNoteEmail"
+ :work-item-state="workItem.state"
+ :work-item-parent-id="workItemParentId"
+ :is-modal="isModal"
+ @deleteWorkItem="$emit('deleteWorkItem')"
+ @toggleWorkItemConfidentiality="
+ $emit('toggleWorkItemConfidentiality', !workItem.confidential)
+ "
+ @error="$emit('error')"
+ @promotedToObjective="$emit('promotedToObjective')"
+ />
+ </div>
+ </div>
+ </transition>
+ </gl-intersection-observer>
+</template>
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index 5422fc0ec0a..e65f716d71a 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -552,7 +552,7 @@ $tabs-holder-z-index: 250;
.mr-widget-section:not(:first-child) > div,
.mr-widget-section:not(:first-child) > section,
- .mr-widget-section .mr-widget-section > div {
+ .mr-widget-section .mr-widget-section > div:not(:first-child) {
border-top: solid 1px var(--border-color, $border-color);
}
diff --git a/app/finders/events_finder.rb b/app/finders/events_finder.rb
index 7bccfe453ab..4ed447a90ce 100644
--- a/app/finders/events_finder.rb
+++ b/app/finders/events_finder.rb
@@ -61,7 +61,6 @@ class EventsFinder
def by_current_user_access(events)
events.merge(Project.public_or_visible_to_user(current_user))
.joins(:project)
- .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417462")
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb
index 6348bceb157..5b4b83652df 100644
--- a/app/finders/members_finder.rb
+++ b/app/finders/members_finder.rb
@@ -90,10 +90,8 @@ class MembersFinder
# enumerate the columns here since we are enumerating them in the union and want to be immune to
# column caching issues when adding/removing columns
- members = Member.select(*Member.column_names)
- .includes(:user).from([Arel.sql("(#{sql}) AS #{Member.table_name}")]) # rubocop: disable CodeReuse/ActiveRecord
- # The left join with the table users in the method distinct_on needs to be resolved
- members.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
+ Member.select(*Member.column_names)
+ .preload(:user).from([Arel.sql("(#{sql}) AS #{Member.table_name}")]) # rubocop: disable CodeReuse/ActiveRecord -- TODO: Usage of `from` forces us to use this.
end
def distinct_on(union)
@@ -102,8 +100,7 @@ class MembersFinder
<<~SQL
SELECT DISTINCT ON (user_id, invite_email) #{member_columns}
FROM (#{union.to_sql}) AS #{member_union_table}
- LEFT JOIN users on users.id = member_union.user_id
- LEFT JOIN project_authorizations on project_authorizations.user_id = users.id
+ LEFT JOIN project_authorizations on project_authorizations.user_id = member_union.user_id
AND
project_authorizations.project_id = #{project.id}
ORDER BY user_id,
diff --git a/app/models/ci/build_need.rb b/app/models/ci/build_need.rb
index 1831b7868f9..fb0a02ca56e 100644
--- a/app/models/ci/build_need.rb
+++ b/app/models/ci/build_need.rb
@@ -11,7 +11,12 @@ module Ci
columns_changing_default :partition_id
- belongs_to :build, class_name: "Ci::Processable", foreign_key: :build_id, inverse_of: :needs
+ belongs_to :build,
+ ->(need) { in_partition(need) },
+ class_name: 'Ci::Processable',
+ foreign_key: :build_id,
+ partition_foreign_key: :partition_id,
+ inverse_of: :needs
partitionable scope: :build
@@ -19,7 +24,10 @@ module Ci
validates :name, presence: true, length: { maximum: MAX_JOB_NAME_LENGTH }
validates :optional, inclusion: { in: [true, false] }
- scope :scoped_build, -> { where("#{Ci::Build.quoted_table_name}.id = #{quoted_table_name}.build_id") }
+ scope :scoped_build, -> {
+ where(arel_table[:build_id].eq(Ci::Build.arel_table[:id]))
+ .where(arel_table[:partition_id].eq(Ci::Build.arel_table[:partition_id]))
+ }
scope :artifacts, -> { where(artifacts: true) }
end
end
diff --git a/app/models/ci/build_report_result.rb b/app/models/ci/build_report_result.rb
index 90b621b8da1..1dabf05e03c 100644
--- a/app/models/ci/build_report_result.rb
+++ b/app/models/ci/build_report_result.rb
@@ -9,7 +9,11 @@ module Ci
self.primary_key = :build_id
- belongs_to :build, class_name: "Ci::Build", inverse_of: :report_results
+ belongs_to :build,
+ ->(report_result) { in_partition(report_result) },
+ class_name: 'Ci::Build',
+ partition_foreign_key: :partition_id,
+ inverse_of: :report_results
belongs_to :project, class_name: "Project", inverse_of: :build_report_results
partitionable scope: :build
diff --git a/app/models/ci/build_runner_session.rb b/app/models/ci/build_runner_session.rb
index e197217bb70..223cb9c5d68 100644
--- a/app/models/ci/build_runner_session.rb
+++ b/app/models/ci/build_runner_session.rb
@@ -15,7 +15,11 @@ module Ci
self.table_name = 'ci_builds_runner_session'
- belongs_to :build, class_name: 'Ci::Build', inverse_of: :runner_session
+ belongs_to :build,
+ ->(runner_session) { in_partition(runner_session) },
+ class_name: 'Ci::Build',
+ partition_foreign_key: :partition_id,
+ inverse_of: :runner_session
partitionable scope: :build
diff --git a/app/models/ci/build_trace_metadata.rb b/app/models/ci/build_trace_metadata.rb
index 525cb08f2ca..859dad29a06 100644
--- a/app/models/ci/build_trace_metadata.rb
+++ b/app/models/ci/build_trace_metadata.rb
@@ -11,7 +11,11 @@ module Ci
self.table_name = 'ci_build_trace_metadata'
self.primary_key = :build_id
- belongs_to :build, class_name: 'Ci::Build'
+ belongs_to :build,
+ ->(trace_metadata) { in_partition(trace_metadata) },
+ class_name: 'Ci::Build',
+ partition_foreign_key: :partition_id,
+ inverse_of: :trace_metadata
belongs_to :trace_artifact, class_name: 'Ci::JobArtifact'
partitionable scope: :build
diff --git a/app/models/ci/job_annotation.rb b/app/models/ci/job_annotation.rb
index a6ce4196cc1..d56830433b1 100644
--- a/app/models/ci/job_annotation.rb
+++ b/app/models/ci/job_annotation.rb
@@ -8,7 +8,11 @@ module Ci
self.table_name = :p_ci_job_annotations
self.primary_key = :id
- belongs_to :job, class_name: 'Ci::Build', inverse_of: :job_annotations
+ belongs_to :job,
+ ->(job_annotation) { in_partition(job_annotation) },
+ class_name: 'Ci::Build',
+ partition_foreign_key: :partition_id,
+ inverse_of: :job_annotations
partitionable scope: :job, partitioned: true
diff --git a/app/models/ci/pending_build.rb b/app/models/ci/pending_build.rb
index dc9a8b7a1bf..80cc74a9946 100644
--- a/app/models/ci/pending_build.rb
+++ b/app/models/ci/pending_build.rb
@@ -9,7 +9,11 @@ module Ci
columns_changing_default :partition_id
belongs_to :project
- belongs_to :build, class_name: 'Ci::Build'
+
+ belongs_to :build, # rubocop: disable Rails/InverseOf -- this relation is not present on build
+ ->(pending_build) { in_partition(pending_build) },
+ class_name: 'Ci::Build',
+ partition_foreign_key: :partition_id
belongs_to :namespace, inverse_of: :pending_builds, class_name: 'Namespace'
partitionable scope: :build
diff --git a/app/models/ci/running_build.rb b/app/models/ci/running_build.rb
index cfdc47de531..22753930b3c 100644
--- a/app/models/ci/running_build.rb
+++ b/app/models/ci/running_build.rb
@@ -17,7 +17,10 @@ module Ci
partitionable scope: :build
belongs_to :project
- belongs_to :build, class_name: 'Ci::Build'
+ belongs_to :build, # rubocop: disable Rails/InverseOf -- this relation is not present on build
+ ->(running_build) { in_partition(running_build) },
+ class_name: 'Ci::Build',
+ partition_foreign_key: :partition_id
belongs_to :runner, class_name: 'Ci::Runner'
enum runner_type: ::Ci::Runner.runner_types
diff --git a/app/models/ci/sources/pipeline.rb b/app/models/ci/sources/pipeline.rb
index 3c6a5563846..6c9d3b9c19f 100644
--- a/app/models/ci/sources/pipeline.rb
+++ b/app/models/ci/sources/pipeline.rb
@@ -13,7 +13,7 @@ module Ci
belongs_to :project, class_name: "::Project"
belongs_to :pipeline, class_name: "Ci::Pipeline", inverse_of: :source_pipeline
- belongs_to :build, class_name: "Ci::Build", foreign_key: :source_job_id, inverse_of: :sourced_pipelines
+ belongs_to :build, class_name: 'Ci::Build', foreign_key: :source_job_id, inverse_of: :sourced_pipelines
belongs_to :source_project, class_name: "::Project", foreign_key: :source_project_id
belongs_to :source_job, class_name: "CommitStatus", foreign_key: :source_job_id
diff --git a/app/models/ci/unit_test_failure.rb b/app/models/ci/unit_test_failure.rb
index 37893f6cdae..bec74d8be20 100644
--- a/app/models/ci/unit_test_failure.rb
+++ b/app/models/ci/unit_test_failure.rb
@@ -12,7 +12,11 @@ module Ci
validates :unit_test, :build, :failed_at, presence: true
belongs_to :unit_test, class_name: "Ci::UnitTest", foreign_key: :unit_test_id
- belongs_to :build, class_name: "Ci::Build", foreign_key: :build_id
+ belongs_to :build,
+ ->(unit_test_failure) { in_partition(unit_test_failure) },
+ class_name: 'Ci::Build',
+ foreign_key: :build_id,
+ partition_foreign_key: :partition_id
partitionable scope: :build
diff --git a/app/models/event.rb b/app/models/event.rb
index 3ff5a46f2d9..7b91727f7d4 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -113,8 +113,8 @@ class Event < ApplicationRecord
scope :with_associations, -> do
# We're using preload for "push_event_payload" as otherwise the association
# is not always available (depending on the query being built).
- includes(:author, :project, project: [:project_feature, :import_data, :namespace])
- .preload(:target, :push_event_payload)
+ includes(:project, project: [:project_feature, :import_data, :namespace])
+ .preload(:author, :target, :push_event_payload)
end
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
diff --git a/app/models/ml/model.rb b/app/models/ml/model.rb
index b6f7e9a0639..bec03c05151 100644
--- a/app/models/ml/model.rb
+++ b/app/models/ml/model.rb
@@ -31,6 +31,10 @@ module Ml
scope :by_name, ->(name) { where("ml_models.name LIKE ?", "%#{sanitize_sql_like(name)}%") } # rubocop:disable GitlabSecurity/SqlInjection
scope :by_project, ->(project) { where(project_id: project.id) }
+ def all_packages
+ Packages::MlModel::Package.where(project: project, id: versions.select(:package_id))
+ end
+
def valid_default_experiment?
return unless default_experiment
diff --git a/app/models/vulnerability.rb b/app/models/vulnerability.rb
index da607dcb771..6bf63bab82c 100644
--- a/app/models/vulnerability.rb
+++ b/app/models/vulnerability.rb
@@ -5,7 +5,7 @@ class Vulnerability < ApplicationRecord
include EachBatch
include IgnorableColumns
- ignore_column %i[epic_id milestone_id last_edited_at last_edited_by_id
+ ignore_column %i[due_date epic_id milestone_id last_edited_at last_edited_by_id
start_date start_date_sourcing_milestone_id updated_by_id],
remove_with: '16.9',
remove_after: '2024-01-19'
diff --git a/app/services/jira_import/users_mapper_service.rb b/app/services/jira_import/users_mapper_service.rb
index 13e0dd5120e..45a607dd2b0 100644
--- a/app/services/jira_import/users_mapper_service.rb
+++ b/app/services/jira_import/users_mapper_service.rb
@@ -63,6 +63,7 @@ module JiraImport
relations << User.by_emails(jira_emails).select("users.id, users.name, users.username, emails.email as user_email")
User.from_union(relations).id_in(project_member_ids).select("users.id as user_id, users.name as name, users.username as username, user_email")
+ .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/432608")
end
end
diff --git a/app/services/ml/destroy_model_service.rb b/app/services/ml/destroy_model_service.rb
new file mode 100644
index 00000000000..308d289fbe1
--- /dev/null
+++ b/app/services/ml/destroy_model_service.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Ml
+ class DestroyModelService
+ def initialize(model, user)
+ @model = model
+ @user = user
+ end
+
+ def execute
+ return unless @model.destroy
+
+ ::Packages::MarkPackagesForDestructionService.new(
+ packages: @model.all_packages,
+ current_user: @user
+ ).execute
+ end
+ end
+end