Add latest changes from gitlab-org/gitlab@master
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v0.0.16
|
||||
v0.0.17
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
935c88d1737e9c58da7e13a9b913fdfc7faedc49
|
||||
f3f31517a9b2d989c4e345d588bc316b01f19e7d
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export default {
|
|||
GlFormGroup,
|
||||
GlFormInput,
|
||||
},
|
||||
inject: ['projectPath', 'maxAllowedFileSize', 'markdownPreviewPath'],
|
||||
inject: ['projectPath', 'markdownPreviewPath'],
|
||||
props: {
|
||||
disableAttachments: {
|
||||
type: Boolean,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:)
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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) } }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -18,3 +18,4 @@ desired_sharding_key:
|
|||
sharding_key: namespace_id
|
||||
belongs_to: issue
|
||||
table_size: small
|
||||
desired_sharding_key_migration_job_name: BackfillResourceWeightEventsNamespaceId
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
9424cfaf0ef1901c77d2be035812764811d78ea903975370ef55d58005af0c7b
|
||||
|
|
@ -0,0 +1 @@
|
|||
f0a1dbd97945d7a6302de20b5603812aacff11f063d0be57f289adee15f75e9b
|
||||
|
|
@ -0,0 +1 @@
|
|||
b2b931e7b644a07bb468b5b4cf8f822094c08f44696044360db83e16bdee5c51
|
||||
|
|
@ -0,0 +1 @@
|
|||
30f26b3bea60cb0a03e0623cc825c6641a3155ab327b2aaafb330e823b256536
|
||||
|
|
@ -0,0 +1 @@
|
|||
fb67017012babaa58f32b3ea301123cf46a606b96967f4dca21e97c6660a3679
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
### View logs details
|
||||
|
||||
It is also possible to see log line details such as metadata and resource attributes.
|
||||
|
||||

|
||||
|
||||
### 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.
|
||||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
The trace details page and a list of spans are displayed.
|
||||
|
||||

|
||||
|
||||
1. Optional. To view the attributes for a single span, select it from the list.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
### View logs details
|
||||
|
||||
It is also possible to see log line details such as metadata and resource attributes.
|
||||
|
||||

|
||||
|
||||
### 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 -->
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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 -->
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
The trace details page and a list of spans are displayed.
|
||||
|
||||

|
||||
|
||||
1. Optional. To view the attributes for a single span, select it from the list.
|
||||
|
||||

|
||||
|
||||
## 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 -->
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||