diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index b6ccc6a00fe..ea80496c3f5 100644
--- a/app/assets/javascripts/boards/components/board_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -13,7 +13,7 @@ import boardCardInner from 'ee_else_ce/boards/mixins/board_card_inner';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { updateHistory } from '~/lib/utils/url_utility';
import { sprintf, __, n__ } from '~/locale';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import { ListType } from '../constants';
import eventHub from '../eventhub';
diff --git a/app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue b/app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue
index 77ec1f1af47..4ab9b36058d 100644
--- a/app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue
+++ b/app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue
@@ -3,7 +3,7 @@ import { GlTable, GlButton, GlBadge, GlTooltipDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
export default {
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index db01d455b2b..be9bfb50de5 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -5,7 +5,7 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { __, s__, sprintf } from '~/locale';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import CommitComponent from '~/vue_shared/components/commit.vue';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import eventHub from '../event_hub';
diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue
index 4adbf5362b7..e00fec6fddf 100644
--- a/app/assets/javascripts/error_tracking/components/error_details.vue
+++ b/app/assets/javascripts/error_tracking/components/error_details.vue
@@ -17,7 +17,7 @@ import createFlash from '~/flash';
import { __, sprintf, n__ } from '~/locale';
import Tracking from '~/tracking';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import TrackEventDirective from '~/vue_shared/directives/track_event';
import query from '../queries/details.query.graphql';
import {
diff --git a/app/assets/javascripts/issues_list/components/issues_list_app.vue b/app/assets/javascripts/issues_list/components/issues_list_app.vue
index 62b672d3e7d..ad810115ef0 100644
--- a/app/assets/javascripts/issues_list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues_list/components/issues_list_app.vue
@@ -302,6 +302,7 @@ export default {
unique: true,
defaultAuthors: [],
fetchAuthors: this.fetchUsers,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-author`,
preloadedAuthors,
},
{
@@ -313,6 +314,7 @@ export default {
unique: !this.hasMultipleIssueAssigneesFeature,
defaultAuthors: DEFAULT_NONE_ANY,
fetchAuthors: this.fetchUsers,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-assignee`,
preloadedAuthors,
},
{
@@ -321,6 +323,7 @@ export default {
icon: 'clock',
token: MilestoneToken,
fetchMilestones: this.fetchMilestones,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-milestone`,
},
{
type: TOKEN_TYPE_LABEL,
@@ -329,6 +332,7 @@ export default {
token: LabelToken,
defaultLabels: DEFAULT_NONE_ANY,
fetchLabels: this.fetchLabels,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-label`,
},
{
type: TOKEN_TYPE_TYPE,
@@ -350,6 +354,7 @@ export default {
icon: 'rocket',
token: ReleaseToken,
fetchReleases: this.fetchReleases,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-release`,
});
}
@@ -361,6 +366,7 @@ export default {
token: EmojiToken,
unique: true,
fetchEmojis: this.fetchEmojis,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-my_reaction`,
});
tokens.push({
@@ -446,7 +452,12 @@ export default {
query: searchLabelsQuery,
variables: { fullPath: this.fullPath, search, isProject: this.isProject },
})
- .then(({ data }) => data[this.namespace]?.labels.nodes);
+ .then(({ data }) => data[this.namespace]?.labels.nodes)
+ .then((labels) =>
+ // TODO remove once we can search by title-only on the backend
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/346353
+ labels.filter((label) => label.title.toLowerCase().includes(search.toLowerCase())),
+ );
},
fetchMilestones(search) {
return this.$apollo
diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue
index 1b50006239c..9aa1503c7c3 100644
--- a/app/assets/javascripts/jobs/components/sidebar.vue
+++ b/app/assets/javascripts/jobs/components/sidebar.vue
@@ -2,7 +2,7 @@
import { GlButton, GlIcon } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import { mapActions, mapGetters, mapState } from 'vuex';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { JOB_SIDEBAR } from '../constants';
import ArtifactsBlock from './artifacts_block.vue';
import CommitBlock from './commit_block.vue';
diff --git a/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue b/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue
index 611b78b3c5e..63bffe702ad 100644
--- a/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue
+++ b/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue
@@ -2,7 +2,7 @@
import { GlIcon, GlLink, GlLoadingIcon } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale';
import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.graphql';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import {
EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_LOADING,
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
index 836333c8bde..793e343a02a 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
@@ -1,5 +1,5 @@
-
+
-
+
-
+
diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js
index e44e5881376..b5c4c81b9d8 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/index.js
+++ b/app/assets/javascripts/repository/components/blob_viewers/index.js
@@ -12,6 +12,8 @@ export const loadViewer = (type) => {
return () => import(/* webpackChunkName: 'blob_image_viewer' */ './image_viewer.vue');
case 'video':
return () => import(/* webpackChunkName: 'blob_video_viewer' */ './video_viewer.vue');
+ case 'pdf':
+ return () => import(/* webpackChunkName: 'blob_pdf_viewer' */ './pdf_viewer.vue');
default:
return null;
}
@@ -36,5 +38,8 @@ export const viewerProps = (type, blob) => {
video: {
url: blob.rawPath,
},
+ pdf: {
+ url: blob.rawPath,
+ },
}[type];
};
diff --git a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
new file mode 100644
index 00000000000..3eefcd64b13
--- /dev/null
+++ b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
index e9cbbc41a13..f8220553db6 100644
--- a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
+++ b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
@@ -116,7 +116,7 @@ export default {
statusTokenConfig,
{
...tagTokenConfig,
- recentTokenValuesStorageKey: `${this.$options.filteredSearchNamespace}-recent-tags`,
+ recentSuggestionsStorageKey: `${this.$options.filteredSearchNamespace}-recent-tags`,
},
];
},
diff --git a/app/assets/javascripts/runner/components/cells/runner_summary_cell.vue b/app/assets/javascripts/runner/components/cells/runner_summary_cell.vue
index 3b476997915..937ec631633 100644
--- a/app/assets/javascripts/runner/components/cells/runner_summary_cell.vue
+++ b/app/assets/javascripts/runner/components/cells/runner_summary_cell.vue
@@ -1,7 +1,7 @@
-
-
-
-
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js
new file mode 100644
index 00000000000..f27901a30a9
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js
@@ -0,0 +1,88 @@
+/* eslint-disable @gitlab/require-i18n-strings */
+import TooltipOnTruncate from './tooltip_on_truncate.vue';
+
+const defaultWidth = '250px';
+
+export default {
+ component: TooltipOnTruncate,
+ title: 'vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue',
+};
+
+const createStory = ({ ...options }) => {
+ return (_, { argTypes }) => {
+ const comp = {
+ components: { TooltipOnTruncate },
+ props: Object.keys(argTypes),
+ template: `
+
+
+ {{title}}
+
+
+ `,
+ ...options,
+ };
+
+ return comp;
+ };
+};
+
+export const Default = createStory();
+Default.args = {
+ width: defaultWidth,
+ title: 'Hover on this text to see the content in a tooltip.',
+};
+
+export const NoOverflow = createStory();
+NoOverflow.args = {
+ width: defaultWidth,
+ title: "Short text doesn't need a tooltip.",
+};
+
+export const Placement = createStory();
+Placement.args = {
+ width: defaultWidth,
+ title: 'Use `placement="right"` to display this tooltip at the right.',
+ placement: 'right',
+};
+
+const TIMEOUT_S = 3;
+
+export const LiveUpdates = createStory({
+ props: ['width', 'placement'],
+ data() {
+ return {
+ title: `(loading in ${TIMEOUT_S}s)`,
+ };
+ },
+ mounted() {
+ setTimeout(() => {
+ this.title = 'Content updated! The content is now overflowing so we use a tooltip!';
+ }, TIMEOUT_S * 1000);
+ },
+});
+LiveUpdates.args = {
+ width: defaultWidth,
+};
+LiveUpdates.argTypes = {
+ title: {
+ control: false,
+ },
+};
+
+export const TruncateTarget = createStory({
+ template: `
+
+ `,
+});
+TruncateTarget.args = {
+ width: defaultWidth,
+ truncateTarget: 'child',
+ title: 'Wrap in container and use `truncate-target="child"` prop.',
+};
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue
similarity index 100%
rename from app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
rename to app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue
diff --git a/app/controllers/admin/plan_limits_controller.rb b/app/controllers/admin/plan_limits_controller.rb
index 88bc5ea0198..420fd93fad5 100644
--- a/app/controllers/admin/plan_limits_controller.rb
+++ b/app/controllers/admin/plan_limits_controller.rb
@@ -31,6 +31,7 @@ class Admin::PlanLimitsController < Admin::ApplicationController
params.require(:plan_limits).permit(%i[
plan_id
conan_max_file_size
+ helm_max_file_size
maven_max_file_size
npm_max_file_size
nuget_max_file_size
diff --git a/app/controllers/groups/dependency_proxy_for_containers_controller.rb b/app/controllers/groups/dependency_proxy_for_containers_controller.rb
index fc930ffebbd..171314b5f26 100644
--- a/app/controllers/groups/dependency_proxy_for_containers_controller.rb
+++ b/app/controllers/groups/dependency_proxy_for_containers_controller.rb
@@ -19,7 +19,7 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy
feature_category :dependency_proxy
def manifest
- result = DependencyProxy::FindOrCreateManifestService.new(group, image, tag, token).execute
+ result = DependencyProxy::FindCachedManifestService.new(group, image, tag, token).execute
if result[:status] == :success
if result[:manifest]
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index a2312484a9b..d49539c56fb 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -19,8 +19,13 @@ class Projects::PipelinesController < Projects::ApplicationController
around_action :allow_gitaly_ref_name_caching, only: [:index, :show]
+ # Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/345074
track_redis_hll_event :charts, name: 'p_analytics_pipelines'
+ track_redis_hll_event :charts, name: 'p_analytics_ci_cd_pipelines', if: -> { should_track_ci_cd_pipelines? }
+ track_redis_hll_event :charts, name: 'p_analytics_ci_cd_deployment_frequency', if: -> { should_track_ci_cd_deployment_frequency? }
+ track_redis_hll_event :charts, name: 'p_analytics_ci_cd_lead_time', if: -> { should_track_ci_cd_lead_time? }
+
wrap_parameters Ci::Pipeline
POLLING_INTERVAL = 10_000
@@ -323,6 +328,18 @@ class Projects::PipelinesController < Projects::ApplicationController
e.record!
end
end
+
+ def should_track_ci_cd_pipelines?
+ params[:chart].blank? || params[:chart] == 'pipelines'
+ end
+
+ def should_track_ci_cd_deployment_frequency?
+ params[:chart] == 'deployment-frequency'
+ end
+
+ def should_track_ci_cd_lead_time?
+ params[:chart] == 'lead-time'
+ end
end
Projects::PipelinesController.prepend_mod_with('Projects::PipelinesController')
diff --git a/app/models/analytics/cycle_analytics/project_stage.rb b/app/models/analytics/cycle_analytics/project_stage.rb
index e8b03fa066a..8d3a032812e 100644
--- a/app/models/analytics/cycle_analytics/project_stage.rb
+++ b/app/models/analytics/cycle_analytics/project_stage.rb
@@ -26,6 +26,12 @@ module Analytics
:project_id
end
+ def self.distinct_stages_within_hierarchy(group)
+ with_preloaded_labels
+ .where(project_id: group.all_projects.select(:id))
+ .select("DISTINCT ON(stage_event_hash_id) #{quoted_table_name}.*")
+ end
+
private
# Project should belong to a group when the stage has Label based events since only GroupLabels are allowed.
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 63df90d1842..2bf33f821ab 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -957,7 +957,7 @@ module Ci
.limit(100)
.pluck(:expanded_environment_name)
- Environment.where(project: project, name: expanded_environment_names)
+ Environment.where(project: project, name: expanded_environment_names).with_deployments
else
environment_ids = self_and_descendants.joins(:deployments).select(:'deployments.environment_id')
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 5d3a5ce9b21..1bbcf8837f6 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -59,9 +59,6 @@ class CommitStatus < Ci::ApplicationRecord
scope :with_pipeline, -> { joins(:pipeline) }
scope :updated_at_before, ->(date) { where('ci_builds.updated_at < ?', date) }
scope :created_at_before, ->(date) { where('ci_builds.created_at < ?', date) }
- scope :updated_before, ->(lookback:, timeout:) {
- where('(ci_builds.created_at BETWEEN ? AND ?) AND (ci_builds.updated_at BETWEEN ? AND ?)', lookback, timeout, lookback, timeout)
- }
scope :scheduled_at_before, ->(date) {
where('ci_builds.scheduled_at IS NOT NULL AND ci_builds.scheduled_at < ?', date)
}
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 2618991c9e5..f51c9fab8dd 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -89,6 +89,7 @@ class Environment < ApplicationRecord
scope :for_project, -> (project) { where(project_id: project) }
scope :for_tier, -> (tier) { where(tier: tier).where.not(tier: nil) }
+ scope :with_deployments, -> { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id')) }
scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id').where(sha: sha)) }
scope :unfoldered, -> { where(environment_type: nil) }
scope :with_rank, -> do
diff --git a/app/models/instance_configuration.rb b/app/models/instance_configuration.rb
index 0bf9e805aa8..bbddc18103a 100644
--- a/app/models/instance_configuration.rb
+++ b/app/models/instance_configuration.rb
@@ -62,6 +62,7 @@ class InstanceConfiguration
def plan_file_size_limits(plan)
{
conan: plan.actual_limits[:conan_max_file_size],
+ helm: plan.actual_limits[:helm_max_file_size],
maven: plan.actual_limits[:maven_max_file_size],
npm: plan.actual_limits[:npm_max_file_size],
nuget: plan.actual_limits[:nuget_max_file_size],
diff --git a/app/services/ci/stuck_builds/drop_pending_service.rb b/app/services/ci/stuck_builds/drop_pending_service.rb
index 4653e701973..dddd1cfb781 100644
--- a/app/services/ci/stuck_builds/drop_pending_service.rb
+++ b/app/services/ci/stuck_builds/drop_pending_service.rb
@@ -7,7 +7,6 @@ module Ci
BUILD_PENDING_OUTDATED_TIMEOUT = 1.day
BUILD_PENDING_STUCK_TIMEOUT = 1.hour
- BUILD_LOOKBACK = 5.days
def execute
Gitlab::AppLogger.info "#{self.class}: Cleaning pending timed-out builds"
@@ -30,11 +29,11 @@ module Ci
# because we want to force the query planner to use the
# `ci_builds_gitlab_monitor_metrics` index all the time.
def pending_builds(timeout)
- if Feature.enabled?(:ci_new_query_for_pending_stuck_jobs)
- Ci::Build.pending.created_at_before(timeout).updated_at_before(timeout).order(created_at: :asc, project_id: :asc)
- else
- Ci::Build.pending.updated_before(lookback: BUILD_LOOKBACK.ago, timeout: timeout)
- end
+ Ci::Build
+ .pending
+ .created_at_before(timeout)
+ .updated_at_before(timeout)
+ .order(created_at: :asc, project_id: :asc)
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/services/dependency_proxy/find_or_create_manifest_service.rb b/app/services/dependency_proxy/find_cached_manifest_service.rb
similarity index 58%
rename from app/services/dependency_proxy/find_or_create_manifest_service.rb
rename to app/services/dependency_proxy/find_cached_manifest_service.rb
index aeb62be9f3a..faf0402edaa 100644
--- a/app/services/dependency_proxy/find_or_create_manifest_service.rb
+++ b/app/services/dependency_proxy/find_cached_manifest_service.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module DependencyProxy
- class FindOrCreateManifestService < DependencyProxy::BaseService
+ class FindCachedManifestService < DependencyProxy::BaseService
def initialize(group, image, tag, token)
@group = group
@image = image
@@ -20,36 +20,13 @@ module DependencyProxy
return respond if cached_manifest_matches?(head_result)
- if Feature.enabled?(:dependency_proxy_manifest_workhorse, @group, default_enabled: :yaml)
- success(manifest: nil, from_cache: false)
- else
- pull_new_manifest
- respond(from_cache: false)
- end
+ success(manifest: nil, from_cache: false)
rescue Timeout::Error, *Gitlab::HTTP::HTTP_ERRORS
respond
end
private
- def pull_new_manifest
- DependencyProxy::PullManifestService.new(@image, @tag, @token).execute_with_manifest do |new_manifest|
- params = {
- file_name: @file_name,
- content_type: new_manifest[:content_type],
- digest: new_manifest[:digest],
- file: new_manifest[:file],
- size: new_manifest[:file].size
- }
-
- if @manifest
- @manifest.update!(params)
- else
- @manifest = @group.dependency_proxy_manifests.create!(params)
- end
- end
- end
-
def cached_manifest_matches?(head_result)
return false if head_result[:status] == :error
diff --git a/app/services/dependency_proxy/pull_manifest_service.rb b/app/services/dependency_proxy/pull_manifest_service.rb
deleted file mode 100644
index e8f0ad6374a..00000000000
--- a/app/services/dependency_proxy/pull_manifest_service.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module DependencyProxy
- class PullManifestService < DependencyProxy::BaseService
- def initialize(image, tag, token)
- @image = image
- @tag = tag
- @token = token
- end
-
- def execute_with_manifest
- raise ArgumentError, 'Block must be provided' unless block_given?
-
- response = Gitlab::HTTP.get(manifest_url, headers: auth_headers.merge(Accept: ::ContainerRegistry::Client::ACCEPTED_TYPES.join(',')))
-
- if response.success?
- file = Tempfile.new
-
- begin
- file.write(response.body)
- file.flush
-
- yield(
- success(
- file: file,
- digest: response.headers[DependencyProxy::Manifest::DIGEST_HEADER],
- content_type: response.headers['content-type']
- )
- )
- ensure
- file.close
- file.unlink
- end
- else
- yield(error(response.body, response.code))
- end
- rescue Timeout::Error => exception
- error(exception.message, 599)
- end
-
- private
-
- def manifest_url
- registry.manifest_url(@image, @tag)
- end
- end
-end
diff --git a/app/services/loose_foreign_keys/cleaner_service.rb b/app/services/loose_foreign_keys/cleaner_service.rb
index c5ee62de4b8..44a922aad87 100644
--- a/app/services/loose_foreign_keys/cleaner_service.rb
+++ b/app/services/loose_foreign_keys/cleaner_service.rb
@@ -16,7 +16,7 @@ module LooseForeignKeys
def execute
result = connection.execute(build_query)
- { affected_rows: result.cmd_tuples, table: loose_foreign_key_definition.to_table }
+ { affected_rows: result.cmd_tuples, table: loose_foreign_key_definition.from_table }
end
def async_delete?
@@ -48,15 +48,15 @@ module LooseForeignKeys
end
def arel_table
- @arel_table ||= Arel::Table.new(loose_foreign_key_definition.to_table)
+ @arel_table ||= Arel::Table.new(loose_foreign_key_definition.from_table)
end
def primary_keys
- @primary_keys ||= connection.primary_keys(loose_foreign_key_definition.to_table).map { |key| arel_table[key] }
+ @primary_keys ||= connection.primary_keys(loose_foreign_key_definition.from_table).map { |key| arel_table[key] }
end
def quoted_table_name
- @quoted_table_name ||= Arel.sql(connection.quote_table_name(loose_foreign_key_definition.to_table))
+ @quoted_table_name ||= Arel.sql(connection.quote_table_name(loose_foreign_key_definition.from_table))
end
def delete_query
diff --git a/app/views/admin/application_settings/_package_registry.html.haml b/app/views/admin/application_settings/_package_registry.html.haml
index 7cdadaaf37b..398e63cdfdc 100644
--- a/app/views/admin/application_settings/_package_registry.html.haml
+++ b/app/views/admin/application_settings/_package_registry.html.haml
@@ -32,6 +32,9 @@
.form-group
= f.label :conan_max_file_size, _('Maximum Conan package file size in bytes'), class: 'label-bold'
= f.number_field :conan_max_file_size, class: 'form-control gl-form-input'
+ .form-group
+ = f.label :helm_max_file_size, _('Maximum Helm chart file size in bytes'), class: 'label-bold'
+ = f.number_field :helm_max_file_size, class: 'form-control gl-form-input'
.form-group
= f.label :maven_max_file_size, _('Maximum Maven package file size in bytes'), class: 'label-bold'
= f.number_field :maven_max_file_size, class: 'form-control gl-form-input'
diff --git a/app/views/groups/settings/_transfer.html.haml b/app/views/groups/settings/_transfer.html.haml
index b2379d77314..c9a0a29a728 100644
--- a/app/views/groups/settings/_transfer.html.haml
+++ b/app/views/groups/settings/_transfer.html.haml
@@ -6,7 +6,7 @@
= hidden_field_tag 'new_parent_group_id'
%ul
- - side_effects_link_start = ''.html_safe
+ - side_effects_link_start = ''.html_safe
- warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended %{side_effects_link_start}side effects%{side_effects_link_end}.") % { side_effects_link_start: side_effects_link_start, side_effects_link_end: ''.html_safe }
%li= warning_text.html_safe
%li= s_('GroupSettings|You can only transfer the group to a group you manage.')
diff --git a/app/views/help/instance_configuration/_package_registry.html.haml b/app/views/help/instance_configuration/_package_registry.html.haml
index 38202b8d6e6..84b8accfebb 100644
--- a/app/views/help/instance_configuration/_package_registry.html.haml
+++ b/app/views/help/instance_configuration/_package_registry.html.haml
@@ -22,6 +22,10 @@
%td= 'Conan'
- package_file_size_limits.each_value do |limits|
%td= instance_configuration_human_size_cell(limits[:conan])
+ %tr
+ %td= 'Helm'
+ - package_file_size_limits.each_value do |limits|
+ %td= instance_configuration_human_size_cell(limits[:helm])
%tr
%td= 'Maven'
- package_file_size_limits.each_value do |limits|
diff --git a/config/feature_flags/development/ci_new_query_for_pending_stuck_jobs.yml b/config/feature_flags/development/ci_new_query_for_pending_stuck_jobs.yml
deleted file mode 100644
index 5e63330d01d..00000000000
--- a/config/feature_flags/development/ci_new_query_for_pending_stuck_jobs.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_new_query_for_pending_stuck_jobs
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68880
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339322
-milestone: '14.3'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/dependency_proxy_manifest_workhorse.yml b/config/feature_flags/development/dependency_proxy_manifest_workhorse.yml
deleted file mode 100644
index f1e3be78da8..00000000000
--- a/config/feature_flags/development/dependency_proxy_manifest_workhorse.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: dependency_proxy_manifest_workhorse
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73033
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/344216
-milestone: '14.4'
-type: development
-group: group::package
-default_enabled: true
diff --git a/config/feature_flags/development/load_balancing_for_update_all_mirrors_worker.yml b/config/feature_flags/development/load_balancing_for_update_all_mirrors_worker.yml
index 1f213f52753..b3f4ccfdfe5 100644
--- a/config/feature_flags/development/load_balancing_for_update_all_mirrors_worker.yml
+++ b/config/feature_flags/development/load_balancing_for_update_all_mirrors_worker.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334162
milestone: '14.1'
type: development
group: group::source code
-default_enabled: false
+default_enabled: true
diff --git a/config/metrics/counts_28d/20210216175016_analytics_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216175016_analytics_total_unique_counts_monthly.yml
index 1e3fd72fb55..b4ac7032df6 100644
--- a/config/metrics/counts_28d/20210216175016_analytics_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216175016_analytics_total_unique_counts_monthly.yml
@@ -13,29 +13,32 @@ data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- - users_viewing_analytics_group_devops_adoption
- - i_analytics_dev_ops_adoption
- - i_analytics_dev_ops_score
- - p_analytics_merge_request
- - i_analytics_instance_statistics
- - g_analytics_contribution
- - g_analytics_insights
- - g_analytics_issues
- - g_analytics_productivity
- - g_analytics_valuestream
- - p_analytics_pipelines
- - p_analytics_code_reviews
- - p_analytics_valuestream
- - p_analytics_insights
- - p_analytics_issues
- - p_analytics_repo
- - i_analytics_cohorts
+ - users_viewing_analytics_group_devops_adoption
+ - i_analytics_dev_ops_adoption
+ - i_analytics_dev_ops_score
+ - p_analytics_merge_request
+ - i_analytics_instance_statistics
+ - g_analytics_contribution
+ - g_analytics_insights
+ - g_analytics_issues
+ - g_analytics_productivity
+ - g_analytics_valuestream
+ - p_analytics_pipelines
+ - p_analytics_ci_cd_pipelines
+ - p_analytics_ci_cd_deployment_frequency
+ - p_analytics_ci_cd_lead_time
+ - p_analytics_code_reviews
+ - p_analytics_valuestream
+ - p_analytics_insights
+ - p_analytics_issues
+ - p_analytics_repo
+ - i_analytics_cohorts
distribution:
-- ce
-- ee
+ - ce
+ - ee
tier:
-- free
-- premium
-- ultimate
+ - free
+ - premium
+ - ultimate
performance_indicator_type: []
-milestone: "<13.9"
+milestone: '<13.9'
diff --git a/config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml b/config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml
new file mode 100644
index 00000000000..bd1e7a74b46
--- /dev/null
+++ b/config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.analytics.p_analytics_ci_cd_pipelines_monthly
+description: Count of unique visits to the project level CI CD Analytics pipelines tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
+options:
+ events:
+ - p_analytics_ci_cd_pipelines
diff --git a/config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml b/config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml
new file mode 100644
index 00000000000..54118e30127
--- /dev/null
+++ b/config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.analytics.p_analytics_ci_cd_deployment_frequency_monthly
+description: Count of unique visits to the project level CI CD Analytics deployment frequency tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
+options:
+ events:
+ - p_analytics_ci_cd_deployment_frequency
diff --git a/config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml b/config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml
new file mode 100644
index 00000000000..9a2e194ed1a
--- /dev/null
+++ b/config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.analytics.p_analytics_ci_cd_lead_time_monthly
+description: Count of unique visits to the project level CI CD Analytics lead time tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
+options:
+ events:
+ - p_analytics_ci_cd_lead_time
diff --git a/config/metrics/counts_7d/20210216175014_analytics_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216175014_analytics_total_unique_counts_weekly.yml
index 3a9efa3f962..4efbc3f14de 100644
--- a/config/metrics/counts_7d/20210216175014_analytics_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216175014_analytics_total_unique_counts_weekly.yml
@@ -13,29 +13,32 @@ data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- - users_viewing_analytics_group_devops_adoption
- - i_analytics_dev_ops_adoption
- - i_analytics_dev_ops_score
- - p_analytics_merge_request
- - i_analytics_instance_statistics
- - g_analytics_contribution
- - g_analytics_insights
- - g_analytics_issues
- - g_analytics_productivity
- - g_analytics_valuestream
- - p_analytics_pipelines
- - p_analytics_code_reviews
- - p_analytics_valuestream
- - p_analytics_insights
- - p_analytics_issues
- - p_analytics_repo
- - i_analytics_cohorts
+ - users_viewing_analytics_group_devops_adoption
+ - i_analytics_dev_ops_adoption
+ - i_analytics_dev_ops_score
+ - p_analytics_merge_request
+ - i_analytics_instance_statistics
+ - g_analytics_contribution
+ - g_analytics_insights
+ - g_analytics_issues
+ - g_analytics_productivity
+ - g_analytics_valuestream
+ - p_analytics_pipelines
+ - p_analytics_ci_cd_pipelines
+ - p_analytics_ci_cd_deployment_frequency
+ - p_analytics_ci_cd_lead_time
+ - p_analytics_code_reviews
+ - p_analytics_valuestream
+ - p_analytics_insights
+ - p_analytics_issues
+ - p_analytics_repo
+ - i_analytics_cohorts
distribution:
-- ce
-- ee
+ - ce
+ - ee
tier:
-- free
-- premium
-- ultimate
+ - free
+ - premium
+ - ultimate
performance_indicator_type: []
-milestone: "<13.9"
+milestone: '<13.9'
diff --git a/config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml b/config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml
new file mode 100644
index 00000000000..e77af4df59a
--- /dev/null
+++ b/config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.analytics.p_analytics_ci_cd_pipelines_weekly
+description: Count of unique visits to the project level CI CD Analytics pipelines tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
+options:
+ events:
+ - p_analytics_ci_cd_pipelines
diff --git a/config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml b/config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml
new file mode 100644
index 00000000000..d2181a95876
--- /dev/null
+++ b/config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.analytics.p_analytics_ci_cd_deployment_frequency_weekly
+description: Count of unique visits to the project level CI CD Analytics deployment frequency tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
+options:
+ events:
+ - p_analytics_ci_cd_deployment_frequency
diff --git a/config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml b/config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml
new file mode 100644
index 00000000000..8d11cc16fcc
--- /dev/null
+++ b/config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.analytics.p_analytics_ci_cd_lead_time_weekly
+description: Count of unique visits to the project level CI CD Analytics lead time tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
+options:
+ events:
+ - p_analytics_ci_cd_lead_time
diff --git a/config/metrics/counts_all/20211126090001_p_analytics_ci_cd_pipelines.yml b/config/metrics/counts_all/20211126090001_p_analytics_ci_cd_pipelines.yml
new file mode 100644
index 00000000000..7e6820b0d24
--- /dev/null
+++ b/config/metrics/counts_all/20211126090001_p_analytics_ci_cd_pipelines.yml
@@ -0,0 +1,21 @@
+---
+data_category: optional
+key_path: analytics_unique_visits.p_analytics_ci_cd_pipelines
+description: Count of unique visits to the project level CI CD Analytics pipelines tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: all
+data_source: redis_hll
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
diff --git a/config/metrics/counts_all/20211126090002_p_analytics_ci_cd_deployment_frequency.yml b/config/metrics/counts_all/20211126090002_p_analytics_ci_cd_deployment_frequency.yml
new file mode 100644
index 00000000000..134f43b1b27
--- /dev/null
+++ b/config/metrics/counts_all/20211126090002_p_analytics_ci_cd_deployment_frequency.yml
@@ -0,0 +1,21 @@
+---
+data_category: optional
+key_path: analytics_unique_visits.p_analytics_ci_cd_deployment_frequency
+description: Count of unique visits to the project level CI CD Analytics deployment frequency tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: all
+data_source: redis_hll
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
diff --git a/config/metrics/counts_all/20211126090003_p_analytics_ci_cd_lead_time.yml b/config/metrics/counts_all/20211126090003_p_analytics_ci_cd_lead_time.yml
new file mode 100644
index 00000000000..a167a380432
--- /dev/null
+++ b/config/metrics/counts_all/20211126090003_p_analytics_ci_cd_lead_time.yml
@@ -0,0 +1,21 @@
+---
+data_category: optional
+key_path: analytics_unique_visits.p_analytics_ci_cd_lead_time
+description: Count of unique visits to the project level CI CD Analytics lead time tab
+product_section: dev
+product_stage: manage
+product_group: group::optimize
+product_category:
+value_type: number
+status: active
+milestone: '14.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75187
+time_frame: all
+data_source: redis_hll
+distribution:
+ - ce
+ - ee
+tier:
+ - free
+ - premium
+ - ultimate
diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md
index 7b8dadc5d75..942bc0af8dd 100644
--- a/doc/administration/instance_limits.md
+++ b/doc/administration/instance_limits.md
@@ -848,16 +848,20 @@ More information can be found in the [Push event activities limit and bulk push
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218017) in GitLab 13.4.
-On GitLab.com, the maximum file size for a package that's uploaded to the [GitLab Package Registry](../user/packages/package_registry/index.md) varies by format:
+The default maximum file size for a package that's uploaded to the [GitLab Package Registry](../user/packages/package_registry/index.md) varies by format:
-- Conan: 5 GB
+- Conan: 3 GB
- Generic: 5 GB
-- Maven: 5 GB
-- npm: 5 GB
-- NuGet: 5 GB
-- PyPI: 5 GB
+- Helm: 5 MB
+- Maven: 3 GB
+- npm: 500 MB
+- NuGet: 500 MB
+- PyPI: 3 GB
+- Terraform: 1 GB
-To set this limit for a self-managed installation, run the following in the
+The [maximum file sizes on GitLab.com](../user/gitlab_com/index.md) might be different.
+
+To set these limits for a self-managed installation, run the following in the
[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
@@ -881,6 +885,9 @@ Plan.default.actual_limits.update!(pypi_max_file_size: 100.megabytes)
# For Debian Packages
Plan.default.actual_limits.update!(debian_max_file_size: 100.megabytes)
+# For Helm Charts
+Plan.default.actual_limits.update!(helm_max_file_size: 100.megabytes)
+
# For Generic Packages
Plan.default.actual_limits.update!(generic_packages_max_file_size: 100.megabytes)
```
diff --git a/doc/development/database/loose_foreign_keys.md b/doc/development/database/loose_foreign_keys.md
index e3274ef38d2..fb84a004f23 100644
--- a/doc/development/database/loose_foreign_keys.md
+++ b/doc/development/database/loose_foreign_keys.md
@@ -62,28 +62,28 @@ following information:
- The data cleanup method (`async_delete` or `async_nullify`)
The YAML file is located at `lib/gitlab/database/gitlab_loose_foreign_keys.yml`. The file groups
-foreign key definitions by the name of the parent table. The parent table can have multiple loose
+foreign key definitions by the name of the child table. The child table can have multiple loose
foreign key definitions, therefore we store them as an array.
Example definition:
```yaml
-projects:
- - to_table: ci_pipelines
+ci_pipelines:
+ - table: projects
column: project_id
on_delete: async_delete
```
-If the `projects` key is already present in the YAML file, then a new entry can be added
+If the `ci_pipelines` key is already present in the YAML file, then a new entry can be added
to the array:
```yaml
-projects:
- - to_table: ci_pipelines
+ci_pipelines:
+ - table: projects
column: project_id
on_delete: async_delete
- - to_table: another_table
- column: project_id
+ - table: another_table
+ column: another_id
on_delete: :async_nullify
```
diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md
index 906fea2e6ad..925f657c099 100644
--- a/doc/topics/autodevops/customize.md
+++ b/doc/topics/autodevops/customize.md
@@ -103,10 +103,14 @@ You can override this behavior by defining specific variables:
| Image Path | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` for branch pipelines. `$CI_REGISTRY_IMAGE` for tag pipelines. | `$CI_APPLICATION_REPOSITORY` |
| Image Tag | `$CI_COMMIT_SHA` for branch pipelines. `$CI_COMMIT_TAG` for tag pipelines. | `$CI_APPLICATION_TAG` |
-These variables also affect Auto Build. If you don't want to build and push an image to
+These variables also affect Auto Build and Auto Container Scanning. If you don't want to build and push an image to
`$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG`, consider
including only `Jobs/Deploy.gitlab-ci.yml`, or [disabling the `build` jobs](#disable-jobs).
+If you use Auto Container Scanning and set a value for `$CI_APPLICATION_REPOSITORY`, then you should
+also update `$CS_DEFAULT_BRANCH_IMAGE`. See [Setting the default branch image](../../user/application_security/container_scanning/index.md#setting-the-default-branch-image)
+for more details.
+
Here is an example setup in your `.gitlab-ci.yml`:
```yaml
diff --git a/lib/api/admin/plan_limits.rb b/lib/api/admin/plan_limits.rb
index ab6a4e4a04a..d595b5b2e09 100644
--- a/lib/api/admin/plan_limits.rb
+++ b/lib/api/admin/plan_limits.rb
@@ -37,6 +37,7 @@ module API
optional :conan_max_file_size, type: Integer, desc: 'Maximum Conan package file size in bytes'
optional :generic_packages_max_file_size, type: Integer, desc: 'Maximum generic package file size in bytes'
+ optional :helm_max_file_size, type: Integer, desc: 'Maximum Helm chart file size in bytes'
optional :maven_max_file_size, type: Integer, desc: 'Maximum Maven package file size in bytes'
optional :npm_max_file_size, type: Integer, desc: 'Maximum NPM package file size in bytes'
optional :nuget_max_file_size, type: Integer, desc: 'Maximum NuGet package file size in bytes'
diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb
index dabb6c7ab3a..29d02e7d1f1 100644
--- a/lib/api/ci/helpers/runner.rb
+++ b/lib/api/ci/helpers/runner.rb
@@ -52,7 +52,7 @@ module API
# HTTP status codes to terminate the job on GitLab Runner:
# - 403
- def authenticate_job!(require_running: true)
+ def authenticate_job!(require_running: true, heartbeat_runner: false)
job = current_job
# 404 is not returned here because we want to terminate the job if it's
@@ -70,7 +70,17 @@ module API
job_forbidden!(job, 'Job is not running') unless job.running?
end
- job.runner&.heartbeat(get_runner_ip)
+ # Only some requests (like updating the job or patching the trace) should trigger
+ # runner heartbeat. Operations like artifacts uploading are executed in context of
+ # the running job and in the job environment, which in many cases will cause the IP
+ # to be updated to not the expected value. And operations like artifacts downloads can
+ # be done even after the job is finished and from totally different runners - while
+ # they would then update the connection status of not the runner that they should.
+ # Runner requests done in context of job authentication should explicitly define when
+ # the heartbeat should be triggered.
+ if heartbeat_runner
+ job.runner&.heartbeat(get_runner_ip)
+ end
job
end
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index aabcf34952c..4317789f7aa 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -176,7 +176,7 @@ module API
optional :exit_code, type: Integer, desc: %q(Job's exit code)
end
put '/:id', feature_category: :continuous_integration do
- job = authenticate_job!
+ job = authenticate_job!(heartbeat_runner: true)
Gitlab::Metrics.add_event(:update_build)
@@ -203,7 +203,7 @@ module API
optional :token, type: String, desc: %q(Job's authentication token)
end
patch '/:id/trace', feature_category: :continuous_integration do
- job = authenticate_job!
+ job = authenticate_job!(heartbeat_runner: true)
error!('400 Missing header Content-Range', 400) unless request.headers.key?('Content-Range')
content_range = request.headers['Content-Range']
diff --git a/lib/api/entities/plan_limit.rb b/lib/api/entities/plan_limit.rb
index 04ec44b5167..9f4d1635998 100644
--- a/lib/api/entities/plan_limit.rb
+++ b/lib/api/entities/plan_limit.rb
@@ -5,6 +5,7 @@ module API
class PlanLimit < Grape::Entity
expose :conan_max_file_size
expose :generic_packages_max_file_size
+ expose :helm_max_file_size
expose :maven_max_file_size
expose :npm_max_file_size
expose :nuget_max_file_size
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 89fd59d98f4..f47c3decd3c 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -53,6 +53,10 @@ variables:
# KUBE_INGRESS_BASE_DOMAIN is the application deployment domain and should be set as a variable at the group or project level.
# KUBE_INGRESS_BASE_DOMAIN: domain.example.com
+ # Allows Container-Scanning to correctly correlate image names when using Jobs/Build.gitlab-ci.yml
+ CI_APPLICATION_TAG: $CI_COMMIT_SHA
+ CS_DEFAULT_BRANCH_IMAGE: $CI_REGISTRY_IMAGE/$CI_DEFAULT_BRANCH:$CI_APPLICATION_TAG
+
POSTGRES_USER: user
POSTGRES_PASSWORD: testing-password
POSTGRES_ENABLED: "true"
diff --git a/lib/gitlab/database/gitlab_loose_foreign_keys.yml b/lib/gitlab/database/gitlab_loose_foreign_keys.yml
index dbea7c9f690..430ac785449 100644
--- a/lib/gitlab/database/gitlab_loose_foreign_keys.yml
+++ b/lib/gitlab/database/gitlab_loose_foreign_keys.yml
@@ -1,19 +1,20 @@
-chat_names:
- - to_table: ci_pipeline_chat_data
+ci_pipeline_chat_data:
+ - table: chat_names
column: chat_name_id
on_delete: async_delete
-ci_builds:
- - to_table: dast_site_profiles_builds
+dast_scanner_profiles_builds:
+ - table: ci_builds
column: ci_build_id
on_delete: async_delete
- - to_table: dast_scanner_profiles_builds
+dast_scanner_profiles_builds:
+ - table: ci_builds
column: ci_build_id
on_delete: async_delete
-ci_pipelines:
- - to_table: dast_profiles_pipelines
+dast_profiles_pipelines:
+ - table: ci_pipelines
column: ci_pipeline_id
on_delete: async_delete
-ci_runners:
- - to_table: clusters_applications_runners
+clusters_applications_runners:
+ - table: ci_runners
column: runner_id
on_delete: async_nullify
diff --git a/lib/gitlab/database/loose_foreign_keys.rb b/lib/gitlab/database/loose_foreign_keys.rb
index 1d885b3fbc8..1ecfb5ce47f 100644
--- a/lib/gitlab/database/loose_foreign_keys.rb
+++ b/lib/gitlab/database/loose_foreign_keys.rb
@@ -4,25 +4,25 @@ module Gitlab
module Database
module LooseForeignKeys
def self.definitions_by_table
- @definitions_by_table ||= definitions.group_by(&:from_table).with_indifferent_access.freeze
+ @definitions_by_table ||= definitions.group_by(&:to_table).with_indifferent_access.freeze
end
def self.definitions
- @definitions ||= loose_foreign_keys_yaml.flat_map do |parent_table_name, configs|
- configs.map { |config| build_definition(parent_table_name, config) }
+ @definitions ||= loose_foreign_keys_yaml.flat_map do |child_table_name, configs|
+ configs.map { |config| build_definition(child_table_name, config) }
end.freeze
end
- def self.build_definition(parent_table_name, config)
- to_table = config.fetch('to_table')
+ def self.build_definition(child_table_name, config)
+ parent_table_name = config.fetch('table')
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
+ child_table_name,
parent_table_name,
- to_table,
{
column: config.fetch('column'),
on_delete: config.fetch('on_delete').to_sym,
- gitlab_schema: GitlabSchema.table_schema(to_table)
+ gitlab_schema: GitlabSchema.table_schema(child_table_name)
}
)
end
diff --git a/lib/gitlab/tracking.rb b/lib/gitlab/tracking.rb
index 216b1d04bf6..a58b4beb0df 100644
--- a/lib/gitlab/tracking.rb
+++ b/lib/gitlab/tracking.rb
@@ -2,11 +2,9 @@
module Gitlab
module Tracking
- SNOWPLOW_NAMESPACE = 'gl'
-
class << self
def enabled?
- snowplow_micro_enabled? || Gitlab::CurrentSettings.snowplow_enabled?
+ snowplow.enabled?
end
def event(category, action, label: nil, property: nil, value: nil, context: [], project: nil, user: nil, namespace: nil, **extra) # rubocop:disable Metrics/ParameterLists
diff --git a/lib/gitlab/tracking/destinations/snowplow.rb b/lib/gitlab/tracking/destinations/snowplow.rb
index 5596e9acd30..ddcd4693738 100644
--- a/lib/gitlab/tracking/destinations/snowplow.rb
+++ b/lib/gitlab/tracking/destinations/snowplow.rb
@@ -8,6 +8,8 @@ module Gitlab
class Snowplow < Base
extend ::Gitlab::Utils::Override
+ SNOWPLOW_NAMESPACE = 'gl'
+
override :event
def event(category, action, label: nil, property: nil, value: nil, context: nil)
return unless enabled?
@@ -19,7 +21,7 @@ module Gitlab
def options(group)
additional_features = Feature.enabled?(:additional_snowplow_tracking, group, type: :ops)
{
- namespace: Gitlab::Tracking::SNOWPLOW_NAMESPACE,
+ namespace: SNOWPLOW_NAMESPACE,
hostname: hostname,
cookie_domain: cookie_domain,
app_id: app_id,
@@ -28,16 +30,16 @@ module Gitlab
}.transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
end
+ def enabled?
+ Gitlab::CurrentSettings.snowplow_enabled?
+ end
+
def hostname
Gitlab::CurrentSettings.snowplow_collector_hostname
end
private
- def enabled?
- Gitlab::Tracking.enabled?
- end
-
def app_id
Gitlab::CurrentSettings.snowplow_app_id
end
@@ -54,7 +56,7 @@ module Gitlab
@tracker ||= SnowplowTracker::Tracker.new(
emitter,
SnowplowTracker::Subject.new,
- Gitlab::Tracking::SNOWPLOW_NAMESPACE,
+ SNOWPLOW_NAMESPACE,
app_id
)
end
diff --git a/lib/gitlab/tracking/destinations/snowplow_micro.rb b/lib/gitlab/tracking/destinations/snowplow_micro.rb
index 8beab910818..3553efba1e1 100644
--- a/lib/gitlab/tracking/destinations/snowplow_micro.rb
+++ b/lib/gitlab/tracking/destinations/snowplow_micro.rb
@@ -18,6 +18,11 @@ module Gitlab
).transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
end
+ override :enabled?
+ def enabled?
+ true
+ end
+
override :hostname
def hostname
"#{uri.host}:#{uri.port}"
diff --git a/lib/gitlab/usage_data_counters/known_events/analytics.yml b/lib/gitlab/usage_data_counters/known_events/analytics.yml
index 261bdeb9bfa..5a1e7f03278 100644
--- a/lib/gitlab/usage_data_counters/known_events/analytics.yml
+++ b/lib/gitlab/usage_data_counters/known_events/analytics.yml
@@ -66,3 +66,15 @@
category: analytics
redis_slot: analytics
aggregation: weekly
+- name: p_analytics_ci_cd_pipelines
+ category: analytics
+ redis_slot: analytics
+ aggregation: weekly
+- name: p_analytics_ci_cd_deployment_frequency
+ category: analytics
+ redis_slot: analytics
+ aggregation: weekly
+- name: p_analytics_ci_cd_lead_time
+ category: analytics
+ redis_slot: analytics
+ aggregation: weekly
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 67fef35eaa7..8ccbea7b460 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5469,6 +5469,9 @@ msgstr ""
msgid "Billing|Users occupying seats in"
msgstr ""
+msgid "Billing|View pending approvals"
+msgstr ""
+
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
@@ -13483,9 +13486,6 @@ msgstr ""
msgid "Epics|Enter a title for your epic"
msgstr ""
-msgid "Epics|How can I solve this?"
-msgstr ""
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -13534,9 +13534,6 @@ msgstr ""
msgid "Epics|Something went wrong while removing issue from epic."
msgstr ""
-msgid "Epics|These dates affect how your epics appear in the roadmap. Dates from milestones come from the milestones assigned to issues in the epic. You can also set fixed dates or remove them entirely."
-msgstr ""
-
msgid "Epics|This epic and any containing child epics are confidential and should only be visible to team members with at least Reporter access."
msgstr ""
@@ -14997,15 +14994,6 @@ msgstr ""
msgid "Fixed burndown chart"
msgstr ""
-msgid "Fixed date"
-msgstr ""
-
-msgid "Fixed due date"
-msgstr ""
-
-msgid "Fixed start date"
-msgstr ""
-
msgid "Fixed:"
msgstr ""
@@ -21412,6 +21400,9 @@ msgstr ""
msgid "Maximum Conan package file size in bytes"
msgstr ""
+msgid "Maximum Helm chart file size in bytes"
+msgstr ""
+
msgid "Maximum Maven package file size in bytes"
msgstr ""
@@ -33059,9 +33050,6 @@ msgstr ""
msgid "Start a review"
msgstr ""
-msgid "Start and due date"
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -35453,12 +35441,6 @@ msgstr ""
msgid "This credential has expired"
msgstr ""
-msgid "This date is after the due date, so this epic won't appear in the roadmap."
-msgstr ""
-
-msgid "This date is before the start date, so this epic won't appear in the roadmap."
-msgstr ""
-
msgid "This device has already been registered with us."
msgstr ""
@@ -37250,9 +37232,6 @@ msgstr ""
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
-msgid "Until"
-msgstr ""
-
msgid "Until revoked, expired personal access tokens pose a security risk."
msgstr ""
@@ -39877,6 +39856,11 @@ msgstr ""
msgid "You don’t have access to Value Stream Analytics for this group"
msgstr ""
+msgid "You have %{pendingMembersCount} pending member that needs approval."
+msgid_plural "You have %{pendingMembersCount} pending members that need approval."
+msgstr[0] ""
+msgstr[1] ""
+
msgid "You have been granted %{access_level} access to the %{source_link} %{source_type}."
msgstr ""
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index 192c5e4b2db..d3c1e91f358 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -368,6 +368,10 @@ module QA
parse_body(response)
end
+ def create_wiki_page(title:, content:)
+ api_post_to(api_wikis_path, title: title, content: content)
+ end
+
# Object comparison
#
# @param [QA::Resource::Project] other
diff --git a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
index b22307578ab..0f262d93d4c 100644
--- a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
+++ b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
@@ -170,7 +170,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do
let(:pull_response) { { status: :success, manifest: manifest, from_cache: false } }
before do
- allow_next_instance_of(DependencyProxy::FindOrCreateManifestService) do |instance|
+ allow_next_instance_of(DependencyProxy::FindCachedManifestService) do |instance|
allow(instance).to receive(:execute).and_return(pull_response)
end
end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 14c613ff9c4..3fe709a0d44 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -745,9 +745,28 @@ RSpec.describe Projects::PipelinesController do
describe 'GET #charts' do
let(:pipeline) { create(:ci_pipeline, project: project) }
- it_behaves_like 'tracking unique visits', :charts do
- let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id } }
- let(:target_id) { 'p_analytics_pipelines' }
+ [
+ {
+ chart_param: '',
+ event: 'p_analytics_ci_cd_pipelines'
+ },
+ {
+ chart_param: 'pipelines',
+ event: 'p_analytics_ci_cd_pipelines'
+ },
+ {
+ chart_param: 'deployment-frequency',
+ event: 'p_analytics_ci_cd_deployment_frequency'
+ },
+ {
+ chart_param: 'lead-time',
+ event: 'p_analytics_ci_cd_lead_time'
+ }
+ ].each do |tab|
+ it_behaves_like 'tracking unique visits', :charts do
+ let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } }
+ let(:target_id) { ['p_analytics_pipelines', tab[:event]] }
+ end
end
end
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 9be09179c6c..502bd01d522 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -29,7 +29,6 @@ RSpec.describe 'Database schema' do
ci_builds: %w[erased_by_id runner_id trigger_request_id user_id],
ci_namespace_monthly_usages: %w[namespace_id],
ci_pipelines: %w[user_id],
- ci_pipeline_chat_data: %w[chat_name_id], # it uses the loose foreign key featue
ci_runner_projects: %w[runner_id],
ci_trigger_requests: %w[commit_id],
cluster_providers_aws: %w[security_group_id vpc_id access_key_id],
@@ -102,6 +101,8 @@ RSpec.describe 'Database schema' do
let(:indexes) { connection.indexes(table) }
let(:columns) { connection.columns(table) }
let(:foreign_keys) { connection.foreign_keys(table) }
+ let(:loose_foreign_keys) { Gitlab::Database::LooseForeignKeys.definitions.group_by(&:from_table).fetch(table, []) }
+ let(:all_foreign_keys) { foreign_keys + loose_foreign_keys }
# take the first column in case we're using a composite primary key
let(:primary_key_column) { Array(connection.primary_key(table)).first }
@@ -114,7 +115,7 @@ RSpec.describe 'Database schema' do
columns = columns.split(',') if columns.is_a?(String)
columns.first.chomp
end
- foreign_keys_columns = foreign_keys.map(&:column)
+ foreign_keys_columns = all_foreign_keys.map(&:column)
# Add the primary key column to the list of indexed columns because
# postgres and mysql both automatically create an index on the primary
@@ -129,7 +130,7 @@ RSpec.describe 'Database schema' do
context 'columns ending with _id' do
let(:column_names) { columns.map(&:name) }
let(:column_names_with_id) { column_names.select { |column_name| column_name.ends_with?('_id') } }
- let(:foreign_keys_columns) { foreign_keys.map(&:column) }
+ let(:foreign_keys_columns) { all_foreign_keys.map(&:column).uniq } # we can have FK and loose FK present at the same time
let(:ignored_columns) { ignored_fk_columns(table) }
it 'do have the foreign keys' do
diff --git a/spec/factories/plan_limits.rb b/spec/factories/plan_limits.rb
index b5921c1b311..ad10629af05 100644
--- a/spec/factories/plan_limits.rb
+++ b/spec/factories/plan_limits.rb
@@ -12,6 +12,7 @@ FactoryBot.define do
trait :with_package_file_sizes do
conan_max_file_size { 100 }
+ helm_max_file_size { 100 }
maven_max_file_size { 100 }
npm_max_file_size { 100 }
nuget_max_file_size { 100 }
diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js
index b4067f6a72b..574756322c7 100644
--- a/spec/frontend/projects/pipelines/charts/components/app_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js
@@ -1,11 +1,12 @@
import { GlTabs, GlTab } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
import { merge } from 'lodash';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
import { TEST_HOST } from 'helpers/test_constants';
import { mergeUrlParams, updateHistory, getParameterValues } from '~/lib/utils/url_utility';
import Component from '~/projects/pipelines/charts/components/app.vue';
import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue';
+import API from '~/api';
jest.mock('~/lib/utils/url_utility');
@@ -17,7 +18,7 @@ describe('ProjectsPipelinesChartsApp', () => {
let wrapper;
function createComponent(mountOptions = {}) {
- wrapper = shallowMount(
+ wrapper = shallowMountExtended(
Component,
merge(
{},
@@ -118,6 +119,23 @@ describe('ProjectsPipelinesChartsApp', () => {
expect(updateHistory).not.toHaveBeenCalled();
});
+
+ describe('event tracking', () => {
+ it.each`
+ testId | event
+ ${'pipelines-tab'} | ${'p_analytics_ci_cd_pipelines'}
+ ${'deployment-frequency-tab'} | ${'p_analytics_ci_cd_deployment_frequency'}
+ ${'lead-time-tab'} | ${'p_analytics_ci_cd_lead_time'}
+ `('tracks the $event event when clicked', ({ testId, event }) => {
+ jest.spyOn(API, 'trackRedisHllUserEvent');
+
+ expect(API.trackRedisHllUserEvent).not.toHaveBeenCalled();
+
+ wrapper.findByTestId(testId).vm.$emit('click');
+
+ expect(API.trackRedisHllUserEvent).toHaveBeenCalledWith(event);
+ });
+ });
});
describe('when provided with a query param', () => {
diff --git a/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
new file mode 100644
index 00000000000..adee5b90863
--- /dev/null
+++ b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
@@ -0,0 +1,22 @@
+import { shallowMount } from '@vue/test-utils';
+import Component from '~/repository/components/blob_viewers/pdf_viewer.vue';
+import PdfViewer from '~/blob/pdf/pdf_viewer.vue';
+
+describe('PDF Viewer', () => {
+ let wrapper;
+
+ const propsData = { url: 'some/pdf_blob.pdf' };
+
+ const createComponent = () => {
+ wrapper = shallowMount(Component, { propsData });
+ };
+
+ const findPDFViewer = () => wrapper.findComponent(PdfViewer);
+
+ it('renders a PDF Viewer component', () => {
+ createComponent();
+
+ expect(findPDFViewer().exists()).toBe(true);
+ expect(findPDFViewer().props('pdf')).toBe(propsData.url);
+ });
+});
diff --git a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
index 526f35086d7..7015fe809b0 100644
--- a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
+++ b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
@@ -147,7 +147,7 @@ describe('AdminRunnersApp', () => {
}),
expect.objectContaining({
type: PARAM_KEY_TAG,
- recentTokenValuesStorageKey: `${ADMIN_FILTERED_SEARCH_NAMESPACE}-recent-tags`,
+ recentSuggestionsStorageKey: `${ADMIN_FILTERED_SEARCH_NAMESPACE}-recent-tags`,
}),
]);
});
diff --git a/spec/frontend/runner/components/search_tokens/tag_token_spec.js b/spec/frontend/runner/components/search_tokens/tag_token_spec.js
index 52b87542243..89c06ba2df4 100644
--- a/spec/frontend/runner/components/search_tokens/tag_token_spec.js
+++ b/spec/frontend/runner/components/search_tokens/tag_token_spec.js
@@ -41,7 +41,7 @@ const mockTagTokenConfig = {
title: 'Tags',
type: 'tag',
token: TagToken,
- recentTokenValuesStorageKey: mockStorageKey,
+ recentSuggestionsStorageKey: mockStorageKey,
operators: OPERATOR_IS_ONLY,
};
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
index f9ce0338d2f..28181e30903 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
@@ -46,13 +46,13 @@ const defaultSlots = {
};
const mockProps = {
- config: mockLabelToken,
+ config: { ...mockLabelToken, recentSuggestionsStorageKey: mockStorageKey },
value: { data: '' },
active: false,
suggestions: [],
suggestionsLoading: false,
defaultSuggestions: DEFAULT_NONE_ANY,
- recentSuggestionsStorageKey: mockStorageKey,
+ getActiveTokenValue: (labels, data) => labels.find((label) => label.title === data),
};
function createComponent({
@@ -152,30 +152,22 @@ describe('BaseToken', () => {
describe('methods', () => {
describe('handleTokenValueSelected', () => {
- it('calls `setTokenValueToRecentlyUsed` when `recentSuggestionsStorageKey` is defined', () => {
- const mockTokenValue = {
- id: 1,
- title: 'Foo',
- };
+ const mockTokenValue = mockLabels[0];
- wrapper.vm.handleTokenValueSelected(mockTokenValue);
+ it('calls `setTokenValueToRecentlyUsed` when `recentSuggestionsStorageKey` is defined', () => {
+ wrapper.vm.handleTokenValueSelected(mockTokenValue.title);
expect(setTokenValueToRecentlyUsed).toHaveBeenCalledWith(mockStorageKey, mockTokenValue);
});
it('does not add token from preloadedSuggestions', async () => {
- const mockTokenValue = {
- id: 1,
- title: 'Foo',
- };
-
wrapper.setProps({
preloadedSuggestions: [mockTokenValue],
});
await wrapper.vm.$nextTick();
- wrapper.vm.handleTokenValueSelected(mockTokenValue);
+ wrapper.vm.handleTokenValueSelected(mockTokenValue.title);
expect(setTokenValueToRecentlyUsed).not.toHaveBeenCalled();
});
@@ -190,7 +182,7 @@ describe('BaseToken', () => {
const glFilteredSearchToken = wrapperWithNoStubs.find(GlFilteredSearchToken);
expect(glFilteredSearchToken.exists()).toBe(true);
- expect(glFilteredSearchToken.props('config')).toBe(mockLabelToken);
+ expect(glFilteredSearchToken.props('config')).toEqual(mockProps.config);
wrapperWithNoStubs.destroy();
});
diff --git a/spec/frontend/vue_shared/components/registry/metadata_item_spec.js b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
index 1ccf3ddc5a5..e4abdc15fd5 100644
--- a/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
+++ b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js
@@ -2,7 +2,7 @@ import { GlIcon, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import component from '~/vue_shared/components/registry/metadata_item.vue';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
describe('Metadata Item', () => {
let wrapper;
diff --git a/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js b/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
deleted file mode 100644
index e72b3bf45c4..00000000000
--- a/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-
-import CollapsedGroupedDatePicker from '~/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue';
-import CollapsedCalendarIcon from '~/vue_shared/components/sidebar/collapsed_calendar_icon.vue';
-
-describe('CollapsedGroupedDatePicker', () => {
- let wrapper;
-
- const defaultProps = {
- showToggleSidebar: true,
- };
-
- const minDate = new Date('07/17/2016');
- const maxDate = new Date('07/17/2017');
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = shallowMount(CollapsedGroupedDatePicker, {
- propsData: { ...defaultProps, ...props },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- const findCollapsedCalendarIcon = () => wrapper.findComponent(CollapsedCalendarIcon);
- const findAllCollapsedCalendarIcons = () => wrapper.findAllComponents(CollapsedCalendarIcon);
-
- describe('toggleCollapse events', () => {
- it('should emit when collapsed-calendar-icon is clicked', () => {
- createComponent();
-
- findCollapsedCalendarIcon().trigger('click');
-
- expect(wrapper.emitted('toggleCollapse')[0]).toBeDefined();
- });
- });
-
- describe('minDate and maxDate', () => {
- it('should render both collapsed-calendar-icon', () => {
- createComponent({
- props: {
- minDate,
- maxDate,
- },
- });
-
- const icons = findAllCollapsedCalendarIcons();
-
- expect(icons.length).toBe(2);
- expect(icons.at(0).text()).toBe('Jul 17 2016');
- expect(icons.at(1).text()).toBe('Jul 17 2017');
- });
- });
-
- describe('minDate', () => {
- it('should render minDate in collapsed-calendar-icon', () => {
- createComponent({
- props: {
- minDate,
- },
- });
-
- const icons = findAllCollapsedCalendarIcons();
-
- expect(icons.length).toBe(1);
- expect(icons.at(0).text()).toBe('From Jul 17 2016');
- });
- });
-
- describe('maxDate', () => {
- it('should render maxDate in collapsed-calendar-icon', () => {
- createComponent({
- props: {
- maxDate,
- },
- });
- const icons = findAllCollapsedCalendarIcons();
-
- expect(icons.length).toBe(1);
- expect(icons.at(0).text()).toBe('Until Jul 17 2017');
- });
- });
-
- describe('no dates', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('should render None', () => {
- const icons = findAllCollapsedCalendarIcons();
-
- expect(icons.length).toBe(1);
- expect(icons.at(0).text()).toBe('None');
- });
-
- it('should have tooltip as `Start and due date`', () => {
- const icons = findAllCollapsedCalendarIcons();
-
- expect(icons.at(0).props('tooltipText')).toBe('Start and due date');
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
index 4b97e16f332..9e7e5c1263f 100644
--- a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
+++ b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
@@ -1,7 +1,7 @@
import { mount, shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { hasHorizontalOverflow } from '~/lib/utils/dom_utils';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
const MOCK_TITLE = 'lorem-ipsum-dolar-sit-amit-consectur-adipiscing-elit-sed-do';
diff --git a/spec/lib/api/entities/plan_limit_spec.rb b/spec/lib/api/entities/plan_limit_spec.rb
index 75e39e4f074..1b8b21d47f3 100644
--- a/spec/lib/api/entities/plan_limit_spec.rb
+++ b/spec/lib/api/entities/plan_limit_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe API::Entities::PlanLimit do
expect(subject).to include(
:conan_max_file_size,
:generic_packages_max_file_size,
+ :helm_max_file_size,
:maven_max_file_size,
:npm_max_file_size,
:nuget_max_file_size,
diff --git a/spec/lib/gitlab/database/loose_foreign_keys_spec.rb b/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
index 8c7d0f439ab..13f2d31bc32 100644
--- a/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
+++ b/spec/lib/gitlab/database/loose_foreign_keys_spec.rb
@@ -24,19 +24,19 @@ RSpec.describe Gitlab::Database::LooseForeignKeys do
Gitlab::Database.schemas_to_base_models.fetch(parent_table_schema)
end
- it 'all `from_table` tables are present' do
- definitions.each do |definition|
- base_models_for(definition.from_table).each do |model|
- expect(model.connection).to be_table_exist(definition.from_table)
- end
- end
- end
-
it 'all `to_table` tables are present' do
definitions.each do |definition|
base_models_for(definition.to_table).each do |model|
expect(model.connection).to be_table_exist(definition.to_table)
- expect(model.connection).to be_column_exist(definition.to_table, definition.column)
+ end
+ end
+ end
+
+ it 'all `from_table` tables are present' do
+ definitions.each do |definition|
+ base_models_for(definition.from_table).each do |model|
+ expect(model.connection).to be_table_exist(definition.from_table)
+ expect(model.connection).to be_column_exist(definition.from_table, definition.column)
end
end
end
diff --git a/spec/lib/gitlab/tracking/destinations/snowplow_spec.rb b/spec/lib/gitlab/tracking/destinations/snowplow_spec.rb
index f8e73a807c6..06cc2d3800c 100644
--- a/spec/lib/gitlab/tracking/destinations/snowplow_spec.rb
+++ b/spec/lib/gitlab/tracking/destinations/snowplow_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow do
expect(SnowplowTracker::Tracker)
.to receive(:new)
- .with(emitter, an_instance_of(SnowplowTracker::Subject), Gitlab::Tracking::SNOWPLOW_NAMESPACE, '_abc123_')
+ .with(emitter, an_instance_of(SnowplowTracker::Subject), described_class::SNOWPLOW_NAMESPACE, '_abc123_')
.and_return(tracker)
end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index f147a15615e..f6d3047609e 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -1210,6 +1210,9 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
'i_analytics_cohorts' => 123,
'i_analytics_dev_ops_score' => 123,
'i_analytics_instance_statistics' => 123,
+ 'p_analytics_ci_cd_deployment_frequency' => 123,
+ 'p_analytics_ci_cd_lead_time' => 123,
+ 'p_analytics_ci_cd_pipelines' => 123,
'p_analytics_merge_request' => 123,
'i_analytics_dev_ops_adoption' => 123,
'users_viewing_analytics_group_devops_adoption' => 123,
diff --git a/spec/models/analytics/cycle_analytics/project_stage_spec.rb b/spec/models/analytics/cycle_analytics/project_stage_spec.rb
index 9efe90e7d41..a67f9fec443 100644
--- a/spec/models/analytics/cycle_analytics/project_stage_spec.rb
+++ b/spec/models/analytics/cycle_analytics/project_stage_spec.rb
@@ -29,4 +29,29 @@ RSpec.describe Analytics::CycleAnalytics::ProjectStage do
let(:default_params) { { project: project } }
end
end
+
+ describe '.distinct_stages_within_hierarchy' do
+ let_it_be(:top_level_group) { create(:group) }
+ let_it_be(:sub_group_1) { create(:group, parent: top_level_group) }
+ let_it_be(:sub_group_2) { create(:group, parent: sub_group_1) }
+
+ let_it_be(:project_1) { create(:project, group: sub_group_1) }
+ let_it_be(:project_2) { create(:project, group: sub_group_2) }
+ let_it_be(:project_3) { create(:project, group: top_level_group) }
+
+ let_it_be(:stage1) { create(:cycle_analytics_project_stage, project: project_1, start_event_identifier: :issue_created, end_event_identifier: :issue_deployed_to_production) }
+ let_it_be(:stage2) { create(:cycle_analytics_project_stage, project: project_3, start_event_identifier: :issue_created, end_event_identifier: :issue_deployed_to_production) }
+
+ let_it_be(:stage3) { create(:cycle_analytics_project_stage, project: project_1, start_event_identifier: :merge_request_created, end_event_identifier: :merge_request_merged) }
+ let_it_be(:stage4) { create(:cycle_analytics_project_stage, project: project_3, start_event_identifier: :merge_request_created, end_event_identifier: :merge_request_merged) }
+
+ subject(:distinct_start_and_end_event_identifiers) { described_class.distinct_stages_within_hierarchy(top_level_group).to_a.pluck(:start_event_identifier, :end_event_identifier) }
+
+ it 'returns distinct stages by start and end events (using stage_event_hash_id)' do
+ expect(distinct_start_and_end_event_identifiers).to match_array([
+ %w[issue_created issue_deployed_to_production],
+ %w[merge_request_created merge_request_merged]
+ ])
+ end
+ end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 0b323cc69ed..841608b96fe 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -3180,6 +3180,20 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
+ context 'when an associated environment does not have deployments' do
+ let_it_be(:pipeline) { create(:ci_pipeline, :created) }
+ let_it_be(:build) { create(:ci_build, :stop_review_app, pipeline: pipeline) }
+ let_it_be(:environment) { create(:environment, project: pipeline.project) }
+
+ before_all do
+ build.metadata.update!(expanded_environment_name: environment.name)
+ end
+
+ it 'does not return environments' do
+ expect(subject).to be_empty
+ end
+ end
+
context 'when pipeline is in extended family' do
let_it_be(:parent) { create(:ci_pipeline) }
let_it_be(:parent_build) { create(:ci_build, :with_deployment, environment: 'staging', pipeline: parent) }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 31421dcf40f..a4d4d0a58ff 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -97,32 +97,6 @@ RSpec.describe CommitStatus do
end
end
- describe '.updated_before' do
- let!(:lookback) { 5.days.ago }
- let!(:timeout) { 1.day.ago }
- let!(:before_lookback) { lookback - 1.hour }
- let!(:after_lookback) { lookback + 1.hour }
- let!(:before_timeout) { timeout - 1.hour }
- let!(:after_timeout) { timeout + 1.hour }
-
- subject { described_class.updated_before(lookback: lookback, timeout: timeout) }
-
- def create_build_with_set_timestamps(created_at:, updated_at:)
- travel_to(created_at) { create(:ci_build, created_at: Time.current) }.tap do |build|
- travel_to(updated_at) { build.update!(status: :failed) }
- end
- end
-
- it 'finds builds updated and created in the window between lookback and timeout' do
- build_in_lookback_timeout_window = create_build_with_set_timestamps(created_at: after_lookback, updated_at: before_timeout)
- build_outside_lookback_window = create_build_with_set_timestamps(created_at: before_lookback, updated_at: before_timeout)
- build_outside_timeout_window = create_build_with_set_timestamps(created_at: after_lookback, updated_at: after_timeout)
-
- expect(subject).to contain_exactly(build_in_lookback_timeout_window)
- expect(subject).not_to include(build_outside_lookback_window, build_outside_timeout_window)
- end
- end
-
describe '.scheduled_at_before' do
let!(:never_scheduled) { create(:commit_status) }
let!(:stale_scheduled) { create(:commit_status, scheduled_at: 1.day.ago) }
diff --git a/spec/models/instance_configuration_spec.rb b/spec/models/instance_configuration_spec.rb
index cc0b69e3526..698d74abf03 100644
--- a/spec/models/instance_configuration_spec.rb
+++ b/spec/models/instance_configuration_spec.rb
@@ -144,6 +144,7 @@ RSpec.describe InstanceConfiguration do
create(:plan_limits,
plan: plan1,
conan_max_file_size: 1001,
+ helm_max_file_size: 1008,
maven_max_file_size: 1002,
npm_max_file_size: 1003,
nuget_max_file_size: 1004,
@@ -154,6 +155,7 @@ RSpec.describe InstanceConfiguration do
create(:plan_limits,
plan: plan2,
conan_max_file_size: 1101,
+ helm_max_file_size: 1108,
maven_max_file_size: 1102,
npm_max_file_size: 1103,
nuget_max_file_size: 1104,
@@ -166,8 +168,8 @@ RSpec.describe InstanceConfiguration do
it 'returns package file size limits' do
file_size_limits = subject.settings[:package_file_size_limits]
- expect(file_size_limits[:Plan1]).to eq({ conan: 1001, maven: 1002, npm: 1003, nuget: 1004, pypi: 1005, terraform_module: 1006, generic: 1007 })
- expect(file_size_limits[:Plan2]).to eq({ conan: 1101, maven: 1102, npm: 1103, nuget: 1104, pypi: 1105, terraform_module: 1106, generic: 1107 })
+ expect(file_size_limits[:Plan1]).to eq({ conan: 1001, helm: 1008, maven: 1002, npm: 1003, nuget: 1004, pypi: 1005, terraform_module: 1006, generic: 1007 })
+ expect(file_size_limits[:Plan2]).to eq({ conan: 1101, helm: 1108, maven: 1102, npm: 1103, nuget: 1104, pypi: 1105, terraform_module: 1106, generic: 1107 })
end
end
diff --git a/spec/requests/api/admin/plan_limits_spec.rb b/spec/requests/api/admin/plan_limits_spec.rb
index f497227789a..03642ad617e 100644
--- a/spec/requests/api/admin/plan_limits_spec.rb
+++ b/spec/requests/api/admin/plan_limits_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response).to be_an Hash
expect(json_response['conan_max_file_size']).to eq(Plan.default.actual_limits.conan_max_file_size)
expect(json_response['generic_packages_max_file_size']).to eq(Plan.default.actual_limits.generic_packages_max_file_size)
+ expect(json_response['helm_max_file_size']).to eq(Plan.default.actual_limits.helm_max_file_size)
expect(json_response['maven_max_file_size']).to eq(Plan.default.actual_limits.maven_max_file_size)
expect(json_response['npm_max_file_size']).to eq(Plan.default.actual_limits.npm_max_file_size)
expect(json_response['nuget_max_file_size']).to eq(Plan.default.actual_limits.nuget_max_file_size)
@@ -45,6 +46,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response).to be_an Hash
expect(json_response['conan_max_file_size']).to eq(Plan.default.actual_limits.conan_max_file_size)
expect(json_response['generic_packages_max_file_size']).to eq(Plan.default.actual_limits.generic_packages_max_file_size)
+ expect(json_response['helm_max_file_size']).to eq(Plan.default.actual_limits.helm_max_file_size)
expect(json_response['maven_max_file_size']).to eq(Plan.default.actual_limits.maven_max_file_size)
expect(json_response['npm_max_file_size']).to eq(Plan.default.actual_limits.npm_max_file_size)
expect(json_response['nuget_max_file_size']).to eq(Plan.default.actual_limits.nuget_max_file_size)
@@ -84,6 +86,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'plan_name': 'default',
'conan_max_file_size': 10,
'generic_packages_max_file_size': 20,
+ 'helm_max_file_size': 25,
'maven_max_file_size': 30,
'npm_max_file_size': 40,
'nuget_max_file_size': 50,
@@ -95,6 +98,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response).to be_an Hash
expect(json_response['conan_max_file_size']).to eq(10)
expect(json_response['generic_packages_max_file_size']).to eq(20)
+ expect(json_response['helm_max_file_size']).to eq(25)
expect(json_response['maven_max_file_size']).to eq(30)
expect(json_response['npm_max_file_size']).to eq(40)
expect(json_response['nuget_max_file_size']).to eq(50)
@@ -129,6 +133,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'plan_name': 'default',
'conan_max_file_size': 'a',
'generic_packages_max_file_size': 'b',
+ 'helm_max_file_size': 'h',
'maven_max_file_size': 'c',
'npm_max_file_size': 'd',
'nuget_max_file_size': 'e',
@@ -140,8 +145,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response['error']).to include(
'conan_max_file_size is invalid',
'generic_packages_max_file_size is invalid',
+ 'helm_max_file_size is invalid',
'maven_max_file_size is invalid',
- 'generic_packages_max_file_size is invalid',
'npm_max_file_size is invalid',
'nuget_max_file_size is invalid',
'pypi_max_file_size is invalid',
diff --git a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
index 195aac2e5f0..f627f207d98 100644
--- a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
@@ -131,8 +131,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
let(:send_request) { subject }
end
- it 'updates runner info' do
- expect { subject }.to change { runner.reload.contacted_at }
+ it "doesn't update runner info" do
+ expect { subject }.not_to change { runner.reload.contacted_at }
end
shared_examples 'authorizes local file' do
@@ -280,8 +280,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
end
- it 'updates runner info' do
- expect { upload_artifacts(file_upload, headers_with_token) }.to change { runner.reload.contacted_at }
+ it "doesn't update runner info" do
+ expect { upload_artifacts(file_upload, headers_with_token) }.not_to change { runner.reload.contacted_at }
end
context 'when the artifact is too large' do
@@ -812,8 +812,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
let(:send_request) { download_artifact }
end
- it 'updates runner info' do
- expect { download_artifact }.to change { runner.reload.contacted_at }
+ it "doesn't update runner info" do
+ expect { download_artifact }.not_to change { runner.reload.contacted_at }
end
context 'when job has artifacts' do
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index ab0c76397e4..7aa3cfec986 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -520,7 +520,7 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac
let(:head_response) { { status: :success } }
before do
- allow_next_instance_of(DependencyProxy::FindOrCreateManifestService) do |instance|
+ allow_next_instance_of(DependencyProxy::FindCachedManifestService) do |instance|
allow(instance).to receive(:execute).and_return(pull_response)
end
allow_next_instance_of(DependencyProxy::HeadManifestService) do |instance|
diff --git a/spec/services/ci/stuck_builds/drop_pending_service_spec.rb b/spec/services/ci/stuck_builds/drop_pending_service_spec.rb
index aa0526edf57..ebc57af77a0 100644
--- a/spec/services/ci/stuck_builds/drop_pending_service_spec.rb
+++ b/spec/services/ci/stuck_builds/drop_pending_service_spec.rb
@@ -3,8 +3,12 @@
require 'spec_helper'
RSpec.describe Ci::StuckBuilds::DropPendingService do
- let!(:runner) { create :ci_runner }
- let!(:job) { create :ci_build, runner: runner }
+ let_it_be(:runner) { create(:ci_runner) }
+ let_it_be(:pipeline) { create(:ci_empty_pipeline) }
+ let_it_be_with_reload(:job) do
+ create(:ci_build, pipeline: pipeline, runner: runner)
+ end
+
let(:created_at) { }
let(:updated_at) { }
@@ -14,6 +18,8 @@ RSpec.describe Ci::StuckBuilds::DropPendingService do
job_attributes = { status: status }
job_attributes[:created_at] = created_at if created_at
job_attributes[:updated_at] = updated_at if updated_at
+ job_attributes.compact!
+
job.update!(job_attributes)
end
@@ -41,12 +47,6 @@ RSpec.describe Ci::StuckBuilds::DropPendingService do
it_behaves_like 'job is dropped with failure reason', 'stuck_or_timeout_failure'
end
-
- context 'when created_at is outside lookback window' do
- let(:created_at) { described_class::BUILD_LOOKBACK - 1.day }
-
- it_behaves_like 'job is unchanged'
- end
end
context 'when job was updated less than 1 day ago' do
@@ -63,12 +63,6 @@ RSpec.describe Ci::StuckBuilds::DropPendingService do
it_behaves_like 'job is unchanged'
end
-
- context 'when created_at is outside lookback window' do
- let(:created_at) { described_class::BUILD_LOOKBACK - 1.day }
-
- it_behaves_like 'job is unchanged'
- end
end
context 'when job was updated more than 1 hour ago' do
@@ -85,12 +79,6 @@ RSpec.describe Ci::StuckBuilds::DropPendingService do
it_behaves_like 'job is unchanged'
end
-
- context 'when created_at is outside lookback window' do
- let(:created_at) { described_class::BUILD_LOOKBACK - 1.day }
-
- it_behaves_like 'job is unchanged'
- end
end
end
@@ -115,12 +103,6 @@ RSpec.describe Ci::StuckBuilds::DropPendingService do
it_behaves_like 'job is dropped with failure reason', 'stuck_or_timeout_failure'
end
-
- context 'when created_at is outside lookback window' do
- let(:created_at) { described_class::BUILD_LOOKBACK - 1.day }
-
- it_behaves_like 'job is unchanged'
- end
end
context 'when job was updated in less than 1 hour ago' do
@@ -137,12 +119,6 @@ RSpec.describe Ci::StuckBuilds::DropPendingService do
it_behaves_like 'job is unchanged'
end
-
- context 'when created_at is outside lookback window' do
- let(:created_at) { described_class::BUILD_LOOKBACK - 1.day }
-
- it_behaves_like 'job is unchanged'
- end
end
end
end
@@ -179,12 +155,6 @@ RSpec.describe Ci::StuckBuilds::DropPendingService do
it_behaves_like 'job is unchanged'
end
-
- context 'when created_at is outside lookback window' do
- let(:created_at) { described_class::BUILD_LOOKBACK - 1.day }
-
- it_behaves_like 'job is unchanged'
- end
end
end
diff --git a/spec/services/dependency_proxy/find_or_create_manifest_service_spec.rb b/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
similarity index 74%
rename from spec/services/dependency_proxy/find_or_create_manifest_service_spec.rb
rename to spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
index ef608c9b113..29bdf1f11c3 100644
--- a/spec/services/dependency_proxy/find_or_create_manifest_service_spec.rb
+++ b/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe DependencyProxy::FindOrCreateManifestService do
+RSpec.describe DependencyProxy::FindCachedManifestService do
include DependencyProxyHelpers
let_it_be(:image) { 'alpine' }
@@ -49,14 +49,6 @@ RSpec.describe DependencyProxy::FindOrCreateManifestService do
end
it_behaves_like 'returning no manifest'
-
- context 'with dependency_proxy_manifest_workhorse feature disabled' do
- before do
- stub_feature_flags(dependency_proxy_manifest_workhorse: false)
- end
-
- it_behaves_like 'downloading the manifest'
- end
end
context 'failed head request' do
@@ -66,14 +58,6 @@ RSpec.describe DependencyProxy::FindOrCreateManifestService do
end
it_behaves_like 'returning no manifest'
-
- context 'with dependency_proxy_manifest_workhorse feature disabled' do
- before do
- stub_feature_flags(dependency_proxy_manifest_workhorse: false)
- end
-
- it_behaves_like 'downloading the manifest'
- end
end
end
@@ -105,20 +89,6 @@ RSpec.describe DependencyProxy::FindOrCreateManifestService do
end
it_behaves_like 'returning no manifest'
-
- context 'with dependency_proxy_manifest_workhorse feature disabled' do
- before do
- stub_feature_flags(dependency_proxy_manifest_workhorse: false)
- end
-
- it 'downloads the new manifest and updates the existing record', :aggregate_failures do
- expect(subject[:status]).to eq(:success)
- expect(subject[:manifest]).to eq(dependency_proxy_manifest)
- expect(subject[:manifest].content_type).to eq(content_type)
- expect(subject[:manifest].digest).to eq(digest)
- expect(subject[:from_cache]).to eq false
- end
- end
end
context 'when the cached manifest is expired' do
@@ -129,14 +99,6 @@ RSpec.describe DependencyProxy::FindOrCreateManifestService do
end
it_behaves_like 'returning no manifest'
-
- context 'with dependency_proxy_manifest_workhorse feature disabled' do
- before do
- stub_feature_flags(dependency_proxy_manifest_workhorse: false)
- end
-
- it_behaves_like 'downloading the manifest'
- end
end
context 'failed connection' do
diff --git a/spec/services/dependency_proxy/pull_manifest_service_spec.rb b/spec/services/dependency_proxy/pull_manifest_service_spec.rb
deleted file mode 100644
index 6018a3229fb..00000000000
--- a/spec/services/dependency_proxy/pull_manifest_service_spec.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe DependencyProxy::PullManifestService do
- include DependencyProxyHelpers
-
- let(:image) { 'alpine' }
- let(:tag) { '3.9' }
- let(:token) { Digest::SHA256.hexdigest('123') }
- let(:manifest) { { foo: 'bar' }.to_json }
- let(:digest) { '12345' }
- let(:content_type) { 'foo' }
- let(:headers) do
- { DependencyProxy::Manifest::DIGEST_HEADER => digest, 'content-type' => content_type }
- end
-
- subject { described_class.new(image, tag, token).execute_with_manifest(&method(:check_response)) }
-
- context 'remote request is successful' do
- before do
- stub_manifest_download(image, tag, headers: headers)
- end
-
- it 'successfully returns the manifest' do
- def check_response(response)
- response[:file].rewind
-
- expect(response[:status]).to eq(:success)
- expect(response[:file].read).to eq(manifest)
- expect(response[:digest]).to eq(digest)
- expect(response[:content_type]).to eq(content_type)
- end
-
- subject
- end
- end
-
- context 'remote request is not found' do
- before do
- stub_manifest_download(image, tag, status: 404, body: 'Not found')
- end
-
- it 'returns a 404 not found error' do
- def check_response(response)
- expect(response[:status]).to eq(:error)
- expect(response[:http_status]).to eq(404)
- expect(response[:message]).to eq('Not found')
- end
-
- subject
- end
- end
-
- context 'net timeout exception' do
- before do
- manifest_link = DependencyProxy::Registry.manifest_url(image, tag)
-
- stub_full_request(manifest_link).to_timeout
- end
-
- it 'returns a 599 error' do
- def check_response(response)
- expect(response[:status]).to eq(:error)
- expect(response[:http_status]).to eq(599)
- expect(response[:message]).to eq('execution expired')
- end
-
- subject
- end
- end
-
- context 'no block is given' do
- subject { described_class.new(image, tag, token).execute_with_manifest }
-
- it { expect { subject }.to raise_error(ArgumentError, 'Block must be provided') }
- end
-end
diff --git a/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb b/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
index f92f918ffd4..ac9b01be0b5 100644
--- a/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
+++ b/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
@@ -24,8 +24,8 @@ RSpec.describe LooseForeignKeys::BatchCleanerService do
let(:loose_foreign_key_definitions) do
[
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
- '_test_loose_fk_parent_table',
'_test_loose_fk_child_table_1',
+ '_test_loose_fk_parent_table',
{
column: 'parent_id',
on_delete: :async_delete,
@@ -33,8 +33,8 @@ RSpec.describe LooseForeignKeys::BatchCleanerService do
}
),
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
- '_test_loose_fk_parent_table',
'_test_loose_fk_child_table_2',
+ '_test_loose_fk_parent_table',
{
column: 'parent_id_with_different_column',
on_delete: :async_nullify,
diff --git a/spec/services/loose_foreign_keys/cleaner_service_spec.rb b/spec/services/loose_foreign_keys/cleaner_service_spec.rb
index 8f992ec4fd0..2cfd8385953 100644
--- a/spec/services/loose_foreign_keys/cleaner_service_spec.rb
+++ b/spec/services/loose_foreign_keys/cleaner_service_spec.rb
@@ -13,8 +13,8 @@ RSpec.describe LooseForeignKeys::CleanerService do
let(:loose_fk_definition) do
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
- 'projects',
'issues',
+ 'projects',
{
column: 'project_id',
on_delete: :async_nullify,
@@ -80,8 +80,8 @@ RSpec.describe LooseForeignKeys::CleanerService do
let(:loose_fk_definition) do
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
- 'users',
'project_authorizations',
+ 'users',
{
column: 'user_id',
on_delete: :async_delete,
diff --git a/spec/support/shared_examples/controllers/unique_visits_shared_examples.rb b/spec/support/shared_examples/controllers/unique_visits_shared_examples.rb
index 30914e61df0..ac7680f7ddb 100644
--- a/spec/support/shared_examples/controllers/unique_visits_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/unique_visits_shared_examples.rb
@@ -6,15 +6,23 @@ RSpec.shared_examples 'tracking unique visits' do |method|
let(:request_params) { {} }
it 'tracks unique visit if the format is HTML' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter)
- .to receive(:track_event).with(target_id, values: kind_of(String))
+ ids = target_id.instance_of?(String) ? [target_id] : target_id
+
+ ids.each do |id|
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .to receive(:track_event).with(id, values: kind_of(String))
+ end
get method, params: request_params, format: :html
end
it 'tracks unique visit if DNT is not enabled' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter)
- .to receive(:track_event).with(target_id, values: kind_of(String))
+ ids = target_id.instance_of?(String) ? [target_id] : target_id
+
+ ids.each do |id|
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .to receive(:track_event).with(id, values: kind_of(String))
+ end
stub_do_not_track('0')
diff --git a/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb b/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb
index 72e32643a49..18a2e29adab 100644
--- a/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb
+++ b/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb
@@ -28,6 +28,9 @@ RSpec.describe 'admin/application_settings/_package_registry' do
expect(rendered).to have_field('Maximum Conan package file size in bytes', type: 'number')
expect(page.find_field('Maximum Conan package file size in bytes').value).to eq(default_plan_limits.conan_max_file_size.to_s)
+ expect(rendered).to have_field('Maximum Helm chart file size in bytes', type: 'number')
+ expect(page.find_field('Maximum Helm chart file size in bytes').value).to eq(default_plan_limits.helm_max_file_size.to_s)
+
expect(rendered).to have_field('Maximum Maven package file size in bytes', type: 'number')
expect(page.find_field('Maximum Maven package file size in bytes').value).to eq(default_plan_limits.maven_max_file_size.to_s)
diff --git a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
index 6d67be61167..3c628d036ff 100644
--- a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
+++ b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
@@ -31,8 +31,8 @@ RSpec.describe LooseForeignKeys::CleanupWorker do
{
'_test_loose_fk_parent_table_1' => [
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
- '_test_loose_fk_parent_table_1',
'_test_loose_fk_child_table_1_1',
+ '_test_loose_fk_parent_table_1',
{
column: 'parent_id',
on_delete: :async_delete,
@@ -40,8 +40,8 @@ RSpec.describe LooseForeignKeys::CleanupWorker do
}
),
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
- '_test_loose_fk_parent_table_1',
'_test_loose_fk_child_table_1_2',
+ '_test_loose_fk_parent_table_1',
{
column: 'parent_id_with_different_column',
on_delete: :async_nullify,
@@ -51,8 +51,8 @@ RSpec.describe LooseForeignKeys::CleanupWorker do
],
'_test_loose_fk_parent_table_2' => [
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
- '_test_loose_fk_parent_table_2',
'_test_loose_fk_child_table_2_1',
+ '_test_loose_fk_parent_table_2',
{
column: 'parent_id',
on_delete: :async_delete,