Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-04-08 15:14:25 +00:00
parent 7de415dd5f
commit bba263d1a3
91 changed files with 678 additions and 309 deletions

View File

@ -67,6 +67,10 @@ start-as-if-foss:
variables:
START_AS_IF_FOSS: $START_AS_IF_FOSS
RUBY_VERSION: $RUBY_VERSION
# Fake merge request variables to make `detect-tests` work from FOSS
CI_MERGE_REQUEST_PROJECT_PATH: $CI_MERGE_REQUEST_PROJECT_PATH
CI_MERGE_REQUEST_IID: $CI_MERGE_REQUEST_IID
# Enabling each individual jobs
ENABLE_RSPEC: $ENABLE_RSPEC
ENABLE_RSPEC_FAST_SPEC_HELPER: $ENABLE_RSPEC_FAST_SPEC_HELPER
ENABLE_RSPEC_PRAEFECT: $ENABLE_RSPEC_PRAEFECT
@ -85,11 +89,13 @@ start-as-if-foss:
ENABLE_COMPILE_STORYBOOK: $ENABLE_COMPILE_STORYBOOK
ENABLE_COMPILE_TEST_ASSETS: $ENABLE_COMPILE_TEST_ASSETS
ENABLE_CACHE_ASSETS: $ENABLE_CACHE_ASSETS
ENABLE_DETECT_TESTS: $ENABLE_DETECT_TESTS
ENABLE_ESLINT: $ENABLE_ESLINT
ENABLE_GENERATE_APOLLO_GRAPHQL_SCHEMA: $ENABLE_GENERATE_APOLLO_GRAPHQL_SCHEMA
ENABLE_GRAPHQL_SCHEMA_DUMP: $ENABLE_GRAPHQL_SCHEMA_DUMP
ENABLE_JEST: $ENABLE_JEST
ENABLE_JEST_INTEGRATION: $ENABLE_JEST_INTEGRATION
ENABLE_RUBOCOP: $ENABLE_RUBOCOP
ENABLE_QA_INTERNAL: $ENABLE_QA_INTERNAL
ENABLE_QA_SELECTORS: $ENABLE_QA_SELECTORS
ENABLE_STATIC_ANALYSIS: $ENABLE_STATIC_ANALYSIS

View File

@ -2205,6 +2205,7 @@
.rails:rules:detect-tests:
rules:
- if: '$ENABLE_DETECT_TESTS == "true"'
- <<: *if-merge-request-labels-run-all-rspec
- <<: *if-merge-request
changes: *code-backstage-qa-patterns
@ -2347,6 +2348,7 @@
.static-analysis:rules:rubocop:
rules:
- if: '$ENABLE_RUBOCOP == "true"'
- <<: *if-default-refs
changes: *rubocop-patterns
variables:

View File

@ -528,7 +528,7 @@ group :test do
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
gem 'derailed_benchmarks', require: false # rubocop:todo Gemfile/MissingFeatureCategory
gem 'gitlab_quality-test_tooling', '~> 1.21.0', require: false, feature_category: :tooling
gem 'gitlab_quality-test_tooling', '~> 1.21.1', require: false, feature_category: :tooling
end
gem 'octokit', '~> 8.0', feature_category: :importers

View File

@ -226,7 +226,7 @@
{"name":"gitlab-styles","version":"11.0.0","platform":"ruby","checksum":"0dd8ec066ce9955ac51d3616c6bfded30f75bb526f39ff392ece6f43d5b9406b"},
{"name":"gitlab_chronic_duration","version":"0.12.0","platform":"ruby","checksum":"0d766944d415b5c831f176871ee8625783fc0c5bfbef2d79a3a616f207ffc16d"},
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
{"name":"gitlab_quality-test_tooling","version":"1.21.0","platform":"ruby","checksum":"b83555c80cffe5ef2709eb6e8674a4942c1bd44a47abea83effc19908d5a0b2c"},
{"name":"gitlab_quality-test_tooling","version":"1.21.1","platform":"ruby","checksum":"83f2a115d21e921b0b540ba87765cad98f0766178244abc3d06d18dd1bd58ebc"},
{"name":"globalid","version":"1.1.0","platform":"ruby","checksum":"b337e1746f0c8cb0a6c918234b03a1ddeb4966206ce288fbb57779f59b2d154f"},
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
{"name":"google-apis-androidpublisher_v3","version":"0.34.0","platform":"ruby","checksum":"d7e1d7dd92f79c498fe2082222a1740d788e022e660c135564b3fd299cab5425"},

View File

@ -741,7 +741,7 @@ GEM
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
gitlab_quality-test_tooling (1.21.0)
gitlab_quality-test_tooling (1.21.1)
activesupport (>= 6.1, < 7.2)
amatch (~> 0.4.1)
gitlab (~> 4.19)
@ -1929,7 +1929,7 @@ DEPENDENCIES
gitlab-utils!
gitlab_chronic_duration (~> 0.12)
gitlab_omniauth-ldap (~> 2.2.0)
gitlab_quality-test_tooling (~> 1.21.0)
gitlab_quality-test_tooling (~> 1.21.1)
gon (~> 6.4.0)
google-apis-androidpublisher_v3 (~> 0.34.0)
google-apis-cloudbilling_v1 (~> 0.21.0)

View File

