Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-12-05 18:33:35 +00:00
parent f585d21434
commit e0391a09d4
83 changed files with 1094 additions and 800 deletions

View File

@ -2,7 +2,6 @@
# Cop supports --autocorrect.
Layout/LineEndStringConcatenationIndentation:
Exclude:
- 'app/helpers/tags_helper.rb'
- 'app/helpers/tree_helper.rb'
- 'app/helpers/visibility_level_helper.rb'
- 'app/mailers/emails/projects.rb'

View File

@ -92,7 +92,6 @@ Layout/LineLength:
- 'app/helpers/labels_helper.rb'
- 'app/models/analytics/cycle_analytics/merge_request_stage_event.rb'
- 'app/models/application_record.rb'
- 'app/models/application_setting.rb'
- 'app/models/application_setting_implementation.rb'
- 'app/models/award_emoji.rb'
- 'app/models/blob_viewer/base.rb'

View File

@ -22,7 +22,6 @@ Layout/SpaceInsideParens:
- 'spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb'
- 'spec/lib/gitlab/database/migrations/runner_spec.rb'
- 'spec/lib/gitlab/database/reindexing/reindex_concurrently_spec.rb'
- 'spec/lib/gitlab/database_spec.rb'
- 'spec/lib/gitlab/diff/highlight_cache_spec.rb'
- 'spec/lib/gitlab/exclusive_lease_helpers_spec.rb'
- 'spec/lib/gitlab/git/blob_spec.rb'

View File

@ -11,7 +11,6 @@ Rails/EnumSyntax:
- 'app/models/anti_abuse/event.rb'
- 'app/models/anti_abuse/trust_score.rb'
- 'app/models/application_record.rb'
- 'app/models/application_setting.rb'
- 'app/models/authentication_event.rb'
- 'app/models/batched_git_ref_updates/deletion.rb'
- 'app/models/bulk_import.rb'

View File

@ -2,7 +2,6 @@
# Cop supports --autocorrect.
Rails/PluralizationGrammar:
Exclude:
- 'app/models/application_setting.rb'
- 'app/models/application_setting_implementation.rb'
- 'app/services/packages/helm/extract_file_metadata_service.rb'
- 'app/services/projects/lfs_pointers/lfs_download_service.rb'

View File

@ -54,7 +54,6 @@ Style/FormatString:
- 'app/mailers/emails/members.rb'
- 'app/mailers/emails/pages_domains.rb'
- 'app/mailers/emails/profile.rb'
- 'app/models/application_setting.rb'
- 'app/models/application_setting_implementation.rb'
- 'app/models/concerns/integrations/has_issue_tracker_fields.rb'
- 'app/models/concerns/limitable.rb'

View File

@ -50,7 +50,6 @@ Style/GuardClause:
- 'app/helpers/visibility_level_helper.rb'
- 'app/mailers/emails/notes.rb'
- 'app/models/alert_management/http_integration.rb'
- 'app/models/application_setting.rb'
- 'app/models/bulk_imports/entity.rb'
- 'app/models/ci/build_trace.rb'
- 'app/models/ci/job_artifact.rb'

View File

@ -25,7 +25,6 @@ Style/HashEachMethods:
- 'app/graphql/types/packages/package_type_enum.rb'
- 'app/graphql/types/release_asset_link_type_enum.rb'
- 'app/graphql/types/user_callout_feature_name_enum.rb'
- 'app/models/application_setting.rb'
- 'app/models/ci/pipeline.rb'
- 'app/models/concerns/bulk_insertable_associations.rb'
- 'app/services/packages/debian/process_package_file_service.rb'

View File

@ -2,7 +2,6 @@
# Cop supports --autocorrect.
Style/RedundantSelf:
Exclude:
- 'app/models/application_setting.rb'
- 'app/models/ci/group.rb'
- 'app/models/ci/job_artifact.rb'
- 'app/models/ci/job_token/project_scope_link.rb'

View File

@ -1 +1 @@
v0.0.16
v0.0.17

View File

@ -1 +1 @@
935c88d1737e9c58da7e13a9b913fdfc7faedc49
f3f31517a9b2d989c4e345d588bc316b01f19e7d

View File

