Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-12-10 12:10:18 +00:00
parent 240609275d
commit e838c62efb
48 changed files with 513 additions and 394 deletions

View File

@ -1,16 +0,0 @@
import Vue from 'vue';
import DeleteLabelModal from '~/vue_shared/components/delete_label_modal.vue';
const mountDeleteLabelModal = (optionalProps) =>
new Vue({
render(h) {
return h(DeleteLabelModal, {
props: {
selector: '.js-delete-label-modal-button',
...optionalProps,
},
});
},
}).$mount();
export default (optionalProps = {}) => mountDeleteLabelModal(optionalProps);

View File

@ -0,0 +1,135 @@
import $ from 'jquery';
import Vue from 'vue';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import Translate from '~/vue_shared/translate';
import DeleteLabelModal from './components/delete_label_modal.vue';
import PromoteLabelModal from './components/promote_label_modal.vue';
import eventHub from './event_hub';
import GroupLabelSubscription from './group_label_subscription';
import LabelManager from './label_manager';
import ProjectLabelSubscription from './project_label_subscription';
export function initDeleteLabelModal(optionalProps = {}) {
new Vue({
render(h) {
return h(DeleteLabelModal, {
props: {
selector: '.js-delete-label-modal-button',
...optionalProps,
},
});
},
}).$mount();
}
export function initLabels() {
if ($('.prioritized-labels').length) {
new LabelManager(); // eslint-disable-line no-new
}
$('.label-subscription').each((i, el) => {
const $el = $(el);
if ($el.find('.dropdown-group-label').length) {
new GroupLabelSubscription($el); // eslint-disable-line no-new
} else {
new ProjectLabelSubscription($el); // eslint-disable-line no-new
}
});
}
export function initLabelIndex() {
Vue.use(Translate);
initLabels();
initDeleteLabelModal();
const onRequestFinished = ({ labelUrl, successful }) => {
const button = document.querySelector(
`.js-promote-project-label-button[data-url="${labelUrl}"]`,
);
if (!successful) {
button.removeAttribute('disabled');
}
};
const onRequestStarted = (labelUrl) => {
const button = document.querySelector(
`.js-promote-project-label-button[data-url="${labelUrl}"]`,
);
button.setAttribute('disabled', '');
eventHub.$once('promoteLabelModal.requestFinished', onRequestFinished);
};
const promoteLabelButtons = document.querySelectorAll('.js-promote-project-label-button');
return new Vue({
el: '#js-promote-label-modal',
data() {
return {
modalProps: {
labelTitle: '',
labelColor: '',
labelTextColor: '',
url: '',
groupName: '',
},
};
},
mounted() {
eventHub.$on('promoteLabelModal.props', this.setModalProps);
eventHub.$emit('promoteLabelModal.mounted');
promoteLabelButtons.forEach((button) => {
button.removeAttribute('disabled');
button.addEventListener('click', () => {
this.$root.$emit(BV_SHOW_MODAL, 'promote-label-modal');
eventHub.$once('promoteLabelModal.requestStarted', onRequestStarted);
this.setModalProps({
labelTitle: button.dataset.labelTitle,
labelColor: button.dataset.labelColor,
labelTextColor: button.dataset.labelTextColor,
url: button.dataset.url,
groupName: button.dataset.groupName,
});
});
});
},
beforeDestroy() {
eventHub.$off('promoteLabelModal.props', this.setModalProps);
},
methods: {
setModalProps(modalProps) {
this.modalProps = modalProps;
},
},
render(createElement) {
return createElement(PromoteLabelModal, {
props: this.modalProps,
});
},
});
}
export function initAdminLabels() {
const pagination = document.querySelector('.labels .gl-pagination');
const emptyState = document.querySelector('.labels .nothing-here-block.hidden');
function removeLabelSuccessCallback() {
this.closest('li').classList.add('gl-display-none!');
const labelsCount = document.querySelectorAll(
'ul.manage-labels-list li:not(.gl-display-none\\!)',
).length;
// display the empty state if there are no more labels
if (labelsCount < 1 && !pagination && emptyState) {
emptyState.classList.remove('hidden');
}
}
document.querySelectorAll('.js-remove-label').forEach((row) => {
row.addEventListener('ajax:success', removeLabelSuccessCallback);
});
}

View File

@ -1,19 +0,0 @@
import $ from 'jquery';
import GroupLabelSubscription from './group_label_subscription';
import LabelManager from './label_manager';
import ProjectLabelSubscription from './project_label_subscription';
export default () => {
if ($('.prioritized-labels').length) {
new LabelManager(); // eslint-disable-line no-new
}
$('.label-subscription').each((i, el) => {
const $el = $(el);
if ($el.find('.dropdown-group-label').length) {
new GroupLabelSubscription($el); // eslint-disable-line no-new
} else {
new ProjectLabelSubscription($el); // eslint-disable-line no-new
}
});
};

View File