@ -35,6 +35,7 @@ export default () => {
expirationPolicy,
isGroupPage,
isAdmin,
isMetadataDatabaseEnabled,
showCleanupPolicyLink,
showContainerRegistrySettings,
showUnfinishedTagCleanupCallout,
@ -74,6 +75,7 @@ export default () => {
showUnfinishedTagCleanupCallout: parseBoolean(showUnfinishedTagCleanupCallout),
connectionError: parseBoolean(connectionError),
invalidPathError: parseBoolean(invalidPathError),
isMetadataDatabaseEnabled: parseBoolean(isMetadataDatabaseEnabled),
},
/* eslint-disable @gitlab/require-i18n-strings */
dockerBuildCommand: `docker build -t ${config.repositoryUrl} .`,

View File

@ -16,11 +16,11 @@ import { fetchPolicies } from '~/lib/graphql';
import Tracking from '~/tracking';
import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
import MetadataDatabaseAlert from '~/packages_and_registries/shared/components/container_registry_metadata_database_alert.vue';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
import DeleteImage from '../components/delete_image.vue';
import RegistryHeader from '../components/list_page/registry_header.vue';
import DeleteModal from '../components/delete_modal.vue';
import {
DELETE_IMAGE_SUCCESS_MESSAGE,
DELETE_IMAGE_ERROR_MESSAGE,
@ -64,6 +64,7 @@ export default {
GlSkeletonLoader,
RegistryHeader,
DeleteImage,
MetadataDatabaseAlert,
PersistedPagination,
PersistedSearch,
},
@ -233,6 +234,7 @@ export default {
<template>
<div>
<metadata-database-alert v-if="!config.isMetadataDatabaseEnabled" />
<gl-alert
v-if="showDeleteAlert"
:variant="deleteAlertType"

View File

@ -9,6 +9,7 @@ import {
import ContainerExpirationPolicy from '~/packages_and_registries/settings/project/components/container_expiration_policy.vue';
import ContainerProtectionRules from '~/packages_and_registries/settings/project/components/container_protection_rules.vue';
import PackagesCleanupPolicy from '~/packages_and_registries/settings/project/components/packages_cleanup_policy.vue';
import MetadataDatabaseAlert from '~/packages_and_registries/shared/components/container_registry_metadata_database_alert.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
@ -20,6 +21,7 @@ export default {
'ee_component/packages_and_registries/settings/project/components/dependency_proxy_packages_settings.vue'
),
GlAlert,
MetadataDatabaseAlert,
PackagesCleanupPolicy,
PackagesProtectionRules: () =>
import('~/packages_and_registries/settings/project/components/packages_protection_rules.vue'),
@ -29,6 +31,7 @@ export default {
'showContainerRegistrySettings',
'showPackageRegistrySettings',
'showDependencyProxySettings',
'isContainerRegistryMetadataDatabaseEnabled',
],
i18n: {
UPDATE_SETTINGS_SUCCESS_MESSAGE,
@ -67,6 +70,7 @@ export default {
<template>
<div data-testid="packages-and-registries-project-settings">
<metadata-database-alert v-if="!isContainerRegistryMetadataDatabaseEnabled" class="gl-mt-5" />
<gl-alert
v-if="showAlert"
variant="success"

View File

@ -21,6 +21,7 @@ export default () => {
cleanupSettingsPath,
tagsRegexHelpPagePath,
helpPagePath,
isContainerRegistryMetadataDatabaseEnabled,
showContainerRegistrySettings,
showPackageRegistrySettings,
showDependencyProxySettings,
@ -39,6 +40,9 @@ export default () => {
cleanupSettingsPath,
tagsRegexHelpPagePath,
helpPagePath,
isContainerRegistryMetadataDatabaseEnabled: parseBoolean(
isContainerRegistryMetadataDatabaseEnabled,
),
showContainerRegistrySettings: parseBoolean(showContainerRegistrySettings),
showPackageRegistrySettings: parseBoolean(showPackageRegistrySettings),
showDependencyProxySettings: parseBoolean(showDependencyProxySettings),

View File

@ -0,0 +1,47 @@
<script>
import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import { getCookie, parseBoolean, setCookie } from '~/lib/utils/common_utils';
import { helpPagePath } from '~/helpers/help_page_helper';
const HIDE_METADATA_DATABASE_ALERT_COOKIE = 'hide_metadata_database_alert';
export default {
name: 'ContainerRegistryMetadataDatabaseAlert',
components: {
GlAlert,
GlLink,
GlSprintf,
},
data() {
return {
showAlert: !parseBoolean(getCookie(HIDE_METADATA_DATABASE_ALERT_COOKIE)),
};
},
metadataDatabaseHelpPagePath: helpPagePath(
'administration/packages/container_registry_metadata_database',
),
methods: {
hideAlert() {
this.showAlert = false;
setCookie(HIDE_METADATA_DATABASE_ALERT_COOKIE, 'true');
this.$emit('dismiss');
},
},
};
</script>
<template>
<gl-alert v-if="showAlert" class="gl-mt-5" @dismiss="hideAlert">
<gl-sprintf
:message="
s__(
'ContainerRegistry|The %{linkStart}next-generation container registry%{linkEnd} is now available for upgrade and testing on self-managed instances as a Beta feature. This upgraded registry supports online garbage collection, and has significant performance and reliability improvements.',
)
"
>
<template #link="{ content }">
<gl-link :href="$options.metadataDatabaseHelpPagePath"> {{ content }}</gl-link>
</template>
</gl-sprintf>
</gl-alert>
</template>

View File

@ -21,7 +21,13 @@ module Ci
title = s_("Runners|Runner has never contacted this instance")
icon = 'warning-solid'
when :offline
title = s_("Runners|Runner is offline; last contact was %{runner_contact} ago") % { runner_contact: time_ago_in_words(contacted_at) }
title =
if contacted_at
s_("Runners|Runner is offline; last contact was %{runner_contact} ago") % { runner_contact: time_ago_in_words(contacted_at) }
else
s_("Runners|Runner is offline; it has never contacted this instance")
end
icon = 'status-waiting'
span_class = 'gl-text-gray-500'
when :stale

View File

@ -80,27 +80,28 @@ module PackagesHelper
Ability.allowed?(current_user, :destroy_package, group)
end
def cleanup_settings_data
def cleanup_settings_data(project)
{
project_id: @project.id,
project_path: @project.full_path,
project_id: project.id,
project_path: project.full_path,
cadence_options: cadence_options.to_json,
keep_n_options: keep_n_options.to_json,
older_than_options: older_than_options.to_json,
is_admin: current_user&.admin.to_s,
admin_settings_path: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'),
project_settings_path: project_settings_packages_and_registries_path(@project),
project_settings_path: project_settings_packages_and_registries_path(project),
enable_historic_entries: container_expiration_policies_historic_entry_enabled?.to_s,
help_page_path: help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'cleanup-policy'),
show_cleanup_policy_link: show_cleanup_policy_link(@project).to_s,
show_cleanup_policy_link: show_cleanup_policy_link(project).to_s,
tags_regex_help_page_path: help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'regex-pattern-examples')
}
end
def settings_data(project)
cleanup_settings_data.merge(
cleanup_settings_data(project).merge(
show_container_registry_settings: show_container_registry_settings(project).to_s,
show_package_registry_settings: show_package_registry_settings(project).to_s,
is_container_registry_metadata_database_enabled: (show_container_registry_settings(project) && ContainerRegistry::GitlabApiClient.supports_gitlab_api?).to_s,
cleanup_settings_path: cleanup_image_tags_project_settings_packages_and_registries_path(project)
)
end

View File

@ -1413,8 +1413,6 @@ module Ci
end
def cancel_async_on_job_failure
return unless Feature.enabled?(:auto_cancel_pipeline_on_job_failure, project)
case auto_cancel_on_job_failure
when 'none'
# no-op

View File

@ -34,6 +34,11 @@ module Ci
project_type: 3
}
enum creation_state: {
started: 0,
finished: 100
}, _suffix: true
enum registration_type: {
registration_token: 0,
authenticated_user: 1
@ -454,7 +459,11 @@ module Ci
#
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config, :executor) || {}
values[:contacted_at] = Time.current if update_contacted_at
if update_contacted_at
values.merge!(contacted_at: Time.current, creation_state: :finished)
end
if values.include?(:executor)
values[:executor_type] = EXECUTOR_NAME_TO_TYPES.fetch(values.delete(:executor), :unknown)
end

View File

@ -17,6 +17,11 @@ module Ci
belongs_to :runner
enum creation_state: {
started: 0,
finished: 100
}, _suffix: true
has_many :runner_manager_builds, inverse_of: :runner_manager, foreign_key: :runner_machine_id,
class_name: 'Ci::RunnerManagerBuild'
has_many :builds, through: :runner_manager_builds, class_name: 'Ci::Build'
@ -109,7 +114,9 @@ module Ci
#
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config, :executor) || {}
values[:contacted_at] = Time.current if update_contacted_at
values.merge!(contacted_at: Time.current, creation_state: :finished) if update_contacted_at
if values.include?(:executor)
values[:executor_type] = Ci::Runner::EXECUTOR_NAME_TO_TYPES.fetch(values.delete(:executor), :unknown)
end

View File

@ -32,7 +32,7 @@ module Ci
def status
return :stale if stale?
return :never_contacted unless contacted_at
return :never_contacted unless finished_creation_state?
online? ? :online : :offline
end

View File

@ -3,5 +3,13 @@
module Achievements
class AchievementPolicy < ::BasePolicy
delegate { @subject.namespace }
condition(:achievement_recipient, scope: :subject) do
@user && @user.user_achievements.any? { |user_achievement| user_achievement.achievement_id == @subject.id }
end
rule { achievement_recipient }.policy do
enable :read_achievement
end
end
end

View File

@ -2,14 +2,15 @@
module Achievements
class UserAchievementPolicy < ::BasePolicy
delegate { @subject.achievement }
delegate { @subject.achievement.namespace }
delegate { @subject.user }
condition(:user_is_owner) { @subject.user == @user }
condition(:user_is_recipient) { @subject.user == @user }
rule { can?(:read_user_profile) | can?(:admin_achievement) }.enable :read_user_achievement
rule { user_is_owner }.enable :update_owned_user_achievement
rule { user_is_recipient }.enable :update_owned_user_achievement
rule { can?(:update_owned_user_achievement) }.enable :update_user_achievement

View File

@ -165,16 +165,23 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :read_namespace
end
rule { achievements_enabled }.policy do
rule { ~achievements_enabled }.policy do
prevent :read_achievement
prevent :admin_achievement
prevent :award_achievement
prevent :destroy_user_achievement
end
rule { can?(:read_group) }.policy do
enable :read_achievement
end
rule { can?(:maintainer_access) & achievements_enabled }.policy do
rule { can?(:maintainer_access) }.policy do
enable :admin_achievement
enable :award_achievement
end
rule { can?(:owner_access) & achievements_enabled }.policy do
rule { can?(:owner_access) }.policy do
enable :destroy_user_achievement
end

View File

@ -19,4 +19,5 @@
invalid_path_error: (!!@invalid_path_error).to_s,
user_callouts_path: callouts_path,
user_callout_id: Users::CalloutsHelper::UNFINISHED_TAG_CLEANUP_CALLOUT,
is_metadata_database_enabled: ContainerRegistry::GitlabApiClient.supports_gitlab_api?.to_s,
show_unfinished_tag_cleanup_callout: show_unfinished_tag_cleanup_callout?.to_s } }

View File

@ -5,9 +5,9 @@
- if total > 0
- final_text = n_("%d approver", "%d approvers", total) % total
- final_self_text = n_("%d approver (you've approved)", "%d approvers (you've approved)", total) % total
- approval_tooltip = self_approved ? final_self_text : final_text
- approval_icon = 'check'
- badge_variant = :success
- badge_label = _("Approved")
- approval_icon = sprite_icon((self_approved ? 'approval-solid' : 'approval'), css_class: 'align-middle')
%li.gl-display-none.gl-sm-display-inline-block.has-tooltip.text-success{ title: self_approved ? final_self_text : final_text }
= approval_icon
= _("Approved")
%li.gl-display-flex= render Pajamas::BadgeComponent.new(badge_label, size: 'sm', variant: badge_variant, icon: approval_icon, title: approval_tooltip, class: 'has-tooltip', data: { 'testid': 'mr-appovals' })

View File

@ -24,4 +24,5 @@
invalid_path_error: (!!@invalid_path_error).to_s,
user_callouts_path: callouts_path,
user_callout_id: Users::CalloutsHelper::UNFINISHED_TAG_CLEANUP_CALLOUT,
is_metadata_database_enabled: ContainerRegistry::GitlabApiClient.supports_gitlab_api?.to_s,
show_unfinished_tag_cleanup_callout: show_unfinished_tag_cleanup_callout?.to_s, } }

View File

@ -2,4 +2,4 @@
- breadcrumb_title s_('ContainerRegistry|Cleanup policies')
- page_title s_('ContainerRegistry|Cleanup policies'), _('Packages and registries settings')
#js-registry-settings-cleanup-image-tags{ data: cleanup_settings_data }
#js-registry-settings-cleanup-image-tags{ data: cleanup_settings_data(@project) }

View File

@ -1,8 +0,0 @@
---
name: auto_cancel_pipeline_on_job_failure
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137815
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433163
milestone: '16.7'
type: development
group: group::pipeline execution
default_enabled: false

View File

@ -1,9 +0,0 @@
---
name: ci_rule_exists_extension_optimization
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/227632
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/143056
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/production/-/issues/17531
milestone: '16.9'
group: group::pipeline authoring
type: gitlab_com_derisk
default_enabled: false

View File

@ -791,6 +791,8 @@
- 1
- - vulnerabilities_statistics_adjustment
- 1
- - vulnerabilities_update_archived_attribute_of_vulnerability_reads
- 1
- - vulnerabilities_update_namespace_ids_of_vulnerability_reads
- 1
- - vulnerability_exports_export
@ -813,6 +815,8 @@
- 1
- - work_items_rolledup_dates_update_rolledup_dates
- 1
- - work_items_rolledup_dates_update_rolledup_dates_event_handler
- 1
- - work_items_update_parent_objectives_progress
- 1
- - work_items_validate_epic_work_item_sync

View File

@ -7,4 +7,19 @@ feature_categories:
description: Debian registry group-level architectures
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51265
milestone: '13.8'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
group_id:
references: namespaces
backfill_via:
parent:
foreign_key: distribution_id
table: packages_debian_group_distributions
sharding_key: group_id
belongs_to: distribution

View File

@ -7,4 +7,19 @@ feature_categories:
description: Debian package group-level distribution components
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51732
milestone: '13.9'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
group_id:
references: namespaces
backfill_via:
parent:
foreign_key: distribution_id
table: packages_debian_group_distributions
sharding_key: group_id
belongs_to: distribution

View File

@ -7,4 +7,19 @@ feature_categories:
description: Debian group-level distribution keys
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60993
milestone: '14.0'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
group_id:
references: namespaces
backfill_via:
parent:
foreign_key: distribution_id
table: packages_debian_group_distributions
sharding_key: group_id
belongs_to: distribution

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
class ReplaceEpicsFkOnParentId < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '16.11'
NEW_FK_NAME = 'fk_epics_on_parent_id_with_on_delete_nullify'
def up
# This will replace the existing fk_25b99c1be3
add_concurrent_foreign_key(
:epics,
:epics,
column: :parent_id,
on_delete: :nullify,
validate: false,
name: NEW_FK_NAME
)
end
def down
with_lock_retries do
remove_foreign_key_if_exists(
:epics,
column: :parent_id,
on_delete: :nullify,
name: NEW_FK_NAME
)
end
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class ValidateEpicsFkOnParentIdWithOnDeleteNullify < Gitlab::Database::Migration[2.2]
milestone '16.11'
FK_NAME = 'fk_epics_on_parent_id_with_on_delete_nullify'
# foreign key added in db/migrate/20240403113607_replace_epics_fk_on_parent_id.rb
def up
validate_foreign_key(:epics, :parent_id, name: FK_NAME)
end
def down
# no-op
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
class RemoveFkEpicsParentId < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '16.11'
FK_NAME = :fk_25b99c1be3
# new foreign key added in db/migrate/20240403113607_replace_epics_fk_on_parent_id.rb
# and validated in db/migrate/20240403114400_validate_epics_fk_on_parent_id_with_on_delete_nullify.rb
def up
with_lock_retries do
remove_foreign_key_if_exists(:epics, column: :parent_id, on_delete: :cascade, name: FK_NAME)
end
end
def down
# Validation is skipped here, so if rolled back, this will need to be revalidated in a separate migration
add_concurrent_foreign_key(:epics, :epics, column: :parent_id, on_delete: :cascade, validate: false, name: FK_NAME)
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddRunnerCreationStatusToCiRunner < Gitlab::Database::Migration[2.2]
milestone '16.11'
def change
add_column :ci_runners, :creation_state, :integer, limit: 2, default: 100, null: false
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class UpdateRunnerCreationStatusDefaultToZero < Gitlab::Database::Migration[2.2]
milestone '16.11'
def change
change_column_default :ci_runners, :creation_state, from: 100, to: 0
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddRunnerCreationStatusToCiRunnerMachines < Gitlab::Database::Migration[2.2]
milestone '16.11'
def change
add_column :ci_runner_machines, :creation_state, :integer, limit: 2, default: 100, null: false
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class UpdateCiRunnerMachinesRunnerCreationStatusDefaultToZero < Gitlab::Database::Migration[2.2]
milestone '16.11'
def change
change_column_default :ci_runner_machines, :creation_state, from: 100, to: 0
end
end

View File

@ -0,0 +1 @@
4dd96835a4134f77ea0df9731fcdbb2d436a42a0829bb7d712c93aa23eda5c06

View File

@ -0,0 +1 @@
e8e5d64ac7ff6ecb9e91701a6b93a35a01a0786b565717c5852f15b5c9441b5b

View File

@ -0,0 +1 @@
ec1ad441c0ceb0ed3a444ada51799b2f758bbadccaad37112745604019a4a231

View File

@ -0,0 +1 @@
31a9c402bac291e3be11363976e10223991afe14868941c91d6d96ab7283bcf5

View File

@ -0,0 +1 @@
1474b0983a8d7b469c6969a5949d8a185be263d23e23f1d9b5da21fb861e6674

View File

@ -0,0 +1 @@
c1e3ee0f7f7dcb8577372d0649b84c0157da0e76b96ed0a23f4bdfcd319e5ee9

View File

@ -0,0 +1 @@
9a0f82dab091ebbd9ec2146d96efed4c0a46e18021e5378913c9dba9244f9d55

View File

@ -6645,6 +6645,7 @@ CREATE TABLE ci_runner_machines (
ip_address text,
config jsonb DEFAULT '{}'::jsonb NOT NULL,
system_xid text,
creation_state smallint DEFAULT 0 NOT NULL,
CONSTRAINT check_1537c1f66f CHECK ((char_length(platform) <= 255)),
CONSTRAINT check_5253913ae9 CHECK ((char_length(system_xid) <= 64)),
CONSTRAINT check_6f45a91da7 CHECK ((char_length(version) <= 2048)),
@ -6730,6 +6731,7 @@ CREATE TABLE ci_runners (
allowed_plans text[] DEFAULT '{}'::text[] NOT NULL,
registration_type smallint DEFAULT 0 NOT NULL,
creator_id bigint,
creation_state smallint DEFAULT 0 NOT NULL,
CONSTRAINT check_ce275cee06 CHECK ((char_length(maintainer_note) <= 1024))
);
@ -29798,9 +29800,6 @@ ALTER TABLE ONLY agent_activity_events
ALTER TABLE ONLY zoekt_repositories
ADD CONSTRAINT fk_25a92aeccd FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET NULL;
ALTER TABLE ONLY epics
ADD CONSTRAINT fk_25b99c1be3 FOREIGN KEY (parent_id) REFERENCES epics(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_pipelines
ADD CONSTRAINT fk_262d4c2d19 FOREIGN KEY (auto_canceled_by_id) REFERENCES ci_pipelines(id) ON DELETE SET NULL;
@ -30746,6 +30745,9 @@ ALTER TABLE ONLY emails
ALTER TABLE ONLY epics
ADD CONSTRAINT fk_epics_issue_id_with_on_delete_nullify FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE SET NULL;
ALTER TABLE ONLY epics
ADD CONSTRAINT fk_epics_on_parent_id_with_on_delete_nullify FOREIGN KEY (parent_id) REFERENCES epics(id) ON DELETE SET NULL;
ALTER TABLE ONLY clusters
ADD CONSTRAINT fk_f05c5e5a42 FOREIGN KEY (management_project_id) REFERENCES projects(id) ON DELETE SET NULL;

View File

@ -447,6 +447,8 @@ Example response:
## Delete epic
- [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/452189) in GitLab 16.11. In GitLab 16.10 and earlier, if you delete an epic, all its child epics and their descendants are deleted as well. If needed, you can remove child epics from the parent epic before you delete it.
Deletes an epic
```plaintext

View File

@ -15384,7 +15384,7 @@ Represents the approval policy.
| <a id="approvalpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="approvalpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
| <a id="approvalpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
| <a id="approvalpolicypolicyscope"></a>`policyScope` **{warning-solid}** | [`PolicyScope`](#policyscope) | **Introduced** in GitLab 16.10. **Status**: Experiment. Scope of the policy. Returns `null` if Security Policy Scope experimental feature is disabled. |
| <a id="approvalpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
| <a id="approvalpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
| <a id="approvalpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
| <a id="approvalpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
@ -28298,7 +28298,7 @@ Represents the scan execution policy.
| <a id="scanexecutionpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
| <a id="scanexecutionpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="scanexecutionpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
| <a id="scanexecutionpolicypolicyscope"></a>`policyScope` **{warning-solid}** | [`PolicyScope`](#policyscope) | **Introduced** in GitLab 16.10. **Status**: Experiment. Scope of the policy. Returns `null` if Security Policy Scope experimental feature is disabled. |
| <a id="scanexecutionpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
| <a id="scanexecutionpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
| <a id="scanexecutionpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
| <a id="scanexecutionpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
@ -28318,7 +28318,7 @@ Represents the scan result policy.
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
| <a id="scanresultpolicypolicyscope"></a>`policyScope` **{warning-solid}** | [`PolicyScope`](#policyscope) | **Introduced** in GitLab 16.10. **Status**: Experiment. Scope of the policy. Returns `null` if Security Policy Scope experimental feature is disabled. |
| <a id="scanresultpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
| <a id="scanresultpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
| <a id="scanresultpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
| <a id="scanresultpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
@ -35165,7 +35165,7 @@ Implementations:
| <a id="orchestrationpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
| <a id="orchestrationpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="orchestrationpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
| <a id="orchestrationpolicypolicyscope"></a>`policyScope` **{warning-solid}** | [`PolicyScope`](#policyscope) | **Introduced** in GitLab 16.10. **Status**: Experiment. Scope of the policy. Returns `null` if Security Policy Scope experimental feature is disabled. |
| <a id="orchestrationpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
| <a id="orchestrationpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
| <a id="orchestrationpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |

View File

@ -531,11 +531,7 @@ In this example:
#### `workflow:auto_cancel:on_job_failure`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23605) in GitLab 16.10 [with a flag](../../administration/feature_flags.md) named `auto_cancel_pipeline_on_job_failure`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available.
To enable the feature, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `auto_cancel_pipeline_on_job_failure`.
On GitLab.com and GitLab Dedicated, this feature is not available.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/433163) in GitLab 16.11. Feature flag `auto_cancel_pipeline_on_job_failure` removed.
Use `workflow:auto_cancel:on_job_failure` to configure which jobs should be cancelled as soon as one job fails.
@ -754,13 +750,17 @@ When the branch is something else:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/436467) in GitLab 16.8 [with a flag](../../administration/feature_flags.md) named `ci_workflow_auto_cancel_on_new_commit`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/434676) in GitLab 16.9.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/434676) in GitLab 16.10. Feature flag `ci_workflow_auto_cancel_on_new_commit` removed.
> - `on_job_failure` option for `workflow:rules` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23605) in GitLab 16.10 [with a flag](../../administration/feature_flags.md) named `auto_cancel_pipeline_on_job_failure`. Disabled by default.
> - `on_job_failure` option for `workflow:rules` [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/433163) in GitLab 16.11. Feature flag `auto_cancel_pipeline_on_job_failure` removed.
Use `workflow:rules:auto_cancel` to configure the behavior of
the [`workflow:auto_cancel:on_new_commit`](#workflowauto_cancelon_new_commit) feature.
the [`workflow:auto_cancel:on_new_commit`](#workflowauto_cancelon_new_commit) or
the [`workflow:auto_cancel:on_job_failure`](#workflowauto_cancelon_job_failure) features.
**Possible inputs**:
- `on_new_commit`: [`workflow:auto_cancel:on_new_commit`](#workflowauto_cancelon_new_commit)
- `on_job_failure`: [`workflow:auto_cancel:on_job_failure`](#workflowauto_cancelon_job_failure)
**Example of `workflow:rules:auto_cancel`**:
@ -768,10 +768,12 @@ the [`workflow:auto_cancel:on_new_commit`](#workflowauto_cancelon_new_commit) fe
workflow:
auto_cancel:
on_new_commit: interruptible
on_job_failure: all
rules:
- if: $CI_COMMIT_REF_PROTECTED == 'true'
auto_cancel:
on_new_commit: none
on_job_failure: none
- when: always # Run the pipeline in other cases
test-job1:
@ -784,8 +786,9 @@ test-job2:
```
In this example, [`workflow:auto_cancel:on_new_commit`](#workflowauto_cancelon_new_commit)
is set to `interruptible` for all jobs by default. But if a pipeline runs for a protected branch,
the rule overrides the default with `on_new_commit: none`. For example, if a pipeline
is set to `interruptible` and [`workflow:auto_cancel:on_job_failure`](#workflowauto_cancelon_job_failure)
is set to `all` for all jobs by default. But if a pipeline runs for a protected branch,
the rule overrides the default with `on_new_commit: none` and `on_job_failure: none`. For example, if a pipeline
is running for:
- A non-protected branch and a new commit is pushed, `test-job1` continues to run and `test-job2` is canceled.

View File

@ -749,7 +749,7 @@ For basic guidance on choosing a cluster configuration you may refer to [Elastic
#### Number of Elasticsearch shards
You must set the number of Elasticsearch shards per index to at least `5`.
Set the number of Elasticsearch shards per index to at least `5`.
To update the shard size for an index, change the setting and trigger [zero-downtime reindexing](#zero-downtime-reindexing).
##### Indices with database data
@ -777,12 +777,13 @@ For indices that contain repository data:
Keep the average shard size between a few GB and 30 GB.
If the average shard size grows to more than 30 GB, increase the shard size
for the index and trigger [zero-downtime reindexing](#zero-downtime-reindexing).
To ensure the health of your cluster, the number of shards per node must be fewer than 20 per GB heap.
To ensure the cluster is healthy, the number of shards per node
must not exceed 20 times the configured heap size.
For example, a node with a 30 GB heap must have a maximum of 600 shards.
#### Number of Elasticsearch replicas
You must set the number of Elasticsearch replicas per index to `1` (each shard has one replica).
Set the number of Elasticsearch replicas per index to `1` (each shard has one replica).
The number must not be `0` because losing one node corrupts the index.
### How to index large instances efficiently

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

View File

@ -27,23 +27,21 @@ This feature is in [Beta](../policy/experiment-beta-support.md). For more inform
To configure distributed tracing:
1. [Create an access token and enable tracing.](#create-an-access-token-and-enable-tracing)
1. [Create an access token and enable tracing.](#create-an-access-token)
1. [Configure your application to use the OpenTelemetry exporter.](#configure-your-application-to-use-the-opentelemetry-exporter)
### Create an access token and enable tracing
### Create an access token
Prerequisites:
- You must have at least the Maintainer role for the project.
To enable tracing in a project:
To enable tracing in a project, you must first create an access token:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Access Tokens**.
1. Create an access token with the following scopes: `read_api`, `read_observability`, `write_observability`.
1. Copy the value of the access token.
1. Select **Monitor > Tracing**.
1. Select **Enable**.
### Configure your application to use the OpenTelemetry exporter
@ -61,7 +59,7 @@ Use the following values:
- `namespace-id`: The top-level namespace ID where your project is located.
- `gitlab-project-id`: The project ID.
- `gitlab-access-token`: The access token you [created previously](#create-an-access-token-and-enable-tracing).
- `gitlab-access-token`: The access token you [created previously](#create-an-access-token).
When your application is configured, run it, and the OpenTelemetry exporter attempts to send
traces to GitLab.
@ -75,9 +73,9 @@ To view the list of traces:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Traces**.
To see the details of a trace, select it from the list. You can also select a trace directly from the scatterplot.
To see the details of a trace, select it from the list.
![list of traces](img/tracing_list_v16_7.png)
![list of traces](img/tracing_list_v16.11.png)
The trace details page and a list of spans are displayed.

View File

@ -4,7 +4,7 @@ group: Source Code
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments"
---
# Partial clone
# Use partial clones to reduce clone size
As Git repositories grow in size, they can become cumbersome to work with
because of:
@ -39,7 +39,7 @@ git clone --filter=blob:limit=1m git@gitlab.com:gitlab-com/www-gitlab-com.git
This would produce the following output:
```plaintext
```shell
Cloning into 'www-gitlab-com'...
remote: Enumerating objects: 832467, done.
remote: Counting objects: 100% (832467/832467), done.
@ -70,7 +70,7 @@ For repositories with millions of files and a long history, you can exclude all
[`git sparse-checkout`](https://git-scm.com/docs/git-sparse-checkout) to reduce the size of
your working copy.
```plaintext
```shell
# Clone the repo excluding all files
$ git clone --filter=blob:none --sparse git@gitlab.com:gitlab-com/www-gitlab-com.git
Cloning into 'www-gitlab-com'...
@ -143,7 +143,6 @@ For more details, see the Git documentation for
clone command is not fully integrated with sparse checkout.
```shell
# Clone the filtered set of objects using the filterspec stored on the
# server. WARNING: this step may be very slow!
git clone --sparse --filter=sparse:oid=master:shiny-app/.gitfilterspec <url>

View File

@ -7,55 +7,30 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Analyze GitLab usage
> - Group-level analytics moved to GitLab Premium in 13.9.
GitLab provides different types of analytics insights at the instance, group, and project level.
These insights appear on the left sidebar, under [**Analyze**](../project/settings/index.md#disable-project-analytics).
## Instance-level analytics
## Analytics features
Use [instance-level analytics](../../administration/analytics/index.md) to aggregate analytics across GitLab,
so that you can view information across multiple projects and groups in one place.
## Group-level analytics
> - Moved to GitLab Premium in 13.9.
Use group-level analytics to get insights into your groups':
- [Security Dashboards](../application_security/security_dashboard/index.md)
- [Contribution analytics](../group/contribution_analytics/index.md)
- [DevOps adoption](../group/devops_adoption/index.md)
- [Insights](../project/insights/index.md)
- [Issue analytics](../group/issues_analytics/index.md)
- [Productivity analytics](productivity_analytics.md)
- [Repository analytics](../group/repositories_analytics/index.md)
- [Value Stream Management Analytics](../group/value_stream_analytics/index.md) and [Value Stream Management Dashboard](value_streams_dashboard.md)
## Project-level analytics
Use project-level analytics to get insights into your projects':
- [Analytics dashboards](analytics_dashboards.md)
- [Security Dashboards](../application_security/security_dashboard/index.md)
- [CI/CD analytics and DORA metrics](ci_cd_analytics.md)
- [Code review analytics](code_review_analytics.md)
- [Contributor analytics](../../user/analytics/contributor_analytics.md)
- [Insights](../project/insights/index.md)
- [Issue analytics](../group/issues_analytics/index.md)
- [Merge request analytics](merge_request_analytics.md), enabled with the `project_merge_request_analytics`
[feature flag](../../development/feature_flags/index.md#enabling-a-feature-flag-locally-in-development)
- [Repository analytics](repository_analytics.md)
- [Value Stream Management Analytics](../group/value_stream_analytics/index.md) and [Value Stream Management Dashboard](value_streams_dashboard.md)
## User-configurable analytics
View vulnerabilities of your selected projects in the [Security Center](../application_security/security_dashboard/index.md#security-center).
## Value streams management
Analyze and visualize the performance of your projects and groups with:
- [Value stream analytics for projects and groups](../group/value_stream_analytics/index.md)
- [Value streams dashboard](value_streams_dashboard.md)
| Feature | Description | Category | Project-level | Group-level | Instance-level |
| ------- | ----------- | -------- | ------------- | ----------- | -------------- |
| [Analytics dashboards](analytics_dashboards.md) | Built-in and customizable dashboards to visualize collected data. | End-to-end insight & visibility | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
| [CI/CD analytics and DORA metrics](ci_cd_analytics.md) | Pipeline duration and successes/failures, and DORA metrics over time. | CI/CD | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
| [Code review analytics](code_review_analytics.md) | Open merge requests with information about merge request activity. | Productivity | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
| [Contribution analytics](../group/contribution_analytics/index.md) | Overview of [contribution events](../../user/profile/contributions_calendar.md) made by group members, with bar chart of push events, merge requests, and issues. | Developer | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
| [Contributor analytics](../../user/analytics/contributor_analytics.md) | Overview of commits made by project members, with line chart of number of commits. | Developer | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
| [DevOps adoption](../group/devops_adoption/index.md) | Organization's maturity in DevOps adoption, with group-level feature adoption over time and adoption by subgroup. | End-to-end insight & visibility | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
| [Insights](../project/insights/index.md) | Customizable reports to explore issues, merged merge requests, and triage hygiene. | End-to-end insight & visibility | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
| [Instance-level analytics](../../administration/analytics/index.md) | Aggregated analytics across GitLab about multiple projects and groups in one place. | End-to-end insight & visibility | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes |
| [Issue analytics](../group/issues_analytics/index.md) | Visualization of issues created each month. | Productivity | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
| [Merge request analytics](merge_request_analytics.md) | Overview of merge requests, with mean time to merge, throughput, and activity details. | Productivity | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
| [Productivity analytics](productivity_analytics.md) | Merge request lifecycle, filterable down to author level. | Productivity | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No |
| [Repository analytics](../group/repositories_analytics/index.md) | Programming languages used in the repository and code coverage statistics. | Developer | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
| [Security Dashboards](../application_security/security_dashboard/index.md) | Collection of metrics, ratings, and charts for vulnerabilities detected by security scanners. | Security | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
| [Value Streams Dashboard](value_streams_dashboard.md) | Insights into DevSecOps trends, patterns, and opportunities for digital transformation improvements. | End-to-end insight & visibility | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
| [Value Stream Management Analytics](../group/value_stream_analytics/index.md) | Insights into time-to-value through customizable stages. | End-to-end insight & visibility | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
## Glossary

View File

@ -139,6 +139,8 @@ To update multiple epics at the same time:
## Delete an epic
- [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/452189) in GitLab 16.11. In GitLab 16.10 and earlier, if you delete an epic, all its child epics and their descendants are deleted as well. If needed, you can [remove child epics](#remove-a-child-epic-from-a-parent-epic) from the parent epic before you delete it.
Prerequisites:
- You must have the Owner role for the epic's group.
@ -150,9 +152,6 @@ To delete the epic:
Deleting an epic releases all existing issues from their associated epic in the system.
WARNING:
If you delete an epic, all its child epics and their descendants are deleted as well. If needed, you can [remove child epics](#remove-a-child-epic-from-a-parent-epic) from the parent epic before you delete it.
## Close an epic
Prerequisites:

View File

@ -59,8 +59,7 @@ To enable or disable individual features in a project:
## Disable project analytics
By default, [analytics for a project](../../analytics/index.md#project-level-analytics)
are displayed under the **Analyze** item in the left sidebar.
By default, project analytics are displayed under the **Analyze** item in the left sidebar.
To disable this feature and remove the **Analyze** item from the left sidebar:
1. On the left sidebar, select **Search or go to** and find your project.

View File

@ -16,10 +16,6 @@ module Gitlab
end
def satisfied_by?(_pipeline, context)
if ::Feature.disabled?(:ci_rule_exists_extension_optimization, context.project, type: :gitlab_com_derisk)
return legacy_satisfied_by?(context)
end
paths = worktree_paths(context)
exact_globs, extension_globs, pattern_globs = separate_globs(context)
@ -30,18 +26,6 @@ module Gitlab
private
def legacy_satisfied_by?(context)
paths = worktree_paths(context)
exact_globs, pattern_globs = legacy_separate_globs(context)
exact_matches?(paths, exact_globs) || pattern_matches?(paths, pattern_globs)
end
def legacy_separate_globs(context)
expanded_globs = expand_globs(context)
expanded_globs.partition(&method(:exact_glob?))
end
def separate_globs(context)
expanded_globs = expand_globs(context)

View File

@ -55,8 +55,6 @@ module Gitlab
end
def set_auto_cancel_on_job_failure(auto_cancel)
return if Feature.disabled?(:auto_cancel_pipeline_on_job_failure, pipeline.project)
auto_cancel_on_job_failure = auto_cancel[:on_job_failure]
return if auto_cancel_on_job_failure.blank?

View File

@ -540,6 +540,9 @@ msgstr ""
msgid "%{address} is an invalid IP address range"
msgstr ""
msgid "%{approvals_given} of %{required} Approvals"
msgstr ""
msgid "%{argument_name} must be formatted correctly. For example: 1h 30m."
msgstr ""
@ -1100,9 +1103,6 @@ msgid_plural "%{releases} releases"
msgstr[0] ""
msgstr[1] ""
msgid "%{remaining_approvals} left"
msgstr ""
msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
msgstr[0] ""
@ -14053,6 +14053,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names that match this regex pattern are removed. %{linkStart}View regex examples.%{linkEnd}"
msgstr ""
msgid "ContainerRegistry|The %{linkStart}next-generation container registry%{linkEnd} is now available for upgrade and testing on self-managed instances as a Beta feature. This upgraded registry supports online garbage collection, and has significant performance and reliability improvements."
msgstr ""
msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}run cleanup now manually%{adminLinkEnd} or you can wait for the next scheduled run of the cleanup policy. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
@ -42949,10 +42952,10 @@ msgstr ""
msgid "Require expiration date"
msgstr ""
msgid "Required approvals (%{approvals_given} given)"
msgid "Required approvals (%{approvals_given} of %{required} given)"
msgstr ""
msgid "Required approvals (%{approvals_given} given, you've approved)"
msgid "Required approvals (%{approvals_given} of %{required} given, you've approved)"
msgstr ""
msgid "Required in this project."
@ -44067,6 +44070,9 @@ msgstr ""
msgid "Runners|Runner is locked and available for currently assigned projects only. Only administrators can change the assigned projects."
msgstr ""
msgid "Runners|Runner is offline; it has never contacted this instance"
msgstr ""
msgid "Runners|Runner is offline; last contact was %{runner_contact} ago"
msgstr ""

View File

@ -12,9 +12,11 @@ class GenerateAsIfFossEnv
compile-production-assets
compile-storybook
compile-test-assets
detect-tests
eslint
generate-apollo-graphql-schema
graphql-schema-dump
rubocop
qa:internal
qa:selectors
static-analysis
@ -47,7 +49,9 @@ class GenerateAsIfFossEnv
{
START_AS_IF_FOSS: 'true',
RUBY_VERSION: ENV['RUBY_VERSION']
RUBY_VERSION: ENV['RUBY_VERSION'],
CI_MERGE_REQUEST_PROJECT_PATH: ENV['CI_MERGE_REQUEST_PROJECT_PATH'],
CI_MERGE_REQUEST_IID: ENV['CI_MERGE_REQUEST_IID']
}.merge(rspec_variables).merge(other_jobs_variables)
end

View File

@ -5,6 +5,13 @@ FactoryBot.define do
runner factory: :ci_runner
system_xid { "r_#{SecureRandom.hex.slice(0, 10)}" }
creation_state { :finished }
trait :unregistered do
contacted_at { nil }
creation_state { :started }
end
trait :stale do
created_at { 1.year.ago }
contacted_at { Ci::RunnerManager::STALE_TIMEOUT.ago }

View File

@ -10,6 +10,8 @@ FactoryBot.define do
runner_type { :instance_type }
creation_state { :finished }
transient do
groups { [] }
projects { [] }
@ -41,6 +43,11 @@ FactoryBot.define do
runner_type { :instance_type }
end
trait :unregistered do
contacted_at { nil }
creation_state { :started }
end
trait :group do
runner_type { :group_type }

View File

@ -258,7 +258,7 @@ RSpec.describe "Admin Runners", feature_category: :fleet_visibility do
describe 'filter by status' do
let_it_be(:never_contacted) do
create(:ci_runner, :instance, description: 'runner-never-contacted', contacted_at: nil)
create(:ci_runner, :instance, :unregistered, description: 'runner-never-contacted')
end
before_all do
@ -614,7 +614,7 @@ RSpec.describe "Admin Runners", feature_category: :fleet_visibility do
describe "Runner edit page" do
let_it_be(:project1) { create(:project) }
let_it_be(:project2) { create(:project) }
let_it_be(:project_runner) { create(:ci_runner, :project) }
let_it_be(:project_runner) { create(:ci_runner, :unregistered, :project) }
before do
visit edit_admin_runner_path(project_runner)

View File

@ -11,12 +11,23 @@ RSpec.describe 'Container Registry', :js, feature_category: :container_registry
create(:container_repository, name: 'my/image')
end
let(:help_page_href) { help_page_path('administration/packages/container_registry_metadata_database') }
before do
group.add_owner(user)
sign_in(user)
stub_container_registry_config(enabled: true)
stub_container_registry_tags(repository: :any, tags: [])
stub_container_registry_info
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
it 'has link to next generation container registry docs' do
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(false)
visit_container_registry
expect(page).to have_link('next-generation container registry', href: help_page_href)
end
it 'has a page title set' do

View File

@ -27,7 +27,11 @@ RSpec.describe 'Merge request > User approves', :js, feature_category: :code_rev
def verify_approvals_count_on_index!
visit(project_merge_requests_path(project, state: :all))
expect(page.all('li').any? { |item| item["title"] == "1 approver (you've approved)" }).to be true
expect(
page.all('[data-testid="mr-appovals"]').any? do |item|
item["title"] == "1 approver (you've approved)"
end
).to be true
visit project_merge_request_path(project, merge_request)
end

View File

@ -16,12 +16,15 @@ RSpec.describe 'Container Registry', :js, feature_category: :container_registry
create(:container_repository, name: '')
end
let(:help_page_href) { help_page_path('administration/packages/container_registry_metadata_database') }
before do
sign_in(user)
project.add_developer(user)
stub_container_registry_config(enabled: true)
stub_container_registry_info
stub_container_registry_tags(repository: :any, tags: [])
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
it 'has a page title set' do
@ -30,6 +33,14 @@ RSpec.describe 'Container Registry', :js, feature_category: :container_registry
expect(page).to have_title _('Container Registry')
end
it 'has link to next generation container registry docs' do
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(false)
visit_container_registry
expect(page).to have_link('next-generation container registry', href: help_page_href)
end
it 'does not have link to settings' do
visit_container_registry

View File

@ -18,6 +18,7 @@ RSpec.describe 'Project > Settings > Packages and registries > Container registr
sign_in(user)
stub_container_registry_config(enabled: container_registry_enabled)
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
context 'as owner', :js do

View File

@ -10,6 +10,8 @@ RSpec.describe 'Project > Settings > Packages and registries > Container registr
let(:container_registry_enabled) { true }
let(:container_registry_enabled_on_project) { ProjectFeature::ENABLED }
let(:help_page_href) { help_page_path('administration/packages/container_registry_metadata_database') }
subject { visit project_settings_packages_and_registries_path(project) }
before do
@ -18,6 +20,7 @@ RSpec.describe 'Project > Settings > Packages and registries > Container registr
sign_in(user)
stub_container_registry_config(enabled: container_registry_enabled)
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
context 'as owner', :js do
@ -51,6 +54,14 @@ RSpec.describe 'Project > Settings > Packages and registries > Container registr
expect(page).to have_link('Edit cleanup rules', href: cleanup_image_tags_project_settings_packages_and_registries_path(project))
end
it 'has link to next generation container registry docs' do
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(false)
subject
expect(page).to have_link('next-generation container registry', href: help_page_href)
end
end
context 'with a project without expiration policy', :js do

View File

@ -555,6 +555,7 @@ RSpec.describe "Internal Project Access", feature_category: :system_access do
stub_container_registry_config(enabled: true)
stub_container_registry_info
project.container_repositories << container_repository
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
subject { project_container_registry_index_path(project) }

View File

@ -574,6 +574,7 @@ RSpec.describe "Private Project Access", feature_category: :system_access do
stub_container_registry_config(enabled: true)
stub_container_registry_info
project.container_repositories << container_repository
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
subject { project_container_registry_index_path(project) }

View File

@ -556,6 +556,7 @@ RSpec.describe "Public Project Access", feature_category: :system_access do
stub_container_registry_config(enabled: true)
stub_container_registry_info
project.container_repositories << container_repository
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
subject { project_container_registry_index_path(project) }

View File

@ -18,7 +18,7 @@ RSpec.describe Ci::RunnerManagersFinder, '#execute', feature_category: :fleet_vi
let_it_be(:offline_runner_manager) { create(:ci_runner_machine, runner: runner, contacted_at: 2.hours.ago) }
let_it_be(:online_runner_manager) { create(:ci_runner_machine, runner: runner, contacted_at: 1.second.ago) }
let_it_be(:never_contacted_runner_manager) { create(:ci_runner_machine, runner: runner, contacted_at: nil) }
let_it_be(:never_contacted_runner_manager) { create(:ci_runner_machine, :unregistered, runner: runner) }
let_it_be(:stale_runner_manager) do
create(
:ci_runner_machine,

View File

@ -13,13 +13,18 @@ RSpec.describe 'Runner (JavaScript fixtures)', feature_category: :fleet_visibili
let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:project_2) { create(:project, :repository, :public) }
let_it_be(:runner) { create(:ci_runner, :instance, description: 'My Runner', creator: admin, version: '1.0.0') }
let_it_be(:runner) do
create(:ci_runner, :instance, :unregistered, description: 'My Runner', creator: admin, version: '1.0.0')
end
let_it_be(:runner_manager_1) { create(:ci_runner_machine, runner: runner, contacted_at: Time.current) }
let_it_be(:runner_manager_2) { create(:ci_runner_machine, runner: runner, contacted_at: Time.current) }
let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group], version: '2.0.0') }
let_it_be(:group_runner_2) { create(:ci_runner, :group, groups: [group], version: '2.0.0') }
let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project, project_2], version: '2.0.0') }
let_it_be(:project_runner) do
create(:ci_runner, :project, :unregistered, projects: [project, project_2], version: '2.0.0')
end
let_it_be(:build) { create(:ci_build, runner: runner) }

View File

@ -25,6 +25,7 @@ import component from '~/packages_and_registries/container_registry/explorer/pag
import Tracking from '~/tracking';
import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
import MetadataDatabaseAlert from '~/packages_and_registries/shared/components/container_registry_metadata_database_alert.vue';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
@ -57,6 +58,7 @@ describe('List Page', () => {
const findRegistryHeader = () => wrapper.findComponent(RegistryHeader);
const findDeleteAlert = () => wrapper.findComponent(GlAlert);
const findMetadataDatabaseAlert = () => wrapper.findComponent(MetadataDatabaseAlert);
const findImageList = () => wrapper.findComponent(ImageList);
const findPersistedSearch = () => wrapper.findComponent(PersistedSearch);
const findEmptySearchMessage = () => wrapper.find('[data-testid="emptySearch"]');
@ -139,6 +141,24 @@ describe('List Page', () => {
});
});
describe('metadata database alert', () => {
it('is rendered when metadata database is not enabled', () => {
mountComponent();
expect(findMetadataDatabaseAlert().exists()).toBe(true);
});
it('is not rendered when metadata database is enabled', () => {
mountComponent({
config: {
isMetadataDatabaseEnabled: true,
},
});
expect(findMetadataDatabaseAlert().exists()).toBe(false);
});
});
describe('link to settings', () => {
beforeEach(() => {
const config = {

View File

@ -9,6 +9,7 @@ import ContainerProtectionRules from '~/packages_and_registries/settings/project
import PackagesCleanupPolicy from '~/packages_and_registries/settings/project/components/packages_cleanup_policy.vue';
import PackagesProtectionRules from '~/packages_and_registries/settings/project/components/packages_protection_rules.vue';
import DependencyProxyPackagesSettings from 'ee_component/packages_and_registries/settings/project/components/dependency_proxy_packages_settings.vue';
import MetadataDatabaseAlert from '~/packages_and_registries/shared/components/container_registry_metadata_database_alert.vue';
import {
SHOW_SETUP_SUCCESS_ALERT,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
@ -26,6 +27,7 @@ describe('Registry Settings app', () => {
const findDependencyProxyPackagesSettings = () =>
wrapper.findComponent(DependencyProxyPackagesSettings);
const findAlert = () => wrapper.findComponent(GlAlert);
const findMetadataDatabaseAlert = () => wrapper.findComponent(MetadataDatabaseAlert);
const defaultProvide = {
projectPath: 'path',
@ -37,6 +39,7 @@ describe('Registry Settings app', () => {
containerRegistryProtectedContainers: true,
packagesProtectedPackages: true,
},
isContainerRegistryMetadataDatabaseEnabled: false,
};
const mountComponent = (provide = defaultProvide) => {
@ -45,6 +48,23 @@ describe('Registry Settings app', () => {
});
};
describe('metadata database alert', () => {
it('is rendered when metadata database is not enabled', () => {
mountComponent();
expect(findMetadataDatabaseAlert().exists()).toBe(true);
});
it('is not rendered when metadata database is enabled', () => {
mountComponent({
...defaultProvide,
isContainerRegistryMetadataDatabaseEnabled: true,
});
expect(findMetadataDatabaseAlert().exists()).toBe(false);
});
});
describe('container policy success alert handling', () => {
const originalLocation = window.location.href;
const search = `?${SHOW_SETUP_SUCCESS_ALERT}=true`;

View File

@ -0,0 +1,56 @@
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import MetadataDatabaseAlert from '~/packages_and_registries/shared/components/container_registry_metadata_database_alert.vue';
import * as utils from '~/lib/utils/common_utils';
describe('container registry metadata database alert', () => {
let wrapper;
const mountComponent = () => {
wrapper = shallowMount(MetadataDatabaseAlert);
};
const findAlert = () => wrapper.findComponent(GlAlert);
describe('with no cookie set', () => {
beforeEach(() => {
utils.setCookie = jest.fn();
mountComponent();
});
it('displays the alert', () => {
expect(findAlert().exists()).toBe(true);
});
it('does not call setCookie', () => {
expect(utils.setCookie).not.toHaveBeenCalled();
});
describe('when the close button is clicked', () => {
beforeEach(() => {
findAlert().vm.$emit('dismiss');
});
it('sets the dismissed cookie', () => {
expect(utils.setCookie).toHaveBeenCalledWith('hide_metadata_database_alert', 'true');
});
it('does not display the alert', () => {
expect(findAlert().exists()).toBe(false);
});
});
});
describe('with the dismissed cookie set', () => {
beforeEach(() => {
jest.spyOn(utils, 'getCookie').mockReturnValue('true');
mountComponent();
});
it('does not display the alert', () => {
expect(findAlert().exists()).toBe(false);
});
});
});

View File

@ -16,7 +16,7 @@ RSpec.describe Ci::RunnersHelper, feature_category: :fleet_visibility do
end
it "returns never contacted" do
runner = create(:ci_runner)
runner = create(:ci_runner, :unregistered)
expect(helper.runner_status_icon(runner)).to include("never contacted")
end
@ -32,7 +32,7 @@ RSpec.describe Ci::RunnersHelper, feature_category: :fleet_visibility do
end
it "returns stale text, when runner never contacted" do
runner = create(:ci_runner, created_at: 4.months.ago)
runner = create(:ci_runner, :unregistered, created_at: 4.months.ago)
expect(helper.runner_status_icon(runner)).to include("is stale")
expect(helper.runner_status_icon(runner)).to include("never contacted")
end

View File

@ -252,6 +252,36 @@ RSpec.describe PackagesHelper, feature_category: :package_registry do
end
end
describe '#settings_data' do
let(:user) { build_stubbed(:user) }
subject { helper.settings_data(project) }
where(:config_registry, :permission, :supports_gitlab_api?, :expected_result) do
false | false | false | false
false | false | true | false
false | true | false | false
false | true | true | false
true | false | false | false
true | false | true | false
true | true | false | false
true | true | true | true
end
with_them do
before do
allow(helper).to receive(:current_user).and_return(user)
stub_config(registry: { enabled: config_registry })
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(supports_gitlab_api?)
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, :admin_container_image, project).and_return(permission)
allow(Ability).to receive(:allowed?).with(user, :admin_package, project).and_return(true)
end
it { is_expected.to include(is_container_registry_metadata_database_enabled: expected_result.to_s) }
end
end
describe '#can_delete_packages?' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }

View File

@ -11,16 +11,6 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Exists, feature_category:
let(:project) { create(:project, :custom_repo, files: files) }
end
context 'with feature flag `ci_rule_exists_extension_optimization` disabled' do
before do
stub_feature_flags(ci_rule_exists_extension_optimization: false)
end
it_behaves_like 'a glob matching rule' do
let(:project) { create(:project, :custom_repo, files: files) }
end
end
context 'when the rules:exists has a variable' do
let_it_be(:project) { create(:project, :custom_repo, files: { 'helm/helm_file.txt' => '' }) }

View File

@ -228,19 +228,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata, feature_category:
end
end
context 'when auto_cancel_pipeline_on_job_failure feature is disabled' do
before do
stub_feature_flags(auto_cancel_pipeline_on_job_failure: false)
end
it 'ignores the auto_cancel_on_job_failure value' do
run_chain
expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none')
expect(pipeline.pipeline_metadata).not_to be_persisted
end
end
context 'with workflow:rules:auto_cancel' do
context 'with auto_cancel:on_new_commit not set and rules:workflow:auto_cancel:on_new_commit set' do
let(:config) do

View File

@ -5949,29 +5949,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
allow(pipeline).to receive(:auto_cancel_on_job_failure).and_return(auto_cancel_on_job_failure)
end
shared_examples 'expected behaviour' do
it 'cancels the pipeline when expected' do
unless errors
if cancels
expect(::Ci::UserCancelPipelineWorker).to receive(:perform_async)
else
expect(::Ci::UserCancelPipelineWorker).not_to receive(:perform_async)
end
subject
end
end
it 'raises errors when expected' do
if errors
expect { subject }.to raise_error(ArgumentError, 'Unknown auto_cancel_on_job_failure value: invalid value')
else
expect { subject }.not_to raise_error
end
end
end
context 'when the auto_cancel_pipeline_on_job_failure feature flag is enabled' do
context 'with different configurations' do
where(:auto_cancel_on_job_failure, :cancels, :errors) do
'none' | false | false
'all' | true | false
@ -5979,23 +5957,25 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
end
with_them do
it_behaves_like 'expected behaviour'
end
end
it 'cancels the pipeline when expected' do
unless errors
if cancels
expect(::Ci::UserCancelPipelineWorker).to receive(:perform_async)
else
expect(::Ci::UserCancelPipelineWorker).not_to receive(:perform_async)
end
context 'when the auto_cancel_pipeline_on_job_failure feature flag is disabled' do
before do
stub_feature_flags(auto_cancel_pipeline_on_job_failure: false)
end
subject
end
end
where(:auto_cancel_on_job_failure, :cancels, :errors) do
'none' | false | false
'all' | false | false
'invalid value' | false | false
end
with_them do
it_behaves_like 'expected behaviour'
it 'raises errors when expected' do
if errors
expect { subject }.to raise_error(ArgumentError, 'Unknown auto_cancel_on_job_failure value: invalid value')
else
expect { subject }.not_to raise_error
end
end
end
end
end

View File

@ -46,7 +46,7 @@ RSpec.describe Ci::RunnerManager, feature_category: :fleet_visibility, type: :mo
let_it_be(:offline_runner_manager) { create(:ci_runner_machine, runner: runner, contacted_at: 2.hours.ago) }
let_it_be(:online_runner_manager) { create(:ci_runner_machine, runner: runner, contacted_at: 1.second.ago) }
let_it_be(:never_contacted_runner_manager) { create(:ci_runner_machine, runner: runner, contacted_at: nil) }
let_it_be(:never_contacted_runner_manager) { create(:ci_runner_machine, :unregistered, runner: runner) }
describe '.online' do
subject(:runner_managers) { described_class.online }
@ -329,46 +329,34 @@ RSpec.describe Ci::RunnerManager, feature_category: :fleet_visibility, type: :mo
end
describe '#status', :freeze_time do
let(:runner_manager) { build(:ci_runner_machine, created_at: 8.days.ago) }
subject { runner_manager.status }
context 'if never connected' do
before do
runner_manager.contacted_at = nil
end
let(:runner_manager) { build(:ci_runner_machine, :unregistered, created_at: 8.days.ago) }
it { is_expected.to eq(:stale) }
context 'if created recently' do
before do
runner_manager.created_at = 1.day.ago
end
let(:runner_manager) { build(:ci_runner_machine, :unregistered, created_at: 1.day.ago) }
it { is_expected.to eq(:never_contacted) }
end
end
context 'if contacted 1s ago' do
before do
runner_manager.contacted_at = 1.second.ago
end
let(:runner_manager) { build(:ci_runner_machine, contacted_at: 1.second.ago) }
it { is_expected.to eq(:online) }
end
context 'if contacted recently' do
before do
runner_manager.contacted_at = 2.hours.ago
end
let(:runner_manager) { build(:ci_runner_machine, contacted_at: 2.hours.ago) }
it { is_expected.to eq(:offline) }
end
context 'if contacted long time ago' do
before do
runner_manager.contacted_at = 7.days.ago
end
let(:runner_manager) { build(:ci_runner_machine, created_at: 8.days.ago, contacted_at: 7.days.ago) }
it { is_expected.to eq(:stale) }
end
@ -436,7 +424,7 @@ RSpec.describe Ci::RunnerManager, feature_category: :fleet_visibility, type: :mo
end
it 'updates only ip_address' do
expect_redis_update(values.merge(contacted_at: Time.current))
expect_redis_update(values.merge(contacted_at: Time.current, creation_state: :finished))
heartbeat
end

View File

@ -493,7 +493,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
let!(:runner3) { create(:ci_runner, :instance, contacted_at: 1.month.ago, created_at: 2.months.ago) }
let!(:runner4) { create(:ci_runner, :instance, contacted_at: 1.month.ago, created_at: 3.months.ago) }
it { is_expected.to eq([runner1, runner3, runner4]) }
it { is_expected.to contain_exactly(runner1, runner3, runner4) }
end
describe '.active' do
@ -887,55 +887,40 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
describe '#status', :freeze_time do
let(:runner) { build(:ci_runner, :instance, created_at: 3.months.ago) }
subject { runner.status }
context 'never connected' do
before do
runner.contacted_at = nil
end
let(:runner) { build(:ci_runner, :instance, :unregistered, created_at: 3.months.ago) }
it { is_expected.to eq(:stale) }
context 'created recently' do
before do
runner.created_at = 1.day.ago
end
let(:runner) { build(:ci_runner, :instance, :unregistered, created_at: 1.day.ago) }
it { is_expected.to eq(:never_contacted) }
end
end
context 'inactive but online' do
before do
runner.contacted_at = 1.second.ago
runner.active = false
end
let(:runner) { build(:ci_runner, :instance, active: false, contacted_at: 1.second.ago) }
it { is_expected.to eq(:online) }
end
context 'contacted 1s ago' do
before do
runner.contacted_at = 1.second.ago
end
let(:runner) { build(:ci_runner, :instance, contacted_at: 1.second.ago) }
it { is_expected.to eq(:online) }
end
context 'contacted recently' do
before do
runner.contacted_at = (3.months - 1.second).ago
end
let(:runner) { build(:ci_runner, :instance, contacted_at: (3.months - 1.second).ago) }
it { is_expected.to eq(:offline) }
end
context 'contacted long time ago' do
before do
runner.contacted_at = 3.months.ago
end
let(:runner) { build(:ci_runner, :instance, created_at: 3.months.ago, contacted_at: 3.months.ago) }
it { is_expected.to eq(:stale) }
end
@ -1100,7 +1085,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
it 'updates only ip_address' do
expect_redis_update(values.merge(contacted_at: Time.current))
expect_redis_update(values.merge(contacted_at: Time.current, creation_state: :finished))
heartbeat
end
@ -2150,7 +2135,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
describe 'status scopes' do
let_it_be(:online_runner) { create(:ci_runner, :instance, contacted_at: 1.second.ago) }
let_it_be(:offline_runner) { create(:ci_runner, :instance, contacted_at: 2.hours.ago) }
let_it_be(:never_contacted_runner) { create(:ci_runner, :instance, contacted_at: nil) }
let_it_be(:never_contacted_runner) { create(:ci_runner, :instance, :unregistered) }
describe '.online' do
subject(:runners) { described_class.online }

View File

@ -0,0 +1,51 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Achievements::AchievementPolicy, feature_category: :user_profile do
let_it_be_with_reload(:current_user) { create(:user) }
subject { described_class.new(current_user, achievement) }
shared_examples 'disallowed when feature flag disabled' do
before do
stub_feature_flags(achievements: false)
end
it { is_expected.to be_disallowed(:read_achievement) }
end
context 'in a public group' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
it { is_expected.to be_allowed(:read_achievement) }
it_behaves_like 'disallowed when feature flag disabled'
end
context 'in a private group' do
let_it_be(:group) { create(:group, :private) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
it { is_expected.to be_disallowed(:read_achievement) }
context 'when a group member' do
before_all do
group.add_guest(current_user)
end
it { is_expected.to be_allowed(:read_achievement) }
it_behaves_like 'disallowed when feature flag disabled'
end
context 'when the user has received the achievement' do
let_it_be(:user_achievement) { create(:user_achievement, user: current_user, achievement: achievement) }
it { is_expected.to be_allowed(:read_achievement) }
it_behaves_like 'disallowed when feature flag disabled'
end
end
end

View File

@ -70,8 +70,8 @@ RSpec.describe Achievements::UserAchievementPolicy, feature_category: :user_prof
end
context 'for others' do
it 'is visible' do
is_expected.to be_allowed(:read_user_achievement)
it 'is not visible' do
is_expected.to be_disallowed(:read_user_achievement)
end
end
end

View File

@ -1727,10 +1727,16 @@ RSpec.describe GroupPolicy, feature_category: :system_access do
specify { is_expected.to be_disallowed(:destroy_user_achievement) }
end
context 'when current user can not see the group' do
context 'when current user is not a group member' do
let(:current_user) { non_group_member }
specify { is_expected.to be_allowed(:read_achievement) }
specify { is_expected.to be_disallowed(:read_achievement) }
context 'when the group is public' do
let_it_be(:group) { create(:group, :public) }
specify { is_expected.to be_allowed(:read_achievement) }
end
end
context 'when current user is not an owner' do

View File

@ -708,7 +708,7 @@ RSpec.describe 'Query.runner(id)', :freeze_time, feature_category: :fleet_visibi
end
let_it_be(:never_contacted_instance_runner) do
create(:ci_runner, description: 'Missing runner 1', created_at: 1.month.ago, contacted_at: nil)
create(:ci_runner, :unregistered, description: 'Missing runner 1', created_at: 1.month.ago)
end
let(:query) do

View File

@ -91,10 +91,8 @@ RSpec.describe 'UserAchievements', feature_category: :user_profile do
context 'when current user is not a member of the private group' do
let(:current_user) { create(:user) }
it 'returns all achievements' do
expect(graphql_data_at(:user, :userAchievements, :nodes)).to contain_exactly(
a_graphql_entity_for(non_revoked_achievement)
)
it 'returns no achievements' do
expect(graphql_data_at(:user, :userAchievements, :nodes)).to be_empty
end
end
end

View File

@ -24,6 +24,7 @@ RSpec.describe Projects::Settings::PackagesAndRegistriesController, feature_cate
before do
sign_in(user)
allow(ContainerRegistry::GitlabApiClient).to receive(:supports_gitlab_api?).and_return(true)
end
it 'pushes the feature flag "packages_protected_packages" to the view' do

View File

@ -37,11 +37,13 @@ RSpec.describe GenerateAsIfFossEnv, feature_category: :tooling do
'compile-storybook',
'compile-test-assets',
'cache-assets:test',
'detect-tests',
'eslint',
'generate-apollo-graphql-schema',
'graphql-schema-dump',
'jest 1/5',
'jest-integration',
'rubocop',
'qa:internal',
'qa:selectors',
'static-analysis'
@ -66,6 +68,8 @@ RSpec.describe GenerateAsIfFossEnv, feature_category: :tooling do
expect(generate.variables).to eq({
START_AS_IF_FOSS: 'true',
RUBY_VERSION: ENV['RUBY_VERSION'],
CI_MERGE_REQUEST_PROJECT_PATH: ENV['CI_MERGE_REQUEST_PROJECT_PATH'],
CI_MERGE_REQUEST_IID: ENV['CI_MERGE_REQUEST_IID'],
ENABLE_RSPEC: 'true',
ENABLE_RSPEC_FAST_SPEC_HELPER: 'true',
ENABLE_RSPEC_UNIT: 'true',
@ -84,11 +88,13 @@ RSpec.describe GenerateAsIfFossEnv, feature_category: :tooling do
ENABLE_COMPILE_STORYBOOK: 'true',
ENABLE_COMPILE_TEST_ASSETS: 'true',
ENABLE_CACHE_ASSETS: 'true',
ENABLE_DETECT_TESTS: 'true',
ENABLE_ESLINT: 'true',
ENABLE_GENERATE_APOLLO_GRAPHQL_SCHEMA: 'true',
ENABLE_GRAPHQL_SCHEMA_DUMP: 'true',
ENABLE_JEST: 'true',
ENABLE_JEST_INTEGRATION: 'true',
ENABLE_RUBOCOP: 'true',
ENABLE_QA_INTERNAL: 'true',
ENABLE_QA_SELECTORS: 'true',
ENABLE_STATIC_ANALYSIS: 'true'
@ -103,6 +109,8 @@ RSpec.describe GenerateAsIfFossEnv, feature_category: :tooling do
expect { generate.display }.to output(<<~ENV).to_stdout
START_AS_IF_FOSS=true
RUBY_VERSION=#{ENV['RUBY_VERSION']}
CI_MERGE_REQUEST_PROJECT_PATH=#{ENV['CI_MERGE_REQUEST_PROJECT_PATH']}
CI_MERGE_REQUEST_IID=#{ENV['CI_MERGE_REQUEST_IID']}
ENABLE_RSPEC=true
ENABLE_RSPEC_FAST_SPEC_HELPER=true
ENABLE_RSPEC_UNIT=true
@ -121,11 +129,13 @@ RSpec.describe GenerateAsIfFossEnv, feature_category: :tooling do
ENABLE_COMPILE_STORYBOOK=true
ENABLE_COMPILE_TEST_ASSETS=true
ENABLE_CACHE_ASSETS=true
ENABLE_DETECT_TESTS=true
ENABLE_ESLINT=true
ENABLE_GENERATE_APOLLO_GRAPHQL_SCHEMA=true
ENABLE_GRAPHQL_SCHEMA_DUMP=true
ENABLE_JEST=true
ENABLE_JEST_INTEGRATION=true
ENABLE_RUBOCOP=true
ENABLE_QA_INTERNAL=true
ENABLE_QA_SELECTORS=true
ENABLE_STATIC_ANALYSIS=true

View File

@ -149,40 +149,6 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
expect(pipeline.errors).to be_empty
expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('all')
end
context 'when auto_cancel_pipeline_on_job_failure feature flag is disabled' do
before do
stub_feature_flags(auto_cancel_pipeline_on_job_failure: false)
end
context 'when there are no other metadata settings present' do
it 'creates a pipeline without metadata' do
expect(pipeline).to be_persisted
expect(pipeline.errors).to be_empty
expect(pipeline.pipeline_metadata).to be_nil
end
end
context 'when other metadata settings are present' do
let(:config) do
<<~YAML
workflow:
name: pipeline_name
auto_cancel:
on_job_failure: all
test1:
script: exit 0
YAML
end
it 'creates a pipeline with on_job_failure' do
expect(pipeline).to be_persisted
expect(pipeline.errors).to be_empty
expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none')
end
end
end
end
context 'when on_job_failure is set to invalid' do

View File

@ -242,7 +242,7 @@ RSpec.describe ::Ci::Runners::RegisterRunnerService, '#execute', feature_categor
context 'when it exceeds the application limits' do
before do
create(:ci_runner, runner_type: :group_type, groups: [group], contacted_at: nil, created_at: 1.month.ago)
create(:ci_runner, :unregistered, runner_type: :group_type, groups: [group], created_at: 1.month.ago)
create(:plan_limits, :default_plan, ci_registered_group_runners: 1)
end
@ -261,7 +261,7 @@ RSpec.describe ::Ci::Runners::RegisterRunnerService, '#execute', feature_categor
context 'when abandoned runners cause application limits to not be exceeded' do
before do
create(:ci_runner, runner_type: :group_type, groups: [group], created_at: 4.months.ago, contacted_at: 3.months.ago)
create(:ci_runner, runner_type: :group_type, groups: [group], contacted_at: nil, created_at: 4.months.ago)
create(:ci_runner, :unregistered, runner_type: :group_type, groups: [group], created_at: 4.months.ago)
create(:plan_limits, :default_plan, ci_registered_group_runners: 1)
end