@ -1,8 +1,11 @@
<script>
import { GlSingleStat } from '@gitlab/ui/dist/charts';
import { countFloatingPointDigits } from '~/lib/utils/number_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import MetricPopover from './metric_popover.vue';
const MAX_DISPLAYED_DECIMAL_PRECISION = 2;
export default {
name: 'MetricTile',
components: {
@ -17,8 +20,13 @@ export default {
},
computed: {
decimalPlaces() {
const parsedFloat = parseFloat(this.metric.value);
return Number.isNaN(parsedFloat) || Number.isInteger(parsedFloat) ? 0 : 1;
const { value } = this.metric;
const parsedFloat = parseFloat(value);
if (!Number.isNaN(parsedFloat) && !Number.isInteger(parsedFloat)) {
return Math.min(countFloatingPointDigits(value), MAX_DISPLAYED_DECIMAL_PRECISION);
}
return 0;
},
hasLinks() {
return this.metric.links?.length && this.metric.links[0].url;

View File

@ -206,3 +206,37 @@ const numberRegex = /^[0-9]+$/;
* @return {boolean}
*/
export const isPositiveInteger = (value) => numberRegex.test(value);
/**
* Splits a number into an integer and decimal component
* returns an object with the integer and decimal values extracted
*
* @param value
* @return {Object}
*/
export const splitDecimalNumber = (value) => {
if (isNumeric(value)) {
const parts = String(value).split('.');
if (value === 0) return { integer: '0', decimal: '0' };
if (parts.length) {
return parts.length > 1
? { integer: parts[0], decimal: parts[1] }
: { integer: parts[0], decimal: null };
}
}
return { integer: null, decimal: null };
};
/**
* Calculates the number of digits after the decimal place
*
* @param num - any numeric value
* @return number of digits after the decimal (if any)
*/
export const countFloatingPointDigits = (num = null) => {
if (!num || !isNumeric(num)) return 0;
const { decimal } = splitDecimalNumber(num);
return String(decimal).length;
};

View File

@ -9,7 +9,6 @@ export default {
provide() {
return {
projectPath: this.projectPath,
maxAllowedFileSize: this.maxAllowedFileSize,
markdownPreviewPath: this.markdownPreviewPath,
};
},
@ -22,10 +21,6 @@ export default {
type: Boolean,
required: true,
},
maxAllowedFileSize: {
type: Number,
required: true,
},
markdownPreviewPath: {
type: String,
required: true,

View File

@ -20,7 +20,7 @@ export default {
GlFormGroup,
GlFormInput,
},
inject: ['projectPath', 'maxAllowedFileSize', 'markdownPreviewPath'],
inject: ['projectPath', 'markdownPreviewPath'],
props: {
disableAttachments: {
type: Boolean,

View File

@ -468,7 +468,7 @@ export default {
>
{{ $options.i18n.fullTextSearchWarning }}
</gl-alert>
<div class="gl-border-b gl-flex gl-flex-col gl-gap-3 gl-bg-gray-10 gl-p-5 sm:gl-flex-row">
<div class="gl-border-b gl-flex gl-flex-col gl-gap-3 gl-bg-subtle gl-p-5 sm:gl-flex-row">
<gl-filtered-search
v-model="filterTokens"
class="gl-min-w-0 gl-flex-grow"

View File

@ -1,6 +1,12 @@
<script>
import { GlSprintf } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import StateContainer from '../state_container.vue';
export default {
components: {
GlSprintf,
StateContainer,
MrSecurityWidget: () =>
import('~/vue_merge_request_widget/widgets/security_reports/mr_widget_security_reports.vue'),
MrTestReportWidget: () => import('~/vue_merge_request_widget/widgets/test_report/index.vue'),
@ -9,14 +15,18 @@ export default {
MrAccessibilityWidget: () =>
import('~/vue_merge_request_widget/widgets/accessibility/index.vue'),
},
mixins: [glFeatureFlagsMixin()],
props: {
mr: {
type: Object,
required: true,
},
},
data() {
return {
collapsed: this.glFeatures.mrReportsTab,
};
},
computed: {
testReportWidget() {
return this.mr.testResultsPath && 'MrTestReportWidget';
@ -55,13 +65,37 @@ export default {
data-testid="mr-widget-app"
class="mr-section-container"
>
<component
:is="widget"
v-for="(widget, index) in widgets"
:key="widget.name || index"
:mr="mr"
class="mr-widget-section"
:class="{ 'gl-border-t gl-border-t-section': index > 0 }"
/>
<state-container
v-if="glFeatures.mrReportsTab"
status="success"
is-collapsible
collapse-on-desktop
:collapsed="collapsed"
:expand-details-tooltip="__('Expand merge request reports')"
:collapse-details-tooltip="__('Collapse merge request reports')"
@toggle="collapsed = !collapsed"
>
<strong>
<gl-sprintf :message="__('Merge reports (%{reportsCount}):')">
<template #reportsCount>{{ widgets.length }}</template>
</gl-sprintf>
</strong>
</state-container>
<div
v-show="!collapsed"
data-testid="reports-widgets-container"
:class="{
'gl-border-t gl-relative gl-border-t-section gl-bg-subtle': glFeatures.mrReportsTab,
}"
>
<component
:is="widget"
v-for="(widget, index) in widgets"
:key="widget.name || index"
:mr="mr"
class="mr-widget-section"
:class="{ 'gl-border-t gl-border-t-section': index > 0 }"
/>
</div>
</section>
</template>

View File

@ -341,9 +341,9 @@ export default {
<template>
<section class="media-section" data-testid="widget-extension">
<div class="gl-flex gl-px-5 gl-py-4 gl-pr-4">
<div class="gl-flex gl-px-5 gl-py-4 gl-pr-4" :class="{ 'gl-pl-9': glFeatures.mrReportsTab }">
<status-icon
:level="1"
:level="glFeatures.mrReportsTab ? 2 : 1"
:name="widgetName"
:is-loading="shouldShowLoadingIcon"
:icon-name="summaryStatusIcon"

View File

@ -54,6 +54,8 @@ export default {
i18n: {
enableConfidentiality: s__('WorkItem|Turn on confidentiality'),
disableConfidentiality: s__('WorkItem|Turn off confidentiality'),
confidentialityEnabled: s__('WorkItem|Confidentiality turned on.'),
confidentialityDisabled: s__('WorkItem|Confidentiality turned off.'),
confidentialParentTooltip: s__(
'WorkItem|Child items of a confidential parent must be confidential. Turn off confidentiality on the parent item first.',
),
@ -280,6 +282,11 @@ export default {
isEpic() {
return this.workItemType === WORK_ITEM_TYPE_VALUE_EPIC;
},
confidentialityToggledText() {
return this.isConfidential
? this.$options.i18n.confidentialityDisabled
: this.$options.i18n.confidentialityEnabled;
},
},
methods: {
copyToClipboard(text, message) {
@ -292,6 +299,7 @@ export default {
handleToggleWorkItemConfidentiality() {
this.track('click_toggle_work_item_confidentiality');
this.$emit('toggleWorkItemConfidentiality', !this.isConfidential);
toast(this.confidentialityToggledText);
this.closeDropdown();
},
handleDelete() {

View File

@ -22,7 +22,6 @@ module Projects
data = {
projectPath: project.full_path,
can_write_model_registry: can_write_model_registry?(user, project),
max_allowed_file_size: max_allowed_file_size(project),
markdown_preview_path: preview_markdown_path(project)
}

View File

@ -15,11 +15,11 @@ module TagsHelper
def tag_description_help_text
text = s_('TagsPage|Optionally, add a message to the tag. Leaving this blank creates '\
'a %{link_start}lightweight tag.%{link_end}') % {
link_start: '<a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging" ' \
'target="_blank" rel="noopener noreferrer">',
link_end: '</a>'
}
'a %{link_start}lightweight tag.%{link_end}') % {
link_start: '<a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging" ' \
'target="_blank" rel="noopener noreferrer">',
link_end: '</a>'
}
text.html_safe
end

View File

@ -17,7 +17,8 @@ class ApplicationSetting < ApplicationRecord
encrypted_vertex_ai_access_token
encrypted_vertex_ai_access_token_iv
], remove_with: '17.5', remove_after: '2024-09-19'
ignore_columns %i[toggle_security_policy_custom_ci lock_toggle_security_policy_custom_ci], remove_with: '17.6', remove_after: '2024-10-17'
ignore_columns %i[toggle_security_policy_custom_ci lock_toggle_security_policy_custom_ci],
remove_with: '17.6', remove_after: '2024-10-17'
INSTANCE_REVIEW_MIN_USERS = 50
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
@ -28,7 +29,11 @@ class ApplicationSetting < ApplicationRecord
# Validate URIs in this model according to the current value of the `deny_all_requests_except_allowed` property,
# rather than the persisted value.
ADDRESSABLE_URL_VALIDATION_OPTIONS = { deny_all_requests_except_allowed: ->(settings) { settings.deny_all_requests_except_allowed } }.freeze
ADDRESSABLE_URL_VALIDATION_OPTIONS = {
deny_all_requests_except_allowed: ->(settings) do
settings.deny_all_requests_except_allowed
end
}.freeze
HUMANIZED_ATTRIBUTES = {
archive_builds_in_seconds: 'Archive job value'
@ -43,8 +48,8 @@ class ApplicationSetting < ApplicationRecord
INACTIVE_RESOURCE_ACCESS_TOKENS_DELETE_AFTER_DAYS = 30
enum whats_new_variant: { all_tiers: 0, current_tier: 1, disabled: 2 }, _prefix: true
enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }, _prefix: true
enum :whats_new_variant, { all_tiers: 0, current_tier: 1, disabled: 2 }, prefix: true
enum :email_confirmation_setting, { off: 0, soft: 1, hard: 2 }, prefix: true
# We won't add a prefix here as this token is deprecated and being
# disabled in 17.0
@ -106,10 +111,13 @@ class ApplicationSetting < ApplicationRecord
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
chronic_duration_attr :group_runner_token_expiration_interval_human_readable, :group_runner_token_expiration_interval
chronic_duration_attr :project_runner_token_expiration_interval_human_readable, :project_runner_token_expiration_interval
chronic_duration_attr :project_runner_token_expiration_interval_human_readable,
:project_runner_token_expiration_interval
validates :default_branch_protection_defaults, json_schema: { filename: 'default_branch_protection_defaults' }
validates :default_branch_protection_defaults, bytesize: { maximum: -> { DEFAULT_BRANCH_PROTECTIONS_DEFAULT_MAX_SIZE } }
validates :default_branch_protection_defaults, bytesize: { maximum: -> {
DEFAULT_BRANCH_PROTECTIONS_DEFAULT_MAX_SIZE
} }
validates :external_pipeline_validation_service_timeout,
:failed_login_attempts_unlock_period_in_minutes,
@ -318,8 +326,10 @@ class ApplicationSetting < ApplicationRecord
validates :default_preferred_language, presence: true, inclusion: { in: Gitlab::I18n.available_locales }
validates :personal_access_token_prefix,
format: { with: %r{\A[a-zA-Z0-9_+=/@:.-]+\z},
message: N_("can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'") },
format: {
with: %r{\A[a-zA-Z0-9_+=/@:.-]+\z},
message: N_("can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'")
},
length: { maximum: 20, message: N_('is too long (maximum is %{count} characters)') },
allow_blank: true
@ -367,12 +377,13 @@ class ApplicationSetting < ApplicationRecord
:push_event_hooks_limit,
numericality: { greater_than_or_equal_to: 0 }
validates :wiki_page_max_content_bytes, numericality: { only_integer: true, greater_than_or_equal_to: 1.kilobytes }
validates :wiki_page_max_content_bytes, numericality: { only_integer: true, greater_than_or_equal_to: 1.kilobyte }
validates :wiki_asciidoc_allow_uri_includes, inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :email_restrictions, untrusted_regexp: true
validates :hashed_storage_enabled, inclusion: { in: [true], message: N_("Hashed storage can't be disabled anymore for new projects") }
validates :hashed_storage_enabled,
inclusion: { in: [true], message: N_("Hashed storage can't be disabled anymore for new projects") }
validates :container_registry_expiration_policies_caching,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
@ -391,7 +402,8 @@ class ApplicationSetting < ApplicationRecord
validates :deactivate_dormant_users_period,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 90, message: N_("'%{value}' days of inactivity must be greater than or equal to 90") },
numericality: { only_integer: true, greater_than_or_equal_to: 90,
message: N_("'%{value}' days of inactivity must be greater than or equal to 90") },
if: :deactivate_dormant_users?
validates :allow_possible_spam,
@ -417,7 +429,7 @@ class ApplicationSetting < ApplicationRecord
validates_each :restricted_visibility_levels do |record, attr, value|
value&.each do |level|
unless Gitlab::VisibilityLevel.options.value?(level)
record.errors.add(attr, _("'%{level}' is not a valid visibility level") % { level: level })
record.errors.add(attr, format(_("'%{level}' is not a valid visibility level"), level: level))
end
end
end
@ -429,7 +441,7 @@ class ApplicationSetting < ApplicationRecord
validates_each :import_sources, on: :update do |record, attr, value|
value&.each do |source|
unless Gitlab::ImportSources.options.value?(source)
record.errors.add(attr, _("'%{source}' is not a import source") % { source: source })
record.errors.add(attr, format(_("'%{source}' is not a import source"), source: source))
end
end
end
@ -463,7 +475,8 @@ class ApplicationSetting < ApplicationRecord
validates :lets_encrypt_notification_email,
devise_email: true,
format: { without: /@example\.(com|org|net)\z/, message: N_("Let's Encrypt does not accept emails on example.com") },
format: { without: /@example\.(com|org|net)\z/,
message: N_("Let's Encrypt does not accept emails on example.com") },
allow_blank: true
validates :lets_encrypt_notification_email,
@ -706,13 +719,13 @@ class ApplicationSetting < ApplicationRecord
validates :floc_enabled,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
enum sidekiq_job_limiter_mode: {
enum :sidekiq_job_limiter_mode, {
Gitlab::SidekiqMiddleware::SizeLimiter::Validator::TRACK_MODE => 0,
Gitlab::SidekiqMiddleware::SizeLimiter::Validator::COMPRESS_MODE => 1 # The default
}
validates :sidekiq_job_limiter_mode,
inclusion: { in: self.sidekiq_job_limiter_modes }
inclusion: { in: sidekiq_job_limiter_modes }
validates :sentry_enabled,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
@ -748,11 +761,13 @@ class ApplicationSetting < ApplicationRecord
validates :inactive_projects_send_warning_email_after_months,
numericality: { only_integer: true, greater_than: 0, less_than: :inactive_projects_delete_after_months }
validates :prometheus_alert_db_indicators_settings, json_schema: { filename: 'application_setting_prometheus_alert_db_indicators_settings' }, allow_nil: true
validates :prometheus_alert_db_indicators_settings,
json_schema: { filename: 'application_setting_prometheus_alert_db_indicators_settings' }, allow_nil: true
validates :sentry_clientside_traces_sample_rate,
presence: true,
numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1, message: N_('must be a value between 0 and 1') }
numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1,
message: N_('must be a value between 0 and 1') }
validates :package_registry_allow_anyone_to_pull_option,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
@ -799,26 +814,35 @@ class ApplicationSetting < ApplicationRecord
attr_encrypted :recaptcha_private_key, encryption_options_base_32_aes_256_gcm
attr_encrypted :recaptcha_site_key, encryption_options_base_32_aes_256_gcm
attr_encrypted :slack_app_secret, encryption_options_base_32_aes_256_gcm
attr_encrypted :slack_app_signing_secret, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :slack_app_signing_secret,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :slack_app_verification_token, encryption_options_base_32_aes_256_gcm
attr_encrypted :ci_jwt_signing_key, encryption_options_base_32_aes_256_gcm
attr_encrypted :ci_job_token_signing_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :ci_job_token_signing_key,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :customers_dot_jwt_signing_key, encryption_options_base_32_aes_256_gcm
attr_encrypted :secret_detection_token_revocation_token, encryption_options_base_32_aes_256_gcm
attr_encrypted :cloud_license_auth_token, encryption_options_base_32_aes_256_gcm
attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_32_aes_256_gcm
attr_encrypted :mailgun_signing_key, encryption_options_base_32_aes_256_gcm.merge(encode: false)
attr_encrypted :database_grafana_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :database_grafana_api_key,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_client_xid, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_client_secret, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_public_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_private_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_data_exchange_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_client_secret,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_public_api_key,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_private_api_key,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_data_exchange_key,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :cube_api_key, encryption_options_base_32_aes_256_gcm
attr_encrypted :telesign_customer_xid, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :telesign_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :product_analytics_configurator_connection_string, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :secret_detection_service_auth_token, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :product_analytics_configurator_connection_string,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :secret_detection_service_auth_token,
encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
# Restricting the validation to `on: :update` only to avoid cyclical dependencies with
# License <--> ApplicationSetting. This method calls a license check when we create
@ -871,7 +895,9 @@ class ApplicationSetting < ApplicationRecord
after_commit do
reset_memoized_terms
end
after_commit :expire_performance_bar_allowed_user_ids_cache, if: -> { previous_changes.key?('performance_bar_allowed_group_id') }
after_commit :expire_performance_bar_allowed_user_ids_cache, if: -> {
previous_changes.key?('performance_bar_allowed_group_id')
}
after_commit :reset_deletion_warning_redis_key, if: :should_reset_inactive_project_deletion_warning?
def validate_grafana_url
@ -948,9 +974,9 @@ class ApplicationSetting < ApplicationRecord
# prevent this from happening, we do a sanity check that the
# primary key constraint is present before inserting a new entry.
def self.check_schema!
return if connection.primary_key(self.table_name).present?
return if connection.primary_key(table_name).present?
raise "The `#{self.table_name}` table is missing a primary key constraint in the database schema"
raise "The `#{table_name}` table is missing a primary key constraint in the database schema"
end
# By default, the backend is Rails.cache, which uses
@ -961,11 +987,15 @@ class ApplicationSetting < ApplicationRecord
Gitlab::ProcessMemoryCache.cache_backend
end
def self.human_attribute_name(attribute, *options)
HUMANIZED_ATTRIBUTES[attribute.to_sym] || super
end
def recaptcha_or_login_protection_enabled
recaptcha_enabled || login_recaptcha_protection_enabled
end
kroki_formats_attributes.keys.each do |key|
kroki_formats_attributes.each_key do |key|
define_method :"kroki_formats_#{key}=" do |value|
super(::Gitlab::Utils.to_boolean(value))
end
@ -998,10 +1028,6 @@ class ApplicationSetting < ApplicationRecord
private
def self.human_attribute_name(attribute, *options)
HUMANIZED_ATTRIBUTES[attribute.to_sym] || super
end
def parsed_grafana_url
@parsed_grafana_url ||= Gitlab::Utils.parse_url(grafana_url)
end
@ -1013,19 +1039,19 @@ class ApplicationSetting < ApplicationRecord
deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?,
outbound_local_requests_allowlist: Gitlab::CurrentSettings.outbound_local_requests_whitelist)[0]
rescue Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError => e
self.errors.add(
errors.add(
:kroki_url,
"is not valid. #{e}"
)
end
def validate_url(parsed_url, name, error_message)
unless parsed_url
self.errors.add(
name,
"must be a valid relative or absolute URL. #{error_message}"
)
end
return if parsed_url
errors.add(
name,
"must be a valid relative or absolute URL. #{error_message}"
)
end
def reset_deletion_warning_redis_key
@ -1039,7 +1065,8 @@ class ApplicationSetting < ApplicationRecord
end
def should_reset_inactive_project_deletion_warning?
saved_change_to_inactive_projects_delete_after_months? || saved_change_to_delete_inactive_projects?(from: true, to: false)
saved_change_to_inactive_projects_delete_after_months? || saved_change_to_delete_inactive_projects?(from: true,
to: false)
end
end

View File

@ -553,11 +553,15 @@ module Ci
end
def compute_token_expiration_group
::Group.where(id: runner_namespaces.map(&:namespace_id)).map(&:effective_runner_token_expiration_interval).compact.min&.from_now
::Group.id_in(runner_namespaces.map(&:namespace_id))
.map(&:effective_runner_token_expiration_interval)
.compact.min&.from_now
end
def compute_token_expiration_project
Project.where(id: runner_projects.map(&:project_id)).map(&:effective_runner_token_expiration_interval).compact.min&.from_now
Project.id_in(runner_projects.map(&:project_id))
.map(&:effective_runner_token_expiration_interval)
.compact.min&.from_now
end
def cleanup_runner_queue

View File

@ -832,22 +832,18 @@ class Namespace < ApplicationRecord
end
def refresh_access_of_projects_invited_groups
if Feature.enabled?(:specialized_worker_for_group_lock_update_auth_recalculation, self)
Project
.where(namespace_id: id)
.joins(:project_group_links)
.distinct
.find_each do |project|
AuthorizedProjectUpdate::ProjectRecalculateWorker.perform_async(project.id)
end
# Until we compare the inconsistency rates of the new specialized worker and
# the old approach, we still run AuthorizedProjectsWorker
# but with some delay and lower urgency as a safety net.
enqueue_jobs_for_groups_requiring_authorizations_refresh(priority: UserProjectAccessChangedService::LOW_PRIORITY)
else
enqueue_jobs_for_groups_requiring_authorizations_refresh(priority: UserProjectAccessChangedService::HIGH_PRIORITY)
Project
.where(namespace_id: id)
.joins(:project_group_links)
.distinct
.find_each do |project|
AuthorizedProjectUpdate::ProjectRecalculateWorker.perform_async(project.id)
end
# Until we compare the inconsistency rates of the new specialized worker and
# the old approach, we still run AuthorizedProjectsWorker
# but with some delay and lower urgency as a safety net.
enqueue_jobs_for_groups_requiring_authorizations_refresh(priority: UserProjectAccessChangedService::LOW_PRIORITY)
end
def enqueue_jobs_for_groups_requiring_authorizations_refresh(priority:)

View File

@ -31,6 +31,8 @@ module Packages
process_package_update
end
end
create_symbol_files
rescue ActiveRecord::RecordInvalid => e
raise InvalidMetadataError, e.message
rescue Zip::Error
@ -57,7 +59,6 @@ module Packages
build_infos = package_to_destroy&.build_infos || []
update_package(target_package, build_infos)
create_symbol_files
::Packages::UpdatePackageFileService.new(@package_file, package_id: target_package.id, file_name: package_filename)
.execute
package_to_destroy&.destroy!

View File

@ -13,10 +13,11 @@
- add_page_specific_style 'page_bundles/reports'
- add_page_specific_style 'page_bundles/ci_status'
- add_page_startup_api_call @endpoint_metadata_url
- add_page_startup_api_call @linked_file_url if @linked_file_url
- if mr_action == 'diffs' && !@file_by_file_default
- add_page_startup_api_call @endpoint_diff_batch_url
- unless ::Feature.enabled?(:rapid_diffs, current_user, type: :wip) && params[:rapid_diffs] == 'true'
- add_page_startup_api_call @endpoint_metadata_url
- add_page_startup_api_call @linked_file_url if @linked_file_url
- if mr_action == 'diffs' && !@file_by_file_default
- add_page_startup_api_call @endpoint_diff_batch_url
.merge-request{ data: { mr_action: mr_action, url: merge_request_path(@merge_request, format: :json), project_path: project_path(@merge_request.project), lock_version: @merge_request.lock_version, diffs_batch_cache_key: @diffs_batch_cache_key } }
= render "projects/merge_requests/mr_title"

View File

@ -1,4 +1,4 @@
- breadcrumb_title s_('ModelRegistry|New model')
- page_title s_('ModelRegistry|New model')
#js-mount-new-ml-model{ data: { view_model: index_ml_model_data(@project, @current_user) } }
#js-mount-new-ml-model{ data: { view_model: new_ml_model_data(@project, @current_user) } }

View File

@ -1,8 +0,0 @@
---
name: specialized_worker_for_group_lock_update_auth_recalculation
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66525
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/336592
milestone: '14.2'
type: development
group: group::authorization
default_enabled: true

View File

@ -0,0 +1,8 @@
---
migration_job_name: BackfillResourceWeightEventsNamespaceId
description: Backfills sharding key `resource_weight_events.namespace_id` from `issues`.
feature_category: team_planning
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/174405
milestone: '17.7'
queued_migration_version: 20241202142254
finalized_by: # version of the migration that finalized this BBM

View File

@ -18,3 +18,4 @@ desired_sharding_key:
sharding_key: namespace_id
belongs_to: issue
table_size: small
desired_sharding_key_migration_job_name: BackfillResourceWeightEventsNamespaceId

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddNamespaceIdToResourceWeightEvents < Gitlab::Database::Migration[2.2]
milestone '17.7'
def change
add_column :resource_weight_events, :namespace_id, :bigint
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class IndexResourceWeightEventsOnNamespaceId < Gitlab::Database::Migration[2.2]
milestone '17.7'
disable_ddl_transaction!
INDEX_NAME = 'index_resource_weight_events_on_namespace_id'
def up
add_concurrent_index :resource_weight_events, :namespace_id, name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :resource_weight_events, INDEX_NAME
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddResourceWeightEventsNamespaceIdFk < Gitlab::Database::Migration[2.2]
milestone '17.7'
disable_ddl_transaction!
def up
add_concurrent_foreign_key :resource_weight_events, :namespaces, column: :namespace_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :resource_weight_events, column: :namespace_id
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class AddResourceWeightEventsNamespaceIdTrigger < Gitlab::Database::Migration[2.2]
milestone '17.7'
def up
install_sharding_key_assignment_trigger(
table: :resource_weight_events,
sharding_key: :namespace_id,
parent_table: :issues,
parent_sharding_key: :namespace_id,
foreign_key: :issue_id
)
end
def down
remove_sharding_key_assignment_trigger(
table: :resource_weight_events,
sharding_key: :namespace_id,
parent_table: :issues,
parent_sharding_key: :namespace_id,
foreign_key: :issue_id
)
end
end

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
class QueueBackfillResourceWeightEventsNamespaceId < Gitlab::Database::Migration[2.2]
milestone '17.7'
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
MIGRATION = "BackfillResourceWeightEventsNamespaceId"
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 1000
SUB_BATCH_SIZE = 100
def up
queue_batched_background_migration(
MIGRATION,
:resource_weight_events,
:id,
:namespace_id,
:issues,
:namespace_id,
:issue_id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(
MIGRATION,
:resource_weight_events,
:id,
[
:namespace_id,
:issues,
:namespace_id,
:issue_id
]
)
end
end

View File

@ -0,0 +1 @@
9424cfaf0ef1901c77d2be035812764811d78ea903975370ef55d58005af0c7b

View File

@ -0,0 +1 @@
f0a1dbd97945d7a6302de20b5603812aacff11f063d0be57f289adee15f75e9b

View File

@ -0,0 +1 @@
b2b931e7b644a07bb468b5b4cf8f822094c08f44696044360db83e16bdee5c51

View File

@ -0,0 +1 @@
30f26b3bea60cb0a03e0623cc825c6641a3155ab327b2aaafb330e823b256536

View File

@ -0,0 +1 @@
fb67017012babaa58f32b3ea301123cf46a606b96967f4dca21e97c6660a3679

View File

@ -2945,6 +2945,22 @@ RETURN NEW;
END
$$;
CREATE FUNCTION trigger_e4a6cde57b42() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW."namespace_id" IS NULL THEN
SELECT "namespace_id"
INTO NEW."namespace_id"
FROM "issues"
WHERE "issues"."id" = NEW."issue_id";
END IF;
RETURN NEW;
END
$$;
CREATE FUNCTION trigger_e815625b59fa() RETURNS trigger
LANGUAGE plpgsql
AS $$
@ -19207,7 +19223,8 @@ CREATE TABLE resource_weight_events (
issue_id bigint NOT NULL,
weight integer,
created_at timestamp with time zone NOT NULL,
previous_weight integer
previous_weight integer,
namespace_id bigint
);
CREATE SEQUENCE resource_weight_events_id_seq
@ -32362,6 +32379,8 @@ CREATE INDEX index_resource_weight_events_on_issue_id_and_created_at ON resource
CREATE INDEX index_resource_weight_events_on_issue_id_and_weight ON resource_weight_events USING btree (issue_id, weight);
CREATE INDEX index_resource_weight_events_on_namespace_id ON resource_weight_events USING btree (namespace_id);
CREATE INDEX index_resource_weight_events_on_user_id ON resource_weight_events USING btree (user_id);
CREATE INDEX index_reviews_on_author_id ON reviews USING btree (author_id);
@ -35748,6 +35767,8 @@ CREATE TRIGGER trigger_e1da4a738230 BEFORE INSERT OR UPDATE ON vulnerability_ext
CREATE TRIGGER trigger_e49ab4d904a0 BEFORE INSERT OR UPDATE ON vulnerability_finding_links FOR EACH ROW EXECUTE FUNCTION trigger_e49ab4d904a0();
CREATE TRIGGER trigger_e4a6cde57b42 BEFORE INSERT OR UPDATE ON resource_weight_events FOR EACH ROW EXECUTE FUNCTION trigger_e4a6cde57b42();
CREATE TRIGGER trigger_e815625b59fa BEFORE INSERT OR UPDATE ON resource_link_events FOR EACH ROW EXECUTE FUNCTION trigger_e815625b59fa();
CREATE TRIGGER trigger_ebab34f83f1d BEFORE INSERT OR UPDATE ON packages_debian_publications FOR EACH ROW EXECUTE FUNCTION trigger_ebab34f83f1d();
@ -36794,6 +36815,9 @@ ALTER TABLE ONLY dependency_proxy_blob_states
ALTER TABLE ONLY issues
ADD CONSTRAINT fk_96b1dd429c FOREIGN KEY (milestone_id) REFERENCES milestones(id) ON DELETE SET NULL;
ALTER TABLE ONLY resource_weight_events
ADD CONSTRAINT fk_97c7849ca4 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY agent_user_access_group_authorizations
ADD CONSTRAINT fk_97ce8e8284 FOREIGN KEY (agent_id) REFERENCES cluster_agents(id) ON DELETE CASCADE;

View File

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 232 KiB

View File

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 176 KiB

View File

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View File

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

107
doc/development/logs.md Normal file
View File

@ -0,0 +1,107 @@
---
stage: Monitor
group: Platform Insights
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
---
# Logs
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed
**Status:** Beta
NOTE:
This feature is not under active development.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/143027) in GitLab 16.10 [with a flag](../administration/feature_flags.md) named `observability_logs`. Disabled by default. This feature is in [beta](../policy/development_stages_support.md#beta).
> - Feature flag [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158786) in GitLab 17.3 to the `observability_features` [feature flag](../administration/feature_flags.md), disabled by default. The previous feature flag (`observability_logs`) was removed.
> - [Introduced](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/100) for self-managed in GitLab 17.3.
> - [Changed](https://gitlab.com/gitlab-com/marketing/digital-experience/buyer-experience/-/issues/4198) to internal Beta in GitLab 17.7.
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
GitLab supports centralized application and infrastructure logs collection, storage, and analysis.
GitLab Logging provides insight about the operational health of monitored systems.
Use logs to learn more about your systems and applications in a given range of time.
## Logs ingestion limits
Logs ingest a maximum of 102,400 bytes per minute.
When the limit is exceeded, a `429 Too Many Requests` response is returned.
To request a limit increase to 1,048,576 bytes per minute, contact [GitLab support](https://about.gitlab.com/support/).
## Configure logging
Configure logging to enable it for a project.
Prerequisites:
- You must have at least the Maintainer role for the project.
1. 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 `api` scope and **Developer** role or greater.
Save the access token value for later.
1. To configure your application to send GitLab logs, set the following environment variables:
```shell
OTEL_EXPORTER = "otlphttp"
OTEL_EXPORTER_OTLP_ENDPOINT = "https://gitlab.example.com/api/v4/projects/<gitlab-project-id>/observability/"
OTEL_EXPORTER_OTLP_HEADERS = "PRIVATE-TOKEN=<gitlab-access-token>"
```
Use the following values:
- `gitlab.example.com` - The hostname for your self-managed instance, or `gitlab.com`
- `gitlab-project-id` - The project ID
- `gitlab-access-token` - The access token you created
Logs are configured for your project.
When you run your application, the OpenTelemetry exporter sends logs to GitLab.
## View logs
You can view the logs for a given project:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Logs**.
A list of logs is displayed. Currently log date, level, service, and message are supported.
Select a log line to view its details.
You can either filter logs by attribute or query log strings with the search bar.
The log volume chart at the top shows the number of logs ingested over the given time period.
![list of logs](img/logs_list_v17_1.png)
### View logs details
It is also possible to see log line details such as metadata and resource attributes.
![logs details](img/logs_details_v17_1.png)
### Create an issue for a log
You can create an issue to track any action taken to resolve or investigate a log. To create an issue for a log:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Logs**.
1. From the list of logs, select a log.
1. In the details drawer, select **Create issue**.
The issue is created in the selected project and pre-filled with information from the log.
You can edit the issue title and description.
### View issues related to a log
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Logs**.
1. From the list of logs, select a log.
1. In the details drawer, scroll to **Related issues**.
1. Optional. To view the issue details, select an issue.

136
doc/development/metrics.md Normal file
View File

@ -0,0 +1,136 @@
---
stage: Monitor
group: Platform Insights
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
---
# Metrics
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed
**Status:** Beta
NOTE:
This feature is not under active development.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124966) in GitLab 16.7 [with a flag](../administration/feature_flags.md) named `observability_metrics`. Disabled by default. This feature is an [experiment](../policy/development_stages_support.md#experiment).
> - Feature flag [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158786) in GitLab 17.3 to the `observability_features` [feature flag](../administration/feature_flags.md), disabled by default. The previous feature flag (`observability_metrics`) was removed.
> - [Introduced](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/100) for self-managed in GitLab 17.3.
> - [Changed](https://gitlab.com/gitlab-com/marketing/digital-experience/buyer-experience/-/issues/4198) to internal beta in GitLab 17.7.
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
Metrics provide insight about the operational health of monitored systems.
Use metrics to learn more about your systems and applications in a given time range.
Metrics are structured as time series data, and are:
- Indexed by timestamp
- Continuously expanding as additional data is gathered
- Usually aggregated, downsampled, and queried by range
- Have write-intensive requirements
## Configure metrics
Configure metrics to enable them for a project.
Prerequisites:
You must have at least the Maintainer role for the project.
1. 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 `api` scope and **Developer** role or greater.
Save the access token value for later.
1. To configure your application to send GitLab metrics, set the following environment variables:
```shell
OTEL_EXPORTER = "otlphttp"
OTEL_EXPORTER_OTLP_ENDPOINT = "https://gitlab.example.com/api/v4/projects/<gitlab-project-id>/observability/"
OTEL_EXPORTER_OTLP_HEADERS = "PRIVATE-TOKEN=<gitlab-access-token>"
```
Use the following values:
- `gitlab.example.com` - The hostname for your self-managed instance, or `gitlab.com`
- `gitlab-project-id` - The project ID
- `gitlab-access-token` - The access token you created
Metrics are configured for your project.
When you run your application, the OpenTelemetry exporter sends metrics to GitLab.
## View metrics
You can view the metrics for a given project:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
A list of metrics is displayed.
Select a metric to view its details.
![list of metrics](img/metrics_list_v17_0.png)
Each metric contains one or more attributes. You can filter
metrics by attribute with the search bar.
### Metric details
Metrics are displayed as either a sum, a gauge, or a histogram.
The metric details page displays a chart depending on the type of metric.
On the metric details page, you can also view metrics for a specific time range, and
aggregate metrics by attribute:
![metrics details](img/metrics_detail_v17_0.png)
To make data lookups fast, depending on what time period you filter by,
GitLab automatically chooses the proper aggregation.
For example, if you search for more than seven days of data, the API returns only daily aggregates.
### Aggregations by search period
The following table shows what type of aggregation is used for each search period:
|Period|Aggregation used|
|---|---|
| Less than 30 minutes | Raw data as ingested |
| More than 30 minutes and less than one hour | By minute |
| More than one hour and less than 72 hours | Hourly |
| More than 72 hours | Daily |
### Metrics ingestion limits
Metrics ingest a maximum of 102,400 bytes per minute.
When the limit is exceeded, a `429 Too Many Requests` response is returned.
To request a limit increase to 1,048,576 bytes per minute, contact [GitLab support](https://about.gitlab.com/support/).
### Data retention
GitLab has a retention limit of 30 days for all ingested metrics.
### Create an issue for a metric
You can create an issue to track any action taken to resolve or investigate a metric. To create an issue for a metric:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
1. From the list of metrics, select a metric.
1. Select **Create issue**.
The issue is created in the selected project and pre-filled with information from the metric.
You can edit the issue title and description.
### View issues related to a metric
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
1. From the list of metrics, select a metric.
1. Scroll to **Related issues**.
1. Optional. To view the issue details, select an issue.

View File

@ -22,21 +22,21 @@ Once you have a project identified to use:
1. Note the ID of the project (from the three dots at upper right of main project page).
1. Note the ID of the top-level group which contains the project.
1. When setting the environment variables for the following steps, add them to `env.runit` in the root of the `gitlab-development-kit` folder.
1. Follow instructions to [configure distributed tracing for a project](../../operations/tracing.md), with the following custom settings:
1. Follow instructions to [configure distributed tracing for a project](../tracing.md), with the following custom settings:
- For the `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` environment variable, use the following value:
```shell
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://<gitlab-host>/v3/<gitlab-top-level-group-id>/<gitlab-project-id>/ingest/traces"
```
1. Follow instructions to [configure distributed metrics for a project](../../operations/metrics.md), with the following custom settings:
1. Follow instructions to [configure distributed metrics for a project](../metrics.md), with the following custom settings:
- For the `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` environment variable, use the following value:
```shell
export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT="https://<gitlab-host>/v3/<gitlab-top-level-group-id>/<gitlab-project-id>/ingest/metrics"
```
1. Follow instructions to [configure distributed logs for a project](../../operations/logs.md), with the following custom settings:
1. Follow instructions to [configure distributed logs for a project](../logs.md), with the following custom settings:
- For the `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` environment variable, use the following value:
```shell
@ -55,9 +55,9 @@ Once you have a project identified to use:
## References
- [Distributed Tracing](../../operations/tracing.md)
- [Metrics](../../operations/metrics.md)
- [Logs](../../operations/logs.md)
- [Distributed Tracing](../tracing.md)
- [Metrics](../metrics.md)
- [Logs](../logs.md)
## Related design documents

110
doc/development/tracing.md Normal file
View File

@ -0,0 +1,110 @@
---
stage: Monitor
group: Platform Insights
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
---
# Distributed tracing
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed
**Status:** Beta
NOTE:
This feature is not under active development.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124966) in GitLab 16.2 [with a flag](../administration/feature_flags.md) named `observability_tracing`. Disabled by default. This feature is in [beta](../policy/development_stages_support.md#beta).
> - Feature flag [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158786) in GitLab 17.3 to the `observability_features` [feature flag](../administration/feature_flags.md), disabled by default. The previous feature flag `observability_tracing` was removed.
> - [Introduced](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/100) for self-managed in GitLab 17.3.
> - [Changed](https://gitlab.com/gitlab-com/marketing/digital-experience/buyer-experience/-/issues/4198) to internal beta in GitLab 17.7.
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
With distributed tracing, you can troubleshoot application performance issues by inspecting how a request moves through different services and systems, the timing of each operation, and any errors or logs as they occur. Tracing is particularly useful in the context of microservice applications, which group multiple independent services collaborating to fulfill user requests.
This feature is in [beta](../policy/development_stages_support.md). For more information, see the [group direction page](https://about.gitlab.com/direction/monitor/observability/). To leave feedback about tracing bugs or functionality, comment in the [feedback issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2590) or open a [new issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/new).
## Tracing ingestion limits
Tracing ingests a maximum of 102,400 bytes per minute.
When the limit is exceeded, a `429 Too Many Requests` response is returned.
To request a limit increase to 1,048,576 bytes per minute, contact [GitLab support](https://about.gitlab.com/support/).
## Data retention
GitLab retains all traces for 30 days.
## Configure distributed tracing for a project
Configure distributed tracing to enable it for a project.
Prerequisites:
- You must have at least the Maintainer role for the project.
1. 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 `api` scope and **Developer** role or greater.
Save the access token value for later.
1. To configure your application to send GitLab traces, set the following environment variables:
```shell
OTEL_EXPORTER = "otlphttp"
OTEL_EXPORTER_OTLP_ENDPOINT = "https://gitlab.example.com/api/v4/projects/<gitlab-project-id>/observability/"
OTEL_EXPORTER_OTLP_HEADERS = "PRIVATE-TOKEN=<gitlab-access-token>"
```
Use the following values:
- `gitlab.example.com` - The hostname for your self-managed instance, or `gitlab.com`
- `gitlab-project-id` - The project ID.
- `gitlab-access-token` - The access token you created
When your application is configured, run it, and the OpenTelemetry exporter attempts to send
traces to GitLab.
## View your traces
If your traces are exported successfully, you can see them in the project.
To view the list of traces:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Traces**.
1. Optional. To view the details of a trace, select it from the list.
![list of traces](img/tracing_list_v16.11.png)
The trace details page and a list of spans are displayed.
![tracing details](img/tracing_details_v16_7.png)
1. Optional. To view the attributes for a single span, select it from the list.
![tracing drawer](img/tracing_drawer_v16_7.png)
## Create an issue for a trace
You can create an issue to track any action taken to resolve or investigate a trace. To create an issue for a trace:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Traces**.
1. From the list of traces, select a trace.
1. Select **Create issue**.
The issue is created in the selected project and pre-filled with information from the trace.
You can edit the issue title and description.
## View issues related to a trace
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Traces**.
1. From the list of traces, select a trace.
1. Scroll to **Related issues**.
1. Optional. To view the issue details, select an issue.

View File

@ -1,107 +1,13 @@
---
stage: Monitor
group: Platform Insights
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
redirect_to: '../development/logs.md'
remove_date: '2025-03-10'
---
# Logs
<!-- markdownlint-disable -->
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed
**Status:** Beta
This document was moved to [another location](../development/logs.md).
NOTE:
This feature is not under active development.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/143027) in GitLab 16.10 [with a flag](../administration/feature_flags.md) named `observability_logs`. Disabled by default. This feature is in [beta](../policy/development_stages_support.md#beta).
> - Feature flag [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158786) in GitLab 17.3 to the `observability_features` [feature flag](../administration/feature_flags.md), disabled by default. The previous feature flag (`observability_logs`) was removed.
> - [Introduced](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/100) for self-managed in GitLab 17.3.
> - [Changed](https://gitlab.com/gitlab-com/marketing/digital-experience/buyer-experience/-/issues/4198) to internal Beta in GitLab 17.7.
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
GitLab supports centralized application and infrastructure logs collection, storage, and analysis.
GitLab Logging provides insight about the operational health of monitored systems.
Use logs to learn more about your systems and applications in a given range of time.
## Logs ingestion limits
Logs ingest a maximum of 102,400 bytes per minute.
When the limit is exceeded, a `429 Too Many Requests` response is returned.
To request a limit increase to 1,048,576 bytes per minute, contact [GitLab support](https://about.gitlab.com/support/).
## Configure logging
Configure logging to enable it for a project.
Prerequisites:
- You must have at least the Maintainer role for the project.
1. 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 `api` scope and **Developer** role or greater.
Save the access token value for later.
1. To configure your application to send GitLab logs, set the following environment variables:
```shell
OTEL_EXPORTER = "otlphttp"
OTEL_EXPORTER_OTLP_ENDPOINT = "https://gitlab.example.com/api/v4/projects/<gitlab-project-id>/observability/"
OTEL_EXPORTER_OTLP_HEADERS = "PRIVATE-TOKEN=<gitlab-access-token>"
```
Use the following values:
- `gitlab.example.com` - The hostname for your self-managed instance, or `gitlab.com`
- `gitlab-project-id` - The project ID
- `gitlab-access-token` - The access token you created
Logs are configured for your project.
When you run your application, the OpenTelemetry exporter sends logs to GitLab.
## View logs
You can view the logs for a given project:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Logs**.
A list of logs is displayed. Currently log date, level, service, and message are supported.
Select a log line to view its details.
You can either filter logs by attribute or query log strings with the search bar.
The log volume chart at the top shows the number of logs ingested over the given time period.
![list of logs](img/logs_list_v17_1.png)
### View logs details
It is also possible to see log line details such as metadata and resource attributes.
![logs details](img/logs_details_v17_1.png)
### Create an issue for a log
You can create an issue to track any action taken to resolve or investigate a log. To create an issue for a log:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Logs**.
1. From the list of logs, select a log.
1. In the details drawer, select **Create issue**.
The issue is created in the selected project and pre-filled with information from the log.
You can edit the issue title and description.
### View issues related to a log
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Logs**.
1. From the list of logs, select a log.
1. In the details drawer, scroll to **Related issues**.
1. Optional. To view the issue details, select an issue.
<!-- This redirect file can be deleted after <2025-03-10>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,136 +1,13 @@
---
stage: Monitor
group: Platform Insights
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
redirect_to: '../development/metrics.md'
remove_date: '2025-03-10'
---
# Metrics
<!-- markdownlint-disable -->
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed
**Status:** Beta
This document was moved to [another location](../development/metrics.md).
NOTE:
This feature is not under active development.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124966) in GitLab 16.7 [with a flag](../administration/feature_flags.md) named `observability_metrics`. Disabled by default. This feature is an [experiment](../policy/development_stages_support.md#experiment).
> - Feature flag [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158786) in GitLab 17.3 to the `observability_features` [feature flag](../administration/feature_flags.md), disabled by default. The previous feature flag (`observability_metrics`) was removed.
> - [Introduced](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/100) for self-managed in GitLab 17.3.
> - [Changed](https://gitlab.com/gitlab-com/marketing/digital-experience/buyer-experience/-/issues/4198) to internal beta in GitLab 17.7.
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
Metrics provide insight about the operational health of monitored systems.
Use metrics to learn more about your systems and applications in a given time range.
Metrics are structured as time series data, and are:
- Indexed by timestamp
- Continuously expanding as additional data is gathered
- Usually aggregated, downsampled, and queried by range
- Have write-intensive requirements
## Configure metrics
Configure metrics to enable them for a project.
Prerequisites:
You must have at least the Maintainer role for the project.
1. 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 `api` scope and **Developer** role or greater.
Save the access token value for later.
1. To configure your application to send GitLab metrics, set the following environment variables:
```shell
OTEL_EXPORTER = "otlphttp"
OTEL_EXPORTER_OTLP_ENDPOINT = "https://gitlab.example.com/api/v4/projects/<gitlab-project-id>/observability/"
OTEL_EXPORTER_OTLP_HEADERS = "PRIVATE-TOKEN=<gitlab-access-token>"
```
Use the following values:
- `gitlab.example.com` - The hostname for your self-managed instance, or `gitlab.com`
- `gitlab-project-id` - The project ID
- `gitlab-access-token` - The access token you created
Metrics are configured for your project.
When you run your application, the OpenTelemetry exporter sends metrics to GitLab.
## View metrics
You can view the metrics for a given project:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
A list of metrics is displayed.
Select a metric to view its details.
![list of metrics](img/metrics_list_v17_0.png)
Each metric contains one or more attributes. You can filter
metrics by attribute with the search bar.
### Metric details
Metrics are displayed as either a sum, a gauge, or a histogram.
The metric details page displays a chart depending on the type of metric.
On the metric details page, you can also view metrics for a specific time range, and
aggregate metrics by attribute:
![metrics details](img/metrics_detail_v17_0.png)
To make data lookups fast, depending on what time period you filter by,
GitLab automatically chooses the proper aggregation.
For example, if you search for more than seven days of data, the API returns only daily aggregates.
### Aggregations by search period
The following table shows what type of aggregation is used for each search period:
|Period|Aggregation used|
|---|---|
| Less than 30 minutes | Raw data as ingested |
| More than 30 minutes and less than one hour | By minute |
| More than one hour and less than 72 hours | Hourly |
| More than 72 hours | Daily |
### Metrics ingestion limits
Metrics ingest a maximum of 102,400 bytes per minute.
When the limit is exceeded, a `429 Too Many Requests` response is returned.
To request a limit increase to 1,048,576 bytes per minute, contact [GitLab support](https://about.gitlab.com/support/).
### Data retention
GitLab has a retention limit of 30 days for all ingested metrics.
### Create an issue for a metric
You can create an issue to track any action taken to resolve or investigate a metric. To create an issue for a metric:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
1. From the list of metrics, select a metric.
1. Select **Create issue**.
The issue is created in the selected project and pre-filled with information from the metric.
You can edit the issue title and description.
### View issues related to a metric
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Metrics**.
1. From the list of metrics, select a metric.
1. Scroll to **Related issues**.
1. Optional. To view the issue details, select an issue.
<!-- This redirect file can be deleted after <025-03-10>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,110 +1,13 @@
---
stage: Monitor
group: Platform Insights
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
redirect_to: '../development/tracing.md'
remove_date: '2025-03-10'
---
# Distributed tracing
<!-- markdownlint-disable -->
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed
**Status:** Beta
This document was moved to [another location](../development/tracing.md).
NOTE:
This feature is not under active development.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124966) in GitLab 16.2 [with a flag](../administration/feature_flags.md) named `observability_tracing`. Disabled by default. This feature is in [beta](../policy/development_stages_support.md#beta).
> - Feature flag [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158786) in GitLab 17.3 to the `observability_features` [feature flag](../administration/feature_flags.md), disabled by default. The previous feature flag `observability_tracing` was removed.
> - [Introduced](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/100) for self-managed in GitLab 17.3.
> - [Changed](https://gitlab.com/gitlab-com/marketing/digital-experience/buyer-experience/-/issues/4198) to internal beta in GitLab 17.7.
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
With distributed tracing, you can troubleshoot application performance issues by inspecting how a request moves through different services and systems, the timing of each operation, and any errors or logs as they occur. Tracing is particularly useful in the context of microservice applications, which group multiple independent services collaborating to fulfill user requests.
This feature is in [beta](../policy/development_stages_support.md). For more information, see the [group direction page](https://about.gitlab.com/direction/monitor/observability/). To leave feedback about tracing bugs or functionality, comment in the [feedback issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2590) or open a [new issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/new).
## Tracing ingestion limits
Tracing ingests a maximum of 102,400 bytes per minute.
When the limit is exceeded, a `429 Too Many Requests` response is returned.
To request a limit increase to 1,048,576 bytes per minute, contact [GitLab support](https://about.gitlab.com/support/).
## Data retention
GitLab retains all traces for 30 days.
## Configure distributed tracing for a project
Configure distributed tracing to enable it for a project.
Prerequisites:
- You must have at least the Maintainer role for the project.
1. 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 `api` scope and **Developer** role or greater.
Save the access token value for later.
1. To configure your application to send GitLab traces, set the following environment variables:
```shell
OTEL_EXPORTER = "otlphttp"
OTEL_EXPORTER_OTLP_ENDPOINT = "https://gitlab.example.com/api/v4/projects/<gitlab-project-id>/observability/"
OTEL_EXPORTER_OTLP_HEADERS = "PRIVATE-TOKEN=<gitlab-access-token>"
```
Use the following values:
- `gitlab.example.com` - The hostname for your self-managed instance, or `gitlab.com`
- `gitlab-project-id` - The project ID.
- `gitlab-access-token` - The access token you created
When your application is configured, run it, and the OpenTelemetry exporter attempts to send
traces to GitLab.
## View your traces
If your traces are exported successfully, you can see them in the project.
To view the list of traces:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Traces**.
1. Optional. To view the details of a trace, select it from the list.
![list of traces](img/tracing_list_v16.11.png)
The trace details page and a list of spans are displayed.
![tracing details](img/tracing_details_v16_7.png)
1. Optional. To view the attributes for a single span, select it from the list.
![tracing drawer](img/tracing_drawer_v16_7.png)
## Create an issue for a trace
You can create an issue to track any action taken to resolve or investigate a trace. To create an issue for a trace:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Traces**.
1. From the list of traces, select a trace.
1. Select **Create issue**.
The issue is created in the selected project and pre-filled with information from the trace.
You can edit the issue title and description.
## View issues related to a trace
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Traces**.
1. From the list of traces, select a trace.
1. Scroll to **Related issues**.
1. Optional. To view the issue details, select an issue.
<!-- This redirect file can be deleted after <2025-03-10>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -43,7 +43,7 @@ to store the token, like HashiCorp Vault or the Keeper Secrets Manager Terraform
### Create a personal access token
> - Maximum allowable lifetime limit [extended to 400 days](https://gitlab.com/gitlab-org/gitlab/-/issues/461901) in GitLab 17.6 [with a flag](../../administration/feature_flags.md) named `buffered_token_expiration_limit`. Disabled by default.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/461901) the maximum allowable lifetime limit to an increased value of 400 days in GitLab 17.6 [with a flag](../../administration/feature_flags.md) named `buffered_token_expiration_limit`. Disabled by default.
FLAG:
The availability of the extended maximum allowable lifetime limit is controlled by a feature flag.
@ -62,7 +62,7 @@ For more information, see the history.
### Create a project or group access token
> - Maximum allowable lifetime limit [extended to 400 days](https://gitlab.com/gitlab-org/gitlab/-/issues/461901) in GitLab 17.6 [with a flag](../../administration/feature_flags.md) named `buffered_token_expiration_limit`. Disabled by default.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/461901) the maximum allowable lifetime limit to an increased value of 400 days in GitLab 17.6 [with a flag](../../administration/feature_flags.md) named `buffered_token_expiration_limit`. Disabled by default.
FLAG:
The availability of the extended maximum allowable lifetime limit is controlled by a feature flag.

View File

@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history of the [**Distributed tracing** feature](../../operations/tracing.md).
For more information, see the history of the [**Distributed tracing** feature](../../development/tracing.md).
<!-- Update this note when observability_features flag is removed -->
In this tutorial, we'll show you how to create, configure, instrument, and monitor a Django application using GitLab observability features.

View File

@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history of the [**Distributed tracing** feature](../../operations/tracing.md).
For more information, see the history of the [**Distributed tracing** feature](../../development/tracing.md).
<!-- Update this note when observability_features flag is removed -->
In this tutorial, you'll learn how to create, configure, instrument, and monitor a .NET Core application using GitLab Observability features.

View File

@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Tutorial: Use GitLab Observability with a Java Spring application
For more information, see the history of the [**Distributed tracing** feature](../../operations/tracing.md).
For more information, see the history of the [**Distributed tracing** feature](../../development/tracing.md).
<!-- Update this note when observability_features flag is removed -->
In this tutorial, you'll learn how to create, configure, instrument, and monitor a Java Spring application using GitLab Observability features.

View File

@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history of the [**Distributed tracing** feature](../../operations/tracing.md).
For more information, see the history of the [**Distributed tracing** feature](../../development/tracing.md).
<!-- Update this note when observability_features flag is removed -->
In this tutorial, you'll learn how to configure, instrument, and monitor a NodeJS application using GitLab Observability features.

View File

@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history of the [**Distributed tracing** feature](../../operations/tracing.md).
For more information, see the history of the [**Distributed tracing** feature](../../development/tracing.md).
<!-- Update this note when observability_features flag is removed -->
In this tutorial, you'll learn how to create, configure, instrument, and monitor a Ruby on Rails application using GitLab Observability features.

View File

@ -47,138 +47,7 @@ For more information, see:
- [How error tracking works](../../operations/error_tracking.md#how-error-tracking-works)
## Step 3: Monitor application performance with tracing, metrics, and logs
### Enable beta features
The following features are available in closed beta:
- [Distributed tracing](../../operations/tracing.md): Follow application requests across multiple services.
- [Metrics](../../operations/metrics.md): Monitor application and infrastructure performance metrics,
like request latency, traffic, error rate, or saturation.
- [Logs](../../operations/logs.md): Centralize and analyze application and infrastructure logs.
To make these features available, an administrator must [enable the feature flag](../../administration/feature_flags.md)
named `observability_features` for your project or group. After these features are enabled, you can set up data collection.
### Instrument your application with OpenTelemetry
Traces, metrics, and logs are generated from your application and collected
by OpenTelemetry, then stored on the GitLab back end.
[OpenTelemetry](https://opentelemetry.io/docs/what-is-opentelemetry/) is an open-source
observability framework that provides a collection of tools, APIs, and SDKs for generating,
collecting, and exporting telemetry data. The OpenTelemetry Collector is a key component of this framework.
You can collect and send telemetry data to GitLab using either direct instrumentation
or the OpenTelemetry Collector. This table compares the two methods:
| Method | Pros | Cons |
|--------|------|------|
| Direct instrumentation | - Simpler setup<br>- No infrastructure changes| - Less flexible<br>- No data sampling or processing<br>- Can generate high volume of data |
| OpenTelemetry Collector | - Centralized configuration<br>- Enables data sampling and processing<br>- Controlled volume of data | - More complex setup<br>- Requires infrastructure changes |
You should use the OpenTelemetry Collector for most setups, especially if your application
is likely to grow in complexity. However, direct instrumentation can be simpler for testing purposes and small applications.
#### Direct instrumentation
You can instrument your application code to send telemetry data directly to GitLab without using a collector.
Choose a guide based on your programming language or framework:
- [Ruby on Rails](../../tutorials/observability/observability_rails_tutorial.md)
- [Node JS](../../tutorials/observability/observability_nodejs_tutorial.md)
- [Python Django](../../tutorials/observability/observability_django_tutorial.md)
- [Java Spring](../../tutorials/observability/observability_java_tutorial.md)
- [.NET](../../tutorials/observability/observability_dotnet_tutorial.md)
For other languages, use the appropriate [OpenTelemetry API or SDK](https://opentelemetry.io/docs/languages/).
#### Using the OpenTelemetry Collector (recommended)
For complex application setups, you should use the OpenTelemetry Collector.
**What is the OpenTelemetry Collector?**
The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) acts like proxy that receives, processes, and exports telemetry data from your application to your monitoring tools such as GitLab Observability. It is open source and vendor-neutral, which means you can use it with any compatible tools and avoid vendor lock-in.
Benefits of using the Collector:
- Simplicity: Application services send data to only one destination (the Collector).
- Flexibility: Add or change data destinations from a single place (if you use multiple vendors).
- Advanced features: Sampling, batching, and compression of data.
- Consistency: Uniform data processing.
- Governance: Centralized configuration.
**Configure the OpenTelemetry Collector**
1. [Quick start installation](https://opentelemetry.io/docs/collector/quick-start/)
1. [Choose a deployment method](https://opentelemetry.io/docs/collector/deployment/) (agent or gateway)
1. [Configure data collection](https://opentelemetry.io/docs/collector/configuration/)
Add the GitLab endpoint as an exporter in the Collector `config.yaml` file:
```yaml
exporters:
otlphttp/gitlab:
endpoint: https://gitlab.com/api/v4/projects/<project_id>/observability/
headers:
"private-token": "<your_token>"
service:
pipelines:
traces:
exporters: [spanmetrics, otlphttp/gitlab]
metrics:
exporters: [otlphttp/gitlab]
logs:
exporters: [otlphttp/gitlab]
```
Replace the placeholders with the following values:
- `<project_id>`: The project ID. On the project homepage,
in the upper-right corner, select the vertical ellipsis (**{ellipsis_v}**), then **Copy project ID**.
- `<your_token>`: An access token created in the project with the `Developer` role and
`api` scope. Create a token at the project's **Settings** > **Access tokens**.
- `gitlab.com`: Replace with your GitLab host if running a self-managed instance.
1. Instrument your application to send data to the Collector.
Use the language-specific guides above, but point to your Collector instead of GitLab.
For example, if your application and your Collector are on the same host, send your application to this URL:
```plaintext
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
```
### Test your setup
After setting up data collection, you can visualize the collected data in your project by viewing the **Monitor** navigation menu.
Use the **Tracing**, **Metrics**, and **Logs** pages to access this information. These features work together to provide a comprehensive view of your application's health and performance, helping you troubleshoot detected issues.
For more information, see:
- [Distributed tracing](../../operations/tracing.md)
- [Metrics](../../operations/metrics.md)
- [Logs](../../operations/logs.md)
## Step 4: Monitor infrastructure with metrics and logs
To monitor your applications' infrastructure performance and availability,
first install the OpenTelemetry Collector as described previously. Then,
based on your setup, you can use various methods to gather metrics and logs data:
- For host-level, OS metrics: Use the OpenTelemetry Collector with a receiver like
[Host Metrics](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/hostmetricsreceiver).
This receiver collects CPU, memory, disk, and network metrics from the host system.
- For cloud-based infrastructure: Use your provider's monitoring solution integrated with OpenTelemetry.
For example, receivers like [AWS CloudWatch](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/awscloudwatchreceiver) or [Azure Monitor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azuremonitorreceiver).
- For containerized applications: Use receivers like
[Docker stats](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/dockerstatsreceiver/) or
[Kubelet stats](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/kubeletstatsreceiver).
- For Kubernetes clusters: Follow the [external Kubernetes guide](https://opentelemetry.io/docs/kubernetes/getting-started/).
## Step 5: Manage alerts and incidents
## Step 3: Manage alerts and incidents
Set up incident management features to troubleshoot issues and resolve incidents collaboratively.
@ -186,7 +55,7 @@ For more information, see:
- [Incident Management](../../operations/incident_management/index.md)
## Step 6: Analyze and improve
## Step 4: Analyze and improve
Use the data and insights gathered to continuously improve your application and the monitoring process:

View File

@ -4,33 +4,34 @@ group: Environments
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
---
# Infrastructure as Code with Terraform and GitLab
# Infrastructure as Code with OpenTofu and GitLab
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
To manage your infrastructure with GitLab, you can use the integration with
Terraform or OpenTofu to define resources that you can version, reuse, and share:
To manage your infrastructure with GitLab, you can use the integration with OpenTofu to define resources that you can version, reuse, and share:
- Manage low-level components like compute, storage, and networking resources.
- Manage high-level components like DNS entries and SaaS features.
- Use GitLab as a Terraform state storage.
- Store and use Terraform modules to simplify common and complex infrastructure patterns.
- Use GitLab as an OpenTofu state storage.
- Store and use OpenTofu modules to simplify common and complex infrastructure patterns.
- Incorporate GitOps deployments and Infrastructure-as-Code (IaC) workflows.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> Watch [a video overview](https://www.youtube.com/watch?v=iGXjUrkkzDI) of the features GitLab provides with the integration with Terraform.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> Watch [a video overview](https://www.youtube.com/watch?v=iGXjUrkkzDI) of the features GitLab provides with the integration with OpenTofu.
The following examples primarily use OpenTofu, but they can work with Terraform as well.
## Terraform and OpenTofu support
GitLab integrates with both Terraform and OpenTofu.
Most features are fully compatible, including:
- [GitLab-managed Terraform state](terraform_state.md)
- [Terraform integration in merge requests](mr_integration.md)
- [Terraform Module Registry](../../../user/packages/terraform_module_registry/index.md)
- [GitLab-managed Terraform/OpenTofu state](terraform_state.md)
- [Terraform/OpenTofu integration in merge requests](mr_integration.md)
- [Terraform/OpenTofu Module Registry](../../../user/packages/terraform_module_registry/index.md)
For simplicity, the GitLab documentation refers primarily to Terraform.
For simplicity, the GitLab documentation refers primarily to OpenTofu.
However, differences between the Terraform and OpenTofu integration
are documented.
@ -53,8 +54,7 @@ include:
stages: [validate, build, deploy]
```
See the [OpenTofu CI/CD component README](https://gitlab.com/components/opentofu) for detailed information
about the usage of the component and all available templates and inputs.
For more information about templates, inputs, and how to use the OpenTofu CI/CD component, see the [OpenTofu CI/CD component README](https://gitlab.com/components/opentofu).
## Quickstart a Terraform project in pipelines
@ -148,9 +148,9 @@ For GitLab-curated template recipes, see [Terraform template recipes](terraform_
## Related topics
- Use GitLab as a [Terraform Module Registry](../../packages/terraform_module_registry/index.md).
- To store state files in local storage or in a remote store, use the [GitLab-managed Terraform state](terraform_state.md).
- To collaborate on Terraform code changes and Infrastructure-as-Code workflows, use the
- Use GitLab as a [Terraform/OpenTofu Module Registry](../../packages/terraform_module_registry/index.md).
- To store state files in local storage or in a remote store, use the [GitLab-managed Terraform/OpenTofu state](terraform_state.md).
- To collaborate on Terraform code changes and IaC workflows, use the
[Terraform integration in merge requests](mr_integration.md).
- To manage GitLab resources like users, groups, and projects, use the
[GitLab Terraform provider](https://gitlab.com/gitlab-org/terraform-provider-gitlab).

View File

@ -92,14 +92,13 @@ The following items are changed when they are imported:
## User assignment
> - Importing approvals by email address or username [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23586) in GitLab 16.7.
> - Matching user mentions with GitLab users [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/433008) in GitLab 16.8.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/153041) to import approvals only by email address in GitLab 17.1.
> - User mapping by email address or username [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36885) in GitLab 13.4 [with a flag](../../../administration/feature_flags.md) named `bitbucket_server_user_mapping_by_username`. Disabled by default.
> - Mapping user mentions to GitLab users [added](https://gitlab.com/gitlab-org/gitlab/-/issues/433008) in GitLab 16.8.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/153041) to map users only by email address in GitLab 17.1.
FLAG:
On self-managed GitLab, matching user mentions with GitLab users is not available. To make it available per user,
an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `bitbucket_server_import_stage_import_users`.
On GitLab.com and GitLab Dedicated, this feature is not available.
The availability of this feature is controlled by a feature flag.
For more information, see the history.
When issues and pull requests are importing, the importer tries to match a Bitbucket Server user's email address
with a confirmed email address in the GitLab user database. If no such user is found:

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
class BackfillResourceWeightEventsNamespaceId < BackfillDesiredShardingKeyJob
operation_name :backfill_resource_weight_events_namespace_id
feature_category :team_planning
end
end
end

View File

@ -22,10 +22,13 @@ module Security
# or contains predictable substrings derived from user attributes.
# Case insensitive.
def weak_for_user?(password, user)
user_info_in_password?(password, user) || common_phrases_in_password?(password)
end
def user_info_in_password?(password, user)
name_appears_in_password?(password, user) ||
username_appears_in_password?(password, user) ||
email_appears_in_password?(password, user) ||
common_phrases_in_password?(password)
email_appears_in_password?(password, user)
end
def common_phrases_in_password?(password)

View File

@ -13452,6 +13452,9 @@ msgstr ""
msgid "Collapse merge details"
msgstr ""
msgid "Collapse merge request reports"
msgstr ""
msgid "Collapse milestones"
msgstr ""
@ -22613,6 +22616,9 @@ msgstr ""
msgid "Expand merge details"
msgstr ""
msgid "Expand merge request reports"
msgstr ""
msgid "Expand milestones"
msgstr ""
@ -33968,6 +33974,9 @@ msgstr ""
msgid "Merge options"
msgstr ""
msgid "Merge reports (%{reportsCount}):"
msgstr ""
msgid "Merge request"
msgstr ""
@ -39735,6 +39744,9 @@ msgstr ""
msgid "Password|To be satisfied"
msgstr ""
msgid "Password|cannot include your name, username, or email"
msgstr ""
msgid "Password|cannot use common phrases (e.g. \"password\")"
msgstr ""
@ -62814,6 +62826,12 @@ msgstr ""
msgid "WorkItem|Comments only"
msgstr ""
msgid "WorkItem|Confidentiality turned off."
msgstr ""
msgid "WorkItem|Confidentiality turned on."
msgstr ""
msgid "WorkItem|Configure work items such as epics, issues, and tasks to represent how your team works."
msgstr ""

View File

@ -258,7 +258,6 @@ spec/frontend/packages_and_registries/settings/project/settings/components/conta
spec/frontend/packages_and_registries/settings/project/settings/components/container_protection_rules_spec.js
spec/frontend/packages_and_registries/settings/project/settings/components/packages_protection_rule_form_spec.js
spec/frontend/packages_and_registries/settings/project/settings/components/packages_protection_rules_spec.js
spec/frontend/pages/import/bulk_imports/failures/index_spec.js
spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
spec/frontend/pages/projects/pipeline_schedules/shared/components/interval_pattern_input_spec.js

View File

@ -60,6 +60,16 @@ describe('MetricTile', () => {
expect(findSingleStat().props('animationDecimalPlaces')).toBe(1);
});
it.each([10.53, 10.53324])(
'will round to a maximum of 2 decimal place for a float value given %s',
(value) => {
const metric = { identifier: 'deploys', label: 'Deploys', value };
wrapper = createComponent({ metric });
expect(findSingleStat().props('animationDecimalPlaces')).toBe(2);
},
);
it('will render using delimiters', () => {
const metric = { identifier: 'deploys', value: '10000', label: 'Deploys' };
wrapper = createComponent({ metric });

View File

@ -12,6 +12,8 @@ import {
formattedChangeInPercent,
isNumeric,
isPositiveInteger,
splitDecimalNumber,
countFloatingPointDigits,
} from '~/lib/utils/number_utils';
describe('Number Utils', () => {
@ -221,4 +223,35 @@ describe('Number Utils', () => {
expect(isPositiveInteger(value)).toBe(outcome);
});
});
describe('splitDecimalNumber', () => {
it.each`
value | integer | decimal
${null} | ${null} | ${null}
${0} | ${'0'} | ${'0'}
${'1.0'} | ${'1'} | ${'0'}
${'1024.1293'} | ${'1024'} | ${'1293'}
`(
'when called with $value it returns integer=$integer and decimal=$decimal',
({ value, integer, decimal }) => {
expect(splitDecimalNumber(value)).toEqual({ integer, decimal });
},
);
});
describe('countFloatingPointDigits', () => {
it.each`
value | digits
${null} | ${0}
${0} | ${0}
${'1.0'} | ${1}
${'5.3'} | ${1}
${'3.20'} | ${2}
${'3.04'} | ${2}
${'14.123'} | ${3}
${'1024.1293'} | ${4}
`('when called with $value it returns $digits', ({ value, digits }) => {
expect(countFloatingPointDigits(value)).toBe(digits);
});
});
});

View File

@ -1,15 +1,19 @@
import Vue from 'vue';
import { initBulkImportDetails } from '~/pages/import/bulk_imports/failures/index';
import { createWrapper } from '@vue/test-utils';
import { initBulkImportDetails } from '~/pages/import/bulk_imports/failures';
import BulkImportDetailsApp from '~/import/details/components/bulk_import_details_app.vue';
jest.mock('~/import/details/components/bulk_import_details_app.vue');
describe('initBulkImportDetails', () => {
let appRoot;
let wrapper;
const createAppRoot = () => {
appRoot = document.createElement('div');
appRoot.setAttribute('class', 'js-bulk-import-details');
document.body.appendChild(appRoot);
wrapper = createWrapper(initBulkImportDetails());
};
afterEach(() => {
@ -19,6 +23,8 @@ describe('initBulkImportDetails', () => {
}
});
const findBulkImportDetailsApp = () => wrapper.findComponent(BulkImportDetailsApp);
describe('when there is no app root', () => {
it('returns null', () => {
expect(initBulkImportDetails()).toBeNull();
@ -30,8 +36,8 @@ describe('initBulkImportDetails', () => {
createAppRoot();
});
it('returns a Vue instance', () => {
expect(initBulkImportDetails()).toBeInstanceOf(Vue);
it('renders the app', () => {
expect(findBulkImportDetailsApp().exists()).toBe(true);
});
});
});

View File

@ -1,6 +1,7 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import App from '~/vue_merge_request_widget/components/widget/app.vue';
import StateContainer from '~/vue_merge_request_widget/components/state_container.vue';
import MrSecurityWidgetCE from '~/vue_merge_request_widget/widgets/security_reports/mr_widget_security_reports.vue';
import MrTestReportWidget from '~/vue_merge_request_widget/widgets/test_report/index.vue';
import MrTerraformWidget from '~/vue_merge_request_widget/widgets/terraform/index.vue';
@ -10,8 +11,9 @@ import MrAccessibilityWidget from '~/vue_merge_request_widget/widgets/accessibil
describe('MR Widget App', () => {
let wrapper;
const createComponent = ({ mr = {} } = {}) => {
const createComponent = ({ mr = {}, provide = {} } = {}) => {
wrapper = shallowMountExtended(App, {
provide,
propsData: {
mr: {
pipeline: {
@ -59,4 +61,22 @@ describe('MR Widget App', () => {
expect(wrapper.findComponent(widget).exists()).toBe(false);
});
});
describe('when mrReportsTab is enabled', () => {
it('hides widgets by default', () => {
createComponent({ provide: { glFeatures: { mrReportsTab: true } } });
expect(wrapper.findByTestId('reports-widgets-container').isVisible()).toBe(false);
});
it('expands widgets when toggling state container', async () => {
createComponent({ provide: { glFeatures: { mrReportsTab: true } } });
wrapper.findComponent(StateContainer).vm.$emit('toggle');
await waitForPromises();
expect(wrapper.findByTestId('reports-widgets-container').isVisible()).toBe(true);
});
});
});

View File

@ -324,6 +324,7 @@ describe('WorkItemActions component', () => {
findConfidentialityToggleButton().vm.$emit('action');
expect(wrapper.emitted('toggleWorkItemConfidentiality')[0]).toEqual([true]);
expect(toast).toHaveBeenCalledWith('Confidentiality turned on.');
});
it('does not render when canUpdate is false', () => {

View File

@ -52,7 +52,6 @@ RSpec.describe Projects::Ml::ModelRegistryHelper, feature_category: :mlops do
is_expected.to eq({
'projectPath' => project.full_path,
'canWriteModelRegistry' => true,
'maxAllowedFileSize' => 10737418240,
'markdownPreviewPath' => "/#{project.full_path}/-/preview_markdown"
})
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillResourceWeightEventsNamespaceId,
feature_category: :team_planning,
schema: 20241202142250 do
include_examples 'desired sharding key backfill job' do
let(:batch_table) { :resource_weight_events }
let(:backfill_column) { :namespace_id }
let(:backfill_via_table) { :issues }
let(:backfill_via_column) { :namespace_id }
let(:backfill_via_foreign_key) { :issue_id }
end
end

View File

@ -173,7 +173,7 @@ RSpec.describe Gitlab::Database, feature_category: :database do
describe '.check_for_non_superuser' do
subject { described_class.check_for_non_superuser }
let(:non_superuser) { Gitlab::Database::PgUser.new(usename: 'foo', usesuper: false ) }
let(:non_superuser) { Gitlab::Database::PgUser.new(usename: 'foo', usesuper: false) }
let(:superuser) { Gitlab::Database::PgUser.new(usename: 'bar', usesuper: true) }
it 'prints user details if not superuser' do

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe QueueBackfillResourceWeightEventsNamespaceId, feature_category: :team_planning do
let!(:batched_migration) { described_class::MIGRATION }
it 'schedules a new batched migration' do
reversible_migration do |migration|
migration.before -> {
expect(batched_migration).not_to have_scheduled_batched_migration
}
migration.after -> {
expect(batched_migration).to have_scheduled_batched_migration(
table_name: :resource_weight_events,
column_name: :id,
interval: described_class::DELAY_INTERVAL,
batch_size: described_class::BATCH_SIZE,
sub_batch_size: described_class::SUB_BATCH_SIZE,
gitlab_schema: :gitlab_main_cell,
job_arguments: [
:namespace_id,
:issues,
:namespace_id,
:issue_id
]
)
}
end
end
end

View File

@ -2,11 +2,13 @@
require 'spec_helper'
RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
RSpec.describe Ci::Runner, type: :model, factory_default: :keep, feature_category: :runner do
include StubGitlabCalls
let_it_be(:organization, freeze: true) { create_default(:organization) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:other_project) { create(:project) }
it_behaves_like 'having unique enum values'
@ -66,6 +68,8 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
context 'tag does not exist' do
let(:tag_name) { 'new-tag' }
it 'creates a tag' do
expect { runner.save! }.to change(Ci::Tag, :count).by(1)
end
@ -288,7 +292,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
context 'when runner has creator' do
let_it_be(:creator) { create(:user) }
let_it_be(:runner) { create(:ci_runner, :instance, creator: creator) }
let_it_be(:runner) { create(:ci_runner, creator: creator) }
it { is_expected.to eq creator }
end
@ -311,7 +315,6 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
own_runner = create(:ci_runner, :project, projects: [own_project])
# other
other_project = create(:project)
create(:ci_runner, :project, projects: [other_project])
expect(described_class.belonging_to_project(own_project.id)).to eq [own_runner]
@ -443,19 +446,29 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
describe '#display_name' do
it 'returns the description if it has a value' do
runner = build(:ci_runner, description: 'Linux/Ruby-1.9.3-p448')
expect(runner.display_name).to eq 'Linux/Ruby-1.9.3-p448'
let(:args) { {} }
let(:runner) { build(:ci_runner, **args) }
subject(:display_name) { runner.display_name }
it 'returns the default description' do
is_expected.to eq runner.description
end
it 'returns the token if it does not have a description' do
runner = create(:ci_runner)
expect(runner.display_name).to eq runner.description
context 'when description has a value' do
let(:args) { { description: 'Linux/Ruby-1.9.3-p448' } }
it 'returns the specified description' do
is_expected.to eq args[:description]
end
end
it 'returns the token if the description is an empty string' do
runner = build(:ci_runner, description: '', token: 'token')
expect(runner.display_name).to eq runner.token
context 'when description is empty and token have a value' do
let(:args) { { description: '', token: 'token' } }
it 'returns the short_sha' do
is_expected.to eq runner.short_sha
end
end
end
@ -475,7 +488,6 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
context 'with runner having multiple projects' do
let_it_be(:other_project) { create(:project) }
let_it_be(:runner_project) { create(:ci_runner_project, project: other_project, runner: runner) }
it { is_expected.to be_falsey }
@ -483,8 +495,6 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
describe '#assign_to' do
let_it_be(:project) { create(:project) }
subject(:assign_to) { runner.assign_to(project) }
context 'with instance runner' do
@ -497,7 +507,6 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
context 'with group runner' do
let(:group) { create(:group) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
it 'raises an error' do
@ -507,8 +516,6 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
context 'with project runner' do
let_it_be(:other_project) { create(:project) }
let(:runner) { create(:ci_runner, :project, projects: [other_project]) }
it 'assigns runner to project' do
@ -740,13 +747,18 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
using RSpec::Parameterized::TableSyntax
let_it_be(:pipeline) { create(:ci_pipeline) }
let_it_be_with_refind(:build) { create(:ci_build, pipeline: pipeline) }
let_it_be(:runner_project) { build.project }
let_it_be_with_refind(:runner) { create(:ci_runner, :project, projects: [runner_project]) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:runner_project) { build.project }
let(:runner) { create(:ci_runner, :project, projects: [runner_project], tag_list: tag_list, run_untagged: run_untagged) }
let(:tag_list) { [] }
let(:run_untagged) { true }
before do
runner.tag_list = tag_list
runner.run_untagged = run_untagged
end
subject { runner.matches_build?(build) }
context 'when runner does not have tags' do
@ -1192,7 +1204,6 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
context 'group runner' do
let(:group) { create(:group) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
it 'returns false' do
@ -1296,7 +1307,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
describe '#pick_build!' do
let_it_be(:runner) { create(:ci_runner) }
let(:build) { create(:ci_build) }
let(:build) { FactoryBot.build(:ci_build) }
context 'runner can pick the build' do
it 'calls #tick_runner_queue' do
@ -1467,14 +1478,14 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
it 'includes runner_ids' do
expect(matchers.size).to eq(1)
expect(matchers.first.runner_ids).to match_array(described_class.all.pluck(:id))
expect(matchers.first.runner_ids).to match_array(described_class.all.ids)
end
end
end
describe '#runner_matcher' do
let(:runner) do
build_stubbed(:ci_runner, :instance_type, tag_list: %w[tag1 tag2], allowed_plan_ids: [1, 2])
build_stubbed(:ci_runner, tag_list: %w[tag1 tag2], allowed_plan_ids: [1, 2])
end
subject(:matcher) { runner.runner_matcher }
@ -1677,7 +1688,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
subject(:short_sha) { runner.short_sha }
context 'when registered via command-line' do
let(:runner) { create(:ci_runner) }
let_it_be(:runner) { create(:ci_runner) }
specify { expect(runner.token).not_to start_with(described_class::CREATED_RUNNER_TOKEN_PREFIX) }
it { is_expected.to match(/[0-9a-zA-Z_-]{8}/) }
@ -1686,7 +1697,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
context 'when creating new runner via UI' do
let(:runner) { create(:ci_runner, registration_type: :authenticated_user) }
let_it_be(:runner) { create(:ci_runner, registration_type: :authenticated_user) }
specify { expect(runner.token).to start_with(described_class::CREATED_RUNNER_TOKEN_PREFIX) }
it { is_expected.to match(/[0-9a-zA-Z_-]{8}/) }
@ -1745,6 +1756,10 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
describe '#token_expires_at', :freeze_time do
let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 6.days.to_i) }
let_it_be(:group_with_expiration) { create(:group, namespace_settings: group_settings) }
let_it_be(:existing_runner) { create(:ci_runner) }
shared_examples 'expiring token' do |interval:|
it 'expires' do
expect(runner.token_expires_at).to eq(interval.from_now)
@ -1758,7 +1773,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
context 'no expiration' do
let(:runner) { create(:ci_runner) }
let(:runner) { existing_runner }
it_behaves_like 'non-expiring token'
end
@ -1778,7 +1793,7 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
end
let(:runner) { create(:ci_runner) }
let(:runner) { existing_runner }
it_behaves_like 'non-expiring token'
end
@ -1788,86 +1803,31 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
end
let(:runner) { create(:ci_runner) }
let(:runner) { existing_runner }
it_behaves_like 'non-expiring token'
end
context 'group expiration' do
let(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 6.days.to_i) }
let(:group) { create(:group, namespace_settings: group_settings) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
let(:runner) { create(:ci_runner, :group, groups: [group_with_expiration]) }
it_behaves_like 'expiring token', interval: 6.days
end
context 'human-readable group expiration' do
let(:group_settings) { create(:namespace_settings, runner_token_expiration_interval_human_readable: '7 days') }
let(:group) { create(:group, namespace_settings: group_settings) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
it_behaves_like 'expiring token', interval: 7.days
end
context 'project expiration' do
let(:project) { create(:project, runner_token_expiration_interval: 4.days.to_i).tap(&:save!) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
it_behaves_like 'expiring token', interval: 4.days
end
context 'human-readable project expiration' do
let(:project) { create(:project, runner_token_expiration_interval_human_readable: '5 days').tap(&:save!) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
it_behaves_like 'expiring token', interval: 5.days
end
context 'multiple projects' do
let(:project1) { create(:project, runner_token_expiration_interval: 8.days.to_i).tap(&:save!) }
let(:project2) { create(:project, runner_token_expiration_interval: 7.days.to_i).tap(&:save!) }
let(:project3) { create(:project, runner_token_expiration_interval: 9.days.to_i).tap(&:save!) }
let(:runner) { create(:ci_runner, :project, projects: [project1, project2, project3]) }
it_behaves_like 'expiring token', interval: 7.days
end
context 'with project runner token expiring' do
let_it_be(:project) { create(:project, runner_token_expiration_interval: 4.days.to_i).tap(&:save!) }
context 'project overrides system' do
context 'with human-readable group expiration' do
before do
stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
group_with_expiration.runner_token_expiration_interval_human_readable = '7 days'
group_with_expiration.save!
end
let(:runner) { create(:ci_runner, :project, projects: [project]) }
it_behaves_like 'expiring token', interval: 4.days
it_behaves_like 'expiring token', interval: 7.days
end
context 'system overrides project' do
before do
stub_application_setting(project_runner_token_expiration_interval: 3.days.to_i)
end
let(:runner) { create(:ci_runner, :project, projects: [project]) }
it_behaves_like 'expiring token', interval: 3.days
end
end
context 'with group runner token expiring' do
let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
context 'group overrides system' do
before do
stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
stub_application_setting(group_runner_token_expiration_interval: 7.days.to_i)
end
let(:runner) { create(:ci_runner, :group, groups: [group]) }
it_behaves_like 'expiring token', interval: 4.days
it_behaves_like 'expiring token', interval: 6.days
end
context 'system overrides group' do
@ -1875,7 +1835,45 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
stub_application_setting(group_runner_token_expiration_interval: 3.days.to_i)
end
let(:runner) { create(:ci_runner, :group, groups: [group]) }
it_behaves_like 'expiring token', interval: 3.days
end
end
context 'project expiration' do
let_it_be(:project) { create(:project, group: group, runner_token_expiration_interval: 4.days.to_i) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
it_behaves_like 'expiring token', interval: 4.days
context 'human-readable project expiration' do
before do
project.runner_token_expiration_interval_human_readable = '5 days'
project.save!
end
it_behaves_like 'expiring token', interval: 5.days
end
context 'with multiple projects' do
let_it_be(:project2) { create(:project, runner_token_expiration_interval: 3.days.to_i) }
let_it_be(:project3) { create(:project, runner_token_expiration_interval: 9.days.to_i) }
let(:runner) { create(:ci_runner, :project, projects: [project, project2, project3]) }
it_behaves_like 'expiring token', interval: 3.days
end
context 'when project overrides system' do
before do
stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
end
it_behaves_like 'expiring token', interval: 4.days
end
context 'when system overrides project' do
before do
stub_application_setting(project_runner_token_expiration_interval: 3.days.to_i)
end
it_behaves_like 'expiring token', interval: 3.days
end
@ -1884,38 +1882,54 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
context "with group's project runner token expiring" do
let_it_be(:parent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 2.days.to_i) }
let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
let_it_be(:group_settings) { create(:namespace_settings) }
let_it_be(:group) { create(:group, parent: parent_group, namespace_settings: group_settings) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
context 'parent group overrides subgroup' do
let(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 3.days.to_i) }
let(:group) { create(:group, parent: parent_group, namespace_settings: group_settings) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
before_all do
group.runner_token_expiration_interval = 3.days.to_i
group.save!
end
it_behaves_like 'expiring token', interval: 2.days
end
context 'subgroup overrides parent group' do
let(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 1.day.to_i) }
let(:group) { create(:group, parent: parent_group, namespace_settings: group_settings) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
before_all do
group.runner_token_expiration_interval = 1.day.to_i
group.save!
end
it_behaves_like 'expiring token', interval: 1.day
end
end
context "with group's project runner token expiring" do
let_it_be(:group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 2.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:project) { create(:project, group: group_with_expiration) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
before_all do
group_with_expiration.project_runner_token_expiration_interval = 2.days.to_i
group_with_expiration.save!
end
context 'group overrides project' do
let(:project) { create(:project, group: group, runner_token_expiration_interval: 3.days.to_i).tap(&:save!) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
before do
project.runner_token_expiration_interval = 3.days.to_i
project.save!
end
it_behaves_like 'expiring token', interval: 2.days
end
context 'project overrides group' do
let(:project) { create(:project, group: group, runner_token_expiration_interval: 1.day.to_i).tap(&:save!) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
before do
project.runner_token_expiration_interval = 1.day.to_i
project.save!
end
it_behaves_like 'expiring token', interval: 1.day
end

View File

@ -1803,28 +1803,6 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
execute_update
end
context 'when the feature flag `specialized_worker_for_group_lock_update_auth_recalculation` is disabled' do
before do
stub_feature_flags(specialized_worker_for_group_lock_update_auth_recalculation: false)
end
it 'updates authorizations leading to users from shared groups losing access', :sidekiq_inline do
expect { execute_update }
.to change { group_one_user.authorized_projects.include?(project) }.from(true).to(false)
.and change { group_two_user.authorized_projects.include?(project) }.from(true).to(false)
end
it 'updates the authorizations in a non-blocking manner' do
expect(AuthorizedProjectsWorker).to(
receive(:bulk_perform_async).with([[group_one_user.id]])).once
expect(AuthorizedProjectsWorker).to(
receive(:bulk_perform_async).with([[group_two_user.id]])).once
execute_update
end
end
end
describe '#share_with_group_lock with subgroups' do

View File

@ -14,12 +14,15 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
end
describe '/api/v4/runners' do
let(:params) { nil }
let(:registration_token) { 'abcdefg123456' }
before do
stub_application_setting(runners_registration_token: registration_token)
end
subject(:perform_request) { delete api('/runners'), params: params }
describe 'DELETE /api/v4/runners' do
it_behaves_like 'runner migrations backoff' do
let(:request) { delete api('/runners') }
@ -27,15 +30,19 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
context 'when no token is provided' do
it 'returns 400 error' do
delete api('/runners')
perform_request
expect(response).to have_gitlab_http_status(:bad_request)
end
end
context 'when invalid token is provided' do
let(:params) do
{ token: 'invalid' }
end
it 'returns 403 error' do
delete api('/runners'), params: { token: 'invalid' }
perform_request
expect(response).to have_gitlab_http_status(:forbidden)
end
@ -44,12 +51,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
context 'when valid token is provided' do
let!(:runner) { create(:ci_runner, *args) }
let(:args) { [] }
subject(:perform_request) { delete api('/runners'), params: { token: runner.token } }
let(:params) { { token: runner.token } }
it 'deletes runner' do
expect { perform_request }
.to change { ::Ci::Runner.count }.by(-1)
expect { perform_request }.to change { ::Ci::Runner.count }.by(-1)
expect(response).to have_gitlab_http_status(:no_content)
end

View File

@ -4,22 +4,30 @@ require 'spec_helper'
RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :fleet_visibility do
describe '/api/v4/runners' do
let(:params) { nil }
subject(:perform_request) do
post api('/runners'), params: params
end
describe 'POST /api/v4/runners' do
it_behaves_like 'runner migrations backoff' do
let(:request) { post api('/runners') }
let(:request) { perform_request }
end
context 'when no token is provided' do
it 'returns 400 error' do
post api('/runners')
perform_request
expect(response).to have_gitlab_http_status(:bad_request)
end
end
context 'when invalid token is provided' do
let(:params) { { token: 'invalid' } }
it 'returns 403 error' do
post api('/runners'), params: { token: 'invalid' }
perform_request
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('403 Forbidden - invalid token supplied')
@ -27,8 +35,9 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
end
context 'when valid parameters are provided' do
def request
post api('/runners'), params: {
let(:new_runner) { build_stubbed(:ci_runner) }
let(:params) do
{
token: 'valid token',
description: 'server.hostname',
maintenance_note: 'Some maintainer notes',
@ -41,8 +50,6 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
}
end
let_it_be(:new_runner) { create(:ci_runner) }
before do
expected_params = {
description: 'server.hostname',
@ -68,49 +75,48 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
context 'when token_expires_at is nil' do
it 'creates runner' do
request
perform_request
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to eq({ 'id' => new_runner.id, 'token' => new_runner.token, 'token_expires_at' => nil })
expect(json_response).to eq('id' => new_runner.id, 'token' => new_runner.token, 'token_expires_at' => nil)
end
end
context 'when token_expires_at is a valid date' do
before do
new_runner.token_expires_at = DateTime.new(2022, 1, 11, 14, 39, 24)
new_runner.token_expires_at = Time.utc(2022, 1, 11, 14, 39, 24)
end
it 'creates runner' do
request
perform_request
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to eq({ 'id' => new_runner.id, 'token' => new_runner.token, 'token_expires_at' => '2022-01-11T14:39:24.000Z' })
expect(json_response).to eq(
'id' => new_runner.id, 'token' => new_runner.token, 'token_expires_at' => '2022-01-11T14:39:24.000Z'
)
end
end
it_behaves_like 'storing arguments in the application context for the API' do
subject { request }
let(:expected_params) { { client_id: "runner/#{new_runner.id}" } }
end
it_behaves_like 'not executing any extra queries for the application context' do
let(:subject_proc) { proc { request } }
let(:subject_proc) { proc { perform_request } }
end
end
context 'when deprecated maintainer_note field is provided' do
RSpec::Matchers.define_negated_matcher :excluding, :include
def request
post api('/runners'), params: {
let(:new_runner) { create(:ci_runner) }
let(:params) do
{
token: 'valid token',
maintainer_note: 'Some maintainer notes'
}
end
let(:new_runner) { create(:ci_runner) }
it 'converts to maintenance_note param' do
allow_next_instance_of(
::Ci::Runners::RegisterRunnerService,
@ -123,22 +129,22 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
.and_return(ServiceResponse.success(payload: { runner: new_runner }))
end
request
perform_request
expect(response).to have_gitlab_http_status(:created)
end
end
context 'when deprecated active parameter is provided' do
def request
post api('/runners'), params: {
let_it_be(:new_runner) { build(:ci_runner) }
let(:params) do
{
token: 'valid token',
active: false
}
end
let_it_be(:new_runner) { build(:ci_runner) }
it 'uses active value in registration' do
expect_next_instance_of(
::Ci::Runners::RegisterRunnerService,
@ -150,7 +156,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
.and_return(ServiceResponse.success(payload: { runner: new_runner }))
end
request
perform_request
expect(response).to have_gitlab_http_status(:created)
end
@ -168,8 +174,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
end
context 'when tags parameter is provided' do
def request
post api('/runners'), params: {
let(:params) do
{
token: registration_token,
tag_list: tag_list
}
@ -189,7 +195,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
.and_call_original
end
request
perform_request
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response.dig('message', 'tags_list')).to contain_exactly("Too many tags specified. Please limit the number of tags to #{::Ci::Runner::TAG_LIST_MAX_LENGTH}")
@ -210,7 +216,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
.and_call_original
end
request
perform_request
expect(response).to have_gitlab_http_status(:created)
end

View File

@ -20,7 +20,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
describe 'POST /api/v4/runners/verify', :freeze_time do
let_it_be_with_reload(:runner) { create(:ci_runner, token_expires_at: 3.days.from_now) }
let(:params) {}
let(:params) { nil }
subject(:verify) { post api('/runners/verify'), params: params }
@ -30,7 +30,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
context 'when no token is provided' do
it 'returns 400 error' do
post api('/runners/verify')
verify
expect(response).to have_gitlab_http_status :bad_request
end
@ -77,11 +77,11 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
verify
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({
expect(json_response).to eq(
'id' => runner.id,
'token' => runner.token,
'token_expires_at' => runner.token_expires_at.iso8601(3)
})
)
end
it 'updates contacted_at' do
@ -97,11 +97,11 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
verify
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({
expect(json_response).to eq(
'id' => runner.id,
'token' => runner.token,
'token_expires_at' => nil
})
)
end
end
@ -127,11 +127,11 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
verify
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq({
expect(json_response).to eq(
'id' => runner.id,
'token' => runner.token,
'token_expires_at' => runner.token_expires_at.iso8601(3)
})
)
end
end

View File

@ -248,10 +248,13 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
end
context 'with existing package' do
let!(:existing_package) { create(:nuget_package, project: package.project, name: package_name, version: package_version) }
let!(:existing_package) do
create(:nuget_package, :with_symbol_package, project: package.project, name: package_name, version: package_version, without_package_files: true)
end
let(:package_id) { existing_package.id }
let(:package_zip_file) do
Zip::File.open(package_file.file.path) do |zipfile|
Zip::File.open(existing_package.package_files.first.file.path) do |zipfile|
zipfile.add('package.pdb', expand_fixture_path('packages/nuget/symbol/package.pdb'))
zipfile
end