@ -9,7 +9,7 @@ import { isScopedLabel } from '~/lib/utils/common_utils';
import createFlash from '~/flash'; import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import CreateLabelDropdown from './create_label'; import CreateLabelDropdown from './create_label_dropdown';
export default class LabelsSelect { export default class LabelsSelect {
constructor(els, options = {}) { constructor(els, options = {}) {

View File

@ -1,23 +1,3 @@
function initLabels() { import { initAdminLabels } from '~/labels';
const pagination = document.querySelector('.labels .gl-pagination');
const emptyState = document.querySelector('.labels .nothing-here-block.hidden');
function removeLabelSuccessCallback() { initAdminLabels();
this.closest('li').classList.add('gl-display-none!');
const labelsCount = document.querySelectorAll(
'ul.manage-labels-list li:not(.gl-display-none\\!)',
).length;
// display the empty state if there are no more labels
if (labelsCount < 1 && !pagination && emptyState) {
emptyState.classList.remove('hidden');
}
}
document.querySelectorAll('.js-remove-label').forEach((row) => {
row.addEventListener('ajax:success', removeLabelSuccessCallback);
});
}
initLabels();

View File

@ -1,5 +1,4 @@
import initDeleteLabelModal from '~/labels/delete_label_modal'; import { initDeleteLabelModal, initLabels } from '~/labels';
import initLabels from '~/labels/init_labels';
initLabels(); initLabels();
initDeleteLabelModal(); initDeleteLabelModal();

View File

@ -1,83 +1,3 @@
import Vue from 'vue'; import { initLabelIndex } from '~/labels';
import initDeleteLabelModal from '~/labels/delete_label_modal';
import initLabels from '~/labels/init_labels';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import Translate from '~/vue_shared/translate';
import PromoteLabelModal from '../components/promote_label_modal.vue';
import eventHub from '../event_hub';
Vue.use(Translate);
const initLabelIndex = () => {
initLabels();
initDeleteLabelModal();
const onRequestFinished = ({ labelUrl, successful }) => {
const button = document.querySelector(
`.js-promote-project-label-button[data-url="${labelUrl}"]`,
);
if (!successful) {
button.removeAttribute('disabled');
}
};
const onRequestStarted = (labelUrl) => {
const button = document.querySelector(
`.js-promote-project-label-button[data-url="${labelUrl}"]`,
);
button.setAttribute('disabled', '');
eventHub.$once('promoteLabelModal.requestFinished', onRequestFinished);
};
const promoteLabelButtons = document.querySelectorAll('.js-promote-project-label-button');
return new Vue({
el: '#js-promote-label-modal',
data() {
return {
modalProps: {
labelTitle: '',
labelColor: '',
labelTextColor: '',
url: '',
groupName: '',
},
};
},
mounted() {
eventHub.$on('promoteLabelModal.props', this.setModalProps);
eventHub.$emit('promoteLabelModal.mounted');
promoteLabelButtons.forEach((button) => {
button.removeAttribute('disabled');
button.addEventListener('click', () => {
this.$root.$emit(BV_SHOW_MODAL, 'promote-label-modal');
eventHub.$once('promoteLabelModal.requestStarted', onRequestStarted);
this.setModalProps({
labelTitle: button.dataset.labelTitle,
labelColor: button.dataset.labelColor,
labelTextColor: button.dataset.labelTextColor,
url: button.dataset.url,
groupName: button.dataset.groupName,
});
});
});
},
beforeDestroy() {
eventHub.$off('promoteLabelModal.props', this.setModalProps);
},
methods: {
setModalProps(modalProps) {
this.modalProps = modalProps;
},
},
render(createElement) {
return createElement(PromoteLabelModal, {
props: this.modalProps,
});
},
});
};
initLabelIndex(); initLabelIndex();

View File

@ -195,12 +195,12 @@ export default {
> >
<template #header> <template #header>
<dropdown-header <dropdown-header
v-if="!isStandalone"
ref="header" ref="header"
v-model="searchKey" :search-key="searchKey"
:labels-create-title="labelsCreateTitle" :labels-create-title="labelsCreateTitle"
:labels-list-title="labelsListTitle" :labels-list-title="labelsListTitle"
:show-dropdown-contents-create-view="showDropdownContentsCreateView" :show-dropdown-contents-create-view="showDropdownContentsCreateView"
:is-standalone="isStandalone"
@toggleDropdownContentsCreateView="toggleDropdownContent" @toggleDropdownContentsCreateView="toggleDropdownContent"
@closeDropdown="$emit('closeDropdown')" @closeDropdown="$emit('closeDropdown')"
@input="debouncedSearchKeyUpdate" @input="debouncedSearchKeyUpdate"

View File

@ -6,9 +6,6 @@ export default {
GlButton, GlButton,
GlSearchBoxByType, GlSearchBoxByType,
}, },
model: {
prop: 'searchKey',
},
props: { props: {
labelsCreateTitle: { labelsCreateTitle: {
type: String, type: String,
@ -31,6 +28,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
isStandalone: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
dropdownTitle() { dropdownTitle() {
@ -47,7 +49,11 @@ export default {
<template> <template>
<div data-testid="dropdown-header"> <div data-testid="dropdown-header">
<div class="dropdown-title gl-display-flex gl-align-items-center gl-pt-0 gl-pb-3!"> <div
v-if="!isStandalone"
class="dropdown-title gl-display-flex gl-align-items-center gl-pt-0 gl-pb-3!"
data-testid="dropdown-header-title"
>
<gl-button <gl-button
v-if="showDropdownContentsCreateView" v-if="showDropdownContentsCreateView"
:aria-label="__('Go back')" :aria-label="__('Go back')"

View File

@ -286,7 +286,7 @@ export default {
<template> <template>
<div <div
class="labels-select-wrapper position-relative" class="labels-select-wrapper gl-relative"
:class="{ :class="{
'is-standalone': isDropdownVariantStandalone(variant), 'is-standalone': isDropdownVariantStandalone(variant),
'is-embedded': isDropdownVariantEmbedded(variant), 'is-embedded': isDropdownVariantEmbedded(variant),

View File

@ -83,8 +83,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
:ci_environments_status, :ci_environments_status,
:destroy, :destroy,
:rebase, :rebase,
:discussions, :discussions
:description_diff
] ]
def index def index

View File

@ -26,7 +26,6 @@ module Git
enqueue_detect_repository_languages enqueue_detect_repository_languages
execute_related_hooks execute_related_hooks
perform_housekeeping
stop_environments stop_environments
unlock_artifacts unlock_artifacts
@ -71,13 +70,6 @@ module Git
BranchHooksService.new(project, current_user, params).execute BranchHooksService.new(project, current_user, params).execute
end end
def perform_housekeeping
housekeeping = Repositories::HousekeepingService.new(project)
housekeeping.increment!
housekeeping.execute if housekeeping.needed?
rescue Repositories::HousekeepingService::LeaseTaken
end
def removing_branch? def removing_branch?
Gitlab::Git.blank_ref?(newrev) Gitlab::Git.blank_ref?(newrev)
end end

View File

@ -9,6 +9,8 @@ module Git
process_changes_by_action(:branch, changes.branch_changes) process_changes_by_action(:branch, changes.branch_changes)
process_changes_by_action(:tag, changes.tag_changes) process_changes_by_action(:tag, changes.tag_changes)
perform_housekeeping
end end
private private
@ -83,5 +85,12 @@ module Git
MergeRequests::PushedBranchesService.new(project: project, current_user: current_user, params: { changes: changes }).execute MergeRequests::PushedBranchesService.new(project: project, current_user: current_user, params: { changes: changes }).execute
end end
def perform_housekeeping
housekeeping = Repositories::HousekeepingService.new(project)
housekeeping.increment!
housekeeping.execute if housekeeping.needed?
rescue Repositories::HousekeepingService::LeaseTaken
end
end end
end end

View File

@ -1,2 +1,2 @@
- if project.archived - if project.archived
%span.badge.badge-warning.badge-pill.gl-badge.md= _('archived') = gl_badge_tag _('archived'), variant: :warning, size: :md

View File

@ -42,7 +42,7 @@
%ul.content-list.all-branches %ul.content-list.all-branches
- @branches.each do |branch| - @branches.each do |branch|
= render "projects/branches/branch", branch: branch, merged: @merged_branch_names.include?(branch.name), commit_status: @branch_pipeline_statuses[branch.name], show_commit_status: @branch_pipeline_statuses.any? = render "projects/branches/branch", branch: branch, merged: @merged_branch_names.include?(branch.name), commit_status: @branch_pipeline_statuses[branch.name], show_commit_status: @branch_pipeline_statuses.any?
- if Feature.enabled?(:branches_pagination_without_count, @project, default_enabled: :yaml) - if Feature.enabled?(:branch_list_keyset_pagination, @project, default_enabled: :yaml)
= render('kaminari/gitlab/without_count', previous_path: @prev_path, next_path: @next_path) = render('kaminari/gitlab/without_count', previous_path: @prev_path, next_path: @next_path)
- else - else
= paginate @branches, theme: 'gitlab' = paginate @branches, theme: 'gitlab'

View File

@ -23,7 +23,7 @@
= form.label :enabled, class: 'form-check-label' do = form.label :enabled, class: 'form-check-label' do
%strong= s_('CICD|Default to Auto DevOps pipeline') %strong= s_('CICD|Default to Auto DevOps pipeline')
- if auto_devops_enabled - if auto_devops_enabled
%span.badge.badge-info.js-instance-default-badge= badge_for_auto_devops_scope(@project) = gl_badge_tag badge_for_auto_devops_scope(@project), { variant: :info }, { class: 'js-instance-default-badge'}
.form-text.text-muted .form-text.text-muted
= s_('CICD|The Auto DevOps pipeline runs if no alternative CI configuration file is found.') = s_('CICD|The Auto DevOps pipeline runs if no alternative CI configuration file is found.')
= link_to _('Learn more.'), help_page_path('topics/autodevops/index.md'), target: '_blank' = link_to _('Learn more.'), help_page_path('topics/autodevops/index.md'), target: '_blank'

View File

@ -1,8 +0,0 @@
---
name: branches_pagination_without_count
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50759
rollout_issue_url:
milestone: '13.9'
type: development
group: group::source code
default_enabled: false

View File

@ -0,0 +1,25 @@
---
data_category: optional
key_path: redis_hll_counters.testing.users_expanding_testing_license_compliance_report_monthly
description: Count of expanding the license compliance widget
product_section: sec
product_stage: secure
product_group: group::static analysis
product_category: dependency_scanning
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75643
time_frame: 28d
data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- users_expanding_testing_license_compliance_report
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,25 @@
---
data_category: optional
key_path: redis_hll_counters.testing.users_visiting_testing_license_compliance_full_report_monthly
description: Count of visiting the license compliance full report
product_section: sec
product_stage: secure
product_group: group::static analysis
product_category: dependency_scanning
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75643
time_frame: 28d
data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- users_visiting_testing_license_compliance_full_report
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,25 @@
---
data_category: optional
key_path: redis_hll_counters.testing.users_visiting_testing_manage_license_compliance_monthly
description: Count of visiting the manage license compliance page
product_section: sec
product_stage: secure
product_group: group::static analysis
product_category: dependency_scanning
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75643
time_frame: 28d
data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- users_visiting_testing_manage_license_compliance
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,25 @@
---
data_category: optional
key_path: redis_hll_counters.testing.users_expanding_testing_license_compliance_report_weekly
description: Count of expanding the license compliance widget
product_section: sec
product_stage: secure
product_group: group::static analysis
product_category: dependency_scanning
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75643
time_frame: 7d
data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- users_expanding_testing_license_compliance_report
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,25 @@
---
data_category: optional
key_path: redis_hll_counters.testing.users_visiting_testing_license_compliance_full_report_weekly
description: Count of visiting the license compliance full report
product_section: sec
product_stage: secure
product_group: group::static analysis
product_category: dependency_scanning
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75643
time_frame: 7d
data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- users_visiting_testing_license_compliance_full_report
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,25 @@
---
data_category: optional
key_path: redis_hll_counters.testing.users_visiting_testing_manage_license_compliance_weekly
description: Count of visiting the manage license compliance page
product_section: sec
product_stage: secure
product_group: group::static analysis
product_category: dependency_scanning
value_type: number
status: active
milestone: '14.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75643
time_frame: 7d
data_source: redis_hll
instrumentation_class: RedisHLLMetric
options:
events:
- users_visiting_testing_manage_license_compliance
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -56,7 +56,7 @@ In `config/gitlab.yml`:
## Storing LFS objects in remote object storage ## Storing LFS objects in remote object storage
You can store LFS objects in remote object storage. This allows you You can store LFS objects in remote object storage. This allows you
to offload reads and writes to the local disk, and free up disk space significantly. to reduce reads and writes to the local disk, and free up disk space significantly.
GitLab is tightly integrated with `Fog`, so you can refer to its [documentation](http://fog.io/about/provider_documentation.html) GitLab is tightly integrated with `Fog`, so you can refer to its [documentation](http://fog.io/about/provider_documentation.html)
to check which storage services can be integrated with GitLab. to check which storage services can be integrated with GitLab.
You can also use external object storage in a private local network. For example, You can also use external object storage in a private local network. For example,
@ -98,32 +98,6 @@ See [the available connection settings for different providers](../object_storag
Here is a configuration example with S3. Here is a configuration example with S3.
### Manual uploading to an object storage
There are two ways to manually do the same thing as automatic uploading (described above).
**Option 1: Rake task**
```shell
gitlab-rake gitlab:lfs:migrate
```
**Option 2: Rails console**
Log into the Rails console:
```shell
sudo gitlab-rails console
```
Upload LFS files manually
```ruby
LfsObject.where(file_store: [nil, 1]).find_each do |lfs_object|
lfs_object.file.migrate!(ObjectStorage::Store::REMOTE) if lfs_object.file.file.exists?
end
```
### S3 for Omnibus installations ### S3 for Omnibus installations
On Omnibus GitLab installations, the settings are prefixed by `lfs_object_store_`: On Omnibus GitLab installations, the settings are prefixed by `lfs_object_store_`:
@ -146,32 +120,10 @@ On Omnibus GitLab installations, the settings are prefixed by `lfs_object_store_
``` ```
1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. 1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Migrate any existing local LFS objects to the object storage: 1. [Migrate any existing local LFS objects to the object storage](#migrating-to-object-storage).
New LFS objects
```shell
gitlab-rake gitlab:lfs:migrate
```
This migrates existing LFS objects to object storage. New LFS objects
are forwarded to object storage unless are forwarded to object storage unless
`gitlab_rails['lfs_object_store_background_upload']` and `gitlab_rails['lfs_object_store_direct_upload']` is set to `false`. `gitlab_rails['lfs_object_store_background_upload']` and `gitlab_rails['lfs_object_store_direct_upload']` is set to `false`.
1. Optional. Verify all files migrated properly.
From [PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database)
(`sudo gitlab-psql -d gitlabhq_production`) verify `objectstg` below (where `file_store=2`) has count of all artifacts:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when file_store = '1' then 1 else 0 end) AS filesystem, sum(case when file_store = '2' then 1 else 0 end) AS objectstg FROM lfs_objects;
total | filesystem | objectstg
------+------------+-----------
2409 | 0 | 2409
```
Verify no files on disk in `artifacts` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/shared/lfs-objects -type f | grep -v tmp/cache | wc -l
```
### S3 for installations from source ### S3 for installations from source
@ -199,31 +151,68 @@ For source installations the settings are nested under `lfs:` and then
``` ```
1. Save the file, and then [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect. 1. Save the file, and then [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
1. Migrate any existing local LFS objects to the object storage: 1. [Migrate any existing local LFS objects to the object storage](#migrating-to-object-storage).
New LFS objects
are forwarded to object storage unless
`background_upload` and `direct_upload` is set to `false`.
```shell ### Migrating to object storage
sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production
```
This migrates existing LFS objects to object storage. New LFS objects **Option 1: Rake task**
are forwarded to object storage unless `background_upload` and `direct_upload` is set to
`false`.
1. Optional. Verify all files migrated properly.
From PostgreSQL console (`sudo -u git -H psql -d gitlabhq_production`) verify `objectstg` below (where `file_store=2`) has count of all artifacts:
```shell After [configuring the object storage](#storing-lfs-objects-in-remote-object-storage), use the following task to
gitlabhq_production=# SELECT count(*) AS total, sum(case when file_store = '1' then 1 else 0 end) AS filesystem, sum(case when file_store = '2' then 1 else 0 end) AS objectstg FROM lfs_objects; migrate existing LFS objects from the local storage to the remote storage.
The processing is done in a background worker and requires **no downtime**.
total | filesystem | objectstg For Omnibus GitLab:
------+------------+-----------
2409 | 0 | 2409
```
Verify no files on disk in `artifacts` folder: ```shell
sudo gitlab-rake "gitlab:lfs:migrate"
```
```shell For installations from source:
sudo find /var/opt/gitlab/gitlab-rails/shared/lfs-objects -type f | grep -v tmp/cache | wc -l
``` ```shell
RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:lfs:migrate
```
You can optionally track progress and verify that all packages migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `store=2`) has count of all LFS objects:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when file_store = '1' then 1 else 0 end) AS filesystem, sum(case when file_store = '2' then 1 else 0 end) AS objectstg FROM lfs_objects;
total | filesystem | objectstg
------+------------+-----------
2409 | 0 | 2409
```
Verify that there are no files on disk in the `objects` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/shared/lfs-objects -type f | grep -v tmp | wc -l
```
**Option 2: Rails console**
Log into the Rails console:
```shell
sudo gitlab-rails console
```
Upload LFS files manually
```ruby
LfsObject.where(file_store: [nil, 1]).find_each do |lfs_object|
lfs_object.file.migrate!(ObjectStorage::Store::REMOTE) if lfs_object.file.file.exists?
end
```
### Migrating back to local storage ### Migrating back to local storage

View File

@ -42,6 +42,28 @@ gitlab-rake "gitlab:uploads:migrate:all"
sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate:all sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate:all
``` ```
You can optionally track progress and verify that all packages migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `store=2`) has count of all artifacts:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when store = '1' then 1 else 0 end) AS filesystem, sum(case when store = '2' then 1 else 0 end) AS objectstg FROM uploads;
total | filesystem | objectstg
------+------------+-----------
2409 | 0 | 2409
```
Verify that there are no files on disk in the `uploads` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/uploads -type f | grep -v tmp | wc -l
```
### Individual Rake tasks ### Individual Rake tasks
If you already ran the [all-in-one Rake task](#all-in-one-rake-task), there is no need to run these If you already ran the [all-in-one Rake task](#all-in-one-rake-task), there is no need to run these

View File

@ -130,6 +130,28 @@ For GitLab 13.8 and earlier versions, you can use a workaround for the Rake task
end end
``` ```
You can optionally track progress and verify that all packages migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `store=2`) has count of all states:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when store = '1' then 1 else 0 end) AS filesystem, sum(case when store = '2' then 1 else 0 end) AS objectstg FROM terraform_states;
total | filesystem | objectstg
------+------------+-----------
15 | 0 | 15
```
Verify that there are no files on disk in the `terraform_state` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/shared/terraform_state -type f | wc -l
```
### S3-compatible connection settings ### S3-compatible connection settings
See [the available connection settings for different providers](object_storage.md#connection-settings). See [the available connection settings for different providers](object_storage.md#connection-settings).
@ -162,11 +184,7 @@ See [the available connection settings for different providers](object_storage.m
``` ```
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. 1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Migrate any existing local states to the object storage (GitLab 13.9 and later): 1. [Migrate any existing local states to the object storage](#migrate-to-object-storage)
```shell
gitlab-rake gitlab:terraform_states:migrate
```
**In installations from source:** **In installations from source:**
@ -187,8 +205,4 @@ See [the available connection settings for different providers](object_storage.m
``` ```
1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect. 1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
1. Migrate any existing local states to the object storage (GitLab 13.9 and later): 1. [Migrate any existing local states to the object storage](#migrate-to-object-storage)
```shell
sudo -u git -H bundle exec rake gitlab:terraform_states:migrate RAILS_ENV=production
```

View File

@ -106,24 +106,7 @@ _The uploads are stored by default in
``` ```
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. 1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate` Rake task](raketasks/uploads/migrate.md). 1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md).
1. Optional: Verify all files migrated properly.
From [PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database)
(`sudo gitlab-psql -d gitlabhq_production`) verify `objectstg` below (where `store=2`) has count of all artifacts:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when store = '1' then 1 else 0 end) AS filesystem, sum(case when store = '2' then 1 else 0 end) AS objectstg FROM uploads;
total | filesystem | objectstg
------+------------+-----------
2409 | 0 | 2409
```
Verify no files on disk in `artifacts` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/uploads -type f | grep -v tmp | wc -l
```
**In installations from source:** **In installations from source:**
@ -147,22 +130,6 @@ _The uploads are stored by default in
1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect. 1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md). 1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md).
1. Optional: Verify all files migrated properly.
From PostgreSQL console (`sudo -u git -H psql -d gitlabhq_production`) verify `objectstg` below (where `file_store=2`) has count of all artifacts:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when store = '1' then 1 else 0 end) AS filesystem, sum(case when store = '2' then 1 else 0 end) AS objectstg FROM uploads;
total | filesystem | objectstg
------+------------+-----------
2409 | 0 | 2409
```
Verify no files on disk in `artifacts` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/uploads -type f | grep -v tmp | wc -l
```
#### OpenStack example #### OpenStack example
@ -189,23 +156,6 @@ _The uploads are stored by default in
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. 1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md). 1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md).
1. Optional: Verify all files migrated properly.
From [PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database)
(`sudo gitlab-psql -d gitlabhq_production`) verify `objectstg` below (where `store=2`) has count of all artifacts:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when store = '1' then 1 else 0 end) AS filesystem, sum(case when store = '2' then 1 else 0 end) AS objectstg FROM uploads;
total | filesystem | objectstg
------+------------+-----------
2409 | 0 | 2409
```
Verify no files on disk in `artifacts` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/uploads -type f | grep -v tmp | wc -l
```
--- ---
@ -237,19 +187,3 @@ _The uploads are stored by default in
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. 1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md). 1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md).
1. Optional: Verify all files migrated properly.
From PostgreSQL console (`sudo -u git -H psql -d gitlabhq_production`) verify `objectstg` below (where `file_store=2`) has count of all artifacts:
```shell
gitlabhq_production=# SELECT count(*) AS total, sum(case when store = '1' then 1 else 0 end) AS filesystem, sum(case when store = '2' then 1 else 0 end) AS objectstg FROM uploads;
total | filesystem | objectstg
------+------------+-----------
2409 | 0 | 2409
```
Verify no files on disk in `artifacts` folder:
```shell
sudo find /var/opt/gitlab/gitlab-rails/uploads -type f | grep -v tmp | wc -l
```

View File

@ -48,20 +48,9 @@ To make sure you can easily run the most recent stable release, we are working
hard to keep the update process simple and reliable. hard to keep the update process simple and reliable.
If you are unable to follow our monthly release cycle, there are a couple of If you are unable to follow our monthly release cycle, there are a couple of
cases you need to consider. cases you need to consider. Follow the
[upgrade paths guide](../update/index.md#upgrade-paths) to safely upgrade
It is considered safe to jump between patch versions and minor versions within between versions.
one major version. For example, it is safe to:
- Upgrade the *minor* version. For example:
- `13.7.5` -> `13.10.5`
- `12.3.4` -> `12.10.11`
- Upgrade the *patch* version. For example:
- `13.0.4` -> `13.0.12`
- `12.10.1` -> `12.10.8`
NOTE: NOTE:
Version specific changes in Omnibus GitLab Linux packages can be found in [the Omnibus GitLab documentation](../update/package/index.md#version-specific-changes). Version specific changes in Omnibus GitLab Linux packages can be found in [the Omnibus GitLab documentation](../update/package/index.md#version-specific-changes).

View File

@ -45,7 +45,6 @@ module Gitlab
end end
def overwrite_headers(message, signed_email) def overwrite_headers(message, signed_email)
message.content_disposition = signed_email.content_disposition
message.content_transfer_encoding = signed_email.content_transfer_encoding message.content_transfer_encoding = signed_email.content_transfer_encoding
message.content_type = signed_email.content_type message.content_type = signed_email.content_type
end end

View File

@ -355,6 +355,19 @@
category: testing category: testing
aggregation: weekly aggregation: weekly
feature_flag: users_expanding_widgets_usage_data feature_flag: users_expanding_widgets_usage_data
- name: users_expanding_testing_license_compliance_report
redis_slot: testing
category: testing
aggregation: weekly
feature_flag: users_expanding_widgets_usage_data
- name: users_visiting_testing_license_compliance_full_report
redis_slot: testing
category: testing
aggregation: weekly
- name: users_visiting_testing_manage_license_compliance
redis_slot: testing
category: testing
aggregation: weekly
# Container Security - Network Policies # Container Security - Network Policies
- name: clusters_using_network_policies_ui - name: clusters_using_network_policies_ui
redis_slot: network_policies redis_slot: network_policies

View File

@ -6785,7 +6785,7 @@ msgstr ""
msgid "Checkout" msgid "Checkout"
msgstr "" msgstr ""
msgid "Checkout|$%{selectedPlanPrice} per 10 GB storage per pack" msgid "Checkout|$%{selectedPlanPrice} per 10 GB storage pack per year"
msgstr "" msgstr ""
msgid "Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes" msgid "Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes"

View File

@ -28,7 +28,7 @@ describe('Blob viewer', () => {
loadFixtures('blob/show_readme.html'); loadFixtures('blob/show_readme.html');
$('#modal-upload-blob').remove(); $('#modal-upload-blob').remove();
mock.onGet(/blob\/master\/README\.md/).reply(200, { mock.onGet(/blob\/.+\/README\.md/).reply(200, {
html: '<div>testing</div>', html: '<div>testing</div>',
}); });

View File

@ -34,7 +34,7 @@ RSpec.describe Projects::BlobController, '(JavaScript fixtures)', type: :control
get(:show, params: { get(:show, params: {
namespace_id: project.namespace, namespace_id: project.namespace,
project_id: project, project_id: project,
id: 'master/README.md' id: "#{project.default_branch}/README.md"
}) })
expect(response).to be_successful expect(response).to be_successful

View File

@ -3,7 +3,7 @@ import { mount } from '@vue/test-utils';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import DeleteLabelModal from '~/vue_shared/components/delete_label_modal.vue'; import DeleteLabelModal from '~/labels/components/delete_label_modal.vue';
const MOCK_MODAL_DATA = { const MOCK_MODAL_DATA = {
labelName: 'label 1', labelName: 'label 1',
@ -11,7 +11,7 @@ const MOCK_MODAL_DATA = {
destroyPath: `${TEST_HOST}/1`, destroyPath: `${TEST_HOST}/1`,
}; };
describe('vue_shared/components/delete_label_modal', () => { describe('~/labels/components/delete_label_modal', () => {
let wrapper; let wrapper;
const createComponent = () => { const createComponent = () => {

View File

@ -2,8 +2,8 @@ import Vue from 'vue';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import promoteLabelModal from '~/pages/projects/labels/components/promote_label_modal.vue'; import promoteLabelModal from '~/labels/components/promote_label_modal.vue';
import eventHub from '~/pages/projects/labels/event_hub'; import eventHub from '~/labels/event_hub';
describe('Promote label modal', () => { describe('Promote label modal', () => {
let vm; let vm;

View File

@ -1,5 +1,5 @@
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import initDeleteLabelModal from '~/labels/delete_label_modal'; import { initDeleteLabelModal } from '~/labels';
describe('DeleteLabelModal', () => { describe('DeleteLabelModal', () => {
const buttons = [ const buttons = [

View File

@ -124,19 +124,7 @@ describe('DropdownContent', () => {
expect(wrapper.emitted('setLabels')).toEqual([[[updatedLabel]]]); expect(wrapper.emitted('setLabels')).toEqual([[[updatedLabel]]]);
}); });
it('does not render header on standalone variant', () => { it('renders header', () => {
createComponent({ props: { variant: DropdownVariant.Standalone } });
expect(findDropdownHeader().exists()).toBe(false);
});
it('renders header on embedded variant', () => {
createComponent({ props: { variant: DropdownVariant.Embedded } });
expect(findDropdownHeader().exists()).toBe(true);
});
it('renders header on sidebar variant', () => {
createComponent(); createComponent();
expect(findDropdownHeader().exists()).toBe(true); expect(findDropdownHeader().exists()).toBe(true);

View File

@ -9,6 +9,7 @@ describe('DropdownHeader', () => {
const createComponent = ({ const createComponent = ({
showDropdownContentsCreateView = false, showDropdownContentsCreateView = false,
labelsFetchInProgress = false, labelsFetchInProgress = false,
isStandalone = false,
} = {}) => { } = {}) => {
wrapper = extendedWrapper( wrapper = extendedWrapper(
shallowMount(DropdownHeader, { shallowMount(DropdownHeader, {
@ -18,6 +19,7 @@ describe('DropdownHeader', () => {
labelsCreateTitle: 'Create label', labelsCreateTitle: 'Create label',
labelsListTitle: 'Select label', labelsListTitle: 'Select label',
searchKey: '', searchKey: '',
isStandalone,
}, },
stubs: { stubs: {
GlSearchBoxByType, GlSearchBoxByType,
@ -32,6 +34,7 @@ describe('DropdownHeader', () => {
const findSearchInput = () => wrapper.findComponent(GlSearchBoxByType); const findSearchInput = () => wrapper.findComponent(GlSearchBoxByType);
const findGoBackButton = () => wrapper.findByTestId('go-back-button'); const findGoBackButton = () => wrapper.findByTestId('go-back-button');
const findDropdownTitle = () => wrapper.findByTestId('dropdown-header-title');
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent();
@ -72,4 +75,18 @@ describe('DropdownHeader', () => {
}, },
); );
}); });
describe('Standalone variant', () => {
beforeEach(() => {
createComponent({ isStandalone: true });
});
it('renders search input', () => {
expect(findSearchInput().exists()).toBe(true);
});
it('does not render title', async () => {
expect(findDropdownTitle().exists()).toBe(false);
});
});
}); });

View File

@ -75,9 +75,9 @@ describe('LabelsSelectRoot', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it('renders component with classes `labels-select-wrapper position-relative`', () => { it('renders component with classes `labels-select-wrapper gl-relative`', () => {
createComponent(); createComponent();
expect(wrapper.classes()).toEqual(['labels-select-wrapper', 'position-relative']); expect(wrapper.classes()).toEqual(['labels-select-wrapper', 'gl-relative']);
}); });
it.each` it.each`

View File

@ -50,6 +50,7 @@ RSpec.describe Gitlab::Email::Hook::SmimeSignatureInterceptor do
expect(mail.header['To'].value).to eq('test@example.com') expect(mail.header['To'].value).to eq('test@example.com')
expect(mail.header['From'].value).to eq('info@example.com') expect(mail.header['From'].value).to eq('info@example.com')
expect(mail.header['Content-Type'].value).to match('multipart/signed').and match('protocol="application/x-pkcs7-signature"') expect(mail.header['Content-Type'].value).to match('multipart/signed').and match('protocol="application/x-pkcs7-signature"')
expect(mail.header.include?('Content-Disposition')).to eq(false)
# verify signature and obtain pkcs7 encoded content # verify signature and obtain pkcs7 encoded content
p7enc = Gitlab::Email::Smime::Signer.verify_signature( p7enc = Gitlab::Email::Smime::Signer.verify_signature(

View File

@ -82,7 +82,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
end.new(time_frame: 'all') end.new(time_frame: 'all')
end end
it 'calculates a correct result' do it 'calculates a correct result', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/348139' do
expect(subject.value).to be_within(Gitlab::Database::PostgresHll::BatchDistinctCounter::ERROR_RATE).percent_of(3) expect(subject.value).to be_within(Gitlab::Database::PostgresHll::BatchDistinctCounter::ERROR_RATE).percent_of(3)
end end

View File

@ -69,7 +69,7 @@ RSpec.describe 'Query current user todos' do
QUERY QUERY
end end
it 'avoids N+1 queries', :request_store do it 'avoids N+1 queries', :request_store, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338671' do
control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) } control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
project2 = create(:project) project2 = create(:project)

View File

@ -554,44 +554,6 @@ RSpec.describe Git::BranchPushService, services: true do
end end
end end
describe "housekeeping", :clean_gitlab_redis_cache, :clean_gitlab_redis_queues, :clean_gitlab_redis_shared_state do
let(:housekeeping) { Repositories::HousekeepingService.new(project) }
before do
allow(Repositories::HousekeepingService).to receive(:new).and_return(housekeeping)
end
it 'does not perform housekeeping when not needed' do
expect(housekeeping).not_to receive(:execute)
execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
end
context 'when housekeeping is needed' do
before do
allow(housekeeping).to receive(:needed?).and_return(true)
end
it 'performs housekeeping' do
expect(housekeeping).to receive(:execute)
execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
end
it 'does not raise an exception' do
allow(housekeeping).to receive(:try_obtain_lease).and_return(false)
execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
end
end
it 'increments the push counter' do
expect(housekeeping).to receive(:increment!)
execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
end
end
describe "CI environments" do describe "CI environments" do
context 'create branch' do context 'create branch' do
let(:oldrev) { blankrev } let(:oldrev) { blankrev }

View File

@ -161,6 +161,50 @@ RSpec.describe Git::ProcessRefChangesService do
end end
end end
end end
describe "housekeeping", :clean_gitlab_redis_cache, :clean_gitlab_redis_queues, :clean_gitlab_redis_shared_state do
let(:housekeeping) { Repositories::HousekeepingService.new(project) }
before do
allow(Repositories::HousekeepingService).to receive(:new).and_return(housekeeping)
allow(push_service_class)
.to receive(:new)
.with(project, project.owner, hash_including(execute_project_hooks: true, create_push_event: true))
.exactly(changes.count).times
.and_return(service)
end
it 'does not perform housekeeping when not needed' do
expect(housekeeping).not_to receive(:execute)
subject.execute
end
context 'when housekeeping is needed' do
before do
allow(housekeeping).to receive(:needed?).and_return(true)
end
it 'performs housekeeping' do
expect(housekeeping).to receive(:execute)
subject.execute
end
it 'does not raise an exception' do
allow(housekeeping).to receive(:try_obtain_lease).and_return(false)
subject.execute
end
end
it 'increments the push counter' do
expect(housekeeping).to receive(:increment!)
subject.execute
end
end
end end
context 'branch changes' do context 'branch changes' do