Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c7531da771
commit
44fb0702f3
|
@ -0,0 +1 @@
|
||||||
|
main
|
|
@ -102,10 +102,10 @@ export default {
|
||||||
return { fullPath: this.groupPath, first: GRAPHQL_PAGE_SIZE };
|
return { fullPath: this.groupPath, first: GRAPHQL_PAGE_SIZE };
|
||||||
},
|
},
|
||||||
pageInfo() {
|
pageInfo() {
|
||||||
return this.group.dependencyProxyManifests.pageInfo;
|
return this.group.dependencyProxyManifests?.pageInfo;
|
||||||
},
|
},
|
||||||
manifests() {
|
manifests() {
|
||||||
return this.group.dependencyProxyManifests.nodes;
|
return this.group.dependencyProxyManifests?.nodes;
|
||||||
},
|
},
|
||||||
modalTitleWithCount() {
|
modalTitleWithCount() {
|
||||||
return sprintf(
|
return sprintf(
|
||||||
|
@ -132,7 +132,7 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
showDeleteDropdown() {
|
showDeleteDropdown() {
|
||||||
return this.group.dependencyProxyBlobCount > 0;
|
return this.group.dependencyProxyManifests?.nodes.length > 0;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlSprintf } from '@gitlab/ui';
|
import { GlIcon, GlSprintf } from '@gitlab/ui';
|
||||||
|
import { MANIFEST_PENDING_DESTRUCTION_STATUS } from '~/packages_and_registries/dependency_proxy/constants';
|
||||||
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
||||||
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||||
import { s__ } from '~/locale';
|
import { s__ } from '~/locale';
|
||||||
|
@ -7,6 +8,7 @@ import { s__ } from '~/locale';
|
||||||
export default {
|
export default {
|
||||||
name: 'ManifestRow',
|
name: 'ManifestRow',
|
||||||
components: {
|
components: {
|
||||||
|
GlIcon,
|
||||||
GlSprintf,
|
GlSprintf,
|
||||||
ListItem,
|
ListItem,
|
||||||
TimeagoTooltip,
|
TimeagoTooltip,
|
||||||
|
@ -24,17 +26,31 @@ export default {
|
||||||
version() {
|
version() {
|
||||||
return this.manifest?.imageName.split(':')[1];
|
return this.manifest?.imageName.split(':')[1];
|
||||||
},
|
},
|
||||||
|
isErrorStatus() {
|
||||||
|
return this.manifest?.status === MANIFEST_PENDING_DESTRUCTION_STATUS;
|
||||||
|
},
|
||||||
|
disabledRowStyle() {
|
||||||
|
return this.isErrorStatus ? 'gl-font-weight-normal gl-text-gray-500' : '';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
i18n: {
|
i18n: {
|
||||||
cachedAgoMessage: s__('DependencyProxy|Cached %{time}'),
|
cachedAgoMessage: s__('DependencyProxy|Cached %{time}'),
|
||||||
|
scheduledForDeletion: s__('DependencyProxy|Scheduled for deletion'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<list-item>
|
<list-item :disabled="isErrorStatus">
|
||||||
<template #left-primary> {{ name }} </template>
|
<template #left-primary>
|
||||||
<template #left-secondary> {{ version }} </template>
|
<span :class="disabledRowStyle">{{ name }}</span>
|
||||||
|
</template>
|
||||||
|
<template #left-secondary>
|
||||||
|
{{ version }}
|
||||||
|
<span v-if="isErrorStatus" class="gl-ml-4" data-testid="status"
|
||||||
|
><gl-icon name="clock" /> {{ $options.i18n.scheduledForDeletion }}</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
<template #right-primary> </template>
|
<template #right-primary> </template>
|
||||||
<template #right-secondary>
|
<template #right-secondary>
|
||||||
<timeago-tooltip :time="manifest.createdAt" data-testid="cached-message">
|
<timeago-tooltip :time="manifest.createdAt" data-testid="cached-message">
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
export const GRAPHQL_PAGE_SIZE = 20;
|
export const GRAPHQL_PAGE_SIZE = 20;
|
||||||
|
export const MANIFEST_PENDING_DESTRUCTION_STATUS = 'PENDING_DESTRUCTION';
|
||||||
|
|
|
@ -20,6 +20,7 @@ query getDependencyProxyDetails(
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
imageName
|
imageName
|
||||||
|
status
|
||||||
}
|
}
|
||||||
pageInfo {
|
pageInfo {
|
||||||
...PageInfo
|
...PageInfo
|
||||||
|
|
|
@ -32,7 +32,6 @@ export default {
|
||||||
return {
|
return {
|
||||||
'gl-border-t-transparent': !this.first && !this.selected,
|
'gl-border-t-transparent': !this.first && !this.selected,
|
||||||
'gl-border-t-gray-100': this.first && !this.selected,
|
'gl-border-t-gray-100': this.first && !this.selected,
|
||||||
'gl-opacity-5': this.disabled,
|
|
||||||
'gl-border-b-gray-100': !this.selected,
|
'gl-border-b-gray-100': !this.selected,
|
||||||
'gl-bg-blue-50 gl-border-blue-200': this.selected,
|
'gl-bg-blue-50 gl-border-blue-200': this.selected,
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,7 +47,7 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_asymmetric_atlassian_jwt!
|
def verify_asymmetric_atlassian_jwt!
|
||||||
asymmetric_jwt = Atlassian::JiraConnect::AsymmetricJwt.new(auth_token, jwt_verification_claims)
|
asymmetric_jwt = Atlassian::JiraConnect::Jwt::Asymmetric.new(auth_token, jwt_verification_claims)
|
||||||
|
|
||||||
return head :unauthorized unless asymmetric_jwt.valid?
|
return head :unauthorized unless asymmetric_jwt.valid?
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
= _('Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one.')
|
= _('Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one.')
|
||||||
|
|
||||||
.settings-content
|
.settings-content
|
||||||
= form_for @project, remote: true, html: { multipart: true, anchor: 'default-branch-settings' }, authenticity_token: true do |f|
|
= gitlab_ui_form_for @project, remote: true, html: { multipart: true, anchor: 'default-branch-settings' }, authenticity_token: true do |f|
|
||||||
%fieldset
|
%fieldset
|
||||||
- if @project.empty_repo?
|
- if @project.empty_repo?
|
||||||
.text-secondary
|
.text-secondary
|
||||||
|
@ -20,12 +20,10 @@
|
||||||
= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide', data: { qa_selector: 'default_branch_dropdown' }})
|
= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide', data: { qa_selector: 'default_branch_dropdown' }})
|
||||||
|
|
||||||
.form-group
|
.form-group
|
||||||
.form-check
|
- help_text = _("When merge requests and commits in the default branch close, any issues they reference also close.")
|
||||||
= f.check_box :autoclose_referenced_issues, class: 'form-check-input'
|
- help_icon = link_to sprite_icon('question-o'), help_page_path('user/project/issues/managing_issues.md', anchor: 'closing-issues-automatically'), target: '_blank', rel: 'noopener noreferrer'
|
||||||
= f.label :autoclose_referenced_issues, class: 'form-check-label' do
|
= f.gitlab_ui_checkbox_component :autoclose_referenced_issues,
|
||||||
%strong= _("Auto-close referenced issues on default branch")
|
_("Auto-close referenced issues on default branch"),
|
||||||
.form-text.text-muted
|
help_text: (help_text + " " + help_icon).html_safe
|
||||||
= _("When merge requests and commits in the default branch close, any issues they reference also close.")
|
|
||||||
= link_to sprite_icon('question-o'), help_page_path('user/project/issues/managing_issues.md', anchor: 'closing-issues-automatically'), target: '_blank', rel: 'noopener noreferrer'
|
|
||||||
|
|
||||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm", data: { qa_selector: 'save_changes_button' }
|
= f.submit _('Save changes'), class: "gl-button btn btn-confirm", data: { qa_selector: 'save_changes_button' }
|
||||||
|
|
|
@ -41,6 +41,6 @@
|
||||||
gitlab-com: true
|
gitlab-com: true
|
||||||
packages: [Free, Premium, Ultimate]
|
packages: [Free, Premium, Ultimate]
|
||||||
url: 'https://docs.gitlab.com/ee/ci/runners/runners_scope.html#group-runners'
|
url: 'https://docs.gitlab.com/ee/ci/runners/runners_scope.html#group-runners'
|
||||||
image_url: 'https://about.gitlab.com/images/14_10/group-runners-view-new-3.pn'
|
image_url: 'https://about.gitlab.com/images/14_10/group-runners-view-new-3.png'
|
||||||
published_at: 2022-04-22
|
published_at: 2022-04-22
|
||||||
release: 14.10
|
release: 14.10
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- incident_management
|
- incident_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32609
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- incident_management
|
- incident_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33217
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- incident_management
|
- incident_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29864
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- value_stream_management
|
- value_stream_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36658
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- authentication_and_authorization
|
- authentication_and_authorization
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39652
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -7,5 +7,5 @@ feature_categories:
|
||||||
description: >-
|
description: >-
|
||||||
The background_migration_jobs table stores information about the jobs processed during the execution of a background migration.
|
The background_migration_jobs table stores information about the jobs processed during the execution of a background migration.
|
||||||
See https://docs.gitlab.com/ee/development/database/background_migrations.html for more details.
|
See https://docs.gitlab.com/ee/development/database/background_migrations.html for more details.
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35913
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- team_planning
|
- team_planning
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33892
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- team_planning
|
- team_planning
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40360
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- continuous_integration
|
- continuous_integration
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41585
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- code_testing
|
- code_testing
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32991
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- code_testing
|
- code_testing
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30387
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- continuous_integration
|
- continuous_integration
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29162
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- pipeline_authoring
|
- pipeline_authoring
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30156
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- build_artifacts
|
- build_artifacts
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37969
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- continuous_integration
|
- continuous_integration
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33762
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- continuous_integration
|
- continuous_integration
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40036
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- kubernetes_management
|
- kubernetes_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33228
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- kubernetes_management
|
- kubernetes_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33228
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -3,7 +3,7 @@ table_name: clusters_applications_cilium
|
||||||
classes:
|
classes:
|
||||||
- Clusters::Applications::Cilium
|
- Clusters::Applications::Cilium
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- kubernetes_management
|
- container_network_security
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34601
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- team_planning
|
- team_planning
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24229
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- dynamic_application_security_testing
|
- dynamic_application_security_testing
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37404
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- dynamic_application_security_testing
|
- dynamic_application_security_testing
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36659
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- dynamic_application_security_testing
|
- dynamic_application_security_testing
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41639
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- dynamic_application_security_testing
|
- dynamic_application_security_testing
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41639
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- dynamic_application_security_testing
|
- dynamic_application_security_testing
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36659
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- source_code_management
|
- source_code_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28113
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- global_search
|
- global_search
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34069
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- experimentation_conversion
|
- experimentation_conversion
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38397
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -3,7 +3,7 @@ table_name: experiments
|
||||||
classes:
|
classes:
|
||||||
- Experiment
|
- Experiment
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- experimentation_expansion
|
- experimentation_conversion
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38397
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- secrets_management
|
- secrets_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30886
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- advanced_deployments
|
- advanced_deployments
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32901
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- wiki
|
- wiki
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31121
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- team_planning
|
- team_planning
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40272
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- code_review
|
- code_review
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34248
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- code_review
|
- code_review
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40358
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- metrics
|
- metrics
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27583
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- metrics
|
- metrics
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29912
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- subgroups
|
- subgroups
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34746
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- subgroups
|
- subgroups
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36321
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- feature_flags
|
- feature_flags
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32876
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- feature_flags
|
- feature_flags
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30243
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- feature_flags
|
- feature_flags
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28822
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- package_registry
|
- package_registry
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30448
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- package_registry
|
- package_registry
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30618
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- package_registry
|
- package_registry
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30994
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- package_registry
|
- package_registry
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27632
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- pages
|
- pages
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41785
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -4,5 +4,5 @@ classes: []
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- authentication_and_authorization
|
- authentication_and_authorization
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33272
|
||||||
milestone: '13.1'
|
milestone: '13.1'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- compliance_management
|
- compliance_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28182
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- source_code_management
|
- source_code_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29095
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- metrics
|
- metrics
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38457
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- planning_analytics
|
- planning_analytics
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37617
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- team_planning
|
- team_planning
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28926
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- vulnerability_management
|
- vulnerability_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40368
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- snippets
|
- snippets
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35026
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- team_planning
|
- team_planning
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30125
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- incident_management
|
- incident_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29994
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- infrastructure_as_code
|
- infrastructure_as_code
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35211
|
||||||
milestone: '13.4'
|
milestone: '13.4'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- infrastructure_as_code
|
- infrastructure_as_code
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26619
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- vulnerability_management
|
- vulnerability_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36955
|
||||||
milestone: '13.3'
|
milestone: '13.3'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- vulnerability_management
|
- vulnerability_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34289
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- vulnerability_management
|
- vulnerability_management
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27515
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
|
|
|
@ -5,5 +5,5 @@ classes:
|
||||||
feature_categories:
|
feature_categories:
|
||||||
- authentication_and_authorization
|
- authentication_and_authorization
|
||||||
description: TODO
|
description: TODO
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35797
|
||||||
milestone: '13.2'
|
milestone: '13.2'
|
||||||
|
|
|
@ -2537,7 +2537,7 @@ POST /projects/:id/housekeeping
|
||||||
|
|
||||||
### Get project push rules
|
### Get project push rules
|
||||||
|
|
||||||
Get the [push rules](../user/project/repository/push_rules.md#enabling-push-rules) of a
|
Get the [push rules](../user/project/repository/push_rules.md) of a
|
||||||
project.
|
project.
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
|
|
|
@ -11,7 +11,7 @@ GPG ([GNU Privacy Guard](https://gnupg.org/)) key. When you add a cryptographic
|
||||||
signature to your commit, you provide extra assurance that a commit
|
signature to your commit, you provide extra assurance that a commit
|
||||||
originated from you, rather than an impersonator. If GitLab can verify a commit
|
originated from you, rather than an impersonator. If GitLab can verify a commit
|
||||||
author's identity with a public GPG key, the commit is marked **Verified** in the
|
author's identity with a public GPG key, the commit is marked **Verified** in the
|
||||||
GitLab UI. You can then configure [push rules](../push_rules.md#enabling-push-rules)
|
GitLab UI. You can then configure [push rules](../push_rules.md)
|
||||||
for your project to reject individual commits not signed with GPG, or reject all
|
for your project to reject individual commits not signed with GPG, or reject all
|
||||||
commits from unverified users.
|
commits from unverified users.
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,9 @@ The following options are available:
|
||||||
by the same user as the user who pushed it, or where the committer's email address
|
by the same user as the user who pushed it, or where the committer's email address
|
||||||
is not [confirmed](../../../security/user_email_confirmation.md).
|
is not [confirmed](../../../security/user_email_confirmation.md).
|
||||||
- **Reject unsigned commits** - Reject commit when it is not signed through GPG.
|
- **Reject unsigned commits** - Reject commit when it is not signed through GPG.
|
||||||
Read [signing commits with GPG](gpg_signed_commits/index.md).
|
Read [signing commits with GPG](gpg_signed_commits/index.md). This push rule
|
||||||
|
can block some legitimate commits [created in the Web IDE](#reject-unsigned-commits-push-rule-disables-web-ide),
|
||||||
|
and allow [unsigned commits created in the GitLab UI](#unsigned-commits-created-in-the-gitlab-ui).
|
||||||
- **Removal of tags with** `git push` - Forbid users to remove Git tags with `git push`.
|
- **Removal of tags with** `git push` - Forbid users to remove Git tags with `git push`.
|
||||||
Tags can be deleted through the web UI.
|
Tags can be deleted through the web UI.
|
||||||
- **Check whether the commit author is a GitLab user** - Restrict commits to existing
|
- **Check whether the commit author is a GitLab user** - Restrict commits to existing
|
||||||
|
@ -45,7 +47,8 @@ These push rules require you to create a regular expression for the rule to eval
|
||||||
this regular expression can be pushed. To allow any commit message, leave empty.
|
this regular expression can be pushed. To allow any commit message, leave empty.
|
||||||
Uses multiline mode, which can be disabled using `(?-m)`.
|
Uses multiline mode, which can be disabled using `(?-m)`.
|
||||||
- **Restrict by branch name** - Only branch names that match this regular expression
|
- **Restrict by branch name** - Only branch names that match this regular expression
|
||||||
can be pushed. To allow any branch name, leave empty.
|
can be pushed. To allow any branch name, leave empty. For more information, read
|
||||||
|
[Restrict branch names](#restrict-branch-names).
|
||||||
- **Restrict by commit author's email** - Only the commit author's email address that matches this
|
- **Restrict by commit author's email** - Only the commit author's email address that matches this
|
||||||
regular expression can be pushed. Checks both the commit author and committer.
|
regular expression can be pushed. Checks both the commit author and committer.
|
||||||
To allow any email address, leave empty.
|
To allow any email address, leave empty.
|
||||||
|
@ -64,7 +67,7 @@ in push rules, and you can test them at the [regex101 regex tester](https://rege
|
||||||
It's possible to create custom push rules rather than the push rules available in
|
It's possible to create custom push rules rather than the push rules available in
|
||||||
**Admin Area > Push Rules** by using more advanced server hooks.
|
**Admin Area > Push Rules** by using more advanced server hooks.
|
||||||
|
|
||||||
See [server hooks](../../../administration/server_hooks.md) for more information.
|
Refer to [server hooks](../../../administration/server_hooks.md) for more information.
|
||||||
|
|
||||||
## Use cases
|
## Use cases
|
||||||
|
|
||||||
|
@ -86,7 +89,11 @@ is accepted.
|
||||||
|
|
||||||
### Restrict branch names
|
### Restrict branch names
|
||||||
|
|
||||||
If your company has a strict policy for branch names, you may want the branches to start
|
> Default restricted branch names were introduced in GitLab 12.10.
|
||||||
|
|
||||||
|
By default, GitLab restricts certain formats of branch names for security purposes.
|
||||||
|
40-character hexadecimal names, similar to Git commit hashes, are prohibited.
|
||||||
|
If your company has a stricter policy for branch names, you may want the branches to start
|
||||||
with a certain name. This approach enables different
|
with a certain name. This approach enables different
|
||||||
GitLab CI/CD jobs (such as `feature`, `hotfix`, `docker`, `android`) that rely on the
|
GitLab CI/CD jobs (such as `feature`, `hotfix`, `docker`, `android`) that rely on the
|
||||||
branch name.
|
branch name.
|
||||||
|
@ -96,11 +103,11 @@ various branches, and CI pipelines might not work as expected. By restricting th
|
||||||
branch names globally in Push Rules, such mistakes are prevented.
|
branch names globally in Push Rules, such mistakes are prevented.
|
||||||
All branch names that don't match your push rule are rejected.
|
All branch names that don't match your push rule are rejected.
|
||||||
|
|
||||||
Note that the name of your default branch is always allowed, regardless of the branch naming
|
NOTE:
|
||||||
|
The name of your default branch is always allowed, regardless of the branch naming
|
||||||
regular expression (regex) specified. GitLab is configured this way
|
regular expression (regex) specified. GitLab is configured this way
|
||||||
because merges typically have the default branch as their target.
|
because merges typically have the default branch as their target.
|
||||||
If you have other target branches, include them in your regex. (See [Enabling push rules](#enabling-push-rules)).
|
If you have other target branches, include them in your regex. (See [Enabling push rules](#enable-global-push-rules)).
|
||||||
|
|
||||||
The default branch also defaults to being a [protected branch](../protected_branches.md),
|
The default branch also defaults to being a [protected branch](../protected_branches.md),
|
||||||
which already limits users from pushing directly.
|
which already limits users from pushing directly.
|
||||||
|
|
||||||
|
@ -111,14 +118,7 @@ Some example regular expressions you can use in push rules:
|
||||||
- `^[a-z0-9\\-]{4,15}$` Branches must be between `4` and `15` characters long,
|
- `^[a-z0-9\\-]{4,15}$` Branches must be between `4` and `15` characters long,
|
||||||
accepting only lowercase letters, numbers and dashes.
|
accepting only lowercase letters, numbers and dashes.
|
||||||
|
|
||||||
#### Default restricted branch names
|
## Enable global push rules
|
||||||
|
|
||||||
> Introduced in GitLab 12.10.
|
|
||||||
|
|
||||||
By default, GitLab restricts certain formats of branch names for security purposes.
|
|
||||||
40-character hexadecimal names, similar to Git commit hashes, are prohibited.
|
|
||||||
|
|
||||||
## Enabling push rules
|
|
||||||
|
|
||||||
You can create push rules for all new projects to inherit, but they can be overridden
|
You can create push rules for all new projects to inherit, but they can be overridden
|
||||||
at the project level or the [group level](../../group/index.md#group-push-rules).
|
at the project level or the [group level](../../group/index.md#group-push-rules).
|
||||||
|
@ -127,8 +127,14 @@ To create global push rules:
|
||||||
|
|
||||||
1. On the top bar, select **Menu > Admin**.
|
1. On the top bar, select **Menu > Admin**.
|
||||||
1. On the left sidebar, select **Push Rules**.
|
1. On the left sidebar, select **Push Rules**.
|
||||||
|
1. Expand **Push rules**.
|
||||||
|
1. Set the rule you want.
|
||||||
|
1. Select **Save push rules**.
|
||||||
|
|
||||||
To override global push rules in a project's settings:
|
## Override global push rules per project
|
||||||
|
|
||||||
|
The push rule of an individual project overrides the global push rule.
|
||||||
|
To override global push rules for a specific project:
|
||||||
|
|
||||||
1. On the top bar, select **Menu > Projects** and find your project.
|
1. On the top bar, select **Menu > Projects** and find your project.
|
||||||
1. On the left sidebar, select **Settings > Repository**.
|
1. On the left sidebar, select **Settings > Repository**.
|
||||||
|
@ -136,28 +142,6 @@ To override global push rules in a project's settings:
|
||||||
1. Set the rule you want.
|
1. Set the rule you want.
|
||||||
1. Select **Save push rules**.
|
1. Select **Save push rules**.
|
||||||
|
|
||||||
### Caveat to "Reject unsigned commits" push rule
|
|
||||||
|
|
||||||
This push rule ignores commits that are authenticated and created by GitLab
|
|
||||||
(either through the UI or API). When the **Reject unsigned commits** push rule is
|
|
||||||
enabled, unsigned commits may still show up in the commit history if a commit was
|
|
||||||
created **in** GitLab itself. As expected, commits created outside GitLab and
|
|
||||||
pushed to the repository are rejected. For more information about how GitLab
|
|
||||||
plans to fix this issue, read [issue #19185](https://gitlab.com/gitlab-org/gitlab/-/issues/19185).
|
|
||||||
|
|
||||||
#### "Reject unsigned commits" push rule disables Web IDE
|
|
||||||
|
|
||||||
In 13.10, if a project has the "Reject unsigned commits" push rule, the user is not allowed to
|
|
||||||
commit through GitLab Web IDE.
|
|
||||||
|
|
||||||
To allow committing through the Web IDE on a project with this push rule, a GitLab administrator
|
|
||||||
must disable the feature flag `reject_unsigned_commits_by_gitlab`. This can be done through a
|
|
||||||
[rails console](../../../administration/operations/rails_console.md) and running:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
Feature.disable(:reject_unsigned_commits_by_gitlab)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Prevent pushing secrets to the repository
|
## Prevent pushing secrets to the repository
|
||||||
|
|
||||||
> Moved to GitLab Premium in 13.9.
|
> Moved to GitLab Premium in 13.9.
|
||||||
|
@ -231,28 +215,6 @@ Files blocked by this rule are listed below. For a complete list of criteria, se
|
||||||
- `*.history`
|
- `*.history`
|
||||||
- `*_history`
|
- `*_history`
|
||||||
|
|
||||||
### Prevent pushing secrets to all projects
|
|
||||||
|
|
||||||
To set a global push rule to prevent pushing secrets to all projects:
|
|
||||||
|
|
||||||
1. On the top bar, select **Menu > Admin**.
|
|
||||||
1. On the left sidebar, select **Push Rules**.
|
|
||||||
1. Expand **Push rules**.
|
|
||||||
1. Select **Prevent pushing secret files**.
|
|
||||||
1. Select **Save push rules**.
|
|
||||||
|
|
||||||
### Prevent pushing secrets to a project
|
|
||||||
|
|
||||||
The push rule of a project overrides the global push rule.
|
|
||||||
|
|
||||||
To prevent pushing secrets to a project:
|
|
||||||
|
|
||||||
1. On the top bar, select **Menu > Projects** and find your project.
|
|
||||||
1. On the left sidebar, select **Settings > Repository**.
|
|
||||||
1. Expand **Push rules**.
|
|
||||||
1. Select **Prevent pushing secret files**.
|
|
||||||
1. Select **Save push rules**.
|
|
||||||
|
|
||||||
## Prohibited file names
|
## Prohibited file names
|
||||||
|
|
||||||
> Moved to GitLab Premium in 13.9.
|
> Moved to GitLab Premium in 13.9.
|
||||||
|
@ -295,14 +257,26 @@ end of the grouped collection of match conditions where it is appended to all ma
|
||||||
(\.exe|^config\.yml|^directory-name\/config\.yml|(^|\/)install\.exe)$
|
(\.exe|^config\.yml|^directory-name\/config\.yml|(^|\/)install\.exe)$
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- ## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
### Reject unsigned commits push rule disables Web IDE
|
||||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
|
||||||
important to describe those, too. Think of things that may go wrong and include them here.
|
|
||||||
This is important to minimize requests for support, and to avoid doc comments with
|
|
||||||
questions that you know someone might ask.
|
|
||||||
|
|
||||||
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
|
In 13.10, if a project has the **Reject unsigned commits** push rule, the user is not allowed to
|
||||||
If you have none to add when creating a doc, leave this section in place
|
commit through GitLab Web IDE.
|
||||||
but commented out to help encourage others to add to it in the future. -->
|
|
||||||
|
To allow committing through the Web IDE on a project with this push rule, a GitLab administrator
|
||||||
|
must disable the feature flag `reject_unsigned_commits_by_gitlab`. This can be done through a
|
||||||
|
[rails console](../../../administration/operations/rails_console.md) and running:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Feature.disable(:reject_unsigned_commits_by_gitlab)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unsigned commits created in the GitLab UI
|
||||||
|
|
||||||
|
This push rule ignores commits that are authenticated and created by GitLab
|
||||||
|
(either through the UI or API). When the **Reject unsigned commits** push rule is
|
||||||
|
enabled, unsigned commits may still show up in the commit history if a commit was
|
||||||
|
created **in** GitLab itself. As expected, commits created outside GitLab and
|
||||||
|
pushed to the repository are rejected. For more information about this issue,
|
||||||
|
read [issue #19185](https://gitlab.com/gitlab-org/gitlab/-/issues/19185).
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Atlassian
|
|
||||||
module JiraConnect
|
|
||||||
# See documentation about Atlassian asymmetric JWT verification:
|
|
||||||
# https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/#verifying-a-asymmetric-jwt-token-for-install-callbacks
|
|
||||||
|
|
||||||
class AsymmetricJwt
|
|
||||||
include Gitlab::Utils::StrongMemoize
|
|
||||||
|
|
||||||
KeyFetchError = Class.new(StandardError)
|
|
||||||
|
|
||||||
ALGORITHM = 'RS256'
|
|
||||||
PUBLIC_KEY_CDN_URL = 'https://connect-install-keys.atlassian.com/'
|
|
||||||
UUID4_REGEX = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/.freeze
|
|
||||||
|
|
||||||
def initialize(token, verification_claims)
|
|
||||||
@token = token
|
|
||||||
@verification_claims = verification_claims
|
|
||||||
end
|
|
||||||
|
|
||||||
def valid?
|
|
||||||
claims.present? && claims['qsh'] == verification_qsh
|
|
||||||
end
|
|
||||||
|
|
||||||
def iss_claim
|
|
||||||
return unless claims
|
|
||||||
|
|
||||||
claims['iss']
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def claims
|
|
||||||
strong_memoize(:claims) do
|
|
||||||
_, jwt_headers = decode_token
|
|
||||||
public_key = retrieve_public_key(jwt_headers['kid'])
|
|
||||||
decoded_claims, _ = decode_token(public_key, true, **relevant_claims, verify_aud: true, verify_iss: true, algorithm: ALGORITHM)
|
|
||||||
|
|
||||||
decoded_claims
|
|
||||||
rescue JWT::DecodeError, OpenSSL::PKey::PKeyError, KeyFetchError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def decode_token(key = nil, verify = false, **claims)
|
|
||||||
Atlassian::Jwt.decode(@token, key, verify, **claims)
|
|
||||||
end
|
|
||||||
|
|
||||||
def retrieve_public_key(key_id)
|
|
||||||
raise KeyFetchError unless UUID4_REGEX.match?(key_id)
|
|
||||||
|
|
||||||
public_key = Gitlab::HTTP.try_get(PUBLIC_KEY_CDN_URL + key_id).try(:body)
|
|
||||||
|
|
||||||
raise KeyFetchError if public_key.blank?
|
|
||||||
|
|
||||||
OpenSSL::PKey.read(public_key)
|
|
||||||
end
|
|
||||||
|
|
||||||
def relevant_claims
|
|
||||||
@verification_claims.slice(:aud, :iss)
|
|
||||||
end
|
|
||||||
|
|
||||||
def verification_qsh
|
|
||||||
@verification_claims[:qsh]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Atlassian
|
||||||
|
module JiraConnect
|
||||||
|
module Jwt
|
||||||
|
# See documentation about Atlassian asymmetric JWT verification:
|
||||||
|
# https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/#verifying-a-asymmetric-jwt-token-for-install-callbacks
|
||||||
|
|
||||||
|
class Asymmetric
|
||||||
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
|
||||||
|
KeyFetchError = Class.new(StandardError)
|
||||||
|
|
||||||
|
ALGORITHM = 'RS256'
|
||||||
|
PUBLIC_KEY_CDN_URL = 'https://connect-install-keys.atlassian.com/'
|
||||||
|
UUID4_REGEX = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/.freeze
|
||||||
|
|
||||||
|
def initialize(token, verification_claims)
|
||||||
|
@token = token
|
||||||
|
@verification_claims = verification_claims
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?
|
||||||
|
claims.present? && claims['qsh'] == verification_qsh
|
||||||
|
end
|
||||||
|
|
||||||
|
def iss_claim
|
||||||
|
return unless claims
|
||||||
|
|
||||||
|
claims['iss']
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def claims
|
||||||
|
strong_memoize(:claims) do
|
||||||
|
_, jwt_headers = decode_token
|
||||||
|
public_key = retrieve_public_key(jwt_headers['kid'])
|
||||||
|
|
||||||
|
decoded_claims(public_key)
|
||||||
|
rescue JWT::DecodeError, OpenSSL::PKey::PKeyError, KeyFetchError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def decoded_claims(public_key)
|
||||||
|
decode_token(
|
||||||
|
public_key,
|
||||||
|
true,
|
||||||
|
**relevant_claims,
|
||||||
|
verify_aud: true,
|
||||||
|
verify_iss: true,
|
||||||
|
algorithm: ALGORITHM
|
||||||
|
).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def decode_token(key = nil, verify = false, **claims)
|
||||||
|
Atlassian::Jwt.decode(@token, key, verify, **claims)
|
||||||
|
end
|
||||||
|
|
||||||
|
def retrieve_public_key(key_id)
|
||||||
|
raise KeyFetchError unless UUID4_REGEX.match?(key_id)
|
||||||
|
|
||||||
|
public_key = Gitlab::HTTP.try_get(PUBLIC_KEY_CDN_URL + key_id).try(:body)
|
||||||
|
|
||||||
|
raise KeyFetchError if public_key.blank?
|
||||||
|
|
||||||
|
OpenSSL::PKey.read(public_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def relevant_claims
|
||||||
|
@verification_claims.slice(:aud, :iss)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verification_qsh
|
||||||
|
@verification_claims[:qsh]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
require_relative Rails.root.join('metrics_server', 'dependencies')
|
||||||
|
require_relative Rails.root.join('metrics_server', 'metrics_server')
|
||||||
|
|
||||||
|
namespace :gitlab do
|
||||||
|
namespace :metrics_exporter do
|
||||||
|
REPO = 'https://gitlab.com/gitlab-org/gitlab-metrics-exporter.git'
|
||||||
|
|
||||||
|
desc "GitLab | Metrics Exporter | Install or upgrade gitlab-metrics-exporter"
|
||||||
|
task :install, [:dir] => :gitlab_environment do |t, args|
|
||||||
|
unless args.dir.present?
|
||||||
|
abort %(Please specify the directory where you want to install the exporter
|
||||||
|
Usage: rake "gitlab:metrics_exporter:install[/installation/dir]")
|
||||||
|
end
|
||||||
|
|
||||||
|
version = ENV['GITLAB_METRICS_EXPORTER_VERSION'] || MetricsServer.version
|
||||||
|
make = Gitlab::Utils.which('gmake') || Gitlab::Utils.which('make')
|
||||||
|
|
||||||
|
abort "Couldn't find a 'make' binary" unless make
|
||||||
|
|
||||||
|
checkout_or_clone_version(version: version, repo: REPO, target_dir: args.dir, clone_opts: %w[--depth 1])
|
||||||
|
|
||||||
|
Dir.chdir(args.dir) { run_command!([make]) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12270,6 +12270,9 @@ msgstr ""
|
||||||
msgid "DependencyProxy|Image list"
|
msgid "DependencyProxy|Image list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DependencyProxy|Scheduled for deletion"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DependencyProxy|Storage settings"
|
msgid "DependencyProxy|Storage settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
||||||
PumaProcessSupervisor = Class.new(Gitlab::ProcessSupervisor)
|
PumaProcessSupervisor = Class.new(Gitlab::ProcessSupervisor)
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
def version
|
||||||
|
Rails.root.join('GITLAB_METRICS_EXPORTER_VERSION').read.chomp
|
||||||
|
end
|
||||||
|
|
||||||
def start_for_puma
|
def start_for_puma
|
||||||
metrics_dir = ::Prometheus::Client.configuration.multiprocess_files_dir
|
metrics_dir = ::Prometheus::Client.configuration.multiprocess_files_dir
|
||||||
|
|
||||||
|
@ -25,15 +29,41 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def spawn(target, metrics_dir:, gitlab_config: nil, wipe_metrics_dir: false)
|
def start_for_sidekiq(**options)
|
||||||
|
if new_metrics_server?
|
||||||
|
self.spawn('sidekiq', **options)
|
||||||
|
else
|
||||||
|
self.fork('sidekiq', **options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def spawn(target, metrics_dir:, **options)
|
||||||
|
return spawn_ruby_server(target, metrics_dir: metrics_dir, **options) unless new_metrics_server?
|
||||||
|
|
||||||
|
settings = settings_for(target)
|
||||||
|
path = options[:path]&.then { |p| Pathname.new(p) } || Pathname.new('')
|
||||||
|
cmd = path.join('gitlab-metrics-exporter').to_path
|
||||||
|
env = {
|
||||||
|
'GME_MMAP_METRICS_DIR' => metrics_dir.to_s,
|
||||||
|
'GME_PROBES' => 'self,mmap',
|
||||||
|
'GME_SERVER_HOST' => settings['address'],
|
||||||
|
'GME_SERVER_PORT' => settings['port'].to_s
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.spawn(env, cmd, err: $stderr, out: $stdout, pgroup: true).tap do |pid|
|
||||||
|
Process.detach(pid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def spawn_ruby_server(target, metrics_dir:, wipe_metrics_dir: false, **options)
|
||||||
ensure_valid_target!(target)
|
ensure_valid_target!(target)
|
||||||
|
|
||||||
cmd = "#{Rails.root}/bin/metrics-server"
|
cmd = "#{Rails.root}/bin/metrics-server"
|
||||||
env = {
|
env = {
|
||||||
'METRICS_SERVER_TARGET' => target,
|
'METRICS_SERVER_TARGET' => target,
|
||||||
'WIPE_METRICS_DIR' => wipe_metrics_dir ? '1' : '0'
|
'WIPE_METRICS_DIR' => wipe_metrics_dir ? '1' : '0',
|
||||||
|
'GITLAB_CONFIG' => ENV['GITLAB_CONFIG']
|
||||||
}
|
}
|
||||||
env['GITLAB_CONFIG'] = gitlab_config if gitlab_config
|
|
||||||
|
|
||||||
Process.spawn(env, cmd, err: $stderr, out: $stdout, pgroup: true).tap do |pid|
|
Process.spawn(env, cmd, err: $stderr, out: $stdout, pgroup: true).tap do |pid|
|
||||||
Process.detach(pid)
|
Process.detach(pid)
|
||||||
|
@ -66,9 +96,23 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def new_metrics_server?
|
||||||
|
Gitlab::Utils.to_boolean(ENV['GITLAB_GOLANG_METRICS_SERVER'])
|
||||||
|
end
|
||||||
|
|
||||||
def ensure_valid_target!(target)
|
def ensure_valid_target!(target)
|
||||||
raise "Target must be one of [puma,sidekiq]" unless %w(puma sidekiq).include?(target)
|
raise "Target must be one of [puma,sidekiq]" unless %w(puma sidekiq).include?(target)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def settings_for(target)
|
||||||
|
settings_key =
|
||||||
|
case target
|
||||||
|
when 'puma' then 'web_exporter'
|
||||||
|
when 'sidekiq' then 'sidekiq_exporter'
|
||||||
|
else ensure_valid_target!(target)
|
||||||
|
end
|
||||||
|
::Settings.monitoring[settings_key]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(target, metrics_dir, wipe_metrics_dir)
|
def initialize(target, metrics_dir, wipe_metrics_dir)
|
||||||
|
|
|
@ -164,8 +164,7 @@ module Gitlab
|
||||||
|
|
||||||
def restart_metrics_server
|
def restart_metrics_server
|
||||||
@logger.info("Starting metrics server on port #{sidekiq_exporter_port}")
|
@logger.info("Starting metrics server on port #{sidekiq_exporter_port}")
|
||||||
MetricsServer.fork(
|
MetricsServer.start_for_sidekiq(
|
||||||
'sidekiq',
|
|
||||||
metrics_dir: @metrics_dir,
|
metrics_dir: @metrics_dir,
|
||||||
reset_signals: TERMINATE_SIGNALS + FORWARD_SIGNALS
|
reset_signals: TERMINATE_SIGNALS + FORWARD_SIGNALS
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,44 +1,83 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
require 'rake_helper'
|
||||||
|
|
||||||
require_relative '../../../metrics_server/metrics_server'
|
require_relative '../../../metrics_server/metrics_server'
|
||||||
|
|
||||||
# End-to-end tests for the metrics server process we use to serve metrics
|
# End-to-end tests for the metrics server process we use to serve metrics
|
||||||
# from forking applications (Sidekiq, Puma) to the Prometheus scraper.
|
# from forking applications (Sidekiq, Puma) to the Prometheus scraper.
|
||||||
RSpec.describe 'bin/metrics-server', :aggregate_failures do
|
RSpec.describe 'GitLab metrics server', :aggregate_failures do
|
||||||
let(:config_file) { Tempfile.new('gitlab.yml') }
|
let(:config_file) { Tempfile.new('gitlab.yml') }
|
||||||
|
let(:address) { '127.0.0.1' }
|
||||||
|
let(:port) { 3807 }
|
||||||
let(:config) do
|
let(:config) do
|
||||||
{
|
{
|
||||||
'test' => {
|
'test' => {
|
||||||
'monitoring' => {
|
'monitoring' => {
|
||||||
'web_exporter' => {
|
'web_exporter' => {
|
||||||
'address' => 'localhost',
|
'address' => address,
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'port' => 3807
|
'port' => port
|
||||||
},
|
},
|
||||||
'sidekiq_exporter' => {
|
'sidekiq_exporter' => {
|
||||||
'address' => 'localhost',
|
'address' => address,
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'port' => 3807
|
'port' => port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(puma sidekiq).each do |target|
|
before(:all) do
|
||||||
context "with a running server targeting #{target}" do
|
Rake.application.rake_require 'tasks/gitlab/metrics_exporter'
|
||||||
|
|
||||||
|
@exporter_path = Rails.root.join('tmp', 'test', 'gme')
|
||||||
|
|
||||||
|
run_rake_task('gitlab:metrics_exporter:install', @exporter_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:all) do
|
||||||
|
FileUtils.rm_rf(@exporter_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'serves metrics endpoint' do
|
||||||
|
it 'serves /metrics endpoint' do
|
||||||
|
start_server!
|
||||||
|
|
||||||
|
expect do
|
||||||
|
Timeout.timeout(10) do
|
||||||
|
http_ok = false
|
||||||
|
until http_ok
|
||||||
|
sleep 1
|
||||||
|
response = Gitlab::HTTP.try_get("http://#{address}:#{port}/metrics", allow_local_requests: true)
|
||||||
|
http_ok = response&.success?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end.not_to raise_error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'spawns a server' do |target, use_golang_server|
|
||||||
|
context "targeting #{target} when using Golang server is #{use_golang_server}" do
|
||||||
let(:metrics_dir) { Dir.mktmpdir }
|
let(:metrics_dir) { Dir.mktmpdir }
|
||||||
|
|
||||||
|
subject(:start_server!) do
|
||||||
|
@pid = MetricsServer.spawn(target, metrics_dir: metrics_dir, path: @exporter_path.join('bin'))
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
if use_golang_server
|
||||||
|
stub_env('GITLAB_GOLANG_METRICS_SERVER', '1')
|
||||||
|
allow(Settings).to receive(:monitoring).and_return(config.dig('test', 'monitoring'))
|
||||||
|
else
|
||||||
|
config_file.write(YAML.dump(config))
|
||||||
|
config_file.close
|
||||||
|
stub_env('GITLAB_CONFIG', config_file.path)
|
||||||
|
end
|
||||||
# We need to send a request to localhost
|
# We need to send a request to localhost
|
||||||
WebMock.allow_net_connect!
|
WebMock.allow_net_connect!
|
||||||
|
|
||||||
config_file.write(YAML.dump(config))
|
|
||||||
config_file.close
|
|
||||||
|
|
||||||
@pid = MetricsServer.spawn(target, metrics_dir: metrics_dir, gitlab_config: config_file.path, wipe_metrics_dir: true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
after do
|
after do
|
||||||
|
@ -54,25 +93,25 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do
|
||||||
|
|
||||||
expect(Gitlab::ProcessManagement.process_alive?(@pid)).to be(false)
|
expect(Gitlab::ProcessManagement.process_alive?(@pid)).to be(false)
|
||||||
end
|
end
|
||||||
rescue Errno::ESRCH => _
|
rescue Errno::ESRCH, Errno::ECHILD => _
|
||||||
# 'No such process' means the process died before
|
# 'No such process' or 'No child processes' means the process died before
|
||||||
ensure
|
ensure
|
||||||
config_file.unlink
|
config_file.unlink
|
||||||
FileUtils.rm_rf(metrics_dir, secure: true)
|
FileUtils.rm_rf(metrics_dir, secure: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'serves /metrics endpoint' do
|
it_behaves_like 'serves metrics endpoint'
|
||||||
expect do
|
|
||||||
Timeout.timeout(10) do
|
context 'when using Pathname instance as target directory' do
|
||||||
http_ok = false
|
let(:metrics_dir) { Pathname.new(Dir.mktmpdir) }
|
||||||
until http_ok
|
|
||||||
sleep 1
|
it_behaves_like 'serves metrics endpoint'
|
||||||
response = Gitlab::HTTP.try_get("http://localhost:3807/metrics", allow_local_requests: true)
|
|
||||||
http_ok = response&.success?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end.not_to raise_error
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'spawns a server', 'puma', true
|
||||||
|
it_behaves_like 'spawns a server', 'puma', false
|
||||||
|
it_behaves_like 'spawns a server', 'sidekiq', true
|
||||||
|
it_behaves_like 'spawns a server', 'sidekiq', false
|
||||||
end
|
end
|
||||||
|
|
|
@ -314,7 +314,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
let(:sidekiq_exporter_enabled) { true }
|
let(:sidekiq_exporter_enabled) { true }
|
||||||
|
|
||||||
it 'does not start a sidekiq metrics server' do
|
it 'does not start a sidekiq metrics server' do
|
||||||
expect(MetricsServer).not_to receive(:fork)
|
expect(MetricsServer).not_to receive(:start_for_sidekiq)
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
end
|
end
|
||||||
|
@ -324,7 +324,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
let(:sidekiq_exporter_enabled) { true }
|
let(:sidekiq_exporter_enabled) { true }
|
||||||
|
|
||||||
it 'does not start a sidekiq metrics server' do
|
it 'does not start a sidekiq metrics server' do
|
||||||
expect(MetricsServer).not_to receive(:fork)
|
expect(MetricsServer).not_to receive(:start_for_sidekiq)
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
end
|
end
|
||||||
|
@ -347,7 +347,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not start a sidekiq metrics server' do
|
it 'does not start a sidekiq metrics server' do
|
||||||
expect(MetricsServer).not_to receive(:fork)
|
expect(MetricsServer).not_to receive(:start_for_sidekiq)
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
end
|
end
|
||||||
|
@ -366,7 +366,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not start a sidekiq metrics server' do
|
it 'does not start a sidekiq metrics server' do
|
||||||
expect(MetricsServer).not_to receive(:fork)
|
expect(MetricsServer).not_to receive(:start_for_sidekiq)
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
end
|
end
|
||||||
|
@ -389,9 +389,9 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
with_them do
|
with_them do
|
||||||
specify do
|
specify do
|
||||||
if start_metrics_server
|
if start_metrics_server
|
||||||
expect(MetricsServer).to receive(:fork).with('sidekiq', metrics_dir: metrics_dir, reset_signals: trapped_signals)
|
expect(MetricsServer).to receive(:start_for_sidekiq).with(metrics_dir: metrics_dir, reset_signals: trapped_signals)
|
||||||
else
|
else
|
||||||
expect(MetricsServer).not_to receive(:fork)
|
expect(MetricsServer).not_to receive(:start_for_sidekiq)
|
||||||
end
|
end
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
|
@ -421,7 +421,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
let(:sidekiq_exporter_enabled) { true }
|
let(:sidekiq_exporter_enabled) { true }
|
||||||
|
|
||||||
it 'does not start the server' do
|
it 'does not start the server' do
|
||||||
expect(MetricsServer).not_to receive(:fork)
|
expect(MetricsServer).not_to receive(:start_for_sidekiq)
|
||||||
|
|
||||||
cli.run(%w(foo --dryrun))
|
cli.run(%w(foo --dryrun))
|
||||||
end
|
end
|
||||||
|
@ -442,7 +442,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
it 'stops the entire process cluster if one of the workers has been terminated' do
|
it 'stops the entire process cluster if one of the workers has been terminated' do
|
||||||
expect(supervisor).to receive(:alive).and_return(true)
|
expect(supervisor).to receive(:alive).and_return(true)
|
||||||
expect(supervisor).to receive(:supervise).and_yield([2])
|
expect(supervisor).to receive(:supervise).and_yield([2])
|
||||||
expect(MetricsServer).to receive(:fork).once.and_return(metrics_server_pid)
|
expect(MetricsServer).to receive(:start_for_sidekiq).once.and_return(metrics_server_pid)
|
||||||
expect(Gitlab::ProcessManagement).to receive(:signal_processes).with([42, 99], :TERM)
|
expect(Gitlab::ProcessManagement).to receive(:signal_processes).with([42, 99], :TERM)
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
|
@ -452,7 +452,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
it 'restarts the metrics server when it is down' do
|
it 'restarts the metrics server when it is down' do
|
||||||
expect(supervisor).to receive(:alive).and_return(true)
|
expect(supervisor).to receive(:alive).and_return(true)
|
||||||
expect(supervisor).to receive(:supervise).and_yield([metrics_server_pid])
|
expect(supervisor).to receive(:supervise).and_yield([metrics_server_pid])
|
||||||
expect(MetricsServer).to receive(:fork).twice.and_return(metrics_server_pid)
|
expect(MetricsServer).to receive(:start_for_sidekiq).twice.and_return(metrics_server_pid)
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
end
|
end
|
||||||
|
@ -462,7 +462,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
|
||||||
it 'does not restart the metrics server' do
|
it 'does not restart the metrics server' do
|
||||||
expect(supervisor).to receive(:alive).and_return(false)
|
expect(supervisor).to receive(:alive).and_return(false)
|
||||||
expect(supervisor).to receive(:supervise).and_yield([metrics_server_pid])
|
expect(supervisor).to receive(:supervise).and_yield([metrics_server_pid])
|
||||||
expect(MetricsServer).to receive(:fork).once.and_return(metrics_server_pid)
|
expect(MetricsServer).to receive(:start_for_sidekiq).once.and_return(metrics_server_pid)
|
||||||
|
|
||||||
cli.run(%w(foo))
|
cli.run(%w(foo))
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ RSpec.describe JiraConnect::EventsController do
|
||||||
|
|
||||||
shared_context 'valid JWT token' do
|
shared_context 'valid JWT token' do
|
||||||
before do
|
before do
|
||||||
allow_next_instance_of(Atlassian::JiraConnect::AsymmetricJwt) do |asymmetric_jwt|
|
allow_next_instance_of(Atlassian::JiraConnect::Jwt::Asymmetric) do |asymmetric_jwt|
|
||||||
allow(asymmetric_jwt).to receive(:valid?).and_return(true)
|
allow(asymmetric_jwt).to receive(:valid?).and_return(true)
|
||||||
allow(asymmetric_jwt).to receive(:iss_claim).and_return(client_key)
|
allow(asymmetric_jwt).to receive(:iss_claim).and_return(client_key)
|
||||||
end
|
end
|
||||||
|
@ -36,7 +36,7 @@ RSpec.describe JiraConnect::EventsController do
|
||||||
|
|
||||||
shared_context 'invalid JWT token' do
|
shared_context 'invalid JWT token' do
|
||||||
before do
|
before do
|
||||||
allow_next_instance_of(Atlassian::JiraConnect::AsymmetricJwt) do |asymmetric_jwt|
|
allow_next_instance_of(Atlassian::JiraConnect::Jwt::Asymmetric) do |asymmetric_jwt|
|
||||||
allow(asymmetric_jwt).to receive(:valid?).and_return(false)
|
allow(asymmetric_jwt).to receive(:valid?).and_return(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
||||||
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||||
import Component from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue';
|
import Component from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue';
|
||||||
|
import { MANIFEST_PENDING_DESTRUCTION_STATUS } from '~/packages_and_registries/dependency_proxy/constants';
|
||||||
import { proxyManifests } from 'jest/packages_and_registries/dependency_proxy/mock_data';
|
import { proxyManifests } from 'jest/packages_and_registries/dependency_proxy/mock_data';
|
||||||
|
|
||||||
describe('Manifest Row', () => {
|
describe('Manifest Row', () => {
|
||||||
|
@ -26,34 +27,63 @@ describe('Manifest Row', () => {
|
||||||
const findListItem = () => wrapper.findComponent(ListItem);
|
const findListItem = () => wrapper.findComponent(ListItem);
|
||||||
const findCachedMessages = () => wrapper.findByTestId('cached-message');
|
const findCachedMessages = () => wrapper.findByTestId('cached-message');
|
||||||
const findTimeAgoTooltip = () => wrapper.findComponent(TimeagoTooltip);
|
const findTimeAgoTooltip = () => wrapper.findComponent(TimeagoTooltip);
|
||||||
|
const findStatus = () => wrapper.findByTestId('status');
|
||||||
beforeEach(() => {
|
|
||||||
createComponent();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has a list item', () => {
|
describe('With a manifest on the DEFAULT status', () => {
|
||||||
expect(findListItem().exists()).toBe(true);
|
beforeEach(() => {
|
||||||
|
createComponent();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has a list item', () => {
|
||||||
|
expect(findListItem().exists()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the name', () => {
|
||||||
|
expect(wrapper.text()).toContain('alpine');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the version', () => {
|
||||||
|
expect(wrapper.text()).toContain('latest');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the cached time', () => {
|
||||||
|
expect(findCachedMessages().text()).toContain('Cached');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has a time ago tooltip component', () => {
|
||||||
|
expect(findTimeAgoTooltip().props()).toMatchObject({
|
||||||
|
time: defaultProps.manifest.createdAt,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not have a status element displayed', () => {
|
||||||
|
expect(findStatus().exists()).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays the name', () => {
|
describe('With a manifest on the PENDING_DESTRUCTION_STATUS', () => {
|
||||||
expect(wrapper.text()).toContain('alpine');
|
const pendingDestructionManifest = {
|
||||||
});
|
manifest: {
|
||||||
|
...defaultProps.manifest,
|
||||||
|
status: MANIFEST_PENDING_DESTRUCTION_STATUS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
it('displays the version', () => {
|
beforeEach(() => {
|
||||||
expect(wrapper.text()).toContain('latest');
|
createComponent(pendingDestructionManifest);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays the cached time', () => {
|
it('has a list item', () => {
|
||||||
expect(findCachedMessages().text()).toContain('Cached');
|
expect(findListItem().exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has a time ago tooltip component', () => {
|
it('has a status element displayed', () => {
|
||||||
expect(findTimeAgoTooltip().props()).toMatchObject({
|
expect(findStatus().exists()).toBe(true);
|
||||||
time: defaultProps.manifest.createdAt,
|
expect(findStatus().text()).toBe('Scheduled for deletion');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,8 +8,18 @@ export const proxyData = () => ({
|
||||||
export const proxySettings = (extend = {}) => ({ enabled: true, ...extend });
|
export const proxySettings = (extend = {}) => ({ enabled: true, ...extend });
|
||||||
|
|
||||||
export const proxyManifests = () => [
|
export const proxyManifests = () => [
|
||||||
{ id: 'proxy-1', createdAt: '2021-09-22T09:45:28Z', imageName: 'alpine:latest' },
|
{
|
||||||
{ id: 'proxy-2', createdAt: '2021-09-21T09:45:28Z', imageName: 'alpine:stable' },
|
id: 'proxy-1',
|
||||||
|
createdAt: '2021-09-22T09:45:28Z',
|
||||||
|
imageName: 'alpine:latest',
|
||||||
|
status: 'DEFAULT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'proxy-2',
|
||||||
|
createdAt: '2021-09-21T09:45:28Z',
|
||||||
|
imageName: 'alpine:stable',
|
||||||
|
status: 'DEFAULT',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const pagination = (extend) => ({
|
export const pagination = (extend) => ({
|
||||||
|
|
|
@ -101,20 +101,6 @@ describe('list item', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('disabled prop', () => {
|
|
||||||
it('when true applies gl-opacity-5 class', () => {
|
|
||||||
mountComponent({ disabled: true });
|
|
||||||
|
|
||||||
expect(wrapper.classes('gl-opacity-5')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('when false does not apply gl-opacity-5 class', () => {
|
|
||||||
mountComponent({ disabled: false });
|
|
||||||
|
|
||||||
expect(wrapper.classes('gl-opacity-5')).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('borders and selection', () => {
|
describe('borders and selection', () => {
|
||||||
it.each`
|
it.each`
|
||||||
first | selected | shouldHave | shouldNotHave
|
first | selected | shouldHave | shouldNotHave
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Atlassian::JiraConnect::AsymmetricJwt do
|
RSpec.describe Atlassian::JiraConnect::Jwt::Asymmetric do
|
||||||
describe '#valid?' do
|
describe '#valid?' do
|
||||||
subject(:asymmetric_jwt) { described_class.new(jwt, verification_claims) }
|
subject(:asymmetric_jwt) { described_class.new(jwt, verification_claims) }
|
||||||
|
|
||||||
|
@ -10,15 +10,19 @@ RSpec.describe Atlassian::JiraConnect::AsymmetricJwt do
|
||||||
let(:jwt_claims) { { aud: aud, iss: client_key, qsh: qsh } }
|
let(:jwt_claims) { { aud: aud, iss: client_key, qsh: qsh } }
|
||||||
let(:aud) { 'https://test.host/-/jira_connect' }
|
let(:aud) { 'https://test.host/-/jira_connect' }
|
||||||
let(:client_key) { '1234' }
|
let(:client_key) { '1234' }
|
||||||
let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/installed', 'POST', 'https://gitlab.test') }
|
|
||||||
let(:public_key_id) { '123e4567-e89b-12d3-a456-426614174000' }
|
let(:public_key_id) { '123e4567-e89b-12d3-a456-426614174000' }
|
||||||
let(:jwt_headers) { { kid: public_key_id } }
|
let(:jwt_headers) { { kid: public_key_id } }
|
||||||
let(:private_key) { OpenSSL::PKey::RSA.generate 2048 }
|
let(:private_key) { OpenSSL::PKey::RSA.generate 2048 }
|
||||||
let(:jwt) { JWT.encode(jwt_claims, private_key, 'RS256', jwt_headers) }
|
let(:jwt) { JWT.encode(jwt_claims, private_key, 'RS256', jwt_headers) }
|
||||||
let(:public_key) { private_key.public_key }
|
let(:public_key) { private_key.public_key }
|
||||||
|
let(:install_keys_url) { "https://connect-install-keys.atlassian.com/#{public_key_id}" }
|
||||||
|
let(:qsh) do
|
||||||
|
Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/installed', 'POST', 'https://gitlab.test')
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, "https://connect-install-keys.atlassian.com/#{public_key_id}").to_return(body: public_key.to_s, status: 200)
|
stub_request(:get, install_keys_url)
|
||||||
|
.to_return(body: public_key.to_s, status: 200)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns true when verified with public key from CDN' do
|
it 'returns true when verified with public key from CDN' do
|
||||||
|
@ -26,7 +30,7 @@ RSpec.describe Atlassian::JiraConnect::AsymmetricJwt do
|
||||||
|
|
||||||
expect(asymmetric_jwt).to be_valid
|
expect(asymmetric_jwt).to be_valid
|
||||||
|
|
||||||
expect(WebMock).to have_requested(:get, "https://connect-install-keys.atlassian.com/#{public_key_id}")
|
expect(WebMock).to have_requested(:get, install_keys_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'JWT does not contain a key ID' do
|
context 'JWT does not contain a key ID' do
|
||||||
|
@ -43,7 +47,7 @@ RSpec.describe Atlassian::JiraConnect::AsymmetricJwt do
|
||||||
|
|
||||||
context 'public key can not be retrieved' do
|
context 'public key can not be retrieved' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, "https://connect-install-keys.atlassian.com/#{public_key_id}").to_return(body: '', status: 404)
|
stub_request(:get, install_keys_url).to_return(body: '', status: 404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it { is_expected.not_to be_valid }
|
it { is_expected.not_to be_valid }
|
|
@ -0,0 +1,81 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rake_helper'
|
||||||
|
require_relative '../../../support/helpers/next_instance_of'
|
||||||
|
|
||||||
|
RSpec.describe 'gitlab:metrics_exporter:install' do
|
||||||
|
before do
|
||||||
|
Rake.application.rake_require 'tasks/gitlab/metrics_exporter'
|
||||||
|
end
|
||||||
|
|
||||||
|
subject(:task) do
|
||||||
|
Rake::Task['gitlab:metrics_exporter:install']
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no target directory is specified' do
|
||||||
|
it 'aborts with an error message' do
|
||||||
|
expect do
|
||||||
|
expect { task.execute }.to output(/Please specify the directory/).to_stdout
|
||||||
|
end.to raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when target directory is specified' do
|
||||||
|
let(:args) { Rake::TaskArguments.new(%w(dir), %w(path/to/exporter)) }
|
||||||
|
let(:context) { TOPLEVEL_BINDING.eval('self') }
|
||||||
|
let(:expected_clone_params) do
|
||||||
|
{
|
||||||
|
repo: 'https://gitlab.com/gitlab-org/gitlab-metrics-exporter.git',
|
||||||
|
version: 'main',
|
||||||
|
target_dir: 'path/to/exporter'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when dependencies are missing' do
|
||||||
|
it 'aborts with an error message' do
|
||||||
|
expect(Gitlab::Utils).to receive(:which).with('gmake').ordered
|
||||||
|
expect(Gitlab::Utils).to receive(:which).with('make').ordered
|
||||||
|
|
||||||
|
expect do
|
||||||
|
expect { task.execute(args) }.to output(/Couldn't find a 'make' binary/).to_stdout
|
||||||
|
end.to raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'installs the exporter with gmake' do
|
||||||
|
expect(Gitlab::Utils).to receive(:which).with('gmake').and_return('path/to/gmake').ordered
|
||||||
|
expect(context).to receive(:checkout_or_clone_version).with(hash_including(expected_clone_params)).ordered
|
||||||
|
expect(Dir).to receive(:chdir).with('path/to/exporter').and_yield.ordered
|
||||||
|
expect(context).to receive(:run_command!).with(['path/to/gmake']).ordered
|
||||||
|
|
||||||
|
task.execute(args)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'installs the exporter with make' do
|
||||||
|
expect(Gitlab::Utils).to receive(:which).with('gmake').ordered
|
||||||
|
expect(Gitlab::Utils).to receive(:which).with('make').and_return('path/to/make').ordered
|
||||||
|
expect(context).to receive(:checkout_or_clone_version).with(hash_including(expected_clone_params)).ordered
|
||||||
|
expect(Dir).to receive(:chdir).with('path/to/exporter').and_yield.ordered
|
||||||
|
expect(context).to receive(:run_command!).with(['path/to/make']).ordered
|
||||||
|
|
||||||
|
task.execute(args)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when overriding version via environment variable' do
|
||||||
|
before do
|
||||||
|
stub_env('GITLAB_METRICS_EXPORTER_VERSION', '1.0')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'clones from repository with that version instead' do
|
||||||
|
expect(Gitlab::Utils).to receive(:which).with('gmake').and_return('path/to/gmake').ordered
|
||||||
|
expect(context).to receive(:checkout_or_clone_version).with(
|
||||||
|
hash_including(expected_clone_params.merge(version: '1.0'))
|
||||||
|
).ordered
|
||||||
|
expect(Dir).to receive(:chdir).with('path/to/exporter').and_yield.ordered
|
||||||
|
expect(context).to receive(:run_command!).with(['path/to/gmake']).ordered
|
||||||
|
|
||||||
|
task.execute(args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,6 +15,8 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
||||||
let(:ruby_sampler_double) { double(Gitlab::Metrics::Samplers::RubySampler) }
|
let(:ruby_sampler_double) { double(Gitlab::Metrics::Samplers::RubySampler) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
# Make sure we never actually spawn any new processes in a unit test.
|
||||||
|
%i(spawn fork detach).each { |m| allow(Process).to receive(m) }
|
||||||
# We do not want this to have knock-on effects on the test process.
|
# We do not want this to have knock-on effects on the test process.
|
||||||
allow(Gitlab::ProcessManagement).to receive(:modify_signals)
|
allow(Gitlab::ProcessManagement).to receive(:modify_signals)
|
||||||
|
|
||||||
|
@ -67,35 +69,69 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.spawn' do
|
describe '.spawn' do
|
||||||
let(:expected_env) do
|
context 'for legacy Ruby server' do
|
||||||
{
|
let(:expected_env) do
|
||||||
'METRICS_SERVER_TARGET' => target,
|
{
|
||||||
'WIPE_METRICS_DIR' => '0'
|
'METRICS_SERVER_TARGET' => target,
|
||||||
}
|
'WIPE_METRICS_DIR' => '0',
|
||||||
end
|
'GITLAB_CONFIG' => 'path/to/config/gitlab.yml'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
it 'spawns a new server process and returns its PID' do
|
before do
|
||||||
expect(Process).to receive(:spawn).with(
|
stub_env('GITLAB_CONFIG', 'path/to/config/gitlab.yml')
|
||||||
expected_env,
|
end
|
||||||
end_with('bin/metrics-server'),
|
|
||||||
hash_including(pgroup: true)
|
|
||||||
).and_return(99)
|
|
||||||
expect(Process).to receive(:detach).with(99)
|
|
||||||
|
|
||||||
pid = described_class.spawn(target, metrics_dir: metrics_dir)
|
it 'spawns a new server process and returns its PID' do
|
||||||
|
|
||||||
expect(pid).to eq(99)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when path to gitlab.yml is passed' do
|
|
||||||
it 'sets the GITLAB_CONFIG environment variable' do
|
|
||||||
expect(Process).to receive(:spawn).with(
|
expect(Process).to receive(:spawn).with(
|
||||||
expected_env.merge('GITLAB_CONFIG' => 'path/to/config/gitlab.yml'),
|
expected_env,
|
||||||
end_with('bin/metrics-server'),
|
end_with('bin/metrics-server'),
|
||||||
hash_including(pgroup: true)
|
hash_including(pgroup: true)
|
||||||
).and_return(99)
|
).and_return(99)
|
||||||
|
expect(Process).to receive(:detach).with(99)
|
||||||
|
|
||||||
described_class.spawn(target, metrics_dir: metrics_dir, gitlab_config: 'path/to/config/gitlab.yml')
|
pid = described_class.spawn(target, metrics_dir: metrics_dir)
|
||||||
|
|
||||||
|
expect(pid).to eq(99)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for Golang server' do
|
||||||
|
let(:expected_port) { target == 'puma' ? '8083' : '8082' }
|
||||||
|
let(:expected_env) do
|
||||||
|
{
|
||||||
|
'GME_MMAP_METRICS_DIR' => metrics_dir,
|
||||||
|
'GME_PROBES' => 'self,mmap',
|
||||||
|
'GME_SERVER_HOST' => 'localhost',
|
||||||
|
'GME_SERVER_PORT' => expected_port
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_env('GITLAB_GOLANG_METRICS_SERVER', '1')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'spawns a new server process and returns its PID' do
|
||||||
|
expect(Process).to receive(:spawn).with(
|
||||||
|
expected_env,
|
||||||
|
'gitlab-metrics-exporter',
|
||||||
|
hash_including(pgroup: true)
|
||||||
|
).and_return(99)
|
||||||
|
expect(Process).to receive(:detach).with(99)
|
||||||
|
|
||||||
|
pid = described_class.spawn(target, metrics_dir: metrics_dir)
|
||||||
|
|
||||||
|
expect(pid).to eq(99)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'can launch from explicit path instead of PATH' do
|
||||||
|
expect(Process).to receive(:spawn).with(
|
||||||
|
expected_env,
|
||||||
|
'/path/to/gme/gitlab-metrics-exporter',
|
||||||
|
hash_including(pgroup: true)
|
||||||
|
).and_return(99)
|
||||||
|
|
||||||
|
described_class.spawn(target, metrics_dir: metrics_dir, path: '/path/to/gme/')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -112,10 +148,21 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.spawn' do
|
describe '.spawn' do
|
||||||
it 'raises an error' do
|
context 'for legacy Ruby server' do
|
||||||
expect { described_class.spawn('unsupported', metrics_dir: metrics_dir) }.to(
|
it 'raises an error' do
|
||||||
raise_error('Target must be one of [puma,sidekiq]')
|
expect { described_class.spawn('unsupported', metrics_dir: metrics_dir) }.to(
|
||||||
)
|
raise_error('Target must be one of [puma,sidekiq]')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for Golang server' do
|
||||||
|
it 'raises an error' do
|
||||||
|
stub_env('GITLAB_GOLANG_METRICS_SERVER', '1')
|
||||||
|
expect { described_class.spawn('unsupported', metrics_dir: metrics_dir) }.to(
|
||||||
|
raise_error('Target must be one of [puma,sidekiq]')
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -245,4 +292,23 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.start_for_sidekiq' do
|
||||||
|
context 'for legacy Ruby server' do
|
||||||
|
it 'forks the parent process' do
|
||||||
|
expect(Process).to receive(:fork).and_return(42)
|
||||||
|
|
||||||
|
described_class.start_for_sidekiq(metrics_dir: '/path/to/metrics')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for Golang server' do
|
||||||
|
it 'spawns the server process' do
|
||||||
|
stub_env('GITLAB_GOLANG_METRICS_SERVER', '1')
|
||||||
|
expect(Process).to receive(:spawn).and_return(42)
|
||||||
|
|
||||||
|
described_class.start_for_sidekiq(metrics_dir: '/path/to/metrics')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue