Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c71c2ba4c2
commit
097eb36475
|
|
@ -229,7 +229,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/administration/index.md @axil
|
||||
/doc/administration/instance_limits.md @axil
|
||||
/doc/administration/instance_review.md @kpaizee
|
||||
/doc/administration/integration/kroki.md @kpaizee
|
||||
/doc/administration/integration/kroki.md @msedlakjakubowski
|
||||
/doc/administration/integration/mailgun.md @kpaizee
|
||||
/doc/administration/integration/plantuml.md @aqualls
|
||||
/doc/administration/integration/terminal.md @kpaizee
|
||||
|
|
|
|||
|
|
@ -483,7 +483,6 @@ Layout/HashAlignment:
|
|||
- 'lib/backup/gitaly_backup.rb'
|
||||
- 'lib/banzai/filter/references/abstract_reference_filter.rb'
|
||||
- 'lib/banzai/reference_redactor.rb'
|
||||
- 'lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb'
|
||||
- 'lib/gitlab/abuse.rb'
|
||||
- 'lib/gitlab/access.rb'
|
||||
- 'lib/gitlab/application_rate_limiter.rb'
|
||||
|
|
|
|||
|
|
@ -3314,7 +3314,6 @@ Layout/LineLength:
|
|||
- 'lib/bulk_imports/common/pipelines/wiki_pipeline.rb'
|
||||
- 'lib/bulk_imports/common/transformers/prohibited_attributes_transformer.rb'
|
||||
- 'lib/bulk_imports/groups/loaders/group_loader.rb'
|
||||
- 'lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb'
|
||||
- 'lib/bulk_imports/projects/pipelines/project_pipeline.rb'
|
||||
- 'lib/bulk_imports/projects/pipelines/repository_pipeline.rb'
|
||||
- 'lib/bulk_imports/projects/transformers/project_attributes_transformer.rb'
|
||||
|
|
@ -4794,7 +4793,6 @@ Layout/LineLength:
|
|||
- 'spec/lib/bulk_imports/pipeline_spec.rb'
|
||||
- 'spec/lib/bulk_imports/projects/pipelines/external_pull_requests_pipeline_spec.rb'
|
||||
- 'spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb'
|
||||
- 'spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb'
|
||||
- 'spec/lib/bulk_imports/projects/pipelines/project_feature_pipeline_spec.rb'
|
||||
- 'spec/lib/bulk_imports/projects/pipelines/project_pipeline_spec.rb'
|
||||
- 'spec/lib/bulk_imports/projects/pipelines/protected_branches_pipeline_spec.rb'
|
||||
|
|
|
|||
|
|
@ -188,7 +188,6 @@ RSpec/ExpectInHook:
|
|||
- 'spec/lib/backup/manager_spec.rb'
|
||||
- 'spec/lib/banzai/reference_redactor_spec.rb'
|
||||
- 'spec/lib/bulk_imports/ndjson_pipeline_spec.rb'
|
||||
- 'spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb'
|
||||
- 'spec/lib/container_registry/gitlab_api_client_spec.rb'
|
||||
- 'spec/lib/file_size_validator_spec.rb'
|
||||
- 'spec/lib/gitlab/alert_management/fingerprint_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
080f9fb5c6d7e1e5e3c3e2a5202b3f0a83ddd180
|
||||
94055b253d05bc04f533c977be892b0cd6f225ea
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
14.6.0
|
||||
14.6.1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
<script>
|
||||
import {
|
||||
GlFormCheckbox,
|
||||
GlFormGroup,
|
||||
GlFormInputGroup,
|
||||
GlFormInput,
|
||||
GlFormText,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { __, s__ } from '~/locale';
|
||||
|
||||
export default {
|
||||
name: 'InactiveProjectDeletionForm',
|
||||
components: {
|
||||
GlFormCheckbox,
|
||||
GlFormGroup,
|
||||
GlFormInputGroup,
|
||||
GlFormInput,
|
||||
GlFormText,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
props: {
|
||||
deleteInactiveProjects: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
inactiveProjectsDeleteAfterMonths: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 2,
|
||||
},
|
||||
inactiveProjectsMinSizeMb: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
inactiveProjectsSendWarningEmailAfterMonths: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 1,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
enabled: this.deleteInactiveProjects,
|
||||
deleteAfterMonths: this.inactiveProjectsDeleteAfterMonths,
|
||||
minSizeMb: this.inactiveProjectsMinSizeMb,
|
||||
sendWarningEmailAfterMonths: this.inactiveProjectsSendWarningEmailAfterMonths,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isMinSizeMbValid() {
|
||||
return parseInt(this.minSizeMb, 10) >= 0;
|
||||
},
|
||||
isDeleteAfterMonthsValid() {
|
||||
return (
|
||||
parseInt(this.deleteAfterMonths, 10) > 0 &&
|
||||
parseInt(this.deleteAfterMonths, 10) > parseInt(this.sendWarningEmailAfterMonths, 10)
|
||||
);
|
||||
},
|
||||
isSendWarningEmailAfterMonthsValid() {
|
||||
return parseInt(this.sendWarningEmailAfterMonths, 10) > 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
checkValidity(ref, feedback, valid) {
|
||||
// These form fields are used within a HAML created form and we don't have direct access to the submit button
|
||||
// So we set the validity of the field so the HAML form can't be submitted until this is set back to blank
|
||||
if (valid) {
|
||||
ref.$el.setCustomValidity('');
|
||||
} else {
|
||||
ref.$el.setCustomValidity(feedback);
|
||||
}
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
checkboxLabel: s__('AdminSettings|Delete inactive projects'),
|
||||
checkboxHelp: s__(
|
||||
'AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}',
|
||||
),
|
||||
checkboxHelpDocLink: helpPagePath('administration/inactive_project_deletion'),
|
||||
minSizeMbLabel: s__('AdminSettings|When to delete inactive projects'),
|
||||
minSizeMbDescription: s__('AdminSettings|Delete inactive projects that exceed'),
|
||||
minSizeMbInvalidFeedback: s__('AdminSettings|Minimum size must be at least 0.'),
|
||||
deleteAfterMonthsLabel: s__('AdminSettings|Delete project after'),
|
||||
deleteAfterMonthsInvalidFeedback: s__(
|
||||
"AdminSettings|You can't delete projects before the warning email is sent.",
|
||||
),
|
||||
sendWarningEmailAfterMonthsLabel: s__('AdminSettings|Send warning email'),
|
||||
sendWarningEmailAfterMonthsDescription: s__(
|
||||
'AdminSettings|Send email to maintainers after project is inactive for',
|
||||
),
|
||||
sendWarningEmailAfterMonthsHelp: s__(
|
||||
'AdminSettings|Requires %{linkStart}email notifications%{linkEnd}',
|
||||
),
|
||||
sendWarningEmailAfterMonthsDocLink: helpPagePath('user/profile/notifications'),
|
||||
sendWarningEmailAfterMonthsInvalidFeedback: s__(
|
||||
'AdminSettings|Setting must be greater than 0.',
|
||||
),
|
||||
mbAppend: __('MB'),
|
||||
monthsAppend: __('months'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<gl-form-group>
|
||||
<input name="application_setting[delete_inactive_projects]" type="hidden" :value="enabled" />
|
||||
<gl-form-checkbox v-model="enabled">
|
||||
{{ $options.i18n.checkboxLabel }}
|
||||
|
||||
<template #help>
|
||||
<gl-sprintf :message="$options.i18n.checkboxHelp">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="$options.i18n.checkboxHelpDocLink" target="_blank">
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
</gl-form-checkbox>
|
||||
</gl-form-group>
|
||||
|
||||
<div v-if="enabled" class="gl-ml-6" data-testid="inactive-project-deletion-settings">
|
||||
<gl-form-group
|
||||
:label="$options.i18n.minSizeMbLabel"
|
||||
:state="isMinSizeMbValid"
|
||||
data-testid="min-size-group"
|
||||
>
|
||||
<template #invalid-feedback>
|
||||
<div class="gl-w-40p">{{ $options.i18n.minSizeMbInvalidFeedback }}</div>
|
||||
</template>
|
||||
<gl-form-text class="gl-mt-0 gl-mb-3 gl-text-body!">
|
||||
{{ $options.i18n.minSizeMbDescription }}
|
||||
</gl-form-text>
|
||||
<gl-form-input-group data-testid="min-size-input-group">
|
||||
<gl-form-input
|
||||
ref="minSizeMbInput"
|
||||
v-model="minSizeMb"
|
||||
:state="isMinSizeMbValid"
|
||||
name="application_setting[inactive_projects_min_size_mb]"
|
||||
size="md"
|
||||
type="number"
|
||||
:min="0"
|
||||
data-testid="min-size-input"
|
||||
@change="
|
||||
checkValidity(
|
||||
$refs.minSizeMbInput,
|
||||
$options.i18n.minSizeMbInvalidFeedback,
|
||||
isMinSizeMbValid,
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
||||
<template #append>
|
||||
<div class="input-group-text">{{ $options.i18n.mbAppend }}</div>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
</gl-form-group>
|
||||
|
||||
<div class="gl-pl-6 gl-border-l">
|
||||
<gl-form-group
|
||||
:label="$options.i18n.deleteAfterMonthsLabel"
|
||||
:state="isDeleteAfterMonthsValid"
|
||||
data-testid="delete-after-months-group"
|
||||
>
|
||||
<template #invalid-feedback>
|
||||
<div class="gl-w-30p">{{ $options.i18n.deleteAfterMonthsInvalidFeedback }}</div>
|
||||
</template>
|
||||
<gl-form-input-group data-testid="delete-after-months-input-group">
|
||||
<gl-form-input
|
||||
ref="deleteAfterMonthsInput"
|
||||
v-model="deleteAfterMonths"
|
||||
:state="isDeleteAfterMonthsValid"
|
||||
name="application_setting[inactive_projects_delete_after_months]"
|
||||
size="sm"
|
||||
type="number"
|
||||
:min="0"
|
||||
data-testid="delete-after-months-input"
|
||||
@change="
|
||||
checkValidity(
|
||||
$refs.deleteAfterMonthsInput,
|
||||
$options.i18n.deleteAfterMonthsInvalidFeedback,
|
||||
isDeleteAfterMonthsValid,
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
||||
<template #append>
|
||||
<div class="input-group-text">{{ $options.i18n.monthsAppend }}</div>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group
|
||||
:label="$options.i18n.sendWarningEmailAfterMonthsLabel"
|
||||
:state="isSendWarningEmailAfterMonthsValid"
|
||||
data-testid="send-warning-email-after-months-group"
|
||||
>
|
||||
<template #invalid-feedback>
|
||||
<div class="gl-w-30p">
|
||||
{{ $options.i18n.sendWarningEmailAfterMonthsInvalidFeedback }}
|
||||
</div>
|
||||
</template>
|
||||
<gl-form-text class="gl-max-w-26 gl-mt-0 gl-mb-3 gl-text-body!">
|
||||
{{ $options.i18n.sendWarningEmailAfterMonthsDescription }}
|
||||
</gl-form-text>
|
||||
<gl-form-input-group data-testid="send-warning-email-after-months-input-group">
|
||||
<gl-form-input
|
||||
ref="sendWarningEmailAfterMonthsInput"
|
||||
v-model="sendWarningEmailAfterMonths"
|
||||
:state="isSendWarningEmailAfterMonthsValid"
|
||||
name="application_setting[inactive_projects_send_warning_email_after_months]"
|
||||
size="sm"
|
||||
type="number"
|
||||
:min="0"
|
||||
data-testid="send-warning-email-after-months-input"
|
||||
@change="
|
||||
checkValidity(
|
||||
$refs.sendWarningEmailAfterMonthsInput,
|
||||
$options.i18n.sendWarningEmailAfterMonthsInvalidFeedback,
|
||||
isSendWarningEmailAfterMonthsValid,
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
||||
<template #append>
|
||||
<div class="input-group-text">{{ $options.i18n.monthsAppend }}</div>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
|
||||
<template #description>
|
||||
<gl-sprintf :message="$options.i18n.sendWarningEmailAfterMonthsHelp">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="$options.i18n.sendWarningEmailAfterMonthsDocLink" target="_blank">
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
</gl-form-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import Vue from 'vue';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import Form from './components/form.vue';
|
||||
|
||||
export default () => {
|
||||
const el = document.querySelector('.js-inactive-project-deletion-form');
|
||||
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
deleteInactiveProjects,
|
||||
inactiveProjectsDeleteAfterMonths,
|
||||
inactiveProjectsMinSizeMb,
|
||||
inactiveProjectsSendWarningEmailAfterMonths,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'InactiveProjectDeletion',
|
||||
render(createElement) {
|
||||
return createElement(Form, {
|
||||
props: {
|
||||
deleteInactiveProjects: parseBoolean(deleteInactiveProjects),
|
||||
inactiveProjectsDeleteAfterMonths: parseInt(inactiveProjectsDeleteAfterMonths, 10),
|
||||
inactiveProjectsMinSizeMb: parseInt(inactiveProjectsMinSizeMb, 10),
|
||||
inactiveProjectsSendWarningEmailAfterMonths: parseInt(
|
||||
inactiveProjectsSendWarningEmailAfterMonths,
|
||||
10,
|
||||
),
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -56,6 +56,9 @@ export default {
|
|||
calculatedTimeTilNextRun() {
|
||||
return timeTilRun(this.expirationPolicy?.next_run);
|
||||
},
|
||||
expireIconName() {
|
||||
return this.failedDelete ? 'expire' : 'clock';
|
||||
},
|
||||
},
|
||||
statusPopoverOptions: {
|
||||
triggers: 'hover',
|
||||
|
|
@ -75,7 +78,7 @@ export default {
|
|||
class="gl-display-inline-flex gl-align-items-center"
|
||||
>
|
||||
<div class="gl-display-inline-flex gl-align-items-center">
|
||||
<gl-icon name="expire" data-testid="main-icon" />
|
||||
<gl-icon :name="expireIconName" data-testid="main-icon" />
|
||||
</div>
|
||||
<span class="gl-mx-2">
|
||||
{{ statusText }}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export default {
|
|||
<metadata-item
|
||||
v-if="!hideExpirationPolicyData"
|
||||
data-testid="expiration-policy"
|
||||
icon="expire"
|
||||
icon="clock"
|
||||
:text="expirationPolicyText"
|
||||
size="xl"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
import initInactiveProjectDeletion from '~/admin/application_settings/inactive_project_deletion';
|
||||
|
||||
initInactiveProjectDeletion();
|
||||
|
|
@ -20,7 +20,7 @@ $system-note-svg-size: 16px;
|
|||
}
|
||||
|
||||
.note-wrapper {
|
||||
padding: $gl-padding;
|
||||
padding: $gl-padding $gl-padding-8 $gl-padding $gl-padding;
|
||||
|
||||
&.outlined {
|
||||
@include outline-comment();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
class Projects::UsageQuotasController < Projects::ApplicationController
|
||||
before_action :authorize_read_usage_quotas!
|
||||
|
||||
before_action do
|
||||
push_frontend_feature_flag(:container_registry_project_statistics, project)
|
||||
end
|
||||
|
||||
layout "project_settings"
|
||||
|
||||
feature_category :utilization
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
module ApplicationSettings
|
||||
module SettingsHelper
|
||||
def inactive_projects_deletion_data(settings)
|
||||
{
|
||||
delete_inactive_projects: settings.delete_inactive_projects.to_s,
|
||||
inactive_projects_delete_after_months: settings.inactive_projects_delete_after_months,
|
||||
inactive_projects_min_size_mb: settings.inactive_projects_min_size_mb,
|
||||
inactive_projects_send_warning_email_after_months: settings.inactive_projects_send_warning_email_after_months
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -513,6 +513,10 @@ class Commit
|
|||
# We don't want to do anything for `Commit` model, so this is empty.
|
||||
end
|
||||
|
||||
# We are continuing to support `(fixup!|squash!)` here as it is the prefix
|
||||
# added by `git commit --fixup` which is used by some community members.
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/342937#note_892065311
|
||||
#
|
||||
DRAFT_REGEX = /\A\s*#{Gitlab::Regex.merge_request_draft}|(fixup!|squash!)\s/.freeze
|
||||
|
||||
def work_in_progress?
|
||||
|
|
|
|||
|
|
@ -39,4 +39,8 @@
|
|||
.form-text.text-muted
|
||||
= html_escape(s_('Number of Git pushes after which %{code_start}git gc%{code_end} is run.')) % { code_start: '<code>'.html_safe, code_end: '</code>'.html_safe }
|
||||
|
||||
.sub-section
|
||||
%h4= s_("AdminSettings|Inactive project deletion")
|
||||
.js-inactive-project-deletion-form{ data: inactive_projects_deletion_data(@application_setting) }
|
||||
|
||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
- bind_out_tag = content_tag(:span, nil, { data: { bind_out: :create_chat_team } })
|
||||
- checkbox_help_text = "%s %s/%s".html_safe % [_('Mattermost URL:'), Settings.mattermost.host, bind_out_tag]
|
||||
|
||||
.form-group
|
||||
.col-sm-2.col-form-label
|
||||
= f.label :create_chat_team do
|
||||
|
|
@ -5,13 +8,5 @@
|
|||
= custom_icon('icon_mattermost')
|
||||
%span.gl-ml-2= _('Mattermost')
|
||||
.col-sm-12
|
||||
.form-check.js-toggle-container
|
||||
.js-toggle-button.form-check-input= f.check_box(:create_chat_team, { checked: false }, true, false)
|
||||
= f.label :create_chat_team, class: 'form-check-label' do
|
||||
= _('Create a Mattermost team for this group')
|
||||
%br
|
||||
%small.light.js-toggle-content
|
||||
= _('Mattermost URL:')
|
||||
= Settings.mattermost.host
|
||||
%span> /
|
||||
%span{ "data-bind-out" => "create_chat_team" }
|
||||
= f.gitlab_ui_checkbox_component :create_chat_team, _('Create a Mattermost team for this group'), help_text: checkbox_help_text, checkbox_options: { checked: false }, checked_value: true, unchecked_value: false
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
.row{ 'v-cloak': true }
|
||||
#create-group-pane.tab-pane
|
||||
= form_for @group, html: { class: 'group-form gl-show-field-errors gl-mt-3' } do |f|
|
||||
= gitlab_ui_form_for @group, html: { class: 'group-form gl-show-field-errors gl-mt-3' } do |f|
|
||||
= render 'new_group_fields', f: f, group_name_id: 'create-group-name'
|
||||
|
||||
#import-group-pane.tab-pane
|
||||
|
|
|
|||
|
|
@ -21,4 +21,4 @@
|
|||
|
||||
- if can_edit_project_settings && !service_desk_enabled
|
||||
.gl-mt-3
|
||||
= link_to s_("ServiceDesk|Enable Service Desk"), edit_project_path(@project), class: 'gl-button btn btn-success'
|
||||
= link_to s_("ServiceDesk|Enable Service Desk"), edit_project_path(@project), class: 'gl-button btn btn-confirm'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: delayed_repository_update_mirror_worker
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87995
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/362894
|
||||
milestone: '15.1'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
|
|
@ -3,7 +3,7 @@ data_category: operational
|
|||
key_path: counts_monthly.aggregated_metrics.code_review_category_monthly_active_users
|
||||
description: Unique users performing actions on code review events
|
||||
product_section: dev
|
||||
product_stage: devops::create
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts_monthly.aggregated_metrics.code_review_extension_category_monthly_active_users
|
||||
description: Number of users performing i_code_review_user_vs_code_api_request event
|
||||
product_section: dev
|
||||
product_stage: devops::create
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts_monthly.aggregated_metrics.code_review_group_monthly_active_users
|
||||
description: Number of users performing at least one of the code review events
|
||||
product_section: dev
|
||||
product_stage: devops::create
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
key_path: redis_hll_counters.importer.github_import_project_start_monthly
|
||||
description: The number of github projects that were enqueued to start monthy
|
||||
product_section: dev
|
||||
product_stage: devops
|
||||
product_stage: manage
|
||||
product_group: group::import
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
key_path: redis_hll_counters.importer.github_import_project_success_monthly
|
||||
description: The number of github projects that were successful monthly
|
||||
product_section: dev
|
||||
product_stage: devops
|
||||
product_stage: manage
|
||||
product_group: group::import
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
key_path: redis_hll_counters.importer.github_import_project_failure_monthly
|
||||
description: The number of github projects that failed monthly
|
||||
product_section: dev
|
||||
product_stage: devops
|
||||
product_stage: manage
|
||||
product_group: group::import
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts_weekly.aggregated_metrics.code_review_group_monthly_active_users
|
||||
description: Number of users performing at least one of the code review events
|
||||
product_section: dev
|
||||
product_stage: devops::create
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts_weekly.aggregated_metrics.code_review_category_monthly_active_users
|
||||
description: Unique users performing actions on code review events
|
||||
product_section: dev
|
||||
product_stage: devops::create
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ data_category: optional
|
|||
key_path: counts_weekly.aggregated_metrics.code_review_extension_category_monthly_active_users
|
||||
description: Number of users performing code review extension_category events
|
||||
product_section: dev
|
||||
product_stage: devops::create
|
||||
product_stage: create
|
||||
product_group: group::code review
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
key_path: redis_hll_counters.importer.github_import_project_start_weekly
|
||||
description: The number of github projects that were enqueued to start weekly
|
||||
product_section: dev
|
||||
product_stage: devops
|
||||
product_stage: manage
|
||||
product_group: group::import
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
key_path: redis_hll_counters.importer.github_import_project_success_weekly
|
||||
description: The number of github projects that were successful weekly
|
||||
product_section: dev
|
||||
product_stage: devops
|
||||
product_stage: manage
|
||||
product_group: group::import
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
key_path: redis_hll_counters.importer.github_import_project_failure_weekly
|
||||
description: The number of github projects that failed weekly
|
||||
product_section: dev
|
||||
product_stage: devops
|
||||
product_stage: manage
|
||||
product_group: group::import
|
||||
product_category:
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
- name: "`fixup!` commit messages setting draft status of associated Merge Request" # The name of the feature to be deprecated
|
||||
announcement_milestone: "14.8" # The milestone when this feature was first announced as deprecated.
|
||||
announcement_date: "2022-02-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
|
||||
removal_milestone: "15.0" # The milestone when this feature is planned to be removed
|
||||
removal_date: "2022-06-22" # This should almost always be the 22nd of a month (YYYY-MM-22), the date of the milestone release when this feature is planned to be removed.
|
||||
body: | # Do not modify this line, instead modify the lines below.
|
||||
The use of `fixup!` as a commit message to trigger draft status
|
||||
of the associated Merge Request is generally unused, and can cause
|
||||
confusion with other uses of the term. "Draft" is the preferred
|
||||
and supported trigger for triggering draft status from commit
|
||||
messages, as part of our streamlining of the feature.
|
||||
Support for `fixup!` is now considered deprecated, and will be
|
||||
removed in GitLab 15.0.
|
||||
documentation_url: "https://docs.gitlab.com/ee/user/project/merge_requests/drafts.html#mark-merge-requests-as-drafts"
|
||||
issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/342937"
|
||||
|
|
@ -20,21 +20,24 @@ deleted, the action generates an audit event that it was performed by the first
|
|||
|
||||
## Configure inactive project deletion
|
||||
|
||||
You can configure inactive projects deletion or turn it off using the
|
||||
[Application settings API](../api/settings.md#change-application-settings).
|
||||
You can configure inactive projects deletion or turn it off using either:
|
||||
|
||||
- [The GitLab API](#using-the-api) (GitLab 15.0 and later).
|
||||
- [The GitLab UI](#using-the-gitlab-ui) (GitLab 15.1 and later).
|
||||
|
||||
The following options are available:
|
||||
|
||||
- `delete_inactive_projects`: Enable or disable inactive project deletion.
|
||||
- `inactive_projects_min_size_mb`: Minimum size (MB) of inactive projects to be considered for deletion.
|
||||
Projects smaller in size than this threshold aren't considered inactive.
|
||||
- `inactive_projects_delete_after_months`: Minimum duration (months) after which a project is scheduled for deletion if
|
||||
it continues be inactive.
|
||||
- `inactive_projects_send_warning_email_after_months`: Minimum duration (months) after which a deletion warning email is
|
||||
sent if a project continues to be inactive. The warning email is sent to users with the Owner and Maintainer roles of
|
||||
the inactive project. This duration should be less than the `inactive_projects_delete_after_months` duration.
|
||||
- **Delete inactive projects** (`delete_inactive_projects`): Enable or disable inactive project deletion.
|
||||
- **Delete inactive projects that exceed** (`inactive_projects_min_size_mb`): Minimum size (MB) of inactive projects to
|
||||
be considered for deletion. Projects smaller in size than this threshold aren't considered inactive.
|
||||
- **Delete project after** (`inactive_projects_delete_after_months`): Minimum duration (months) after which a project is
|
||||
scheduled for deletion if it continues be inactive.
|
||||
- **Send warning email** (`inactive_projects_send_warning_email_after_months`): Minimum duration (months) after which a
|
||||
deletion warning email is sent if a project continues to be inactive. The warning email is sent to users with the
|
||||
Owner and Maintainer roles of the inactive project. This duration must be less than the
|
||||
**Delete project after** (`inactive_projects_delete_after_months`) duration.
|
||||
|
||||
For example:
|
||||
For example (using the API):
|
||||
|
||||
- `delete_inactive_projects` enabled.
|
||||
- `inactive_projects_min_size_mb` set to `50`.
|
||||
|
|
@ -49,6 +52,22 @@ In this scenario, when a project's size is:
|
|||
with the scheduled date of deletion.
|
||||
- More than 12 months, the project is scheduled for deletion.
|
||||
|
||||
### Using the API
|
||||
|
||||
You can use the [Application settings API](../api/settings.md#change-application-settings) to configure inactive projects.
|
||||
|
||||
### Using the GitLab UI
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85575) in GitLab 15.1.
|
||||
|
||||
To configure inactive projects with the GitLab UI:
|
||||
|
||||
1. On the top bar, select **Menu > Admin**.
|
||||
1. On the left sidebar, select **Settings > Repository**.
|
||||
1. Expand **Repository maintenance**.
|
||||
1. In the **Inactive project deletion** section, configure the necessary options.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Determine when a project was last active
|
||||
|
||||
You can view a project's activities and determine when the project was last active in the following ways:
|
||||
|
|
|
|||
|
|
@ -104,3 +104,13 @@ After that restart GitLab with:
|
|||
```shell
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
### Search Sidekiq logs in Kibana
|
||||
|
||||
To locate a specific integration in Kibana, use the following KQL search string:
|
||||
|
||||
```plaintext
|
||||
`json.integration_class.keyword : "Integrations::Jira" and json.project_path : "path/to/project"`
|
||||
```
|
||||
|
||||
You can find information in `json.exception.backtrace`, `json.exception.class`, `json.exception.message`, and `json.message`.
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ set up for the integration has permission to:
|
|||
|
||||
Jira issue references and update comments do not work if the GitLab issue tracker is disabled.
|
||||
|
||||
If you [restrict IP addresses for Jira access](https://support.atlassian.com/security-and-access-policies/docs/specify-ip-addresses-for-product-access/), make sure you add your self-managed IP addresses or [GitLab.com IP range](../../user/gitlab_com/index.md#ip-range) to the allowlist in Jira.
|
||||
|
||||
### GitLab cannot close a Jira issue
|
||||
|
||||
If GitLab cannot close a Jira issue:
|
||||
|
|
|
|||
|
|
@ -1094,21 +1094,6 @@ The predefined CI/CD variables that start with `CI_BUILD_*` were deprecated in G
|
|||
**Planned removal milestone: <span class="removal-milestone">16.0</span> (2023-04-22)**
|
||||
</div>
|
||||
|
||||
<div class="deprecation removal-150">
|
||||
|
||||
### `fixup!` commit messages setting draft status of associated Merge Request
|
||||
|
||||
The use of `fixup!` as a commit message to trigger draft status
|
||||
of the associated Merge Request is generally unused, and can cause
|
||||
confusion with other uses of the term. "Draft" is the preferred
|
||||
and supported trigger for triggering draft status from commit
|
||||
messages, as part of our streamlining of the feature.
|
||||
Support for `fixup!` is now considered deprecated, and will be
|
||||
removed in GitLab 15.0.
|
||||
|
||||
**Planned removal milestone: <span class="removal-milestone">15.0</span> (2022-06-22)**
|
||||
</div>
|
||||
|
||||
<div class="deprecation removal-150 breaking-change">
|
||||
|
||||
### `projectFingerprint` in `PipelineSecurityReportFinding` GraphQL
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ You might also be interested in templates for various
|
|||
|
||||
### Set a default template for merge requests and issues
|
||||
|
||||
> `Default.md` template [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302) in GitLab 14.8.
|
||||
> `Default.md` (case insensitive) template [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302) in GitLab 14.8.
|
||||
|
||||
In a project, you can choose a default description template for new issues and merge requests.
|
||||
As a result, every time a new merge request or issue is created, it's pre-filled with the text you
|
||||
|
|
@ -129,9 +129,9 @@ Prerequisites:
|
|||
|
||||
To set a default description template for merge requests, either:
|
||||
|
||||
- [Create a merge request template](#create-a-merge-request-template) named `Default.md` or `default.md`
|
||||
- [In GitLab 14.8 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302), [create a merge request template](#create-a-merge-request-template) named `Default.md` (case insensitive)
|
||||
and save it in `.gitlab/merge_request_templates/`.
|
||||
This doesn't overwrite the default template if one has been set in the project settings.
|
||||
This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
|
||||
- Users on GitLab Premium and higher: set the default template in project settings:
|
||||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
|
|
@ -142,9 +142,9 @@ To set a default description template for merge requests, either:
|
|||
|
||||
To set a default description template for issues, either:
|
||||
|
||||
- [Create an issue template](#create-an-issue-template) named `Default.md` or `default.md`
|
||||
- [In GitLab 14.8 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302), [create an issue template](#create-an-issue-template) named `Default.md` (case insensitive) [in GitLab 14.8 or higher]
|
||||
and save it in `.gitlab/issue_templates/`.
|
||||
This doesn't overwrite the default template if one has been set in the project settings.
|
||||
This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
|
||||
- Users on GitLab Premium and higher: set the default template in project settings:
|
||||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
|
|
@ -159,15 +159,15 @@ headings, lists, and so on.
|
|||
You can also provide `issues_template` and `merge_requests_template` attributes in the
|
||||
[Projects REST API](../../api/projects.md) to keep your default issue and merge request templates up to date.
|
||||
|
||||
#### Priority of description templates
|
||||
#### Priority of default description templates
|
||||
|
||||
When you set [merge request and issue description templates](#set-a-default-template-for-merge-requests-and-issues)
|
||||
in various places, they have the following priorities in a project.
|
||||
The ones higher up override the ones below:
|
||||
|
||||
1. Template selected in project settings.
|
||||
1. `Default.md` from the parent group.
|
||||
1. `Default.md` from the project repository.
|
||||
1. Template set in project settings.
|
||||
1. `Default.md` (case insensitive) from the parent group.
|
||||
1. `Default.md` (case insensitive) from the project repository.
|
||||
|
||||
## Example description template
|
||||
|
||||
|
|
|
|||
|
|
@ -10,17 +10,10 @@ module BulkImports
|
|||
|
||||
relation_name BulkImports::FileTransfer::BaseConfig::SELF_RELATION
|
||||
|
||||
extractor ::BulkImports::Common::Extractors::JsonExtractor, relation: relation
|
||||
|
||||
transformer ::BulkImports::Common::Transformers::ProhibitedAttributesTransformer
|
||||
|
||||
def extract(_context)
|
||||
download_service.execute
|
||||
decompression_service.execute
|
||||
|
||||
project_attributes = json_decode(json_attributes)
|
||||
|
||||
BulkImports::Pipeline::ExtractedData.new(data: project_attributes)
|
||||
end
|
||||
|
||||
def transform(_context, data)
|
||||
subrelations = config.portable_relations_tree.keys.map(&:to_s)
|
||||
|
||||
|
|
@ -39,51 +32,14 @@ module BulkImports
|
|||
end
|
||||
|
||||
def after_run(_context)
|
||||
FileUtils.remove_entry(tmpdir) if Dir.exist?(tmpdir)
|
||||
end
|
||||
|
||||
def json_attributes
|
||||
@json_attributes ||= File.read(File.join(tmpdir, filename))
|
||||
extractor.remove_tmpdir
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tmpdir
|
||||
@tmpdir ||= Dir.mktmpdir('bulk_imports')
|
||||
end
|
||||
|
||||
def config
|
||||
@config ||= BulkImports::FileTransfer.config_for(portable)
|
||||
end
|
||||
|
||||
def download_service
|
||||
@download_service ||= BulkImports::FileDownloadService.new(
|
||||
configuration: context.configuration,
|
||||
relative_url: context.entity.relation_download_url_path(self.class.relation),
|
||||
tmpdir: tmpdir,
|
||||
filename: compressed_filename
|
||||
)
|
||||
end
|
||||
|
||||
def decompression_service
|
||||
@decompression_service ||= BulkImports::FileDecompressionService.new(tmpdir: tmpdir, filename: compressed_filename)
|
||||
end
|
||||
|
||||
def compressed_filename
|
||||
"#{filename}.gz"
|
||||
end
|
||||
|
||||
def filename
|
||||
"#{self.class.relation}.json"
|
||||
end
|
||||
|
||||
def json_decode(string)
|
||||
Gitlab::Json.parse(string)
|
||||
rescue JSON::ParserError => e
|
||||
Gitlab::ErrorTracking.log_exception(e)
|
||||
|
||||
raise BulkImports::Error, 'Incorrect JSON format'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2640,6 +2640,18 @@ msgstr ""
|
|||
msgid "AdminSettings|Configure Let's Encrypt"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Delete inactive projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Delete inactive projects that exceed"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Delete project after"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Disable Elasticsearch until indexing completes."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -2706,6 +2718,9 @@ msgstr ""
|
|||
msgid "AdminSettings|Import sources"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Inactive project deletion"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -2742,6 +2757,9 @@ msgstr ""
|
|||
msgid "AdminSettings|Maximum number of runners registered per project"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Minimum size must be at least 0."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|New CI/CD variables in projects and groups default to protected."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -2772,6 +2790,9 @@ msgstr ""
|
|||
msgid "AdminSettings|Required pipeline configuration"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Requires %{linkStart}email notifications%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Restrict group access by IP address. %{link_start}Learn more%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -2790,6 +2811,12 @@ msgstr ""
|
|||
msgid "AdminSettings|Select to disable public access for Pages sites, which requires users to sign in for access to the Pages sites in your instance. %{link_start}Learn more.%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Send email to maintainers after project is inactive for"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Send warning email"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Service ping is disabled in your configuration file, and cannot be enabled through this form. For more information, see the documentation on %{link_start}deactivating service ping%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -2808,6 +2835,9 @@ msgstr ""
|
|||
msgid "AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Setting must be greater than 0."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Size and domain settings for Pages static sites."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -2841,9 +2871,15 @@ msgstr ""
|
|||
msgid "AdminSettings|When paused, GitLab still tracks the changes. This is useful for cluster/index migrations."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|When to delete inactive projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|You can enable Registration Features because Service Ping is enabled. To continue using Registration Features in the future, you will also need to register with GitLab via a new cloud licensing service."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|You can't delete projects before the warning email is sent."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminStatistics|Active Users"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -6028,6 +6064,9 @@ msgstr ""
|
|||
msgid "Billings|Shared runners cannot be enabled until a valid credit card is on file."
|
||||
msgstr ""
|
||||
|
||||
msgid "Billings|The last owner cannot be removed from a seat."
|
||||
msgstr ""
|
||||
|
||||
msgid "Billings|To make this member active, you must first remove an existing active member, or toggle them to over limit."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -6049,6 +6088,9 @@ msgstr ""
|
|||
msgid "Billings|You can't change the seat status of a user who was invited via a group or project."
|
||||
msgstr ""
|
||||
|
||||
msgid "Billings|You can't remove yourself from a seat, but you can leave the group."
|
||||
msgstr ""
|
||||
|
||||
msgid "Billings|You'll now be able to take advantage of free CI/CD minutes on shared runners."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -40764,6 +40806,9 @@ msgstr ""
|
|||
msgid "UsageQuota|Code packages and container images."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Container Registry"
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Current period usage"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -40779,6 +40824,9 @@ msgstr ""
|
|||
msgid "UsageQuota|Git repository."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker Images."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Includes artifacts, repositories, wiki, uploads, and other items."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -45154,6 +45202,9 @@ msgstr ""
|
|||
msgid "missing"
|
||||
msgstr ""
|
||||
|
||||
msgid "months"
|
||||
msgstr ""
|
||||
|
||||
msgid "most recent deployment"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
FROM registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-ruby-2.7:bundler-2.3-git-2.33-lfs-2.9-chrome-99-docker-20.10.14-gcloud-383-kubectl-1.23
|
||||
LABEL maintainer="GitLab Quality Department <quality@gitlab.com>"
|
||||
|
||||
ENV DEBIAN_FRONTEND="noninteractive" \
|
||||
BUNDLE_WITHOUT=development
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
# Override config path to make sure local config doesn't override it when building image locally
|
||||
ENV BUNDLE_APP_CONFIG=/home/gitlab/.bundle
|
||||
|
||||
##
|
||||
# Install system libs
|
||||
|
|
@ -27,7 +28,8 @@ WORKDIR /home/gitlab/qa
|
|||
# Install qa dependencies or fetch from cache if unchanged
|
||||
#
|
||||
COPY ./qa/Gemfile* /home/gitlab/qa/
|
||||
RUN bundle install --jobs=$(nproc) --retry=3
|
||||
RUN bundle config set --local without development \
|
||||
&& bundle install --retry=3
|
||||
|
||||
##
|
||||
# Fetch chromedriver based on version of chrome
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ RSpec.describe 'Group' do
|
|||
|
||||
describe 'Mattermost team creation' do
|
||||
before do
|
||||
stub_mattermost_setting(enabled: mattermost_enabled)
|
||||
stub_mattermost_setting(enabled: mattermost_enabled, host: 'https://mattermost.test')
|
||||
|
||||
visit new_group_path
|
||||
click_link 'Create group'
|
||||
|
|
@ -145,13 +145,14 @@ RSpec.describe 'Group' do
|
|||
end
|
||||
|
||||
it 'updates the team URL on graph path update', :js do
|
||||
out_span = find('span[data-bind-out="create_chat_team"]', visible: false)
|
||||
label = find('#group_create_chat_team ~ label[for=group_create_chat_team]')
|
||||
url = 'https://mattermost.test/test-group'
|
||||
|
||||
expect(out_span.text).to be_empty
|
||||
expect(label.text).not_to match(url)
|
||||
|
||||
fill_in('group_path', with: 'test-group')
|
||||
|
||||
expect(out_span.text).to eq('test-group')
|
||||
expect(label.text).to match(url)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,148 @@
|
|||
import { GlFormCheckbox } from '@gitlab/ui';
|
||||
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import SettingsForm from '~/admin/application_settings/inactive_project_deletion/components/form.vue';
|
||||
|
||||
describe('Form component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findEnabledCheckbox = () => wrapper.findComponent(GlFormCheckbox);
|
||||
const findProjectDeletionSettings = () =>
|
||||
wrapper.findByTestId('inactive-project-deletion-settings');
|
||||
const findMinSizeGroup = () => wrapper.findByTestId('min-size-group');
|
||||
const findMinSizeInputGroup = () => wrapper.findByTestId('min-size-input-group');
|
||||
const findMinSizeInput = () => wrapper.findByTestId('min-size-input');
|
||||
const findDeleteAfterMonthsGroup = () => wrapper.findByTestId('delete-after-months-group');
|
||||
const findDeleteAfterMonthsInputGroup = () =>
|
||||
wrapper.findByTestId('delete-after-months-input-group');
|
||||
const findDeleteAfterMonthsInput = () => wrapper.findByTestId('delete-after-months-input');
|
||||
const findSendWarningEmailAfterMonthsGroup = () =>
|
||||
wrapper.findByTestId('send-warning-email-after-months-group');
|
||||
const findSendWarningEmailAfterMonthsInputGroup = () =>
|
||||
wrapper.findByTestId('send-warning-email-after-months-input-group');
|
||||
const findSendWarningEmailAfterMonthsInput = () =>
|
||||
wrapper.findByTestId('send-warning-email-after-months-input');
|
||||
|
||||
const createComponent = (
|
||||
mountFn = shallowMountExtended,
|
||||
propsData = { deleteInactiveProjects: true },
|
||||
) => {
|
||||
wrapper = mountFn(SettingsForm, { propsData });
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('Enable inactive project deletion', () => {
|
||||
it('has the checkbox', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findEnabledCheckbox().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it.each([[true], [false]])(
|
||||
'when the checkbox is %s then the project deletion settings visibility is set to %s',
|
||||
(visible) => {
|
||||
createComponent(shallowMountExtended, { deleteInactiveProjects: visible });
|
||||
|
||||
expect(findProjectDeletionSettings().exists()).toBe(visible);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('Minimum size for deletion', () => {
|
||||
beforeEach(() => {
|
||||
createComponent(mountExtended);
|
||||
});
|
||||
|
||||
it('has the minimum size input', () => {
|
||||
expect(findMinSizeInput().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the field description', () => {
|
||||
expect(findMinSizeGroup().text()).toContain('Delete inactive projects that exceed');
|
||||
});
|
||||
|
||||
it('has the appended text on the field', () => {
|
||||
expect(findMinSizeInputGroup().text()).toContain('MB');
|
||||
});
|
||||
|
||||
it.each`
|
||||
value | valid
|
||||
${'0'} | ${true}
|
||||
${'250'} | ${true}
|
||||
${'-1'} | ${false}
|
||||
`(
|
||||
'when the minimum size input has a value of $value, then its validity should be $valid',
|
||||
async ({ value, valid }) => {
|
||||
await findMinSizeInput().find('input').setValue(value);
|
||||
|
||||
expect(findMinSizeGroup().classes('is-valid')).toBe(valid);
|
||||
expect(findMinSizeInput().classes('is-valid')).toBe(valid);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('Delete project after', () => {
|
||||
beforeEach(() => {
|
||||
createComponent(mountExtended);
|
||||
});
|
||||
|
||||
it('has the delete after months input', () => {
|
||||
expect(findDeleteAfterMonthsInput().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the appended text on the field', () => {
|
||||
expect(findDeleteAfterMonthsInputGroup().text()).toContain('months');
|
||||
});
|
||||
|
||||
it.each`
|
||||
value | valid
|
||||
${'0'} | ${false}
|
||||
${'1'} | ${false /* Less than the default send warning email months */}
|
||||
${'2'} | ${true}
|
||||
`(
|
||||
'when the delete after months input has a value of $value, then its validity should be $valid',
|
||||
async ({ value, valid }) => {
|
||||
await findDeleteAfterMonthsInput().find('input').setValue(value);
|
||||
|
||||
expect(findDeleteAfterMonthsGroup().classes('is-valid')).toBe(valid);
|
||||
expect(findDeleteAfterMonthsInput().classes('is-valid')).toBe(valid);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('Send warning email', () => {
|
||||
beforeEach(() => {
|
||||
createComponent(mountExtended);
|
||||
});
|
||||
|
||||
it('has the send warning email after months input', () => {
|
||||
expect(findSendWarningEmailAfterMonthsInput().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the field description', () => {
|
||||
expect(findSendWarningEmailAfterMonthsGroup().text()).toContain(
|
||||
'Send email to maintainers after project is inactive for',
|
||||
);
|
||||
});
|
||||
|
||||
it('has the appended text on the field', () => {
|
||||
expect(findSendWarningEmailAfterMonthsInputGroup().text()).toContain('months');
|
||||
});
|
||||
|
||||
it.each`
|
||||
value | valid
|
||||
${'2'} | ${true}
|
||||
${'0'} | ${false}
|
||||
`(
|
||||
'when the minimum size input has a value of $value, then its validity should be $valid',
|
||||
async ({ value, valid }) => {
|
||||
await findSendWarningEmailAfterMonthsInput().find('input').setValue(value);
|
||||
|
||||
expect(findSendWarningEmailAfterMonthsGroup().classes('is-valid')).toBe(valid);
|
||||
expect(findSendWarningEmailAfterMonthsInput().classes('is-valid')).toBe(valid);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
|
||||
import { GlIcon, GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import CleanupStatus from '~/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue';
|
||||
|
|
@ -16,6 +16,7 @@ describe('cleanup_status', () => {
|
|||
let wrapper;
|
||||
|
||||
const findMainIcon = () => wrapper.findByTestId('main-icon');
|
||||
const findMainIconName = () => wrapper.findByTestId('main-icon').find(GlIcon);
|
||||
const findExtraInfoIcon = () => wrapper.findByTestId('extra-info');
|
||||
const findPopover = () => wrapper.findComponent(GlPopover);
|
||||
|
||||
|
|
@ -61,6 +62,23 @@ describe('cleanup_status', () => {
|
|||
|
||||
expect(findMainIcon().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it.each`
|
||||
status | visible | iconName
|
||||
${UNFINISHED_STATUS} | ${true} | ${'expire'}
|
||||
${SCHEDULED_STATUS} | ${true} | ${'clock'}
|
||||
${ONGOING_STATUS} | ${true} | ${'clock'}
|
||||
${UNSCHEDULED_STATUS} | ${false} | ${''}
|
||||
`('matches "$iconName" when the status is "$status"', ({ status, visible, iconName }) => {
|
||||
mountComponent({ status });
|
||||
|
||||
expect(findMainIcon().exists()).toBe(visible);
|
||||
if (visible) {
|
||||
const actualIcon = findMainIconName();
|
||||
expect(actualIcon.exists()).toBe(true);
|
||||
expect(actualIcon.props('name')).toBe(iconName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('extra info icon', () => {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ describe('registry_header', () => {
|
|||
expect(text.exists()).toBe(true);
|
||||
expect(text.props()).toMatchObject({
|
||||
text: EXPIRATION_POLICY_DISABLED_TEXT,
|
||||
icon: 'expire',
|
||||
icon: 'clock',
|
||||
size: 'xl',
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Admin::ApplicationSettings::SettingsHelper do
|
||||
describe '#inactive_projects_deletion_data' do
|
||||
let(:delete_inactive_projects) { true }
|
||||
let(:inactive_projects_delete_after_months) { 2 }
|
||||
let(:inactive_projects_min_size_mb) { 250 }
|
||||
let(:inactive_projects_send_warning_email_after_months) { 1 }
|
||||
|
||||
let_it_be(:application_settings) { build(:application_setting) }
|
||||
|
||||
before do
|
||||
stub_application_setting(delete_inactive_projects: delete_inactive_projects)
|
||||
stub_application_setting(inactive_projects_delete_after_months: inactive_projects_delete_after_months)
|
||||
stub_application_setting(inactive_projects_min_size_mb: inactive_projects_min_size_mb)
|
||||
stub_application_setting(
|
||||
inactive_projects_send_warning_email_after_months: inactive_projects_send_warning_email_after_months
|
||||
)
|
||||
end
|
||||
|
||||
subject(:result) { helper.inactive_projects_deletion_data(application_settings) }
|
||||
|
||||
it 'has the expected data' do
|
||||
expect(result).to eq({
|
||||
delete_inactive_projects: delete_inactive_projects.to_s,
|
||||
inactive_projects_delete_after_months: inactive_projects_delete_after_months,
|
||||
inactive_projects_min_size_mb: inactive_projects_min_size_mb,
|
||||
inactive_projects_send_warning_email_after_months: inactive_projects_send_warning_email_after_months
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -54,17 +54,13 @@ RSpec.describe BulkImports::Projects::Pipelines::ProjectAttributesPipeline do
|
|||
|
||||
subject(:pipeline) { described_class.new(context) }
|
||||
|
||||
before do
|
||||
allow(Dir).to receive(:mktmpdir).with('bulk_imports').and_return(tmpdir)
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.remove_entry(tmpdir) if Dir.exist?(tmpdir)
|
||||
end
|
||||
|
||||
describe '#run' do
|
||||
before do
|
||||
allow(pipeline).to receive(:extract).and_return(BulkImports::Pipeline::ExtractedData.new(data: project_attributes))
|
||||
allow_next_instance_of(BulkImports::Common::Extractors::JsonExtractor) do |extractor|
|
||||
allow(extractor).to receive(:extract).and_return(
|
||||
BulkImports::Pipeline::ExtractedData.new(data: project_attributes)
|
||||
)
|
||||
end
|
||||
|
||||
pipeline.run
|
||||
end
|
||||
|
|
@ -84,46 +80,6 @@ RSpec.describe BulkImports::Projects::Pipelines::ProjectAttributesPipeline do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#extract' do
|
||||
before do
|
||||
file_download_service = instance_double("BulkImports::FileDownloadService")
|
||||
file_decompression_service = instance_double("BulkImports::FileDecompressionService")
|
||||
|
||||
expect(BulkImports::FileDownloadService)
|
||||
.to receive(:new)
|
||||
.with(
|
||||
configuration: context.configuration,
|
||||
relative_url: "/#{entity.pluralized_name}/#{entity.source_full_path}/export_relations/download?relation=self",
|
||||
tmpdir: tmpdir,
|
||||
filename: 'self.json.gz')
|
||||
.and_return(file_download_service)
|
||||
|
||||
expect(BulkImports::FileDecompressionService)
|
||||
.to receive(:new)
|
||||
.with(tmpdir: tmpdir, filename: 'self.json.gz')
|
||||
.and_return(file_decompression_service)
|
||||
|
||||
expect(file_download_service).to receive(:execute)
|
||||
expect(file_decompression_service).to receive(:execute)
|
||||
end
|
||||
|
||||
it 'downloads, decompresses & decodes json' do
|
||||
allow(pipeline).to receive(:json_attributes).and_return("{\"test\":\"test\"}")
|
||||
|
||||
extracted_data = pipeline.extract(context)
|
||||
|
||||
expect(extracted_data.data).to match_array([{ 'test' => 'test' }])
|
||||
end
|
||||
|
||||
context 'when json parsing error occurs' do
|
||||
it 'raises an error' do
|
||||
allow(pipeline).to receive(:json_attributes).and_return("invalid")
|
||||
|
||||
expect { pipeline.extract(context) }.to raise_error(BulkImports::Error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#transform' do
|
||||
it 'removes prohibited attributes from hash' do
|
||||
input = { 'description' => 'description', 'issues' => [], 'milestones' => [], 'id' => 5 }
|
||||
|
|
@ -145,35 +101,13 @@ RSpec.describe BulkImports::Projects::Pipelines::ProjectAttributesPipeline do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#json_attributes' do
|
||||
it 'reads raw json from file' do
|
||||
filepath = File.join(tmpdir, 'self.json')
|
||||
|
||||
FileUtils.touch(filepath)
|
||||
expect_file_read(filepath)
|
||||
|
||||
pipeline.json_attributes
|
||||
end
|
||||
end
|
||||
|
||||
describe '#after_run' do
|
||||
it 'removes tmp dir' do
|
||||
allow(FileUtils).to receive(:remove_entry).and_call_original
|
||||
expect(FileUtils).to receive(:remove_entry).with(tmpdir).and_call_original
|
||||
it 'calls extractor#remove_tmpdir' do
|
||||
expect_next_instance_of(BulkImports::Common::Extractors::JsonExtractor) do |extractor|
|
||||
expect(extractor).to receive(:remove_tmpdir)
|
||||
end
|
||||
|
||||
pipeline.after_run(nil)
|
||||
|
||||
expect(Dir.exist?(tmpdir)).to eq(false)
|
||||
end
|
||||
|
||||
context 'when dir does not exist' do
|
||||
it 'does not attempt to remove tmpdir' do
|
||||
FileUtils.remove_entry(tmpdir)
|
||||
|
||||
expect(FileUtils).not_to receive(:remove_entry).with(tmpdir)
|
||||
|
||||
pipeline.after_run(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -35,5 +35,26 @@ RSpec.describe 'Project Usage Quotas' do
|
|||
|
||||
it_behaves_like 'response with 404 status'
|
||||
end
|
||||
|
||||
context 'container_registry_project_statistics feature flag' do
|
||||
subject(:body) { response.body }
|
||||
|
||||
before do
|
||||
stub_feature_flags(container_registry_project_statistics: container_registry_project_statistics_enabled)
|
||||
get project_usage_quotas_path(project)
|
||||
end
|
||||
|
||||
context 'when disabled' do
|
||||
let(:container_registry_project_statistics_enabled) { false }
|
||||
|
||||
it { is_expected.to have_pushed_frontend_feature_flags(containerRegistryProjectStatistics: false)}
|
||||
end
|
||||
|
||||
context 'when enabled' do
|
||||
let(:container_registry_project_statistics_enabled) { true }
|
||||
|
||||
it { is_expected.to have_pushed_frontend_feature_flags(containerRegistryProjectStatistics: true)}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'admin/application_settings/_repository_check.html.haml' do
|
||||
let_it_be(:user) { create(:admin) }
|
||||
let_it_be(:application_setting) { build(:application_setting) }
|
||||
|
||||
before do
|
||||
assign(:application_setting, application_setting)
|
||||
allow(view).to receive(:current_user).and_return(user)
|
||||
end
|
||||
|
||||
describe 'repository checks' do
|
||||
it 'has the setting subsection' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_content('Repository checks')
|
||||
end
|
||||
|
||||
it 'renders the correct setting subsection content' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_field('Enable repository checks')
|
||||
expect(rendered).to have_link(
|
||||
'Clear all repository checks',
|
||||
href: clear_repository_check_states_admin_application_settings_path
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'housekeeping' do
|
||||
it 'has the setting subsection' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_content('Housekeeping')
|
||||
end
|
||||
|
||||
it 'renders the correct setting subsection content' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_field('Enable automatic repository housekeeping')
|
||||
expect(rendered).to have_field('Incremental repack period')
|
||||
expect(rendered).to have_field('Full repack period')
|
||||
expect(rendered).to have_field('Git GC period')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'inactive project deletion' do
|
||||
let_it_be(:application_setting) do
|
||||
build(:application_setting,
|
||||
delete_inactive_projects: true,
|
||||
inactive_projects_delete_after_months: 2,
|
||||
inactive_projects_min_size_mb: 250,
|
||||
inactive_projects_send_warning_email_after_months: 1
|
||||
)
|
||||
end
|
||||
|
||||
it 'has the setting subsection' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_content('Inactive project deletion')
|
||||
end
|
||||
|
||||
it 'renders the correct setting subsection content' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_selector('.js-inactive-project-deletion-form')
|
||||
expect(rendered).to have_selector('[data-delete-inactive-projects="true"]')
|
||||
expect(rendered).to have_selector('[data-inactive-projects-delete-after-months="2"]')
|
||||
expect(rendered).to have_selector('[data-inactive-projects-min-size-mb="250"]')
|
||||
expect(rendered).to have_selector('[data-inactive-projects-send-warning-email-after-months="1"]')
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue