Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
47d2cd0b94
commit
1cc5b352a3
|
|
@ -851,7 +851,6 @@ Gitlab/BoundedContexts:
|
|||
- 'app/models/concerns/enums/internal_id.rb'
|
||||
- 'app/models/concerns/enums/issuable_link.rb'
|
||||
- 'app/models/concerns/enums/package_metadata.rb'
|
||||
- 'app/models/concerns/enums/prometheus_metric.rb'
|
||||
- 'app/models/concerns/enums/sbom.rb'
|
||||
- 'app/models/concerns/enums/vulnerability.rb'
|
||||
- 'app/models/concerns/enums/web_ide/extensions_marketplace_opt_in_status.rb'
|
||||
|
|
@ -1212,7 +1211,6 @@ Gitlab/BoundedContexts:
|
|||
- 'app/models/project_statistics.rb'
|
||||
- 'app/models/project_team.rb'
|
||||
- 'app/models/project_wiki.rb'
|
||||
- 'app/models/prometheus_metric.rb'
|
||||
- 'app/models/protectable_dropdown.rb'
|
||||
- 'app/models/protected_branch.rb'
|
||||
- 'app/models/protected_branch/cache_key.rb'
|
||||
|
|
|
|||
|
|
@ -268,7 +268,6 @@ Gitlab/NamespacedClass:
|
|||
- 'app/models/project_statistics.rb'
|
||||
- 'app/models/project_team.rb'
|
||||
- 'app/models/project_wiki.rb'
|
||||
- 'app/models/prometheus_metric.rb'
|
||||
- 'app/models/protectable_dropdown.rb'
|
||||
- 'app/models/protected_branch.rb'
|
||||
- 'app/models/protected_tag.rb'
|
||||
|
|
|
|||
|
|
@ -268,7 +268,6 @@ Layout/LineLength:
|
|||
- 'app/models/concerns/ci/has_status.rb'
|
||||
- 'app/models/concerns/each_batch.rb'
|
||||
- 'app/models/concerns/enums/ci/pipeline.rb'
|
||||
- 'app/models/concerns/enums/prometheus_metric.rb'
|
||||
- 'app/models/concerns/enums/vulnerability.rb'
|
||||
- 'app/models/concerns/fast_destroy_all.rb'
|
||||
- 'app/models/concerns/group_descendant.rb'
|
||||
|
|
@ -374,7 +373,6 @@ Layout/LineLength:
|
|||
- 'app/models/project_feature.rb'
|
||||
- 'app/models/project_statistics.rb'
|
||||
- 'app/models/projects/topic.rb'
|
||||
- 'app/models/prometheus_metric.rb'
|
||||
- 'app/models/release.rb'
|
||||
- 'app/models/releases/link.rb'
|
||||
- 'app/models/remote_mirror.rb'
|
||||
|
|
@ -3844,7 +3842,6 @@ Layout/LineLength:
|
|||
- 'spec/models/project_team_spec.rb'
|
||||
- 'spec/models/projects/build_artifacts_size_refresh_spec.rb'
|
||||
- 'spec/models/projects/triggered_hooks_spec.rb'
|
||||
- 'spec/models/prometheus_metric_spec.rb'
|
||||
- 'spec/models/protected_branch_spec.rb'
|
||||
- 'spec/models/redirect_route_spec.rb'
|
||||
- 'spec/models/release_highlight_spec.rb'
|
||||
|
|
|
|||
|
|
@ -3721,7 +3721,6 @@ RSpec/FeatureCategory:
|
|||
- 'spec/models/projects/project_topic_spec.rb'
|
||||
- 'spec/models/projects/topic_spec.rb'
|
||||
- 'spec/models/projects/wiki_repository_spec.rb'
|
||||
- 'spec/models/prometheus_metric_spec.rb'
|
||||
- 'spec/models/protectable_dropdown_spec.rb'
|
||||
- 'spec/models/push_event_payload_spec.rb'
|
||||
- 'spec/models/push_event_spec.rb'
|
||||
|
|
|
|||
|
|
@ -2647,7 +2647,6 @@ RSpec/NamedSubject:
|
|||
- 'spec/models/projects/import_export/relation_export_upload_spec.rb'
|
||||
- 'spec/models/projects/project_topic_spec.rb'
|
||||
- 'spec/models/projects/topic_spec.rb'
|
||||
- 'spec/models/prometheus_metric_spec.rb'
|
||||
- 'spec/models/protected_branch_spec.rb'
|
||||
- 'spec/models/release_highlight_spec.rb'
|
||||
- 'spec/models/releases/source_spec.rb'
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
<section class="header-main-content gl-mr-3 gl-flex gl-items-center">
|
||||
<ci-icon class="gl-mr-3" :status="status" show-status-text />
|
||||
<ci-icon class="gl-mr-3 gl-leading-1" :status="status" show-status-text />
|
||||
|
||||
<template v-if="shouldRenderTriggeredLabel">{{ __('Started') }}</template>
|
||||
<template v-else>{{ __('Created') }}</template>
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ export default {
|
|||
:key="tab.namespace"
|
||||
:title-link-attributes="tab.attrs"
|
||||
:query-param-value="tab.queryParamValue"
|
||||
:lazy="tab.lazy"
|
||||
>
|
||||
<template #title>
|
||||
<span>{{ tab.title }}</span>
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ export default {
|
|||
:initial-filter-value="initialFilterValue"
|
||||
:tokens="filteredSearchTokens"
|
||||
:search-input-placeholder="s__('UserMapping|Search placeholder users')"
|
||||
terms-as-tokens
|
||||
class="row-content-block gl-grow gl-border-t-0 sm:gl-flex"
|
||||
@onFilter="onFilter"
|
||||
/>
|
||||
|
|
@ -196,6 +197,7 @@ export default {
|
|||
:initial-filter-value="initialFilterValue"
|
||||
:tokens="filteredSearchTokens"
|
||||
:search-input-placeholder="s__('UserMapping|Search placeholder users')"
|
||||
terms-as-tokens
|
||||
class="row-content-block gl-grow gl-border-t-0 sm:gl-flex"
|
||||
@onFilter="onFilter"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -31,5 +31,6 @@ export const TABS = [
|
|||
title: s__('UserMapping|Placeholders'),
|
||||
queryParamValue: TAB_QUERY_PARAM_VALUES.placeholder,
|
||||
component: PlaceholdersTabApp,
|
||||
lazy: true,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { isScopedLabel } from '~/lib/utils/common_utils';
|
|||
import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue';
|
||||
import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/shared/work_item_link_child_metadata.vue';
|
||||
import WorkItemTypeIcon from '../work_item_type_icon.vue';
|
||||
import WorkItemStateBadge from '../work_item_state_badge.vue';
|
||||
import {
|
||||
STATE_OPEN,
|
||||
WIDGET_TYPE_PROGRESS,
|
||||
|
|
@ -44,6 +45,7 @@ export default {
|
|||
RichTimestampTooltip,
|
||||
WorkItemLinkChildMetadata,
|
||||
WorkItemTypeIcon,
|
||||
WorkItemStateBadge,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
|
|
@ -99,21 +101,18 @@ export default {
|
|||
isChildItemOpen() {
|
||||
return this.childItem.state === STATE_OPEN;
|
||||
},
|
||||
statusIconName() {
|
||||
return this.isChildItemOpen ? 'issue-open-m' : 'issue-close';
|
||||
},
|
||||
childItemType() {
|
||||
return this.childItem.workItemType.name;
|
||||
},
|
||||
statusIconClass() {
|
||||
return this.isChildItemOpen ? 'gl-text-green-500' : 'gl-text-blue-500';
|
||||
},
|
||||
stateTimestamp() {
|
||||
return this.isChildItemOpen ? this.childItem.createdAt : this.childItem.closedAt;
|
||||
},
|
||||
stateTimestampTypeText() {
|
||||
return this.isChildItemOpen ? this.$options.i18n.created : this.$options.i18n.closed;
|
||||
},
|
||||
childItemTypeColorClass() {
|
||||
return this.isChildItemOpen ? 'gl-text-secondary' : 'gl-text-gray-300';
|
||||
},
|
||||
hasMetadata() {
|
||||
if (this.metadataWidgets) {
|
||||
return (
|
||||
|
|
@ -152,7 +151,7 @@ export default {
|
|||
data-testid="links-child"
|
||||
>
|
||||
<div ref="stateIcon" class="gl-cursor-help">
|
||||
<work-item-type-icon class="gl-text-secondary" :work-item-type="childItemType" />
|
||||
<work-item-type-icon :color-class="childItemTypeColorClass" :work-item-type="childItemType" />
|
||||
<gl-tooltip :target="() => $refs.stateIcon">
|
||||
{{ childItemType }}
|
||||
</gl-tooltip>
|
||||
|
|
@ -172,6 +171,7 @@ export default {
|
|||
</span>
|
||||
<gl-link
|
||||
:href="childItem.webUrl"
|
||||
:class="{ '!gl-text-secondary': !isChildItemOpen }"
|
||||
class="gl-hyphens-auto gl-break-words gl-font-semibold"
|
||||
@click.exact="$emit('click', $event)"
|
||||
@mouseover="$emit('mouseover')"
|
||||
|
|
@ -180,7 +180,7 @@ export default {
|
|||
{{ childItem.title }}
|
||||
</gl-link>
|
||||
</div>
|
||||
<div class="gl-flex gl-justify-end">
|
||||
<div class="gl-flex gl-items-center gl-justify-end">
|
||||
<gl-avatars-inline
|
||||
v-if="assignees.length"
|
||||
:avatars="assignees"
|
||||
|
|
@ -202,11 +202,7 @@ export default {
|
|||
class="gl-cursor-help"
|
||||
data-testid="item-status-icon"
|
||||
>
|
||||
<gl-icon
|
||||
:class="statusIconClass"
|
||||
:name="statusIconName"
|
||||
:aria-label="stateTimestampTypeText"
|
||||
/>
|
||||
<work-item-state-badge :work-item-state="childItem.state" :show-icon="false" />
|
||||
</span>
|
||||
<rich-timestamp-tooltip
|
||||
:target="`statusIcon-${childItem.id}`"
|
||||
|
|
@ -237,7 +233,7 @@ export default {
|
|||
<div v-if="canUpdate">
|
||||
<gl-button
|
||||
v-gl-tooltip
|
||||
class="-gl-mr-2 -gl-mt-2"
|
||||
class="-gl-mr-1 -gl-mt-1"
|
||||
category="tertiary"
|
||||
size="small"
|
||||
icon="close"
|
||||
|
|
|
|||
|
|
@ -262,13 +262,7 @@ export default {
|
|||
return this.isWidgetPresent(WIDGET_TYPE_HIERARCHY)?.parent;
|
||||
},
|
||||
hasParent() {
|
||||
// TODO: This is a temporary check till the issue work item migration is completed
|
||||
// Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/468114
|
||||
const { workItemType, glFeatures, parentWorkItem, hasSubepicsFeature } = this;
|
||||
|
||||
if (workItemType === WORK_ITEM_TYPE_VALUE_TASK) {
|
||||
return glFeatures.namespaceLevelWorkItems && parentWorkItem;
|
||||
}
|
||||
const { workItemType, parentWorkItem, hasSubepicsFeature } = this;
|
||||
|
||||
if (workItemType === WORK_ITEM_TYPE_VALUE_EPIC) {
|
||||
return hasSubepicsFeature && parentWorkItem;
|
||||
|
|
@ -277,6 +271,15 @@ export default {
|
|||
return Boolean(parentWorkItem);
|
||||
},
|
||||
shouldShowAncestors() {
|
||||
// TODO: This is a temporary check till the issue work item migration is completed
|
||||
// Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/468114
|
||||
if (
|
||||
this.workItemType === WORK_ITEM_TYPE_VALUE_TASK &&
|
||||
!this.glFeatures.namespaceLevelWorkItems
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks whether current work item has parent
|
||||
// or it is in hierarchy but there is no permission to view the parent
|
||||
return this.hasParent || this.workItemHierarchy?.hasParent;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
showIcon: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isWorkItemOpen() {
|
||||
|
|
@ -21,6 +26,10 @@ export default {
|
|||
return this.isWorkItemOpen ? __('Open') : __('Closed');
|
||||
},
|
||||
workItemStateIcon() {
|
||||
if (!this.showIcon) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.isWorkItemOpen ? 'issue-open-m' : 'issue-close';
|
||||
},
|
||||
workItemStateVariant() {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
colorClass: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'gl-text-secondary',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
workItemTypeUppercase() {
|
||||
|
|
@ -63,7 +68,7 @@ export default {
|
|||
v-gl-tooltip.hover="showTooltipOnHover"
|
||||
:name="iconName"
|
||||
:title="workItemTooltipTitle"
|
||||
class="gl-text-secondary"
|
||||
:class="colorClass"
|
||||
/>
|
||||
<span v-if="workItemTypeName" :class="{ 'gl-sr-only': !showText }">{{ workItemTypeName }}</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -96,3 +96,9 @@
|
|||
margin-left: $gl-spacing-scale-5;
|
||||
}
|
||||
}
|
||||
|
||||
// Timeline avatars
|
||||
|
||||
.timeline-avatar {
|
||||
@apply gl-bg-default;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Enums
|
||||
module PrometheusMetric
|
||||
def self.groups
|
||||
{
|
||||
# built-in groups
|
||||
nginx_ingress_vts: -1,
|
||||
ha_proxy: -2,
|
||||
aws_elb: -3,
|
||||
nginx: -4,
|
||||
kubernetes: -5,
|
||||
nginx_ingress: -6,
|
||||
cluster_health: -100
|
||||
}.merge(custom_groups).freeze
|
||||
end
|
||||
|
||||
# custom/user groups
|
||||
def self.custom_groups
|
||||
{
|
||||
business: 0,
|
||||
response: 1,
|
||||
system: 2,
|
||||
custom: 3
|
||||
}.freeze
|
||||
end
|
||||
|
||||
def self.group_details
|
||||
{
|
||||
# built-in groups
|
||||
nginx_ingress_vts: {
|
||||
group_title: _('Response metrics (NGINX Ingress VTS)'),
|
||||
required_metrics: %w[nginx_upstream_responses_total nginx_upstream_response_msecs_avg],
|
||||
priority: 10
|
||||
}.freeze,
|
||||
nginx_ingress: {
|
||||
group_title: _('Response metrics (NGINX Ingress)'),
|
||||
required_metrics: %w[nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum],
|
||||
priority: 10
|
||||
}.freeze,
|
||||
ha_proxy: {
|
||||
group_title: _('Response metrics (HA Proxy)'),
|
||||
required_metrics: %w[haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total],
|
||||
priority: 10
|
||||
}.freeze,
|
||||
aws_elb: {
|
||||
group_title: _('Response metrics (AWS ELB)'),
|
||||
required_metrics: %w[aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum],
|
||||
priority: 10
|
||||
}.freeze,
|
||||
nginx: {
|
||||
group_title: _('Response metrics (NGINX)'),
|
||||
required_metrics: %w[nginx_server_requests nginx_server_requestMsec],
|
||||
priority: 10
|
||||
}.freeze,
|
||||
kubernetes: {
|
||||
group_title: _('System metrics (Kubernetes)'),
|
||||
required_metrics: %w[container_memory_usage_bytes container_cpu_usage_seconds_total],
|
||||
priority: 5
|
||||
}.freeze,
|
||||
cluster_health: {
|
||||
group_title: _('Cluster Health'),
|
||||
required_metrics: %w[container_memory_usage_bytes container_cpu_usage_seconds_total],
|
||||
priority: 10
|
||||
}.freeze
|
||||
}.merge(custom_group_details).freeze
|
||||
end
|
||||
|
||||
# custom/user groups
|
||||
def self.custom_group_details
|
||||
{
|
||||
business: {
|
||||
group_title: _('Business metrics (Custom)'),
|
||||
priority: 0
|
||||
}.freeze,
|
||||
response: {
|
||||
group_title: _('Response metrics (Custom)'),
|
||||
priority: -5
|
||||
}.freeze,
|
||||
system: {
|
||||
group_title: _('System metrics (Custom)'),
|
||||
priority: -10
|
||||
}.freeze,
|
||||
custom: {
|
||||
group_title: _('Custom metrics'),
|
||||
priority: 0
|
||||
}
|
||||
}.freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -23,10 +23,12 @@ class LfsObject < ApplicationRecord
|
|||
find_by(oid: oid, size: size)
|
||||
end
|
||||
|
||||
def self.not_linked_to_project(project)
|
||||
def self.not_linked_to_project(project, repository_type: nil)
|
||||
linked_to_project = project.lfs_objects_projects.where('lfs_objects_projects.lfs_object_id = lfs_objects.id')
|
||||
linked_to_project = linked_to_project.where(repository_type: repository_type) if repository_type
|
||||
where(
|
||||
'NOT EXISTS (?)',
|
||||
project.lfs_objects_projects.select(1).where('lfs_objects_projects.lfs_object_id = lfs_objects.id')
|
||||
linked_to_project.select(1)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ class Namespace < ApplicationRecord
|
|||
validate :nesting_level_allowed, unless: -> { project_namespace? }
|
||||
validate :changing_shared_runners_enabled_is_allowed, unless: -> { project_namespace? }
|
||||
validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed, unless: -> { project_namespace? }
|
||||
validate :parent_organization_match, if: :require_organization?
|
||||
|
||||
delegate :name, to: :owner, allow_nil: true, prefix: true
|
||||
delegate :avatar_url, to: :owner, allow_nil: true
|
||||
|
|
@ -733,6 +734,13 @@ class Namespace < ApplicationRecord
|
|||
|
||||
private
|
||||
|
||||
def parent_organization_match
|
||||
return unless parent
|
||||
return if parent.organization_id == organization_id
|
||||
|
||||
errors.add(:organization_id, _("must match the parent organization's ID"))
|
||||
end
|
||||
|
||||
def cross_namespace_reference?(from)
|
||||
return false if from == self
|
||||
|
||||
|
|
|
|||
|
|
@ -422,8 +422,6 @@ class Project < ApplicationRecord
|
|||
has_many :cluster_agents, class_name: 'Clusters::Agent'
|
||||
has_many :ci_access_project_authorizations, class_name: 'Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization'
|
||||
|
||||
has_many :prometheus_metrics
|
||||
|
||||
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project
|
||||
has_many :alert_management_http_integrations, class_name: 'AlertManagement::HttpIntegration', inverse_of: :project
|
||||
|
||||
|
|
@ -632,9 +630,8 @@ class Project < ApplicationRecord
|
|||
validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level?
|
||||
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
|
||||
validate :changing_shared_runners_enabled_is_allowed
|
||||
validates :repository_storage,
|
||||
presence: true,
|
||||
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
|
||||
validate :parent_organization_match, if: :require_organization?
|
||||
validates :repository_storage, presence: true, inclusion: { in: ->(_) { Gitlab.config.repositories.storages.keys } }
|
||||
validates :variables, nested_attributes_duplicates: { scope: :environment_scope }
|
||||
validates :bfg_object_map, file_size: { maximum: :max_attachment_size }
|
||||
validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true }
|
||||
|
|
@ -1699,6 +1696,13 @@ class Project < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def parent_organization_match
|
||||
return unless parent
|
||||
return if parent.organization_id == organization_id
|
||||
|
||||
errors.add(:organization_id, _("must match the parent organization's ID"))
|
||||
end
|
||||
|
||||
def shared_runners_setting_conflicting_with_group?
|
||||
shared_runners_enabled && group&.shared_runners_setting == Namespace::SR_DISABLED_AND_UNOVERRIDABLE
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PrometheusMetric < ApplicationRecord
|
||||
include EachBatch
|
||||
|
||||
belongs_to :project, validate: true, inverse_of: :prometheus_metrics
|
||||
|
||||
enum group: Enums::PrometheusMetric.groups
|
||||
|
||||
validates :title, presence: true
|
||||
validates :query, presence: true
|
||||
validates :group, presence: true
|
||||
validates :y_label, presence: true
|
||||
validates :unit, presence: true
|
||||
validates :identifier, uniqueness: { scope: :project_id }, allow_nil: true
|
||||
|
||||
validates :project, presence: true, unless: :common?
|
||||
validates :project, absence: true, if: :common?
|
||||
|
||||
scope :for_dashboard_path, ->(dashboard_path) { where(dashboard_path: dashboard_path) }
|
||||
scope :for_project, ->(project) { where(project: project) }
|
||||
scope :for_group, ->(group) { where(group: group) }
|
||||
scope :for_title, ->(title) { where(title: title) }
|
||||
scope :for_y_label, ->(y_label) { where(y_label: y_label) }
|
||||
scope :for_identifier, ->(identifier) { where(identifier: identifier) }
|
||||
scope :not_identifier, ->(identifier) { where.not(identifier: identifier) }
|
||||
scope :common, -> { where(common: true) }
|
||||
scope :ordered, -> { reorder(created_at: :asc) }
|
||||
|
||||
def priority
|
||||
group_details(group).fetch(:priority)
|
||||
end
|
||||
|
||||
def group_title
|
||||
group_details(group).fetch(:group_title)
|
||||
end
|
||||
|
||||
def required_metrics
|
||||
group_details(group).fetch(:required_metrics, []).map(&:to_s)
|
||||
end
|
||||
|
||||
def to_query_metric
|
||||
Gitlab::Prometheus::Metric.new(id: id, title: title, required_metrics: required_metrics, weight: 0, y_label: y_label, queries: queries)
|
||||
end
|
||||
|
||||
def to_metric_hash
|
||||
queries.first.merge(metric_id: id)
|
||||
end
|
||||
|
||||
def queries
|
||||
[
|
||||
{
|
||||
query_range: query,
|
||||
unit: unit,
|
||||
label: legend,
|
||||
series: query_series
|
||||
}.compact
|
||||
]
|
||||
end
|
||||
|
||||
def query_series
|
||||
case legend
|
||||
when 'Status Code'
|
||||
[{
|
||||
label: 'status_code',
|
||||
when: [
|
||||
{ value: '2xx', color: 'green' },
|
||||
{ value: '4xx', color: 'orange' },
|
||||
{ value: '5xx', color: 'red' }
|
||||
]
|
||||
}]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def group_details(group)
|
||||
Enums::PrometheusMetric.group_details.fetch(group.to_sym)
|
||||
end
|
||||
end
|
||||
|
|
@ -272,7 +272,11 @@ module DesignManagement
|
|||
oids = blobs.values.flat_map(&:values).map(&:lfs_oid)
|
||||
repository_type = LfsObjectsProject.repository_types[:design]
|
||||
|
||||
new_rows = LfsObject.where(oid: oids).find_each(batch_size: 1000).map do |lfs_object|
|
||||
lfs_objects = oids.each_slice(1000).flat_map do |oids_batch|
|
||||
LfsObject.for_oids(oids_batch).not_linked_to_project(target_project, repository_type: repository_type)
|
||||
end
|
||||
|
||||
new_rows = lfs_objects.compact.map do |lfs_object|
|
||||
{
|
||||
project_id: target_project.id,
|
||||
lfs_object_id: lfs_object.id,
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@
|
|||
source_hostname: source_user.source_hostname,
|
||||
destination_group: source_user.namespace.name)
|
||||
- c.with_actions do
|
||||
= render Pajamas::ButtonComponent.new(variant: :default, href: help_page_path('user/group/import/index'), button_options: { class: 'deferred-link gl-alert-action', rel: 'noreferrer noopener' }, target: '_blank') do
|
||||
= render Pajamas::ButtonComponent.new(variant: :default,
|
||||
href: help_page_path('user/project/import/index', anchor: 'accept-contribution-reassignment'),
|
||||
button_options: { class: 'deferred-link gl-alert-action', rel: 'noreferrer noopener' }, target: '_blank') do
|
||||
= _('Learn more')
|
||||
|
|
|
|||
|
|
@ -2,5 +2,7 @@
|
|||
- c.with_body do
|
||||
= s_('UserMapping|The reassignment has been cancelled by the group owner.')
|
||||
- c.with_actions do
|
||||
= render Pajamas::ButtonComponent.new(variant: :default, href: help_page_path('user/group/import/index'), button_options: { class: 'deferred-link gl-alert-action', rel: 'noreferrer noopener' }, target: '_blank') do
|
||||
= render Pajamas::ButtonComponent.new(variant: :default,
|
||||
href: help_page_path('user/project/import/index', anchor: 'accept-contribution-reassignment'),
|
||||
button_options: { class: 'deferred-link gl-alert-action', rel: 'noreferrer noopener' }, target: '_blank') do
|
||||
= _('Learn more')
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@
|
|||
source_hostname: source_user.source_hostname,
|
||||
destination_group: source_user.namespace.name)
|
||||
- c.with_actions do
|
||||
= render Pajamas::ButtonComponent.new(variant: :default, href: help_page_path('user/group/import/index'), button_options: { class: 'deferred-link gl-alert-action', rel: 'noreferrer noopener' }, target: '_blank') do
|
||||
= render Pajamas::ButtonComponent.new(variant: :default,
|
||||
href: help_page_path('user/project/import/index', anchor: 'accept-contribution-reassignment'),
|
||||
button_options: { class: 'deferred-link gl-alert-action', rel: 'noreferrer noopener' }, target: '_blank') do
|
||||
= _('Learn more')
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
source_hostname: source_hostname,
|
||||
destination_group: destination_group)
|
||||
= succeed '.' do
|
||||
= link_to s_('UserMapping|Learn more about reassignments'), help_page_path('user/project/import/index', anchor: 'reassign-contributions-and-memberships')
|
||||
= link_to s_('UserMapping|Learn more about reassignments'), help_page_path('user/project/import/index', anchor: 'accept-contribution-reassignment')
|
||||
%h5
|
||||
= s_('UserMapping|Import details:')
|
||||
%p.gl-mb-5
|
||||
|
|
@ -44,10 +44,11 @@
|
|||
= safe_format(s_('UserMapping|Reassigned by: %{reassigned_by_name} (%{reassigned_by_username})'), reassigned_by_name: reassigned_by_name, reassigned_by_username: reassigned_by_username)
|
||||
%p.gl-mb-0
|
||||
%strong
|
||||
= s_('UserMapping|Accept reassignments only from users that you trust. Reassignment of contributions is permanent. Accepting these reassignments might cause contributions to be incorrectly attributed to you.')
|
||||
= s_('UserMapping|Approve reassignments only from users that you trust. After approval, contributions will be assigned to you. The assignment is permanent.')
|
||||
|
||||
- c.with_footer do
|
||||
= render Pajamas::ButtonComponent.new(variant: :danger, method: :post, href: accept_import_source_user_path(@source_user)) do
|
||||
= s_('UserMapping|Approve reassignment')
|
||||
= render Pajamas::ButtonComponent.new(method: :post, href: decline_import_source_user_path(@source_user)) do
|
||||
= s_('UserMapping|Reject')
|
||||
.gl-flex.gl-gap-3
|
||||
= render Pajamas::ButtonComponent.new(variant: :danger, method: :post, href: accept_import_source_user_path(@source_user)) do
|
||||
= s_('UserMapping|Approve reassignment')
|
||||
= render Pajamas::ButtonComponent.new(method: :post, href: decline_import_source_user_path(@source_user)) do
|
||||
= s_('UserMapping|Reject')
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
- button_style = 'border: 1px solid #694cc0; border-radius: 4px; font-size: 14px; padding: 8px 16px; background-color: #7b58cf; color: #fff; cursor: pointer;'
|
||||
|
||||
- strong_tag_pair = tag_pair(tag.strong, :strong_open, :strong_close)
|
||||
- help_link_tag_pair = tag_pair(link_to('', help_page_url('user/project/import/index', anchor: 'reassign-contributions-and-memberships'), target: '_blank', rel: 'noopener noreferrer'), :link_start, :link_end)
|
||||
- help_link_tag_pair = tag_pair(link_to('', help_page_url('user/project/import/index', anchor: 'accept-contribution-reassignment'), target: '_blank', rel: 'noopener noreferrer'), :link_start, :link_end)
|
||||
- report_link_tag_pair = tag_pair(link_to('', help_page_url('user/report_abuse'), target: '_blank', rel: 'noopener noreferrer'), :report_link_start, :report_link_end)
|
||||
|
||||
%p{ style: text_style }
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<% reassigned_by_name = reassigned_by.name %>
|
||||
<% reassigned_by_username = "#{reassigned_by.to_reference} - #{user_url(reassigned_by)}" %>
|
||||
<% destination_group = "#{@source_user.namespace.name} (/#{@source_user.namespace.full_path})" %>
|
||||
<% help_link = help_page_url('user/group/import/index', anchor: 'memberships') %>
|
||||
<% help_link = help_page_url('user/project/import/index', anchor: 'accept-contribution-reassignment') %>
|
||||
<% report_link = help_page_url('user/report_abuse') %>
|
||||
<%= s_('UserMapping|%{reassigned_by_name} (%{reassigned_by_username}) wants to reassign contributions made by %{source_name} (%{source_username}) on %{source_hostname} to you in %{destination_group}.') % { reassigned_by_name: reassigned_by_name,
|
||||
reassigned_by_username: reassigned_by_username,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,23 @@ experiences. Several projects were started with different standards and they
|
|||
can still have specifics. They are described in their respective
|
||||
`README.md` or `PROCESS.md` files.
|
||||
|
||||
## Project structure
|
||||
|
||||
According to the [basic layout for Go application projects](https://github.com/golang-standards/project-layout?tab=readme-ov-file#overview), there is no official Go project layout. However, there are some good suggestions
|
||||
in Ben Johnson's [Standard Package Layout](https://www.gobeyond.dev/standard-package-layout/).
|
||||
|
||||
The following is a list of GitLab Go-based projects for inspiration:
|
||||
|
||||
- [Gitaly](https://gitlab.com/gitlab-org/gitaly)
|
||||
- [GitLab Agent for Kubernetes](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent)
|
||||
- [GitLab CLI](https://gitlab.com/gitlab-org/cli)
|
||||
- [GitLab Container Registry](https://gitlab.com/gitlab-org/container-registry)
|
||||
- [GitLab Operator](https://gitlab.com/gitlab-org/cloud-native/gitlab-operator)
|
||||
- [GitLab Pages](https://gitlab.com/gitlab-org/gitlab-pages)
|
||||
- [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner)
|
||||
- [GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell)
|
||||
- [Workhorse](https://gitlab.com/gitlab-org/gitlab/-/tree/master/workhorse)
|
||||
|
||||
## Go language versions
|
||||
|
||||
The Go upgrade documentation [provides an overview](go_upgrade.md#overview)
|
||||
|
|
|
|||
|
|
@ -195,6 +195,33 @@ GitLab has several features to help you manage the number of users. You can:
|
|||
- View a breakdown of users by role in the
|
||||
[Users statistics](../../administration/admin_area.md#users-statistics) page.
|
||||
|
||||
### Add seats to a subscription
|
||||
|
||||
To increase the number of users covered by your license, add seats to your subscription
|
||||
during the subscription period. The cost of seats added during the subscription
|
||||
period is prorated from the date of purchase through to the end of the subscription
|
||||
period. You can continue to add users even if you reach the number of users in
|
||||
license count. GitLab [bills you for the overage](../quarterly_reconciliation.md).
|
||||
|
||||
To add seats to a subscription:
|
||||
|
||||
1. Sign in to the [Customers Portal](https://customers.gitlab.com/).
|
||||
1. Go to the **Subscriptions & purchases** page.
|
||||
1. Select **Add seats** on the relevant subscription card.
|
||||
1. Enter the number of additional users.
|
||||
1. Review the **Purchase summary** section, which lists the total price for
|
||||
all users on the system and a credit for what you've already paid. You are only
|
||||
charged for the net change.
|
||||
1. Enter your payment information.
|
||||
1. Select **Purchase seats**.
|
||||
|
||||
A payment receipt is emailed to you, which you can also access in the Customers Portal under [**Invoices**](https://customers.gitlab.com/invoices).
|
||||
|
||||
If your subscription was activated with an activation code, the additional seats are reflected in
|
||||
your instance immediately. If you're using a license file, you receive an updated file.
|
||||
To add the seats, [add the license file](../../administration/license_file.md)
|
||||
to your instance.
|
||||
|
||||
## Subscription data synchronization
|
||||
|
||||
Prerequisites:
|
||||
|
|
@ -360,10 +387,16 @@ A custom format is used for [dates](https://gitlab.com/gitlab-org/gitlab/blob/3b
|
|||
|
||||
## Renew your subscription
|
||||
|
||||
You can renew your subscription starting from 15 days before your subscription expires. To renew your subscription:
|
||||
You can [renew your subscription automatically](#automatic-subscription-renewal)
|
||||
or manually.
|
||||
|
||||
1. [Prepare for renewal by reviewing your account](#review-your-account).
|
||||
1. [Renew your GitLab self-managed subscription](#renew-subscription-manually).
|
||||
You should [renew your subscription manually](#renew-subscription-manually) if
|
||||
you want to either:
|
||||
|
||||
- [Upgrade your subscription tier](#upgrade-your-subscription-tier).
|
||||
- [Renew for fewer seats](#renew-for-fewer-seats).
|
||||
|
||||
Before your subscription renewal date, you should review your account.
|
||||
|
||||
### Review your account
|
||||
|
||||
|
|
@ -394,32 +427,14 @@ Contact the [support team](https://support.gitlab.com/hc/en-us/requests/new?tick
|
|||
if you need assistance accessing the Customers Portal or if you need to change
|
||||
the contact person who manages your subscription.
|
||||
|
||||
### Add seats to a subscription
|
||||
### Renew for fewer seats
|
||||
|
||||
To increase the number of users covered by your license, add seats to your subscription
|
||||
during the subscription period. The cost of seats added during the subscription
|
||||
period is prorated from the date of purchase through to the end of the subscription
|
||||
period. You can continue to add users even if you reach the number of users in license count. GitLab
|
||||
[bills you for the overage](../quarterly_reconciliation.md)
|
||||
If you want to renew with fewer seats, you can do either of the following:
|
||||
|
||||
To add seats to a subscription:
|
||||
|
||||
1. Sign in to the [Customers Portal](https://customers.gitlab.com/).
|
||||
1. Go to the **Subscriptions & purchases** page.
|
||||
1. Select **Add seats** on the relevant subscription card.
|
||||
1. Enter the number of additional users.
|
||||
1. Review the **Purchase summary** section, which lists the total price for
|
||||
all users on the system and a credit for what you've already paid. You are only
|
||||
charged for the net change.
|
||||
1. Enter your payment information.
|
||||
1. Select **Purchase seats**.
|
||||
|
||||
A payment receipt is emailed to you, which you can also access in the Customers Portal under [**Invoices**](https://customers.gitlab.com/invoices).
|
||||
|
||||
If your subscription was activated with an activation code, the additional seats are reflected in
|
||||
your instance immediately. If you're using a license file, you receive an updated file.
|
||||
To add the seats, [add the license file](../../administration/license_file.md)
|
||||
to your instance.
|
||||
- [Manually renew your subscription](#renew-subscription-manually).
|
||||
- [Cancel your subscription](#enable-or-disable-automatic-subscription-renewal)
|
||||
and contact the Sales team to specify how many seats you need in your subscription
|
||||
going forward.
|
||||
|
||||
### Renew subscription manually
|
||||
|
||||
|
|
@ -446,7 +461,7 @@ To manually renew your subscription:
|
|||
|
||||
To change to a lower tier, [contact the GitLab sales team](https://about.gitlab.com/sales/).
|
||||
1. Under **Subscription details**, in the **Billable users** text box, enter the
|
||||
total number of user licenses you'll need for the upcoming year.
|
||||
total number of user seats you'll need for the upcoming year.
|
||||
|
||||
NOTE:
|
||||
Make sure this number is equal to, or greater than
|
||||
|
|
@ -464,31 +479,38 @@ To manually renew your subscription:
|
|||
a copy of the renewal term activation code.
|
||||
1. [Add the activation code](../../administration/license.md) to your instance.
|
||||
|
||||
An invoice is generated for the renewal and available for viewing or download on the [Invoices](https://customers.gitlab.com/invoices) page. If you have difficulty during the renewal process, contact our [support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293) for assistance.
|
||||
|
||||
### Automatic subscription renewal
|
||||
|
||||
When a subscription is set to auto-renew, it renews automatically on the expiration date (at midnight UTC) without a gap in available service. Subscriptions purchased through the Customers Portal are set to auto-renew by default.
|
||||
Prerequisites:
|
||||
|
||||
The number of user licenses is adjusted to fit the [number of billable users in your instance](#view-users) at the time of renewal, if that number is higher than the current subscription quantity. Before auto-renewal you should [prepare for the renewal](#review-your-account) at least 2 days before the renewal date, so that your changes synchronize to GitLab in time for your renewal. To auto-renew your subscription,
|
||||
you must have enabled the [synchronization of subscription data](#subscription-data-synchronization).
|
||||
- You must have enabled the [synchronization of subscription data](#subscription-data-synchronization).
|
||||
|
||||
You can view and download your renewal invoice on the Customers Portal [Invoices](https://customers.gitlab.com/invoices) page. If your account has a [saved credit card](../customers_portal.md#change-your-payment-method), the card is charged for the invoice amount. If we are unable to process a payment or the auto-renewal fails for any other reason, you have 14 days to renew your subscription, after which your GitLab tier is downgraded.
|
||||
At least two days before your renewal date, you should [review your account](#review-your-account)
|
||||
so that your changes synchronize to GitLab in time for your renewal.
|
||||
|
||||
When a subscription is set to automatically renew, it renews automatically at
|
||||
midnight UTC on the expiration date without a gap in available service. Subscriptions
|
||||
purchased through the Customers Portal are set to automatically renew by default.
|
||||
|
||||
The number of user seats is adjusted to fit the [number of billable users in your instance](#view-users)
|
||||
at the time of renewal, if that number is higher than the current subscription quantity.
|
||||
|
||||
#### Email notifications
|
||||
|
||||
15 days before a subscription automatically renews, an email is sent with information about the renewal.
|
||||
15 days before a subscription automatically renews, an email is sent with information
|
||||
about the renewal.
|
||||
|
||||
- If your credit card is expired, the email tells you how to update it.
|
||||
- If you have any outstanding overages or subscription isn't able to auto-renew for any other reason, the email tells you to contact our Sales team or [renew in Customers Portal](#renew-subscription-manually).
|
||||
- If there are no issues, the email specifies the names and quantity of the products being renewed. The email also includes the total amount you owe. If your usage increases before renewal, this amount will change.
|
||||
- If you have any outstanding overages or your subscription is not able to automatically
|
||||
renew for any other reason, the email tells you to contact our Sales team or
|
||||
[manually renew in the Customers Portal](#renew-subscription-manually).
|
||||
- If there are no issues, the email specifies the:
|
||||
- Names and quantity of the products being renewed
|
||||
- Total amount you owe. If your usage increases before renewal, this amount will change.
|
||||
|
||||
#### Enable or disable automatic subscription renewal
|
||||
|
||||
Use the Customers Portal to enable or disable automatic subscription renewal.
|
||||
The subscription is renewed at the same tier as the previous period.
|
||||
|
||||
To enable or disable automatic subscription renewal:
|
||||
You can use the Customers Portal to enable or disable automatic subscription renewal:
|
||||
|
||||
1. Sign in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
|
||||
You are taken to the **Subscriptions & purchases** page.
|
||||
|
|
@ -504,14 +526,23 @@ To enable or disable automatic subscription renewal:
|
|||
1. Select **Cancel subscription**.
|
||||
|
||||
If you have difficulty during the renewal process, contact the
|
||||
[Support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293) for assistance.
|
||||
[Support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293)
|
||||
for assistance.
|
||||
|
||||
#### Renew for fewer seats
|
||||
### Manage renewal invoice
|
||||
|
||||
There are two options to renew a subscription for fewer seats, as long as the seat total is equal to or greater than the billable user quantity at the time of renewal:
|
||||
An invoice is generated for your renewal. To view or download this renewal invoice,
|
||||
go to the [Customers Portal invoices page](https://customers.gitlab.com/invoices).
|
||||
|
||||
- [Manually renew](#renew-subscription-manually) within 15 days of subscription renewal date, and **specify the desired seat quantity** on the renewal page.
|
||||
- Work with the Sales team to renew your subscription. To avoid auto-renewing at a higher seat quantity while you work with Sales, [cancel your subscription](#enable-or-disable-automatic-subscription-renewal).
|
||||
If your account has a [saved credit card](../customers_portal.md#change-your-payment-method),
|
||||
the card is charged for the invoice amount.
|
||||
|
||||
If we are unable to process a payment or the auto-renewal fails for any other reason,
|
||||
you have 14 days to renew your subscription, after which your GitLab tier is downgraded.
|
||||
|
||||
If you have difficulty during the renewal process, contact our
|
||||
[support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293)
|
||||
for help.
|
||||
|
||||
## Upgrade your subscription tier
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ Use `git add` to files to the staging area.
|
|||
git add <file_path>
|
||||
```
|
||||
|
||||
You can recursively stage changes from the current working directory with `git add .`, or stage all changes in the Git repository with `git add --all`.
|
||||
You can recursively stage changes from the current working directory with `git add .`, or stage all changes in the Git
|
||||
repository with `git add --all`.
|
||||
|
||||
For more information, see [Add files to your branch](add_files.md).
|
||||
|
||||
## `git blame`
|
||||
|
||||
|
|
@ -26,11 +29,13 @@ Use `git blame` to report which users changed which parts of a file.
|
|||
git blame <file_name>
|
||||
```
|
||||
|
||||
You can use `git blame -L <line_start>, <line_end>` to check a
|
||||
specific range of lines.
|
||||
You can use `git blame -L <line_start>, <line_end>` to check a specific range of lines.
|
||||
|
||||
For example, to check which user most recently modified line five of
|
||||
`example.txt`:
|
||||
For more information, see [Git file blame](../../user/project/repository/files/git_blame.md).
|
||||
|
||||
### Example
|
||||
|
||||
To check which user most recently modified line five of `example.txt`:
|
||||
|
||||
```shell
|
||||
$ git blame -L 5, 5 example.txt
|
||||
|
|
@ -49,7 +54,8 @@ git bisect bad # Current version is bad
|
|||
git bisect good v2.6.13-rc2 # v2.6.13-rc2 is known to be good
|
||||
```
|
||||
|
||||
`git bisect`then picks a commit in between the two points and asks you identify if the commit is "good" or "bad" with `git bisect good`or `git bisect bad`. Repeat the process until the commit is found.
|
||||
`git bisect` then picks a commit in between the two points and asks you identify if the commit is "good" or "bad" with
|
||||
`git bisect good`or `git bisect bad`. Repeat the process until the commit is found.
|
||||
|
||||
## `git checkout`
|
||||
|
||||
|
|
@ -61,6 +67,8 @@ git checkout <branch_name>
|
|||
|
||||
To create a new branch and switch to it, use `git checkout -b <branch_name>`.
|
||||
|
||||
For more information, see [Create a Git branch for your changes](branch.md).
|
||||
|
||||
## `git clone`
|
||||
|
||||
Use `git clone` to copy an existing Git repository.
|
||||
|
|
@ -69,6 +77,8 @@ Use `git clone` to copy an existing Git repository.
|
|||
git clone <repository>
|
||||
```
|
||||
|
||||
For more information, see [Clone a Git repository to your local computer](clone.md).
|
||||
|
||||
## `git commit`
|
||||
|
||||
Use `git commit` to commits staged changes to the repository.
|
||||
|
|
@ -77,10 +87,12 @@ Use `git commit` to commits staged changes to the repository.
|
|||
git commit -m "<commit_message>"
|
||||
```
|
||||
|
||||
If the commit message contains a blank line, the first line becomes
|
||||
the commit subject while the remainder becomes the commit body. Use
|
||||
the subject to briefly summarize a change, and the commit body to
|
||||
provide additional details.
|
||||
If the commit message contains a blank line, the first line becomes the commit subject while the remainder becomes the
|
||||
commit body. Use the subject to briefly summarize a change, and the commit body to provide additional details.
|
||||
|
||||
For more information, see [Stage, commit, and push changes](commit.md).
|
||||
|
||||
## `git commit --amend`
|
||||
|
||||
Use `git commit --amend` to modify the most recent commit.
|
||||
|
||||
|
|
@ -90,16 +102,16 @@ git commit --amend
|
|||
|
||||
## `git diff`
|
||||
|
||||
You can display the difference (or diff) between your local changes and the most recent version of a branch. View a
|
||||
diff to understand your local changes before you commit them to the branch.
|
||||
|
||||
To view the differences between your local unstaged changes and the latest version that you cloned or
|
||||
pulled, use `git diff`.
|
||||
Use `git diff` to view the differences between your local unstaged changes and the latest version that you cloned or
|
||||
pulled.
|
||||
|
||||
```shell
|
||||
git diff
|
||||
```
|
||||
|
||||
You can display the difference (or diff) between your local changes and the most recent version of a branch. View a
|
||||
diff to understand your local changes before you commit them to the branch.
|
||||
|
||||
To compare your changes against a specific branch, run:
|
||||
|
||||
```shell
|
||||
|
|
@ -119,17 +131,14 @@ Use `git init` to initialize a directory so Git tracks it as a repository.
|
|||
git init
|
||||
```
|
||||
|
||||
A `.git` file with configuration and log files is added to the
|
||||
directory. You shouldn't edit the `.git` file directly.
|
||||
A `.git` file with configuration and log files is added to the directory. You shouldn't edit the `.git` file directly.
|
||||
|
||||
The default branch is set to `master`. You can change the name of the
|
||||
default branch with `git branch -m <branch_name>`, or initialize with
|
||||
`git init -b <branch_name>`.
|
||||
The default branch is set to `main`. You can change the name of the default branch with `git branch -m <branch_name>`,
|
||||
or initialize with `git init -b <branch_name>`.
|
||||
|
||||
## `git pull`
|
||||
|
||||
Use `git pull` to get all the changes made by users since the last
|
||||
time you cloned or pulled the project.
|
||||
Use `git pull` to get all the changes made by users after the last time you cloned or pulled the project.
|
||||
|
||||
```shell
|
||||
git pull <optional_remote> <branch_name>
|
||||
|
|
@ -143,9 +152,11 @@ Use `git push` to update remote refs.
|
|||
git push
|
||||
```
|
||||
|
||||
For more information, see [Stage, commit, and push changes](commit.md).
|
||||
|
||||
## `git reflog`
|
||||
|
||||
To display a list of changes to the Git reference logs, use `git reflog`.
|
||||
Use `git reflog` to display a list of changes to the Git reference logs.
|
||||
|
||||
```shell
|
||||
git reflog
|
||||
|
|
@ -153,21 +164,23 @@ git reflog
|
|||
|
||||
By default, `git reflog` shows a list of changes to `HEAD`.
|
||||
|
||||
For more information, see [Undo changes](undo.md).
|
||||
|
||||
## `git remote add`
|
||||
|
||||
Use `git remote add` to tell Git which remote repository in GitLab is
|
||||
linked to a local directory.
|
||||
Use `git remote add` to tell Git which remote repository in GitLab is linked to a local directory.
|
||||
|
||||
```shell
|
||||
git remote add <remote_name> <repository_url>
|
||||
```
|
||||
|
||||
When you clone a repository, by default the source repository is
|
||||
associated with the remote name `origin`.
|
||||
When you clone a repository, by default the source repository is associated with the remote name `origin`.
|
||||
|
||||
For more information on configuring additional remotes, see [Forks](../../user/project/repository/forking_workflow.md).
|
||||
|
||||
## `git log`
|
||||
|
||||
To display a list of commits in chronological order, use `git log`.
|
||||
Use `git log` to display a list of commits in chronological order.
|
||||
|
||||
```shell
|
||||
git log
|
||||
|
|
@ -175,9 +188,11 @@ git log
|
|||
|
||||
## `git show`
|
||||
|
||||
To show information about an object in Git, use `git show`.
|
||||
Use `git show` to show information about an object in Git.
|
||||
|
||||
For example, to see what commit `HEAD` points to:
|
||||
### Example
|
||||
|
||||
To see what commit `HEAD` points to:
|
||||
|
||||
```shell
|
||||
$ git show HEAD
|
||||
|
|
@ -186,9 +201,13 @@ commit ab123c (HEAD -> main, origin/main, origin/HEAD)
|
|||
|
||||
## `git merge`
|
||||
|
||||
To combine the changes from one branch with another, use `git merge`.
|
||||
Use `git merge` to combine the changes from one branch with another.
|
||||
|
||||
For example, to apply the changes in `feature_branch` to the `target_branch`:
|
||||
For more information on an alternative to `git merge`, see [Rebase to address merge conflicts](git_rebase.md).
|
||||
|
||||
### Example
|
||||
|
||||
To apply the changes in `feature_branch` to the `target_branch`:
|
||||
|
||||
```shell
|
||||
git checkout target_branch
|
||||
|
|
@ -197,29 +216,32 @@ git merge feature_branch
|
|||
|
||||
## `git rebase`
|
||||
|
||||
To rewrite the commit history of a branch, use `git rebase`.
|
||||
|
||||
You can use `git rebase` to resolve merge conflicts.
|
||||
Use `git rebase` to rewrite the commit history of a branch.
|
||||
|
||||
```shell
|
||||
git rebase <branch_name>
|
||||
```
|
||||
|
||||
You can use `git rebase` to [resolve merge conflicts](git_rebase.md).
|
||||
|
||||
In most cases, you want to rebase against the default branch.
|
||||
|
||||
## `git reset`
|
||||
|
||||
To undo a commit, use `git reset` to rewind the commit history and continue on from an earlier commit.
|
||||
Use `git reset` to undo a commit and rewind the commit history and continue on from an earlier commit.
|
||||
|
||||
```shell
|
||||
git reset
|
||||
```
|
||||
|
||||
For more information, see [Undo changes](undo.md).
|
||||
|
||||
## `git status`
|
||||
|
||||
When you add, change, or delete files, Git can identify the changes. Use `git status` to show the status of the working
|
||||
directory and staged files.
|
||||
Use `git status` to show the status of the working directory and staged files.
|
||||
|
||||
```shell
|
||||
git status
|
||||
```
|
||||
|
||||
When you add, change, or delete files, Git can show you the changes.
|
||||
|
|
|
|||
|
|
@ -193,3 +193,7 @@ To create and use a Git alias for the
|
|||
```shell
|
||||
git mwps origin <local-branch-name>
|
||||
```
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Common Git commands](commands.md)
|
||||
|
|
|
|||
|
|
@ -332,18 +332,18 @@ To compare branches in a repository:
|
|||
1. Select the **Target** repository and branch. Exact matches are shown first.
|
||||
1. Below **Show changes**, select the method to compare branches:
|
||||
<!-- vale gitlab_base.SubstitutionWarning = NO -->
|
||||
<!-- Disable Vale so it doesn't flag "since" -->
|
||||
<!-- Disable Vale gitlab_base.SubstitutionWarning rule so that Vale doesn't flag "since" -->
|
||||
- **Only incoming changes from source** (default) shows differences from the source branch since
|
||||
the latest common commit on both branches.
|
||||
It doesn't include unrelated changes made to the target branch after the source branch was created.
|
||||
This method uses the `git diff <from>...<to>`
|
||||
[Git command](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-emgitdiffemltoptionsgtltcommitgtltcommitgt--ltpathgt82308203-1).
|
||||
[Git command](../../../../topics/git/commands.md).
|
||||
To compare branches, this method uses the merge base instead of the actual commit, so
|
||||
changes from cherry-picked commits are shown as new changes.
|
||||
- **Include changes to target since source was created** shows all the differences between the two
|
||||
branches.
|
||||
This method uses the `git diff <from> <to>`
|
||||
[Git command](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-emgitdiffemltoptionsgt--merge-baseltcommitgtltcommitgt--ltpathgt82308203).
|
||||
[Git command](../../../../topics/git/commands.md).
|
||||
<!-- vale gitlab_base.SubstitutionWarning = YES -->
|
||||
1. Select **Compare** to show the list of commits, and changed files.
|
||||
1. Optional. To reverse the **Source** and **Target**, select **Swap revisions** (**{substitute}**).
|
||||
|
|
|
|||
|
|
@ -85,4 +85,5 @@ The output includes:
|
|||
|
||||
## Related topics
|
||||
|
||||
- [Git file blame REST API](../../../../api/repository_files.md#get-file-blame-from-repository).
|
||||
- [Git file blame REST API](../../../../api/repository_files.md#get-file-blame-from-repository)
|
||||
- [Common Git commands](../../../../topics/git/commands.md)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ Date: Fri Oct 20 17:53:25 2023 +0000
|
|||
## Related topics
|
||||
|
||||
- [Git blame](git_blame.md) for line-by-line information about a file
|
||||
- [Common Git commands](../../../../topics/git/commands.md)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
# rubocop: disable BackgroundMigration/FeatureCategory -- Feature category to be specified by inheriting class
|
||||
class BackfillDesiredShardingKeyPartitionJob < BackfillDesiredShardingKeyJob
|
||||
job_arguments :backfill_column,
|
||||
:backfill_via_table,
|
||||
:backfill_via_column,
|
||||
:backfill_via_foreign_key,
|
||||
:partition_column
|
||||
|
||||
def construct_query(sub_batch:)
|
||||
<<~SQL
|
||||
UPDATE #{batch_table}
|
||||
SET #{backfill_column} = #{backfill_via_table}.#{backfill_via_column}
|
||||
FROM #{backfill_via_table}
|
||||
WHERE #{backfill_via_table}.id = #{batch_table}.#{backfill_via_foreign_key}
|
||||
AND #{backfill_via_table}.#{partition_column} = #{batch_table}.#{partition_column}
|
||||
AND #{batch_table}.id IN (#{sub_batch.select(:id).to_sql})
|
||||
SQL
|
||||
end
|
||||
end
|
||||
# rubocop: enable BackgroundMigration/FeatureCategory
|
||||
end
|
||||
end
|
||||
|
|
@ -113,7 +113,6 @@ tree:
|
|||
- :create_access_levels
|
||||
- :project_feature
|
||||
- :custom_attributes
|
||||
- :prometheus_metrics
|
||||
- :project_badges
|
||||
- :ci_cd_settings
|
||||
- :error_tracking_setting
|
||||
|
|
@ -325,17 +324,6 @@ included_attributes:
|
|||
- :infrastructure_access_level
|
||||
- :model_experiments_access_level
|
||||
- :model_registry_access_level
|
||||
prometheus_metrics:
|
||||
- :created_at
|
||||
- :updated_at
|
||||
- :project_id
|
||||
- :y_label
|
||||
- :unit
|
||||
- :legend
|
||||
- :title
|
||||
- :query
|
||||
- :group
|
||||
- :dashboard_path
|
||||
service_desk_setting:
|
||||
- :project_id
|
||||
- :issue_template_key
|
||||
|
|
@ -870,9 +858,6 @@ excluded_attributes:
|
|||
- :jid
|
||||
- :last_update_at
|
||||
- :last_successful_update_at
|
||||
prometheus_metrics:
|
||||
- :common
|
||||
- :identifier
|
||||
snippets:
|
||||
- :expired_at
|
||||
- :secret
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Prometheus
|
||||
class Metric
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_accessor :id, :title, :required_metrics, :weight, :y_label, :queries
|
||||
|
||||
validates :title, :required_metrics, :weight, :y_label, :queries, presence: true
|
||||
|
||||
def initialize(params = {})
|
||||
super(params)
|
||||
@y_label ||= 'Values'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -280,7 +280,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def ml_model_file_name_regex
|
||||
maven_file_name_regex
|
||||
@ml_model_file_name_regex ||= %r{\A[A-Za-z0-9\.\_\-\+ ]+\z}
|
||||
end
|
||||
|
||||
def vs_code_user_agent_regex
|
||||
|
|
|
|||
|
|
@ -10220,9 +10220,6 @@ msgstr ""
|
|||
msgid "Burnup chart could not be generated due to too many events"
|
||||
msgstr ""
|
||||
|
||||
msgid "Business metrics (Custom)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Busy"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -12338,9 +12335,6 @@ msgstr ""
|
|||
msgid "Cluster"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cluster Health"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cluster cache cleared."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -16579,9 +16573,6 @@ msgstr ""
|
|||
msgid "Custom hostname (for private commit emails)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Custom metrics"
|
||||
msgstr ""
|
||||
|
||||
msgid "Custom notification events"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -45730,24 +45721,6 @@ msgstr ""
|
|||
msgid "Response initiated"
|
||||
msgstr ""
|
||||
|
||||
msgid "Response metrics (AWS ELB)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Response metrics (Custom)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Response metrics (HA Proxy)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Response metrics (NGINX Ingress VTS)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Response metrics (NGINX Ingress)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Response metrics (NGINX)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Response text"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -53243,12 +53216,6 @@ msgstr ""
|
|||
msgid "System information"
|
||||
msgstr ""
|
||||
|
||||
msgid "System metrics (Custom)"
|
||||
msgstr ""
|
||||
|
||||
msgid "System metrics (Kubernetes)"
|
||||
msgstr ""
|
||||
|
||||
msgid "System output"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -57013,7 +56980,7 @@ msgstr[1] ""
|
|||
msgid "Trials|Your 30-day trial has ended"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
|
||||
msgid "Trials|Your trial ends on %{strongStart}%{trialEndDate}%{strongEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trial|Activate my trial"
|
||||
|
|
@ -58577,10 +58544,10 @@ msgstr ""
|
|||
msgid "UserMapping|%{reassigned_by_name} (%{reassigned_by_username}) wants to reassign contributions made by %{source_name} (%{source_username}) on %{source_hostname} to you in %{destination_group}."
|
||||
msgstr ""
|
||||
|
||||
msgid "UserMapping|Accept reassignments only from users that you trust. Reassignment of contributions is permanent. Accepting these reassignments might cause contributions to be incorrectly attributed to you."
|
||||
msgid "UserMapping|Approve reassignment"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserMapping|Approve reassignment"
|
||||
msgid "UserMapping|Approve reassignments only from users that you trust. After approval, contributions will be assigned to you. The assignment is permanent."
|
||||
msgstr ""
|
||||
|
||||
msgid "UserMapping|Awaiting reassignment"
|
||||
|
|
@ -64804,6 +64771,9 @@ msgstr ""
|
|||
msgid "must match one of the following file types: %{extension_list}"
|
||||
msgstr ""
|
||||
|
||||
msgid "must match the parent organization's ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "must not be an owner of the namespace"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ module RuboCop
|
|||
BASE_CLASSES = %i[
|
||||
BatchedMigrationJob
|
||||
BackfillDesiredShardingKeyJob
|
||||
BackfillDesiredShardingKeyPartitionJob
|
||||
].to_set.freeze
|
||||
|
||||
def_node_search :top_level_module?, <<~PATTERN
|
||||
|
|
|
|||
|
|
@ -323,7 +323,6 @@ RSpec.describe 'Database schema', feature_category: :database do
|
|||
'NotificationSetting' => %w[level],
|
||||
'Project' => %w[auto_cancel_pending_pipelines],
|
||||
'ProjectAutoDevops' => %w[deploy_strategy],
|
||||
'PrometheusMetric' => %w[group],
|
||||
'ResourceLabelEvent' => %w[action],
|
||||
'User' => %w[layout dashboard project_view],
|
||||
'Users::Callout' => %w[feature_name]
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ FactoryBot.define do
|
|||
|
||||
owner { association(:user, strategy: :build, namespace: instance, username: path) }
|
||||
|
||||
association :organization
|
||||
# TODO: Remove usage of default organization https://gitlab.com/gitlab-org/gitlab/-/issues/446293
|
||||
organization { parent ? parent.organization : association(:organization, :default) }
|
||||
|
||||
after(:create) do |namespace, evaluator|
|
||||
# simulating ::Namespaces::ProcessSyncEventsWorker because most tests don't run Sidekiq inline
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ FactoryBot.define do
|
|||
path { project.path }
|
||||
type { Namespaces::ProjectNamespace.sti_name }
|
||||
owner { nil }
|
||||
association :organization
|
||||
organization { parent.organization }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,8 +16,17 @@ FactoryBot.define do
|
|||
has_external_wiki { false }
|
||||
|
||||
# Associations
|
||||
namespace do
|
||||
next group if group
|
||||
|
||||
if @overrides[:organization]
|
||||
association(:namespace, organization: @overrides[:organization])
|
||||
else
|
||||
association(:namespace)
|
||||
end
|
||||
end
|
||||
|
||||
organization { namespace&.organization }
|
||||
namespace
|
||||
creator { group ? association(:user) : namespace&.owner }
|
||||
|
||||
transient do
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :prometheus_metric, class: 'PrometheusMetric' do
|
||||
title { 'title' }
|
||||
query { 'avg(metric)' }
|
||||
y_label { 'y_label' }
|
||||
unit { 'm/s' }
|
||||
group { :business }
|
||||
project
|
||||
legend { 'legend' }
|
||||
dashboard_path { '.gitlab/dashboards/dashboard_path.yml' }
|
||||
|
||||
trait :common do
|
||||
common { true }
|
||||
project { nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -21,7 +21,8 @@ FactoryBot.define do
|
|||
true
|
||||
end
|
||||
|
||||
user.assign_personal_namespace(create(:organization)) if assign_ns
|
||||
# TODO: Remove usage of default organization https://gitlab.com/gitlab-org/gitlab/-/issues/446293
|
||||
user.assign_personal_namespace(create(:organization, :default)) if assign_ns
|
||||
end
|
||||
|
||||
trait :without_default_org do
|
||||
|
|
@ -30,7 +31,8 @@ FactoryBot.define do
|
|||
|
||||
trait :with_namespace do
|
||||
# rubocop: disable RSpec/FactoryBot/InlineAssociation -- We need to pass an Organization to this method
|
||||
namespace { assign_personal_namespace(create(:organization)) }
|
||||
# TODO: Remove usage of default organization https://gitlab.com/gitlab-org/gitlab/-/issues/446293
|
||||
namespace { assign_personal_namespace(create(:organization, :default)) }
|
||||
# rubocop: enable RSpec/FactoryBot/InlineAssociation
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlLabel, GlIcon, GlLink, GlButton, GlAvatarsInline } from '@gitlab/ui';
|
||||
import { GlLabel, GlLink, GlButton, GlAvatarsInline } from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
|
|
@ -7,7 +7,7 @@ import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/shared/w
|
|||
|
||||
import { createAlert } from '~/alert';
|
||||
import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue';
|
||||
|
||||
import WorkItemStateBadge from '~/work_items/components/work_item_state_badge.vue';
|
||||
import WorkItemLinkChildContents from '~/work_items/components/shared/work_item_link_child_contents.vue';
|
||||
import { WORK_ITEM_TYPE_VALUE_OBJECTIVE } from '~/work_items/constants';
|
||||
|
||||
|
|
@ -30,8 +30,8 @@ describe('WorkItemLinkChildContents', () => {
|
|||
const mockAssignees = ASSIGNEES.assignees.nodes;
|
||||
const mockLabels = LABELS.labels.nodes;
|
||||
|
||||
const findStatusIconComponent = () =>
|
||||
wrapper.findByTestId('item-status-icon').findComponent(GlIcon);
|
||||
const findStatusBadgeComponent = () =>
|
||||
wrapper.findByTestId('item-status-icon').findComponent(WorkItemStateBadge);
|
||||
const findConfidentialIconComponent = () => wrapper.findByTestId('confidential-icon');
|
||||
const findTitleEl = () => wrapper.findComponent(GlLink);
|
||||
const findStatusTooltipComponent = () => wrapper.findComponent(RichTimestampTooltip);
|
||||
|
|
@ -61,16 +61,15 @@ describe('WorkItemLinkChildContents', () => {
|
|||
});
|
||||
|
||||
it.each`
|
||||
status | childItem | statusIconName | statusIconColorClass | rawTimestamp | tooltipContents
|
||||
${'open'} | ${workItemTask} | ${'issue-open-m'} | ${'gl-text-green-500'} | ${workItemTask.createdAt} | ${'Created'}
|
||||
${'closed'} | ${closedWorkItemTask} | ${'issue-close'} | ${'gl-text-blue-500'} | ${closedWorkItemTask.closedAt} | ${'Closed'}
|
||||
status | childItem | workItemState | rawTimestamp | tooltipContents
|
||||
${'open'} | ${workItemTask} | ${'OPEN'} | ${workItemTask.createdAt} | ${'Created'}
|
||||
${'closed'} | ${closedWorkItemTask} | ${'CLOSED'} | ${closedWorkItemTask.closedAt} | ${'Closed'}
|
||||
`(
|
||||
'renders item status icon and tooltip when item status is `$status`',
|
||||
({ childItem, statusIconName, statusIconColorClass, rawTimestamp, tooltipContents }) => {
|
||||
({ childItem, workItemState, rawTimestamp, tooltipContents }) => {
|
||||
createComponent({ childItem });
|
||||
|
||||
expect(findStatusIconComponent().props('name')).toBe(statusIconName);
|
||||
expect(findStatusIconComponent().classes()).toContain(statusIconColorClass);
|
||||
expect(findStatusBadgeComponent().props('workItemState')).toBe(workItemState);
|
||||
expect(findStatusTooltipComponent().props('rawTimestamp')).toBe(rawTimestamp);
|
||||
expect(findStatusTooltipComponent().props('timestampTypeText')).toContain(tooltipContents);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,23 +6,26 @@ import WorkItemStateBadge from '~/work_items/components/work_item_state_badge.vu
|
|||
describe('WorkItemStateBadge', () => {
|
||||
let wrapper;
|
||||
|
||||
const createComponent = ({ workItemState = STATE_OPEN } = {}) => {
|
||||
const createComponent = ({ workItemState = STATE_OPEN, showIcon = true } = {}) => {
|
||||
wrapper = shallowMount(WorkItemStateBadge, {
|
||||
propsData: {
|
||||
workItemState,
|
||||
showIcon,
|
||||
},
|
||||
});
|
||||
};
|
||||
const findStatusBadge = () => wrapper.findComponent(GlBadge);
|
||||
|
||||
it.each`
|
||||
state | icon | stateText | variant
|
||||
${STATE_OPEN} | ${'issue-open-m'} | ${'Open'} | ${'success'}
|
||||
${STATE_CLOSED} | ${'issue-close'} | ${'Closed'} | ${'info'}
|
||||
state | showIcon | icon | stateText | variant
|
||||
${STATE_OPEN} | ${true} | ${'issue-open-m'} | ${'Open'} | ${'success'}
|
||||
${STATE_CLOSED} | ${true} | ${'issue-close'} | ${'Closed'} | ${'info'}
|
||||
${STATE_OPEN} | ${false} | ${null} | ${'Open'} | ${'success'}
|
||||
${STATE_CLOSED} | ${false} | ${null} | ${'Closed'} | ${'info'}
|
||||
`(
|
||||
'renders icon as "$icon" and text as "$stateText" when the work item state is "$state"',
|
||||
({ state, icon, stateText, variant }) => {
|
||||
createComponent({ workItemState: state });
|
||||
({ state, showIcon, icon, stateText, variant }) => {
|
||||
createComponent({ workItemState: state, showIcon });
|
||||
|
||||
expect(findStatusBadge().props('icon')).toBe(icon);
|
||||
expect(findStatusBadge().props('variant')).toBe(variant);
|
||||
|
|
|
|||
|
|
@ -18,30 +18,31 @@ describe('Work Item type component', () => {
|
|||
const findIcon = () => wrapper.findComponent(GlIcon);
|
||||
|
||||
describe.each`
|
||||
workItemType | workItemIconName | iconName | text | showTooltipOnHover
|
||||
${'TASK'} | ${''} | ${'issue-type-task'} | ${'Task'} | ${false}
|
||||
${''} | ${'issue-type-task'} | ${'issue-type-task'} | ${''} | ${true}
|
||||
${'ISSUE'} | ${''} | ${'issue-type-issue'} | ${'Issue'} | ${true}
|
||||
${''} | ${'issue-type-issue'} | ${'issue-type-issue'} | ${''} | ${true}
|
||||
${'REQUIREMENT'} | ${''} | ${'issue-type-requirements'} | ${'Requirements'} | ${true}
|
||||
${'INCIDENT'} | ${''} | ${'issue-type-incident'} | ${'Incident'} | ${false}
|
||||
${'TEST_CASE'} | ${''} | ${'issue-type-test-case'} | ${'Test case'} | ${true}
|
||||
${'random-issue-type'} | ${''} | ${'issue-type-issue'} | ${''} | ${true}
|
||||
${'Task'} | ${''} | ${'issue-type-task'} | ${'Task'} | ${false}
|
||||
${'Issue'} | ${''} | ${'issue-type-issue'} | ${'Issue'} | ${true}
|
||||
${'Requirement'} | ${''} | ${'issue-type-requirements'} | ${'Requirements'} | ${true}
|
||||
${'Incident'} | ${''} | ${'issue-type-incident'} | ${'Incident'} | ${false}
|
||||
${'Test_case'} | ${''} | ${'issue-type-test-case'} | ${'Test case'} | ${true}
|
||||
${'Objective'} | ${''} | ${'issue-type-objective'} | ${'Objective'} | ${true}
|
||||
${'Key Result'} | ${''} | ${'issue-type-keyresult'} | ${'Key result'} | ${true}
|
||||
workItemType | workItemIconName | iconName | text | showTooltipOnHover | colorClass
|
||||
${'TASK'} | ${''} | ${'issue-type-task'} | ${'Task'} | ${false} | ${'gl-text-secondary'}
|
||||
${''} | ${'issue-type-task'} | ${'issue-type-task'} | ${''} | ${true} | ${'gl-text-secondary'}
|
||||
${'ISSUE'} | ${''} | ${'issue-type-issue'} | ${'Issue'} | ${true} | ${'gl-text-secondary'}
|
||||
${''} | ${'issue-type-issue'} | ${'issue-type-issue'} | ${''} | ${true} | ${'gl-text-secondary'}
|
||||
${'REQUIREMENT'} | ${''} | ${'issue-type-requirements'} | ${'Requirements'} | ${true} | ${'gl-text-secondary'}
|
||||
${'INCIDENT'} | ${''} | ${'issue-type-incident'} | ${'Incident'} | ${false} | ${'gl-text-secondary'}
|
||||
${'TEST_CASE'} | ${''} | ${'issue-type-test-case'} | ${'Test case'} | ${true} | ${'gl-text-secondary'}
|
||||
${'random-issue-type'} | ${''} | ${'issue-type-issue'} | ${''} | ${true} | ${'gl-text-secondary'}
|
||||
${'Task'} | ${''} | ${'issue-type-task'} | ${'Task'} | ${false} | ${'gl-text-secondary'}
|
||||
${'Issue'} | ${''} | ${'issue-type-issue'} | ${'Issue'} | ${true} | ${'gl-text-secondary'}
|
||||
${'Requirement'} | ${''} | ${'issue-type-requirements'} | ${'Requirements'} | ${true} | ${'gl-text-secondary'}
|
||||
${'Incident'} | ${''} | ${'issue-type-incident'} | ${'Incident'} | ${false} | ${'gl-text-secondary'}
|
||||
${'Test_case'} | ${''} | ${'issue-type-test-case'} | ${'Test case'} | ${true} | ${'gl-text-secondary'}
|
||||
${'Objective'} | ${''} | ${'issue-type-objective'} | ${'Objective'} | ${true} | ${'gl-text-secondary'}
|
||||
${'Key Result'} | ${''} | ${'issue-type-keyresult'} | ${'Key result'} | ${true} | ${'gl-text-gray-300'}
|
||||
`(
|
||||
'with workItemType set to "$workItemType" and workItemIconName set to "$workItemIconName"',
|
||||
({ workItemType, workItemIconName, iconName, text, showTooltipOnHover }) => {
|
||||
({ workItemType, workItemIconName, iconName, text, showTooltipOnHover, colorClass }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
workItemType,
|
||||
workItemIconName,
|
||||
showTooltipOnHover,
|
||||
colorClass,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -53,8 +54,8 @@ describe('Work Item type component', () => {
|
|||
expect(wrapper.text()).toBe(text);
|
||||
});
|
||||
|
||||
it('renders the icon in gray color', () => {
|
||||
expect(findIcon().classes()).toContain('gl-text-secondary');
|
||||
it(`renders the icon in gray color based on '${colorClass}'`, () => {
|
||||
expect(findIcon().classes()).toContain(colorClass);
|
||||
});
|
||||
|
||||
it('shows tooltip on hover when props passed', () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BackgroundMigration::BackfillDesiredShardingKeyPartitionJob, migration: :gitlab_ci, feature_category: :cell do
|
||||
let(:example_job_class) do
|
||||
Class.new(described_class) do
|
||||
operation_name :backfill_test_batch_table_project_id
|
||||
feature_category :cell
|
||||
end
|
||||
end
|
||||
|
||||
let(:start_id) { table(batch_table).minimum(:id) }
|
||||
let(:end_id) { table(batch_table).maximum(:id) }
|
||||
let(:batch_table) { :_test_batch_table }
|
||||
let(:backfill_via_table) { :p_ci_builds }
|
||||
let(:backfill_column) { :project_id }
|
||||
let(:backfill_via_column) { :project_id }
|
||||
let(:backfill_via_foreign_key) { :build_id }
|
||||
let(:partition_column) { :partition_id }
|
||||
|
||||
let(:test_table) { table(:_test_batch_table) }
|
||||
let(:connection) { ::Ci::ApplicationRecord.connection }
|
||||
|
||||
let(:migration_attrs) do
|
||||
{
|
||||
start_id: start_id,
|
||||
end_id: end_id,
|
||||
batch_table: batch_table,
|
||||
batch_column: :id,
|
||||
sub_batch_size: 10,
|
||||
pause_ms: 2,
|
||||
connection: connection,
|
||||
job_arguments: [
|
||||
backfill_column,
|
||||
backfill_via_table,
|
||||
backfill_via_column,
|
||||
backfill_via_foreign_key,
|
||||
partition_column
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
let(:migration) { example_job_class.new(**migration_attrs) }
|
||||
|
||||
before do
|
||||
connection.create_table :_test_batch_table do |t|
|
||||
t.timestamps_with_timezone null: false
|
||||
t.integer :build_id, null: false
|
||||
t.integer :partition_id, null: false
|
||||
t.integer :project_id
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
connection.drop_table(:_test_batch_table)
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
let(:ci_pipelines_table) { table(:ci_pipelines, primary_key: :id) }
|
||||
let(:ci_builds_table) { table(:p_ci_builds, primary_key: :id) }
|
||||
|
||||
let(:pipeline) { ci_pipelines_table.create!(partition_id: 100, project_id: 1) }
|
||||
let!(:job1) { ci_builds_table.create!(partition_id: 100, project_id: 1, commit_id: pipeline.id) }
|
||||
let!(:job2) { ci_builds_table.create!(partition_id: 100, project_id: 2, commit_id: pipeline.id) }
|
||||
|
||||
let(:test1) { test_table.create!(id: 1, partition_id: 100, build_id: job1.id, project_id: nil) }
|
||||
let(:test2) { test_table.create!(id: 2, partition_id: 100, build_id: job2.id, project_id: nil) }
|
||||
|
||||
it 'backfills the missing project_id for the batch' do
|
||||
expect { migration.perform }
|
||||
.to change { test1.reload.project_id }.from(nil).to(job1.project_id)
|
||||
.and change { test2.reload.project_id }.from(nil).to(job2.project_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#constuct_query' do
|
||||
it 'constructs a query using the supplied job arguments' do
|
||||
sub_batch = table(batch_table).all
|
||||
|
||||
expect(migration.construct_query(sub_batch: sub_batch)).to eq(<<~SQL)
|
||||
UPDATE _test_batch_table
|
||||
SET project_id = p_ci_builds.project_id
|
||||
FROM p_ci_builds
|
||||
WHERE p_ci_builds.id = _test_batch_table.build_id
|
||||
AND p_ci_builds.partition_id = _test_batch_table.partition_id
|
||||
AND _test_batch_table.id IN (#{sub_batch.select(:id).to_sql})
|
||||
SQL
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -762,7 +762,6 @@ project:
|
|||
- wiki_repository_state
|
||||
- source_pipelines
|
||||
- sourced_pipelines
|
||||
- prometheus_metrics
|
||||
- vulnerabilities
|
||||
- vulnerability_exports
|
||||
- vulnerability_findings
|
||||
|
|
@ -898,8 +897,6 @@ award_emoji:
|
|||
- user
|
||||
priorities:
|
||||
- label
|
||||
prometheus_metrics:
|
||||
- project
|
||||
timelogs:
|
||||
- issue
|
||||
- merge_request
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter, feature_category: :imp
|
|||
:timelogs | true
|
||||
:container_expiration_policy | true
|
||||
:project_feature | true
|
||||
:prometheus_metrics | true
|
||||
:service_desk_setting | true
|
||||
:external_pull_request | true
|
||||
:external_pull_requests | true
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ RSpec.describe 'Test coverage of the Project Import', feature_category: :importe
|
|||
project.ci_pipelines.notes.events
|
||||
project.ci_pipelines.notes.events.push_event_payload
|
||||
project.protected_branches.unprotect_access_levels
|
||||
project.prometheus_metrics
|
||||
project.boards.lists.label.priorities
|
||||
project.service_desk_setting
|
||||
project.security_setting
|
||||
|
|
|
|||
|
|
@ -796,20 +796,6 @@ ProjectCustomAttribute:
|
|||
- project_id
|
||||
- key
|
||||
- value
|
||||
PrometheusMetric:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- project_id
|
||||
- y_label
|
||||
- unit
|
||||
- legend
|
||||
- title
|
||||
- query
|
||||
- group
|
||||
- common
|
||||
- identifier
|
||||
- dashboard_path
|
||||
Badge:
|
||||
- id
|
||||
- name
|
||||
|
|
|
|||
|
|
@ -1133,4 +1133,22 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
|
|||
it { expect(subject.match(markdown)[:html_comment_block]).to eq expected }
|
||||
end
|
||||
end
|
||||
|
||||
describe '.ml_model_file_name_regex' do
|
||||
subject { described_class.ml_model_file_name_regex }
|
||||
|
||||
it { is_expected.to match('123') }
|
||||
it { is_expected.to match('foo') }
|
||||
it { is_expected.to match('foo+bar-2_0.pom') }
|
||||
it { is_expected.to match('foo.bar.baz-2.0-20190901.47283-1.jar') }
|
||||
it { is_expected.to match('maven-metadata.xml') }
|
||||
it { is_expected.to match('1.0-SNAPSHOT') }
|
||||
it { is_expected.not_to match('../../foo') }
|
||||
it { is_expected.not_to match('..\..\foo') }
|
||||
it { is_expected.not_to match('%2f%2e%2e%2f%2essh%2fauthorized_keys') }
|
||||
it { is_expected.not_to match('$foo/bar') }
|
||||
it { is_expected.to match('my file name') }
|
||||
it { is_expected.to match('1.0-SNAPSHOT_v1_snapshot edited') }
|
||||
it { is_expected.not_to match('!!()()') }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,15 +2,22 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe LfsObject do
|
||||
RSpec.describe LfsObject, feature_category: :source_code_management do
|
||||
context 'scopes' do
|
||||
describe '.not_existing_in_project' do
|
||||
it 'contains only lfs objects not linked to the project' do
|
||||
project = create(:project)
|
||||
create(:lfs_objects_project, project: project)
|
||||
other_lfs_object = create(:lfs_object)
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:lfs_objects_project) { create(:lfs_objects_project, project: project) }
|
||||
let_it_be(:design_lfs_object_project) { create(:lfs_objects_project, project: project, repository_type: :design) }
|
||||
let_it_be(:other_lfs_object) { create(:lfs_object) }
|
||||
|
||||
expect(described_class.not_linked_to_project(project)).to contain_exactly(other_lfs_object)
|
||||
subject { described_class.not_linked_to_project(project) }
|
||||
|
||||
it { is_expected.to contain_exactly(other_lfs_object) }
|
||||
|
||||
context 'when repository_type is specified' do
|
||||
subject { described_class.not_linked_to_project(project, repository_type: :design) }
|
||||
|
||||
it { is_expected.to contain_exactly(other_lfs_object, lfs_objects_project.lfs_object) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1322,7 +1322,8 @@ RSpec.describe Member, feature_category: :groups_and_projects do
|
|||
end
|
||||
|
||||
context 'for updating organization_users' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:organization) { create(:organization) }
|
||||
let_it_be(:group) { create(:group, organization: organization) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:member) { create(:group_member, source: group, user: user) }
|
||||
|
||||
|
|
|
|||
|
|
@ -253,6 +253,27 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parent_organization_match' do
|
||||
let_it_be(:group) { create(:group, :with_organization) }
|
||||
|
||||
subject(:namespace) { build(:group, parent: group, organization: organization) }
|
||||
|
||||
context "when namespace belongs to parent's organization" do
|
||||
let(:organization) { group.organization }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
|
||||
context "when namespace does not belong to parent's organization" do
|
||||
let(:organization) { build(:organization) }
|
||||
|
||||
it 'is not valid and adds an error message' do
|
||||
expect(namespace).not_to be_valid
|
||||
expect(namespace.errors[:organization_id]).to include("must match the parent organization's ID")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "ReferencePatternValidation" do
|
||||
|
|
|
|||
|
|
@ -7488,7 +7488,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
|
|||
end
|
||||
end
|
||||
|
||||
describe 'validation #changing_shared_runners_enabled_is_allowed' do
|
||||
describe '#changing_shared_runners_enabled_is_allowed' do
|
||||
where(:shared_runners_setting, :project_shared_runners_enabled, :valid_record) do
|
||||
:shared_runners_enabled | true | true
|
||||
:shared_runners_enabled | false | true
|
||||
|
|
@ -7512,6 +7512,27 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
|
|||
end
|
||||
end
|
||||
|
||||
describe '#parent_organization_match' do
|
||||
let_it_be(:group) { create(:group, :with_organization) }
|
||||
|
||||
subject(:project) { build(:project, namespace: group, organization: organization) }
|
||||
|
||||
context "when project belongs to parent's organization" do
|
||||
let(:organization) { group.organization }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
|
||||
context "when project does not belong to parent's organization" do
|
||||
let(:organization) { build(:organization) }
|
||||
|
||||
it 'is not valid and adds an error message' do
|
||||
expect(project).not_to be_valid
|
||||
expect(project.errors[:organization_id]).to include("must match the parent organization's ID")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#mark_pages_onboarding_complete' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,160 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe PrometheusMetric do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
subject { build(:prometheus_metric) }
|
||||
|
||||
it_behaves_like 'having unique enum values'
|
||||
|
||||
it { is_expected.to belong_to(:project) }
|
||||
it { is_expected.to validate_presence_of(:title) }
|
||||
it { is_expected.to validate_presence_of(:query) }
|
||||
it { is_expected.to validate_presence_of(:group) }
|
||||
it { is_expected.to validate_uniqueness_of(:identifier).scoped_to(:project_id).allow_nil }
|
||||
|
||||
describe 'common metrics' do
|
||||
where(:common, :with_project, :result) do
|
||||
false | true | true
|
||||
false | false | false
|
||||
true | true | false
|
||||
true | false | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
subject.common = common
|
||||
subject.project = with_project ? build(:project) : nil
|
||||
end
|
||||
|
||||
it { expect(subject.valid?).to eq(result) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#query_series' do
|
||||
where(:legend, :type) do
|
||||
'Some other legend' | NilClass
|
||||
'Status Code' | Array
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
subject.legend = legend
|
||||
end
|
||||
|
||||
it { expect(subject.query_series).to be_a(type) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#group_title' do
|
||||
shared_examples 'group_title' do |group, title|
|
||||
subject { build(:prometheus_metric, group: group).group_title }
|
||||
|
||||
it "returns text #{title} for group #{group}" do
|
||||
expect(subject).to eq(title)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'group_title', :nginx_ingress_vts, 'Response metrics (NGINX Ingress VTS)'
|
||||
it_behaves_like 'group_title', :nginx_ingress, 'Response metrics (NGINX Ingress)'
|
||||
it_behaves_like 'group_title', :ha_proxy, 'Response metrics (HA Proxy)'
|
||||
it_behaves_like 'group_title', :aws_elb, 'Response metrics (AWS ELB)'
|
||||
it_behaves_like 'group_title', :nginx, 'Response metrics (NGINX)'
|
||||
it_behaves_like 'group_title', :kubernetes, 'System metrics (Kubernetes)'
|
||||
it_behaves_like 'group_title', :business, 'Business metrics (Custom)'
|
||||
it_behaves_like 'group_title', :response, 'Response metrics (Custom)'
|
||||
it_behaves_like 'group_title', :system, 'System metrics (Custom)'
|
||||
it_behaves_like 'group_title', :cluster_health, 'Cluster Health'
|
||||
end
|
||||
|
||||
describe '#priority' do
|
||||
where(:group, :priority) do
|
||||
:nginx_ingress_vts | 10
|
||||
:nginx_ingress | 10
|
||||
:ha_proxy | 10
|
||||
:aws_elb | 10
|
||||
:nginx | 10
|
||||
:kubernetes | 5
|
||||
:business | 0
|
||||
:response | -5
|
||||
:system | -10
|
||||
:cluster_health | 10
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
subject.group = group
|
||||
end
|
||||
|
||||
it { expect(subject.priority).to eq(priority) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#required_metrics' do
|
||||
where(:group, :required_metrics) do
|
||||
:nginx_ingress_vts | %w[nginx_upstream_responses_total nginx_upstream_response_msecs_avg]
|
||||
:nginx_ingress | %w[nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum]
|
||||
:ha_proxy | %w[haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total]
|
||||
:aws_elb | %w[aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum]
|
||||
:nginx | %w[nginx_server_requests nginx_server_requestMsec]
|
||||
:kubernetes | %w[container_memory_usage_bytes container_cpu_usage_seconds_total]
|
||||
:business | %w[]
|
||||
:response | %w[]
|
||||
:system | %w[]
|
||||
:cluster_health | %w[container_memory_usage_bytes container_cpu_usage_seconds_total]
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
subject.group = group
|
||||
end
|
||||
|
||||
it { expect(subject.required_metrics).to eq(required_metrics) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_query_metric' do
|
||||
it 'converts to queryable metric object' do
|
||||
expect(subject.to_query_metric).to be_instance_of(Gitlab::Prometheus::Metric)
|
||||
end
|
||||
|
||||
it 'queryable metric object has title' do
|
||||
expect(subject.to_query_metric.title).to eq(subject.title)
|
||||
end
|
||||
|
||||
it 'queryable metric object has y_label' do
|
||||
expect(subject.to_query_metric.y_label).to eq(subject.y_label)
|
||||
end
|
||||
|
||||
it 'queryable metric has no required_metric' do
|
||||
expect(subject.to_query_metric.required_metrics).to eq([])
|
||||
end
|
||||
|
||||
it 'queryable metrics has query description' do
|
||||
queries = [
|
||||
{
|
||||
query_range: subject.query,
|
||||
unit: subject.unit,
|
||||
label: subject.legend
|
||||
}
|
||||
]
|
||||
|
||||
expect(subject.to_query_metric.queries).to eq(queries)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_metric_hash' do
|
||||
it 'returns a hash suitable for inclusion on a metrics dashboard' do
|
||||
expected_output = {
|
||||
query_range: subject.query,
|
||||
unit: subject.unit,
|
||||
label: subject.legend,
|
||||
metric_id: subject.id
|
||||
}
|
||||
|
||||
expect(subject.to_metric_hash).to eq(expected_output)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -250,7 +250,6 @@ RSpec.describe User, feature_category: :user_profile do
|
|||
describe 'organizations association' do
|
||||
it 'does not create a cross-database query' do
|
||||
user = create(:user)
|
||||
create(:organization_user, user: user)
|
||||
|
||||
with_cross_joins_prevented do
|
||||
expect(user.organizations.count).to eq(1)
|
||||
|
|
|
|||
|
|
@ -303,10 +303,10 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do
|
|||
describe 'GET /api/v4/projects/:project_id/packages/ml_models/:model_version_id/files/(*path)/:file_name' do
|
||||
include_context 'ml model authorize permissions table'
|
||||
|
||||
let_it_be(:file_name) { 'model.md5' }
|
||||
let_it_be(:file_name) { Addressable::URI.escape('Mo_de-l v12.md5') }
|
||||
let_it_be(:package) { model_version.package }
|
||||
let_it_be(:package_file_1) { create(:package_file, :generic, package: package, file_name: 'model.md5') }
|
||||
let_it_be(:package_file_2) { create(:package_file, :generic, package: package, file_name: 'my_dir%2Fmodel.md5') }
|
||||
let_it_be(:package_file_1) { create(:package_file, :generic, package: package, file_name: file_name) }
|
||||
let_it_be(:package_file_2) { create(:package_file, :generic, package: package, file_name: "my_dir%2F#{file_name}") }
|
||||
|
||||
let(:file_path) { '' }
|
||||
let(:full_path) { "#{file_path}#{file_name}" }
|
||||
|
|
|
|||
|
|
@ -1323,6 +1323,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
|
|||
has_external_issue_tracker has_external_wiki issues_enabled merge_requests_enabled wiki_enabled storage_version
|
||||
container_registry_access_level releases_access_level environments_access_level feature_flags_access_level
|
||||
infrastructure_access_level monitor_access_level model_experiments_access_level model_registry_access_level
|
||||
namespace
|
||||
].include?(k)
|
||||
|
||||
expect(json_response[k.to_s]).to eq(v)
|
||||
|
|
@ -1346,6 +1347,16 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
|
|||
expect(project.project_feature.merge_requests_access_level).to eq(ProjectFeature::DISABLED)
|
||||
expect(project.project_feature.issues_access_level).to eq(ProjectFeature::DISABLED)
|
||||
expect(project.project_feature.snippets_access_level).to eq(ProjectFeature::DISABLED)
|
||||
|
||||
# Check namespace attributes
|
||||
expect(project.namespace.id).to eq(user.namespace.id)
|
||||
expect(project.namespace.name).to eq(user.namespace.name)
|
||||
expect(project.namespace.path).to eq(user.namespace.path)
|
||||
expect(project.namespace.kind).to eq(user.namespace.kind)
|
||||
expect(project.namespace.full_path).to eq(user.namespace.full_path)
|
||||
expect(project.namespace.parent_id).to be_nil
|
||||
expect(project.namespace.avatar_url).to eq(user.namespace.avatar_url)
|
||||
expect(project.namespace.web_url).to eq(user.namespace.web_url)
|
||||
end
|
||||
|
||||
it 'assigns container_registry_enabled to project' do
|
||||
|
|
@ -2114,10 +2125,14 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
|
|||
expect(response).to have_gitlab_http_status(:created)
|
||||
|
||||
project.each_pair do |k, v|
|
||||
next if %i[has_external_issue_tracker has_external_wiki path storage_version].include?(k)
|
||||
next if %i[has_external_issue_tracker has_external_wiki path storage_version namespace].include?(k)
|
||||
|
||||
expect(json_response[k.to_s]).to eq(v)
|
||||
end
|
||||
|
||||
# Check namespace
|
||||
created_project = Project.find_by_path(project[:path])
|
||||
expect(created_project.namespace.id).to eq(user.namespace.id)
|
||||
end
|
||||
|
||||
it 'sets a project as public' do
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ RSpec.describe RuboCop::Cop::Migration::BatchedMigrationBaseClass, feature_categ
|
|||
|
||||
it_behaves_like 'inheritance from the right base class does not register an offense', 'BatchedMigrationJob'
|
||||
it_behaves_like 'inheritance from the right base class does not register an offense', 'BackfillDesiredShardingKeyJob'
|
||||
it_behaves_like 'inheritance from the right base class does not register an offense',
|
||||
'BackfillDesiredShardingKeyPartitionJob'
|
||||
|
||||
context 'when the migration class inherits from another class' do
|
||||
it 'registers an offense' do
|
||||
|
|
|
|||
|
|
@ -192,6 +192,23 @@ RSpec.describe DesignManagement::CopyDesignCollection::CopyService, :clean_gitla
|
|||
|
||||
it 'links the LfsObjects' do
|
||||
expect { subject }.to change { target_issue.project.lfs_objects.count }.by(3)
|
||||
.and change { target_issue.project.lfs_objects_projects.count }.by(3)
|
||||
end
|
||||
|
||||
context 'when some LfsObjects are already linked to the design repository' do
|
||||
let!(:lfs_objects_project) do
|
||||
create(
|
||||
:lfs_objects_project,
|
||||
lfs_object: project.lfs_objects.first,
|
||||
project: target_issue.project,
|
||||
repository_type: :design
|
||||
)
|
||||
end
|
||||
|
||||
it 'links the LfsObjects' do
|
||||
expect { subject }.to change { target_issue.project.lfs_objects.count }.by(2)
|
||||
.and change { target_issue.project.lfs_objects_projects.count }.by(2)
|
||||
end
|
||||
end
|
||||
|
||||
it 'copies the Git repository data', :aggregate_failures do
|
||||
|
|
|
|||
|
|
@ -6577,7 +6577,6 @@
|
|||
- './spec/models/projects/triggered_hooks_spec.rb'
|
||||
- './spec/models/project_team_spec.rb'
|
||||
- './spec/models/project_wiki_spec.rb'
|
||||
- './spec/models/prometheus_metric_spec.rb'
|
||||
- './spec/models/protectable_dropdown_spec.rb'
|
||||
- './spec/models/protected_branch/merge_access_level_spec.rb'
|
||||
- './spec/models/protected_branch/push_access_level_spec.rb'
|
||||
|
|
|
|||
|
|
@ -168,7 +168,6 @@ module Support
|
|||
project_namespace
|
||||
project_repository
|
||||
project_security_setting
|
||||
prometheus_metric
|
||||
protected_branch
|
||||
protected_branch_merge_access_level
|
||||
protected_branch_push_access_level
|
||||
|
|
|
|||
Loading…
Reference in New Issue