Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-06-16 12:09:00 +00:00
parent 6cf1f4c521
commit 9bfdb5cf67
159 changed files with 2352 additions and 433 deletions

View File

@ -355,7 +355,7 @@ rspec foss-impact:
- run_timed_command "scripts/gitaly-test-spawn"
- source scripts/rspec_helpers.sh
- tooling/bin/find_foss_tests tmp/matching_foss_tests.txt
- 'if [[ -n "$(cat tmp/matching_foss_tests.txt)" ]]; then rspec_simple_job "--tag ~quarantine --tag ~geo --tag ~level:migration $(cat tmp/matching_foss_tests.txt)"; fi'
- rspec_matched_tests tmp/matching_foss_tests.txt "--tag ~quarantine --tag ~geo --tag ~level:migration"
artifacts:
expire_in: 7d
paths:

View File

@ -422,6 +422,8 @@
rules:
- <<: *if-not-ee
when: never
- <<: *if-merge-request-title-as-if-foss
when: never
- <<: *if-security-merge-request
changes: *code-backstage-patterns
- <<: *if-dot-com-gitlab-org-merge-request

View File

@ -1,16 +0,0 @@
import $ from 'jquery';
export default function initAvatarPicker() {
$('.js-choose-avatar-button').on('click', function onClickAvatar() {
const form = $(this).closest('form');
return form.find('.js-avatar-input').click();
});
$('.js-avatar-input').on('change', function onChangeAvatarInput() {
const form = $(this).closest('form');
const filename = $(this)
.val()
.replace(/^.*[\\\/]/, ''); // eslint-disable-line no-useless-escape
return form.find('.js-avatar-filename').text(filename);
});
}

View File

@ -66,9 +66,7 @@ class ListIssue {
}
removeMilestone(removeMilestone) {
if (IS_EE && removeMilestone && removeMilestone.id === this.milestone.id) {
this.milestone = {};
}
boardsStore.removeIssueMilestone(this, removeMilestone);
}
getLists() {

View File

@ -817,6 +817,12 @@ const boardsStore = {
issue.isFetching[key] = value;
},
removeIssueMilestone(issue, removeMilestone) {
if (IS_EE && removeMilestone && removeMilestone.id === issue.milestone.id) {
issue.milestone = {};
}
},
refreshIssueData(issue, obj) {
issue.id = obj.id;
issue.iid = obj.iid;

View File

@ -0,0 +1,21 @@
export default function initFilePickers() {
const filePickers = document.querySelectorAll('.js-filepicker');
filePickers.forEach(filePicker => {
const button = filePicker.querySelector('.js-filepicker-button');
button.addEventListener('click', () => {
const form = button.closest('form');
form.querySelector('.js-filepicker-input').click();
});
const input = filePicker.querySelector('.js-filepicker-input');
input.addEventListener('change', () => {
const form = input.closest('form');
const filename = input.value.replace(/^.*[\\\/]/, ''); // eslint-disable-line no-useless-escape
form.querySelector('.js-filepicker-filename').textContent = filename;
});
});
}

View File

@ -1,4 +1,3 @@
import $ from 'jquery';
import { slugify } from './lib/utils/text_utility';
import fetchGroupPathAvailability from '~/pages/groups/new/fetch_group_path_availability';
import flash from '~/flash';
@ -6,44 +5,69 @@ import { __ } from '~/locale';
export default class Group {
constructor() {
this.groupPath = $('#group_path');
this.groupName = $('#group_name');
this.parentId = $('#group_parent_id');
this.groupPaths = Array.from(document.querySelectorAll('.js-autofill-group-path'));
this.groupNames = Array.from(document.querySelectorAll('.js-autofill-group-name'));
this.parentId = document.getElementById('group_parent_id');
this.updateHandler = this.update.bind(this);
this.resetHandler = this.reset.bind(this);
this.updateGroupPathSlugHandler = this.updateGroupPathSlug.bind(this);
if (this.groupName.val() === '') {
this.groupName.on('keyup', this.updateHandler);
this.groupPath.on('keydown', this.resetHandler);
if (!this.parentId.val()) {
this.groupName.on('blur', this.updateGroupPathSlugHandler);
this.groupNames.forEach(groupName => {
if (groupName.value === '') {
groupName.addEventListener('keyup', this.updateHandler);
if (!this.parentId.value) {
groupName.addEventListener('blur', this.updateGroupPathSlugHandler);
}
}
}
});
this.groupPaths.forEach(groupPath => {
groupPath.addEventListener('keydown', this.resetHandler);
});
}
update() {
const slug = slugify(this.groupName.val());
this.groupPath.val(slug);
update({ currentTarget: { value: updatedValue } }) {
const slug = slugify(updatedValue);
this.groupNames.forEach(element => {
element.value = updatedValue;
});
this.groupPaths.forEach(element => {
element.value = slug;
});
}
reset() {
this.groupName.off('keyup', this.updateHandler);
this.groupPath.off('keydown', this.resetHandler);
this.groupName.off('blur', this.checkPathHandler);
this.groupNames.forEach(groupName => {
groupName.removeEventListener('keyup', this.updateHandler);
groupName.removeEventListener('blur', this.checkPathHandler);
});
this.groupPaths.forEach(groupPath => {
groupPath.removeEventListener('keydown', this.resetHandler);
});
}
updateGroupPathSlug() {
const slug = this.groupPath.val() || slugify(this.groupName.val());
updateGroupPathSlug({ currentTarget: { value } = '' } = {}) {
const slug = this.groupPaths[0]?.value || slugify(value);
if (!slug) return;
fetchGroupPathAvailability(slug)
.then(({ data }) => data)
.then(data => {
if (data.exists && data.suggests.length > 0) {
const suggestedSlug = data.suggests[0];
this.groupPath.val(suggestedSlug);
.then(({ exists, suggests }) => {
if (exists && suggests.length) {
const [suggestedSlug] = suggests;
this.groupPaths.forEach(element => {
element.value = suggestedSlug;
});
} else if (exists && !suggests.length) {
flash(__('Unable to suggest a path. Please refresh and try again.'));
}
})
.catch(() => flash(__('An error occurred while checking group path')));
.catch(() =>
flash(__('An error occurred while checking group path. Please refresh and try again.')),
);
}
}

View File

@ -1,6 +1,7 @@
import $ from 'jquery';
import { parseBoolean, getCookie, setCookie, removeCookie } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import Tracking from '~/tracking';
const COOKIE_NAME = 'onboarding_issues_settings';
@ -18,6 +19,7 @@ function disposePopover(event) {
event.preventDefault();
this.popover('dispose');
removeLearnGitLabCookie();
Tracking.event('Growth::Conversion::Experiment::OnboardingIssues', 'dismiss_popover');
}
const showPopover = (el, path, footer, options) => {

View File

@ -1,3 +1,3 @@
import initAvatarPicker from '~/avatar_picker';
import initFilePickers from '~/file_pickers';
document.addEventListener('DOMContentLoaded', initAvatarPicker);
document.addEventListener('DOMContentLoaded', initFilePickers);

View File

@ -1,9 +1,10 @@
import BindInOut from '../../../../behaviors/bind_in_out';
import Group from '../../../../group';
import initAvatarPicker from '~/avatar_picker';
import initFilePickers from '~/file_pickers';
document.addEventListener('DOMContentLoaded', () => {
BindInOut.initAll();
new Group(); // eslint-disable-line no-new
initAvatarPicker();
initFilePickers();
return new Group();
});

View File

@ -1,4 +1,4 @@
import initAvatarPicker from '~/avatar_picker';
import initFilePickers from '~/file_pickers';
import TransferDropdown from '~/groups/transfer_dropdown';
import initConfirmDangerModal from '~/confirm_danger_modal';
import initSettingsPanels from '~/settings_panels';
@ -10,8 +10,7 @@ import groupsSelect from '~/groups_select';
import projectSelect from '~/project_select';
document.addEventListener('DOMContentLoaded', () => {
initAvatarPicker();
new TransferDropdown(); // eslint-disable-line no-new
initFilePickers();
initConfirmDangerModal();
initSettingsPanels();
dirtySubmitFactory(
@ -24,4 +23,6 @@ document.addEventListener('DOMContentLoaded', () => {
groupsSelect();
projectSelect();
return new TransferDropdown();
});

View File

@ -1,8 +1,8 @@
import $ from 'jquery';
import BindInOut from '~/behaviors/bind_in_out';
import Group from '~/group';
import initAvatarPicker from '~/avatar_picker';
import GroupPathValidator from './group_path_validator';
import initFilePickers from '~/file_pickers';
document.addEventListener('DOMContentLoaded', () => {
const parentId = $('#group_parent_id');
@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => {
new GroupPathValidator(); // eslint-disable-line no-new
}
BindInOut.initAll();
new Group(); // eslint-disable-line no-new
initAvatarPicker();
initFilePickers();
return new Group();
});

View File

@ -4,12 +4,12 @@ import setupTransferEdit from '~/transfer_edit';
import initConfirmDangerModal from '~/confirm_danger_modal';
import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
import dirtySubmitFactory from '~/dirty_submit/dirty_submit_factory';
import initAvatarPicker from '~/avatar_picker';
import initFilePickers from '~/file_pickers';
import initProjectLoadingSpinner from '../shared/save_project_loader';
import initProjectPermissionsSettings from '../shared/permissions';
document.addEventListener('DOMContentLoaded', () => {
initAvatarPicker();
initFilePickers();
initConfirmDangerModal();
initSettingsPanels();
mountBadgeSettings(PROJECT_BADGE);

View File

@ -55,7 +55,7 @@ export default {
{
metric: 'redis',
header: s__('PerformanceBar|Redis calls'),
keys: ['cmd'],
keys: ['cmd', 'instance'],
},
{
metric: 'es',

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Types
module Snippets
class FileInputActionEnum < BaseEnum
graphql_name 'SnippetFileInputActionEnum'
description 'Type of a snippet file input action'
value 'create', value: :create
value 'update', value: :update
value 'delete', value: :delete
value 'move', value: :move
end
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
module Types
module Snippets
class FileInputType < BaseInputObject # rubocop:disable Graphql/AuthorizeTypes
graphql_name 'SnippetFileInputType'
description 'Represents an action to perform over a snippet file'
argument :action, Types::Snippets::FileInputActionEnum,
description: 'Type of input action',
required: true
argument :previous_path, GraphQL::STRING_TYPE,
description: 'Previous path of the snippet file',
required: false
argument :file_path, GraphQL::STRING_TYPE,
description: 'Path of the snippet file',
required: true
argument :content, GraphQL::STRING_TYPE,
description: 'Snippet file content',
required: false
end
end
end

View File

@ -26,6 +26,17 @@ module ApplicationSettingsHelper
end
end
def storage_weights
ApplicationSetting.repository_storages_weighted_attributes.map do |attribute|
storage = attribute.to_s.delete_prefix('repository_storages_weighted_')
{
name: attribute,
label: storage,
value: @application_setting.repository_storages_weighted[storage] || 0
}
end
end
def all_protocols_enabled?
Gitlab::CurrentSettings.enabled_git_access_protocol.blank?
end

View File

@ -734,7 +734,7 @@ module ProjectsHelper
end
def native_code_navigation_enabled?(project)
Feature.enabled?(:code_navigation, project)
Feature.enabled?(:code_navigation, project, default_enabled: true)
end
def show_visibility_confirm_modal?(project)

View File

@ -156,7 +156,6 @@ module AlertManagement
end
def execute_services
return unless Feature.enabled?(:alert_slack_event, project)
return unless project.has_active_services?(:alert_hooks)
project.execute_services(hook_data, :alert_hooks)

View File

@ -16,6 +16,9 @@ module Ci
has_many :sourced_pipelines, class_name: "::Ci::Sources::Pipeline",
foreign_key: :source_job_id
has_one :sourced_pipeline, class_name: "::Ci::Sources::Pipeline", foreign_key: :source_job_id
has_one :downstream_pipeline, through: :sourced_pipeline, source: :pipeline
validates :ref, presence: true
# rubocop:disable Cop/ActiveRecordSerialize

View File

@ -41,6 +41,7 @@ module Ci
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :processables, class_name: 'Ci::Processable', foreign_key: :commit_id, inverse_of: :pipeline
has_many :bridges, class_name: 'Ci::Bridge', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
has_many :job_artifacts, through: :builds
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent

View File

@ -30,7 +30,8 @@ module Ci
webide: 9,
merge_request_event: 10,
external_pull_request_event: 11,
parent_pipeline: 12
parent_pipeline: 12,
ondemand_scan: 13
}
end

View File

@ -18,7 +18,7 @@ module Ci
variables.concat(deployment_variables(environment: environment))
variables.concat(yaml_variables)
variables.concat(user_variables)
variables.concat(dependency_variables) if Feature.enabled?(:ci_dependency_variables, project)
variables.concat(dependency_variables)
variables.concat(secret_instance_variables)
variables.concat(secret_group_variables)
variables.concat(secret_project_variables(environment: environment))

View File

@ -1198,14 +1198,6 @@ class Project < ApplicationRecord
get_issue(issue_id)
end
def default_issue_tracker
gitlab_issue_tracker_service || create_gitlab_issue_tracker_service
end
def issues_tracker
external_issue_tracker || default_issue_tracker
end
def external_issue_reference_pattern
external_issue_tracker.class.reference_pattern(only_long: issues_enabled?)
end

View File

@ -414,7 +414,7 @@ class JiraService < IssueTrackerService
# Handle errors when doing Jira API calls
def jira_request
yield
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, URI::InvalidURIError, JIRA::HTTPError, OpenSSL::SSL::SSLError => error
rescue => error
@error = error
log_error("Error sending message", client_url: client_url, error: @error.message)
nil

View File

@ -25,7 +25,7 @@ class SlackService < ChatNotificationService
def supported_events
additional = []
additional << 'alert' if Feature.enabled?(:alert_slack_event, project)
additional << 'alert'
super + additional
end

View File

@ -78,7 +78,7 @@ class DiffsEntity < Grape::Entity
options[:merge_request_diffs]
end
expose :definition_path_prefix, if: -> (diff_file) { Feature.enabled?(:code_navigation, merge_request.project) } do |diffs|
expose :definition_path_prefix, if: -> (diff_file) { Feature.enabled?(:code_navigation, merge_request.project, default_enabled: true) } do |diffs|
project_blob_path(merge_request.project, diffs.diff_refs&.head_sha)
end
@ -89,7 +89,7 @@ class DiffsEntity < Grape::Entity
private
def code_navigation_path(diffs)
return unless Feature.enabled?(:code_navigation, merge_request.project)
return unless Feature.enabled?(:code_navigation, merge_request.project, default_enabled: true)
Gitlab::CodeNavigationPath.new(merge_request.project, diffs.diff_refs&.head_sha)
end

View File

@ -37,7 +37,7 @@ class PaginatedDiffEntity < Grape::Entity
private
def code_navigation_path(diffs)
return unless Feature.enabled?(:code_navigation, merge_request.project)
return unless Feature.enabled?(:code_navigation, merge_request.project, default_enabled: true)
Gitlab::CodeNavigationPath.new(merge_request.project, diffs.diff_refs&.head_sha)
end

View File

@ -36,7 +36,7 @@ module Ci
def code_navigation_enabled?
strong_memoize(:code_navigation_enabled) do
Feature.enabled?(:code_navigation, job.project)
Feature.enabled?(:code_navigation, job.project, default_enabled: true)
end
end

View File

@ -3,7 +3,7 @@
%fieldset
.form-group
= f.label :issues_create_limit, 'Max requests per second per user', class: 'label-bold'
= f.label :issues_create_limit, 'Max requests per minute per user', class: 'label-bold'
= f.number_field :issues_create_limit, class: 'form-control'
= f.submit 'Save changes', class: "btn btn-success", data: { qa_selector: 'save_changes_button' }

View File

@ -15,12 +15,12 @@
.form-group
.form-text
%p.text-secondary
= _('Select the configured storage available for new repositories to be placed on.')
= _('Select a weight for the storage new repositories will be placed on.')
= link_to icon('question-circle'), help_page_path('administration/repository_storage_paths')
.form-check
- @application_setting.repository_storages_weighted.each_key do |storage|
= f.text_field "repository_storages_weighted_#{storage}".to_sym, class: 'form-text-input'
= f.label storage, storage, class: 'label-bold form-check-label'
- storage_weights.each do |attribute|
= f.text_field attribute[:name], class: 'form-text-input', value: attribute[:value]
= f.label attribute[:label], attribute[:label], class: 'label-bold form-check-label'
%br
= f.submit _('Save changes'), class: "btn btn-success qa-save-changes-button"

View File

@ -0,0 +1,52 @@
- parent = @group.parent
- group_path = root_url
- group_path << parent.full_path + '/' if parent
= form_with url: import_gitlab_group_path, class: 'group-form gl-show-field-errors', multipart: true do |f|
= form_errors(@group)
.row
.form-group.group-name.col-sm-12
= f.label :name, _('Group name'), class: 'label-bold'
= f.text_field :name, placeholder: s_('GroupsNew|My Awesome Group'), class: 'js-autofill-group-name form-control input-lg',
required: true,
title: _('Please fill in a descriptive name for your group.'),
autofocus: true
.row
.form-group.col-xs-12.col-sm-8
= f.label :path, _('Group URL'), class: 'label-bold'
.input-group.gl-field-error-anchor
.group-root-path.input-group-prepend.has-tooltip{ title: group_path, :'data-placement' => 'bottom' }
.input-group-text
%span
= root_url
- if parent
%strong= parent.full_path + '/'
= f.hidden_field :parent_id, value: parent&.id
= f.text_field :path, placeholder: 'my-awesome-group', class: 'form-control js-validate-group-path js-autofill-group-path',
id: 'import_group_path',
required: true,
pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
title: _('Please choose a group URL with no special characters.'),
"data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
%p.validation-error.gl-field-error.field-validation.hide
= _('Group path is already taken. Suggestions: ')
%span.gl-path-suggestions
%p.validation-success.gl-field-success.field-validation.hide= _('Group path is available.')
%p.validation-pending.gl-field-error-ignore.field-validation.hide= _('Checking group path availability...')
.row
.form-group.col-md-12
= s_('GroupsNew|To copy a GitLab group between installations, navigate to the group settings page for the original installation, generate an export file, and upload it here.')
.row
.form-group.col-sm-12
= f.label :file, s_('GroupsNew|GitLab group export'), class: 'label-bold'
%div
= render 'shared/file_picker_button', f: f, field: :file, help_text: nil
.row
.form-actions.col-sm-12
= f.submit s_('GroupsNew|Import group'), class: 'btn btn-success'
= link_to _('Cancel'), new_group_path, class: 'btn btn-cancel'

View File

@ -0,0 +1,22 @@
= form_errors(@group)
= render 'shared/group_form', f: f, autofocus: true
.row
.form-group.group-description-holder.col-sm-12
= f.label :avatar, _("Group avatar"), class: 'label-bold'
%div
= render 'shared/choose_avatar_button', f: f
.form-group.col-sm-12
%label.label-bold
= _('Visibility level')
%p
= _('Who will be able to see this group?')
= link_to _('View the documentation'), help_page_path("public_access/public_access"), target: '_blank'
= render 'shared/visibility_level', f: f, visibility_level: default_group_visibility, can_change_visibility_level: true, form_model: @group, with_label: false
= render 'create_chat_team', f: f if Gitlab.config.mattermost.enabled
.form-actions.col-sm-12
= f.submit _('Create group'), class: "btn btn-success"
= link_to _('Cancel'), dashboard_groups_path, class: 'btn btn-cancel'

View File

@ -2,43 +2,44 @@
- @hide_top_links = true
- page_title _('New Group')
- header_title _("Groups"), dashboard_groups_path
- active_tab = local_assigns.fetch(:active_tab, 'create')
.page-title-holder.d-flex.align-items-center
%h1.page-title= _('New group')
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
%p
- group_docs_path = help_page_path('user/group/index')
- group_docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: group_docs_path }
= s_('%{group_docs_link_start}Groups%{group_docs_link_end} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects.').html_safe % { group_docs_link_start: group_docs_link_start, group_docs_link_end: '</a>'.html_safe }
%p
- subgroup_docs_path = help_page_path('user/group/subgroups/index')
- subgroup_docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: subgroup_docs_path }
= s_('Groups can also be nested by creating %{subgroup_docs_link_start}subgroups%{subgroup_docs_link_end}.').html_safe % { subgroup_docs_link_start: subgroup_docs_link_start, subgroup_docs_link_end: '</a>'.html_safe }
%p
= _('Projects that belong to a group are prefixed with the group namespace. Existing projects may be moved into a group.')
.group-edit-container.prepend-top-default
.row
.col-lg-3.group-settings-sidebar
%h4.prepend-top-0
= _('New group')
%p
- group_docs_path = help_page_path('user/group/index')
- group_docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: group_docs_path }
= s_('%{group_docs_link_start}Groups%{group_docs_link_end} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects.').html_safe % { group_docs_link_start: group_docs_link_start, group_docs_link_end: '</a>'.html_safe }
%p
- subgroup_docs_path = help_page_path('user/group/subgroups/index')
- subgroup_docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: subgroup_docs_path }
= s_('Groups can also be nested by creating %{subgroup_docs_link_start}subgroups%{subgroup_docs_link_end}.').html_safe % { subgroup_docs_link_start: subgroup_docs_link_start, subgroup_docs_link_end: '</a>'.html_safe }
%p
= _('Projects that belong to a group are prefixed with the group namespace. Existing projects may be moved into a group.')
.col-lg-9
= form_for @group, html: { class: 'group-form gl-show-field-errors' } do |f|
= form_errors(@group)
= render 'shared/group_form', f: f, autofocus: true
.col-lg-9.js-toggle-container
%ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
%li.nav-item{ role: 'presentation' }
%a.nav-link.active{ href: '#create-group-pane', id: 'create-group-tab', role: 'tab', data: { toggle: 'tab', track_label: 'create_group', track_event: 'click_tab', track_value: '' } }
%span.d-none.d-sm-block= s_('GroupsNew|Create group')
%span.d-block.d-sm-none= s_('GroupsNew|Create')
%li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#import-group-pane', id: 'import-group-tab', role: 'tab', data: { toggle: 'tab', track_label: 'import_group', track_event: 'click_tab', track_value: '' } }
%span.d-none.d-sm-block= s_('GroupsNew|Import group')
%span.d-block.d-sm-none= s_('GroupsNew|Import')
.row
.form-group.group-description-holder.col-sm-12
= f.label :avatar, _("Group avatar"), class: 'label-bold'
%div
= render 'shared/choose_avatar_button', f: f
.tab-content.gitlab-tab-content
.tab-pane.js-toggle-container{ id: 'create-group-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
= form_for @group, html: { class: 'group-form gl-show-field-errors' } do |f|
= render 'new_group_fields', f: f, group_name_id: 'create-group-name'
.form-group.col-sm-12
%label.label-bold
= _('Visibility level')
%p
= _('Who will be able to see this group?')
= link_to _('View the documentation'), help_page_path("public_access/public_access"), target: '_blank'
= render 'shared/visibility_level', f: f, visibility_level: default_group_visibility, can_change_visibility_level: true, form_model: @group, with_label: false
= render 'create_chat_team', f: f if Gitlab.config.mattermost.enabled
.form-actions
= f.submit _('Create group'), class: "btn btn-success"
= link_to _('Cancel'), dashboard_groups_path, class: 'btn btn-cancel'
.tab-pane.js-toggle-container{ id: 'import-group-pane', class: active_when(active_tab) == 'import', role: 'tabpanel' }
- if import_sources_enabled?
= render 'import_group_pane', active_tab: active_tab, autofocus: true
- else
.nothing-here-block
%h4= s_('GroupsNew|No import options available')
%p= s_('GroupsNew|Contact an administrator to enable options for importing your group.')

View File

@ -1,4 +1 @@
%button.btn.js-choose-avatar-button{ type: 'button' }= _("Choose file…")
%span.file_name.js-avatar-filename= _("No file chosen")
= f.file_field :avatar, class: "js-avatar-input hidden"
.form-text.text-muted= _("The maximum file size allowed is 200KB.")
= render 'shared/file_picker_button', f: f, field: :avatar, help_text: _("The maximum file size allowed is 200KB.")

View File

@ -0,0 +1,6 @@
%span.js-filepicker
%button.btn.js-filepicker-button{ type: 'button' }= _("Choose file…")
%span.file_name.js-filepicker-filename= _("No file chosen")
= f.file_field field, class: "js-filepicker-input hidden"
- if help_text.present?
.form-text.text-muted= help_text

View File

@ -6,7 +6,7 @@
.form-group.group-name-holder.col-sm-12
= f.label :name, class: 'label-bold' do
= _("Group name")
= f.text_field :name, placeholder: _('My Awesome Group'), class: 'form-control input-lg',
= f.text_field :name, placeholder: _('My Awesome Group'), class: 'js-autofill-group-name form-control input-lg',
required: true,
title: _('Please fill in a descriptive name for your group.'),
autofocus: true
@ -22,7 +22,7 @@
- if parent
%strong= parent.full_path + '/'
= f.hidden_field :parent_id
= f.text_field :path, placeholder: _('my-awesome-group'), class: 'form-control js-validate-group-path',
= f.text_field :path, placeholder: _('my-awesome-group'), class: 'form-control js-validate-group-path js-autofill-group-path',
autofocus: local_assigns[:autofocus] || false, required: true,
pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
title: _('Please choose a group URL with no special characters.'),

View File

@ -0,0 +1,5 @@
---
title: Add system check for CI JWT signing key
merge_request: 33920
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Enable CI Inheriting Env Variables feature
merge_request: 34495
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add route for the lost-and-found group and update the route of orphaned projects
merge_request: 34285
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Enable Slack notifications for alerts
merge_request: 34038
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Remove removeMilestone logic from issue model
merge_request: 32253
author: nuwe1
type: other

View File

@ -0,0 +1,5 @@
---
title: Add API endpoint for listing bridge jobs.
merge_request: 31370
author: Abhijith Sivarajan
type: added

View File

@ -0,0 +1,5 @@
---
title: Update issue limits template to use minutes
merge_request: 34254
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add GraphQL snippet FileInputType
merge_request: 34442
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Add native code intelligence
merge_request: 34542
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Show all storages in settings
merge_request: 34093
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Create Group import UI for creating new Groups
merge_request: 29271
author:
type: added

View File

@ -0,0 +1,6 @@
---
title: Add detailed logs of each Redis instance usage during job execution and web
requests
merge_request: 34110
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add Verify/FailFast CI template
merge_request: 31812
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Show Redis instance in performance bar
merge_request: 34377
author:
type: changed

View File

@ -17,6 +17,8 @@ class CreateMergeRequestAssigneesTable < ActiveRecord::Migration[5.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :merge_request_assignees
# rubocop:enable Migration/DropTable
end
end

View File

@ -193,7 +193,9 @@ class BackportEnterpriseSchema < ActiveRecord::Migration[5.0]
end
def drop_table_if_exists(table)
# rubocop:disable Migration/DropTable
drop_table(table) if table_exists?(table)
# rubocop:enable Migration/DropTable
end
def add_column_with_default_if_not_exists(table, name, *args)

View File

@ -15,6 +15,8 @@ class CreateMilestoneReleasesTable < ActiveRecord::Migration[5.2]
end
def down
# rubocop:disable Migration/DropTable
drop_table :milestone_releases
# rubocop:enable Migration/DropTable
end
end

View File

@ -24,6 +24,8 @@ class CreateDescriptionVersions < ActiveRecord::Migration[5.2]
def down
remove_column :system_note_metadata, :description_version_id
# rubocop:disable Migration/DropTable
drop_table :description_versions
# rubocop:enable Migration/DropTable
end
end

View File

@ -23,6 +23,8 @@ class AddGroupDeletionSchedules < ActiveRecord::Migration[5.2]
end
def down
# rubocop:disable Migration/DropTable
drop_table :group_deletion_schedules
# rubocop:enable Migration/DropTable
end
end

View File

@ -23,6 +23,8 @@ class CreateGitlabSubscriptionHistories < ActiveRecord::Migration[5.2]
end
def down
# rubocop:disable Migration/DropTable
drop_table :gitlab_subscription_histories
# rubocop:enable Migration/DropTable
end
end

View File

@ -7,7 +7,9 @@ class DropAnalyticsRepositoryFilesTable < ActiveRecord::Migration[5.2]
def up
# Requires ExclusiveLock on the table. Not in use, no records, no FKs.
# rubocop:disable Migration/DropTable
drop_table :analytics_repository_files
# rubocop:enable Migration/DropTable
end
def down

View File

@ -7,7 +7,9 @@ class DropAnalyticsRepositoryFileCommitsTable < ActiveRecord::Migration[5.2]
def up
# Requires ExclusiveLock on the table. Not in use, no records, no FKs.
# rubocop:disable Migration/DropTable
drop_table :analytics_repository_file_commits
# rubocop:enable Migration/DropTable
end
def down

View File

@ -7,7 +7,9 @@ class DropAnalyticsRepositoryFileEditsTable < ActiveRecord::Migration[5.2]
def up
# Requires ExclusiveLock on the table. Not in use, no records, no FKs.
# rubocop:disable Migration/DropTable
drop_table :analytics_repository_file_edits if table_exists?(:analytics_repository_file_edits) # this table might be already dropped on development environment
# rubocop:enable Migration/DropTable
end
def down

View File

@ -20,7 +20,9 @@ class AddCanonicalEmails < ActiveRecord::Migration[6.0]
def down
with_lock_retries do
# rubocop:disable Migration/DropTable
drop_table(:user_canonical_emails)
# rubocop:enable Migration/DropTable
end
end
end

View File

@ -8,6 +8,7 @@ class DropForkedProjectLinksTable < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
# rubocop:disable Migration/DropTable
drop_table "forked_project_links", id: :serial do |t|
t.integer "forked_to_project_id", null: false
t.integer "forked_from_project_id", null: false
@ -15,5 +16,6 @@ class DropForkedProjectLinksTable < ActiveRecord::Migration[6.0]
t.datetime "updated_at"
t.index ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true
end
# rubocop:enable Migration/DropTable
end
end

View File

@ -20,7 +20,9 @@ class CreateUserDetails < ActiveRecord::Migration[6.0]
def down
with_lock_retries do
# rubocop:disable Migration/DropTable
drop_table :user_details
# rubocop:enable Migration/DropTable
end
end
end

View File

@ -19,7 +19,9 @@ class CreateUserHighestRoles < ActiveRecord::Migration[6.0]
def down
with_lock_retries do
# rubocop:disable Migration/DropTable
drop_table :user_highest_roles
# rubocop:enable Migration/DropTable
end
end
end

View File

@ -30,6 +30,8 @@ class CreateDiffNotePositions < ActiveRecord::Migration[6.0]
# rubocop:enable Migration/AddLimitToTextColumns
def down
# rubocop:disable Migration/DropTable
drop_table :diff_note_positions
# rubocop:enable Migration/DropTable
end
end

View File

@ -9,7 +9,9 @@ class RecreateCiRef < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
# rubocop:disable Migration/DropTable
drop_table :ci_refs
# rubocop:enable Migration/DropTable
create_table :ci_refs do |t|
t.references :project, null: false, index: false, foreign_key: { on_delete: :cascade }, type: :bigint
@ -23,7 +25,9 @@ class RecreateCiRef < ActiveRecord::Migration[6.0]
def down
with_lock_retries do
# rubocop:disable Migration/DropTable
drop_table :ci_refs
# rubocop:enable Migration/DropTable
create_table :ci_refs do |t|
t.references :project, null: false, index: false, foreign_key: { on_delete: :cascade }, type: :integer

View File

@ -16,7 +16,9 @@ class AddProjectComplianceFrameworkSettingsTable < ActiveRecord::Migration[6.0]
def down
with_lock_retries do
# rubocop:disable Migration/DropTable
drop_table :project_compliance_framework_settings
# rubocop:enable Migration/DropTable
end
end
end

View File

@ -26,6 +26,8 @@ class CreatePartitionedForeignKeys < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :partitioned_foreign_keys
# rubocop:enable Migration/DropTable
end
end

View File

@ -26,6 +26,8 @@ class CreateProjectRepositoryStorageMoves < ActiveRecord::Migration[6.0]
remove_check_constraint(:project_repository_storage_moves, 'project_repository_storage_moves_source_storage_name')
remove_check_constraint(:project_repository_storage_moves, 'project_repository_storage_moves_destination_storage_name')
# rubocop:disable Migration/DropTable
drop_table :project_repository_storage_moves
# rubocop:enable Migration/DropTable
end
end

View File

@ -25,6 +25,8 @@ class CreateCiFreezePeriods < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :ci_freeze_periods
# rubocop:enable Migration/DropTable
end
end

View File

@ -15,6 +15,8 @@ class CreateStatusPagePublishedIncidents < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :status_page_published_incidents
# rubocop:enable Migration/DropTable
end
end

View File

@ -39,6 +39,8 @@ class CreateAlertManagementAlerts < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :alert_management_alerts
# rubocop:enable Migration/DropTable
end
end

View File

@ -20,6 +20,8 @@ class AddGroupImportStatesTable < ActiveRecord::Migration[6.0]
# rubocop:enable Migration/AddLimitToTextColumns
def down
# rubocop:disable Migration/DropTable
drop_table :group_import_states
# rubocop:enable Migration/DropTable
end
end

View File

@ -20,6 +20,8 @@ class CreateMetricsUsersStarredDashboard < ActiveRecord::Migration[6.0]
# rubocop: enable Migration/AddLimitToTextColumns
def down
# rubocop:disable Migration/DropTable
drop_table :metrics_users_starred_dashboards
# rubocop:enable Migration/DropTable
end
end

View File

@ -26,6 +26,8 @@ class CreateCiInstanceVariables < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :ci_instance_variables
# rubocop:enable Migration/DropTable
end
end

View File

@ -21,6 +21,8 @@ class CreateNugetDependencyLinkMetadata < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :packages_nuget_dependency_link_metadata
# rubocop:enable Migration/DropTable
end
end

View File

@ -29,6 +29,8 @@ class CreatePackagesNugetMetadata < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :packages_nuget_metadata
# rubocop:enable Migration/DropTable
end
end

View File

@ -31,6 +31,8 @@ class CreateGroupDeployKeys < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :group_deploy_keys
# rubocop:enable Migration/DropTable
end
end

View File

@ -17,6 +17,8 @@ class CreateAlertManagementAlertAssignees < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :alert_management_alert_assignees
# rubocop:enable Migration/DropTable
end
end

View File

@ -21,7 +21,9 @@ class CreateProjectSecuritySettings < ActiveRecord::Migration[6.0]
def down
with_lock_retries do
# rubocop:disable Migration/DropTable
drop_table :project_security_settings
# rubocop:enable Migration/DropTable
end
end
end

View File

@ -15,6 +15,8 @@ class CreateBoardUserPreferences < ActiveRecord::Migration[6.0]
end
def down
# rubocop:disable Migration/DropTable
drop_table :board_user_preferences
# rubocop:enable Migration/DropTable
end
end

View File

@ -0,0 +1,178 @@
# frozen_string_literal: true
# This migration adds or updates the routes for all the entities affected by
# post-migration '20200511083541_cleanup_projects_with_missing_namespace'
# - A route is added for the 'lost-and-found' group
# - A route is added for the Ghost user (if not already defined)
# - The routes for all the orphaned projects that were moved under the 'lost-and-found'
# group are updated to reflect the new path
class UpdateRoutesForLostAndFoundGroupAndOrphanedProjects < ActiveRecord::Migration[6.0]
DOWNTIME = false
class User < ActiveRecord::Base
self.table_name = 'users'
LOST_AND_FOUND_GROUP = 'lost-and-found'
USER_TYPE_GHOST = 5
ACCESS_LEVEL_OWNER = 50
has_one :namespace, -> { where(type: nil) },
foreign_key: :owner_id, inverse_of: :owner, autosave: true,
class_name: 'UpdateRoutesForLostAndFoundGroupAndOrphanedProjects::Namespace'
def lost_and_found_group
# Find the 'lost-and-found' group
# There should only be one Group owned by the Ghost user starting with 'lost-and-found'
Group
.joins('INNER JOIN members ON namespaces.id = members.source_id')
.where('namespaces.type = ?', 'Group')
.where('members.type = ?', 'GroupMember')
.where('members.source_type = ?', 'Namespace')
.where('members.user_id = ?', self.id)
.where('members.access_level = ?', ACCESS_LEVEL_OWNER)
.find_by(Group.arel_table[:name].matches("#{LOST_AND_FOUND_GROUP}%"))
end
class << self
# Return the ghost user
def ghost
User.find_by(user_type: USER_TYPE_GHOST)
end
end
end
# Temporary Concern to not repeat the same methods twice
module HasPath
extend ActiveSupport::Concern
def full_path
if parent && path
parent.full_path + '/' + path
else
path
end
end
def full_name
if parent && name
parent.full_name + ' / ' + name
else
name
end
end
end
class Namespace < ActiveRecord::Base
include HasPath
self.table_name = 'namespaces'
belongs_to :owner, class_name: 'UpdateRoutesForLostAndFoundGroupAndOrphanedProjects::User'
belongs_to :parent, class_name: "UpdateRoutesForLostAndFoundGroupAndOrphanedProjects::Namespace"
has_many :children, foreign_key: :parent_id,
class_name: "UpdateRoutesForLostAndFoundGroupAndOrphanedProjects::Namespace"
has_many :projects, class_name: "UpdateRoutesForLostAndFoundGroupAndOrphanedProjects::Project"
def ensure_route!
unless Route.for_source('Namespace', self.id)
Route.create!(
source_id: self.id,
source_type: 'Namespace',
path: self.full_path,
name: self.full_name
)
end
end
def generate_unique_path
# Generate a unique path if there is no route for the namespace
# (an existing route guarantees that the path is already unique)
unless Route.for_source('Namespace', self.id)
self.path = Uniquify.new.string(self.path) do |str|
Route.where(path: str).exists?
end
end
end
end
class Group < Namespace
# Disable STI to allow us to manually set "type = 'Group'"
# Otherwise rails forces "type = CleanupProjectsWithMissingNamespace::Group"
self.inheritance_column = :_type_disabled
end
class Route < ActiveRecord::Base
self.table_name = 'routes'
def self.for_source(source_type, source_id)
Route.find_by(source_type: source_type, source_id: source_id)
end
end
class Project < ActiveRecord::Base
include HasPath
self.table_name = 'projects'
belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id',
class_name: "UpdateRoutesForLostAndFoundGroupAndOrphanedProjects::Group"
belongs_to :namespace,
class_name: "UpdateRoutesForLostAndFoundGroupAndOrphanedProjects::Namespace"
alias_method :parent, :namespace
alias_attribute :parent_id, :namespace_id
def ensure_route!
Route.find_or_initialize_by(source_type: 'Project', source_id: self.id).tap do |record|
record.path = self.full_path
record.name = self.full_name
record.save!
end
end
end
def up
# Reset the column information of all the models that update the database
# to ensure the Active Record's knowledge of the table structure is current
Namespace.reset_column_information
Route.reset_column_information
# Find the ghost user, its namespace and the "lost and found" group
ghost_user = User.ghost
return unless ghost_user # No reason to continue if there is no Ghost user
ghost_namespace = ghost_user.namespace
lost_and_found_group = ghost_user.lost_and_found_group
# No reason to continue if there is no 'lost-and-found' group
# 1. No orphaned projects were found in this instance, or
# 2. The 'lost-and-found' group and the orphaned projects have been already deleted
return unless lost_and_found_group
# Update the 'lost-and-found' group description to be more self-explanatory
lost_and_found_group.generate_unique_path
lost_and_found_group.description =
'Group for storing projects that were not properly deleted. '\
'It should be considered as a system level Group with non-working '\
'projects inside it. The contents may be deleted with a future update. '\
'More info: gitlab.com/gitlab-org/gitlab/-/issues/198603'
lost_and_found_group.save!
# Update the routes for the Ghost user, the "lost and found" group
# and all the orphaned projects
ghost_namespace.ensure_route!
lost_and_found_group.ensure_route!
# The following does a fast index scan by namespace_id
# No reason to process in batches:
# - 66 projects in GitLab.com, less than 1ms execution time to fetch them
# with a constant update time for each
lost_and_found_group.projects.each do |project|
project.ensure_route!
end
end
def down
# no-op
end
end

View File

@ -13974,6 +13974,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200601210148
20200602013900
20200602013901
20200602143020
20200603073101
20200603180338
20200604143628

View File

@ -64,13 +64,17 @@ seconds:
1. `queue_duration_s`: total time that the request was queued inside GitLab Workhorse
1. `view_duration_s`: total time taken inside the Rails views
1. `db_duration_s`: total time to retrieve data from PostgreSQL
1. `redis_duration_s`: total time to retrieve data from Redis
1. `cpu_s`: total time spent on CPU
1. `gitaly_duration_s`: total time taken by Gitaly calls
1. `gitaly_calls`: total number of calls made to Gitaly
1. `redis_calls`: total number of calls made to Redis
1. `redis_duration_s`: total time to retrieve data from Redis
1. `redis_read_bytes`: total bytes read from Redis
1. `redis_write_bytes`: total bytes written to Redis
1. `redis_<instance>_calls`: total number of calls made to a Redis instance
1. `redis_<instance>_duration_s`: total time to retrieve data from a Redis instance
1. `redis_<instance>_read_bytes`: total bytes read from a Redis instance
1. `redis_<instance>_write_bytes`: total bytes written to a Redis instance
User clone and fetch activity using HTTP transport appears in this log as `action: git_upload_pack`.

View File

@ -208,7 +208,6 @@ control over how the Pages daemon runs and serves content in your environment.
| `gitlab_secret` | The OAuth application secret. Leave blank to automatically fill when Pages authenticates with GitLab.
| `gitlab_server` | Server to use for authentication when access control is enabled; defaults to GitLab `external_url`.
| `headers` | Specify any additional http headers that should be sent to the client with each response.
| `http_proxy` | Configure GitLab Pages to use an HTTP Proxy to mediate traffic between Pages and GitLab. Sets an environment variable `http_proxy` when starting Pages daemon.
| `inplace_chroot` | On [systems that don't support bind-mounts](index.md#additional-configuration-for-docker-container), this instructs GitLab Pages to chroot into its `pages_path` directory. Some caveats exist when using inplace chroot; refer to the GitLab Pages [README](https://gitlab.com/gitlab-org/gitlab-pages/blob/master/README.md#caveats) for more information.
| `insecure_ciphers` | Use default list of cipher suites, may contain insecure ones like 3DES and RC4.
| `internal_gitlab_server` | Internal GitLab server address used exclusively for API requests. Useful if you want to send that traffic over an internal load balancer. Defaults to GitLab `external_url`.
@ -226,6 +225,8 @@ control over how the Pages daemon runs and serves content in your environment.
| `tls_max_version` | Specifies the maximum SSL/TLS version ("ssl3", "tls1.0", "tls1.1" or "tls1.2").
| `tls_min_version` | Specifies the minimum SSL/TLS version ("ssl3", "tls1.0", "tls1.1" or "tls1.2").
| `use_http2` | Enable HTTP2 support.
| **gitlab_pages['env'][]** | |
| `http_proxy` | Configure GitLab Pages to use an HTTP Proxy to mediate traffic between Pages and GitLab. Sets an environment variable `http_proxy` when starting Pages daemon.
| **gitlab_rails[]** | |
| `pages_domain_verification_cron_worker` | Schedule for verifying custom GitLab Pages domains.
| `pages_domain_ssl_renewal_cron_worker` | Schedule for obtaining and renewing SSL certificates through Let's Encrypt for GitLab Pages domains.
@ -400,7 +401,7 @@ pages:
1. Configure in `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_pages['http_proxy'] = 'http://example:8080'
gitlab_pages['env']['http_proxy'] = 'http://example:8080'
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.

View File

@ -51,6 +51,40 @@ Hooks: /home/git/gitlab-shell/hooks/
Git: /usr/bin/git
```
## Show GitLab license information **(STARTER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20501) in GitLab Starter 12.6.
This command shows information about your [GitLab license](../../user/admin_area/license.md) and
how many seats are used. It is only available on GitLab Enterprise
installations: a license cannot be installed into GitLab Community Edition.
These may be useful when raising tickets with Support, or for programmatically
checking your license parameters.
**Omnibus Installation**
```shell
sudo gitlab-rake gitlab:license:info
```
**Source Installation**
```shell
bundle exec rake gitlab:license:info RAILS_ENV=production
```
Example output:
```plaintext
Today's Date: 2020-02-29
Current User Count: 30
Max Historical Count: 30
Max Users in License: 40
License valid from: 2019-11-29 to 2020-11-28
Email associated with license: user@example.com
```
## Check GitLab configuration
The `gitlab:check` Rake task runs the following Rake tasks:

View File

@ -7,11 +7,18 @@ For a full list of reference architectures, see
> - **Supported users (approximate):** 1,000
> - **High Availability:** False
| Users | Configuration([8](#footnotes)) | GCP | AWS | Azure |
|-------|--------------------------------|-----------------|----------------------|------------------------|
| 100 | 2 vCPU, 7.2GB Memory | `n1-standard-2` | `m5.large` | D2s v3 |
| 500 | 4 vCPU, 15GB Memory | `n1-standard-4` | `m5.xlarge` | D4s v3 |
| 1000 | 8 vCPU, 30GB Memory | `n1-standard-8` | `m5.2xlarge` | D8s v3 |
| Users | Configuration([8](#footnotes)) | GCP | AWS | Azure |
|-------|------------------------------------|----------------|---------------------|------------------------|
| 500 | 4 vCPU, 3.6GB Memory | `n1-highcpu-4` | `c5.xlarge` | F4s v2 |
| 1000 | 8 vCPU, 7.2GB Memory | `n1-highcpu-8` | `c5.2xlarge` | F8s v2 |
In addition to the above, we recommend having at least
2GB of swap on your server, even if you currently have
enough available RAM. Having swap will help reduce the chance of errors occurring
if your available memory changes. We also recommend
configuring the kernel's swappiness setting
to a low value like `10` to make the most of your RAM while still having the swap
available when needed.
For situations where you need to serve up to 1,000 users, a single-node
solution with [frequent backups](index.md#automated-backups-core-only) is appropriate

View File

@ -171,6 +171,25 @@ column.
| [GitLab application services](../../development/architecture.md#unicorn)([1](#footnotes)) | Puma/Unicorn, Workhorse, GitLab Shell - serves front-end requests (UI, API, Git over HTTP/SSH) | [GitLab app scaling configuration](../high_availability/gitlab.md) | Yes |
| [Prometheus](../../development/architecture.md#prometheus) and [Grafana](../../development/architecture.md#grafana) | GitLab environment monitoring | [Monitoring node for scaling](../high_availability/monitoring_node.md) | Yes |
### Configuring select components with Cloud Native Helm
We also provide [Helm charts](https://docs.gitlab.com/charts/) as a Cloud Native installation
method for GitLab. For the reference architectures, select components can be set up in this
way as an alternative if so desired.
For these kind of setups we support using the charts in an [advanced configuration](https://docs.gitlab.com/charts/#advanced-configuration)
where stateful backend components, such as the database or Gitaly, are run externally - either
via Omnibus or reputable third party services. Note that we don't currently support running the
stateful components via Helm _at large scales_.
When designing these environments you should refer to the respective [Reference Architecture](#available-reference-architectures)
above for guidance on sizing. Components run via Helm would be similarly scaled to their Omnibus
specs, only translated into Kubernetes resources.
For example, if you were to set up a 50k installation with the Rails nodes being run in Helm,
then the same amount of resources as given for Omnibus should be given to the Kubernetes
cluster with the Rails nodes broken down into a number of smaller Pods across that cluster.
## Footnotes
1. In our architectures we run each GitLab Rails node using the Puma webserver

View File

@ -269,6 +269,90 @@ Example of response
]
```
## List pipeline bridges
Get a list of bridge jobs for a pipeline.
```plaintext
GET /projects/:id/pipelines/:pipeline_id/bridges
```
| Attribute | Type | Required | Description |
|---------------|--------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
| `pipeline_id` | integer | yes | ID of a pipeline. |
| `scope` | string **or** array of strings | no | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/1/pipelines/6/bridges?scope[]=pending&scope[]=running'
```
Example of response
```json
[
{
"commit": {
"author_email": "admin@example.com",
"author_name": "Administrator",
"created_at": "2015-12-24T16:51:14.000+01:00",
"id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
"message": "Test the CI integration.",
"short_id": "0ff3ae19",
"title": "Test the CI integration."
},
"coverage": null,
"allow_failure": false,
"created_at": "2015-12-24T15:51:21.802Z",
"started_at": "2015-12-24T17:54:27.722Z",
"finished_at": "2015-12-24T17:58:27.895Z",
"duration": 240,
"id": 7,
"name": "teaspoon",
"pipeline": {
"id": 6,
"ref": "master",
"sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
"status": "pending",
"created_at": "2015-12-24T15:50:16.123Z",
"updated_at": "2015-12-24T18:00:44.432Z",
"web_url": "https://example.com/foo/bar/pipelines/6"
},
"ref": "master",
"stage": "test",
"status": "pending",
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/7",
"user": {
"id": 1,
"name": "Administrator",
"username": "root",
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
"created_at": "2015-12-21T13:14:24.077Z",
"bio": null,
"location": null,
"public_email": "",
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
"organization": ""
},
"downstream_pipeline": {
"id": 5,
"sha": "f62a4b2fb89754372a346f24659212eb8da13601",
"ref": "master",
"status": "pending",
"created_at": "2015-12-24T17:54:27.722Z",
"updated_at": "2015-12-24T17:58:27.896Z",
"web_url": "https://example.com/diaspora/diaspora-client/pipelines/5"
}
}
]
```
## Get a single job
Get a single job of a project

View File

@ -474,8 +474,8 @@ Feature.enable(:instance_variables_ui)
## Inherit environment variables
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22638) in GitLab 13.0.
> - It's deployed behind a feature flag (`ci_dependency_variables`), disabled by default.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22638) in GitLab 13.0 behind a disabled [feature flag](../../administration/feature_flags.md): `ci_dependency_variables`.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/217834) in GitLab 13.1.
You can inherit environment variables from dependent jobs.
@ -520,25 +520,6 @@ deploy:
artifacts: true
```
### Enable inherited environment variables **(CORE ONLY)**
The Inherited Environment Variables feature is under development and not ready for production use. It is
deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can enable it for your instance.
To enable it:
```ruby
Feature.enable(:ci_dependency_variables)
```
To disable it:
```ruby
Feature.disable(:ci_dependency_variables)
```
## Priority of environment variables
Variables of different types can take precedence over other

View File

@ -92,42 +92,31 @@ NOTE: **Note:** Since file system performance may affect GitLab's overall perfor
### CPU
This is the recommended minimum hardware for a handful of example GitLab user base sizes. Your exact needs may be more, depending on your workload. Your workload is influenced by factors such as - but not limited to - how active your users are, how much automation you use, mirroring, and repository/change size.
CPU requirements are dependent on the number of users and expected workload. Your exact needs may be more, depending on your workload. Your workload is influenced by factors such as - but not limited to - how active your users are, how much automation you use, mirroring, and repo/change size.
- 1 core supports up to 100 users but the application can be a bit slower due to having all workers and background jobs running on the same core
- **2 cores** is the **recommended** minimum number of cores and supports up to 100 users
- 4 cores support up to 500 users
- 8 cores support up to 1,000 users
- 32 cores support up to 5,000 users
The following is the recommended minimum CPU hardware guidance for a handful of example GitLab user base sizes.
- **4 cores** is the **recommended** minimum number of cores and supports up to 500 users
- 8 cores supports up to 1000 users
- More users? Consult the [reference architectures page](../administration/reference_architectures/index.md)
### Memory
This is the recommended minimum hardware for a handful of example GitLab user base sizes. Your exact needs may be more, depending on your workload. Your workload is influenced by factors such as - but not limited to - how active your users are, how much automation you use, mirroring, and the size of repositories as well as changes/commits.
Memory requirements are dependent on the number of users and expected workload. Your exact needs may be more, depending on your workload. Your workload is influenced by factors such as - but not limited to - how active your users are, how much automation you use, mirroring, and repo/change size.
You need at least 8GB of addressable memory (RAM + swap) to install and use GitLab!
The operating system and any other running applications will also be using memory
so keep in mind that you need at least 4GB available before running GitLab. With
less memory GitLab will give strange errors during the reconfigure run and 500
errors during usage.
The following is the recommended minimum Memory hardware guidance for a handful of example GitLab user base sizes.
- 4GB RAM + 4GB swap supports up to 100 users but it will be very slow
- **8GB RAM** is the **recommended** minimum memory size for all installations and supports up to 100 users
- 16GB RAM supports up to 500 users
- 32GB RAM supports up to 1,000 users
- 128GB RAM supports up to 5,000 users
- **4GB RAM** is the **required** minimum memory size and supports up to 500 users
- Our [Memory Team](https://about.gitlab.com/handbook/engineering/development/enablement/memory/) is working to reduce the memory requirement.
- 8GB RAM supports up to 1000 users
- More users? Consult the [reference architectures page](../administration/reference_architectures/index.md)
We recommend having at least [2GB of swap on your server](https://askubuntu.com/a/505344/310789), even if you currently have
enough available RAM. Having swap will help reduce the chance of errors occurring
if your available memory changes. We also recommend [configuring the kernel's swappiness setting](https://askubuntu.com/a/103916)
In addition to the above, we generally recommend having at least 2GB of swap on your server,
even if you currently have enough available RAM. Having swap will help reduce the chance of errors occurring
if your available memory changes. We also recommend configuring the kernel's swappiness setting
to a low value like `10` to make the most of your RAM while still having the swap
available when needed.
Our [Memory Team](https://about.gitlab.com/handbook/engineering/development/enablement/memory/) is actively working to reduce the memory requirement.
NOTE: **Note:** The 25 workers of Sidekiq will show up as separate processes in your process overview (such as `top` or `htop`). However, they share the same RAM allocation, as Sidekiq is a multi-threaded application. See the section below about Unicorn workers for information about how many you need for those.
## Database
PostgreSQL is the only supported database, which is bundled with the Omnibus GitLab package.
@ -168,22 +157,6 @@ If you're using [GitLab Geo](../administration/geo/replication/index.md):
[can be enabled](https://www.postgresql.org/docs/11/sql-createextension.html)
using a PostgreSQL super user.
## Unicorn Workers
For most instances we recommend using: (CPU cores * 1.5) + 1 = Unicorn workers.
For example a node with 4 cores would have 7 Unicorn workers.
For all machines that have 2GB and up we recommend a minimum of three Unicorn workers.
If you have a 1GB machine we recommend to configure only two Unicorn workers to prevent excessive
swapping.
As long as you have enough available CPU and memory capacity, it's okay to increase the number of
Unicorn workers and this will usually help to reduce the response time of the applications and
increase the ability to handle parallel requests.
To change the Unicorn workers when you have the Omnibus package (which defaults to the
recommendation above) please see [the Unicorn settings in the Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/settings/unicorn.html).
## Puma settings
The recommended settings for Puma are determined by the infrastructure on which it's running.
@ -219,6 +192,22 @@ of [legacy Rugged code](../development/gitaly.md#legacy-rugged-code).
higher, due to how [Ruby MRI multi-threading](https://en.wikipedia.org/wiki/Global_interpreter_lock)
works.
## Unicorn Workers
For most instances we recommend using: (CPU cores * 1.5) + 1 = Unicorn workers.
For example a node with 4 cores would have 7 Unicorn workers.
For all machines that have 2GB and up we recommend a minimum of three Unicorn workers.
If you have a 1GB machine we recommend to configure only two Unicorn workers to prevent excessive
swapping.
As long as you have enough available CPU and memory capacity, it's okay to increase the number of
Unicorn workers and this will usually help to reduce the response time of the applications and
increase the ability to handle parallel requests.
To change the Unicorn workers when you have the Omnibus package (which defaults to the
recommendation above) please see [the Unicorn settings in the Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/settings/unicorn.html).
## Redis and Sidekiq
Redis stores all user sessions and the background task queue.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,5 +1,8 @@
---
type: reference
stage: Plan
group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Rate limits on issue creation
@ -14,7 +17,7 @@ For example, requests using the
[Projects::IssuesController#create](https://gitlab.com/gitlab-org/gitlab/raw/master/app/controllers/projects/issues_controller.rb)
action exceeding a rate of 300 per minute are blocked. Access to the endpoint is allowed after one minute.
![Rate limits on issues creation](img/rate_limit_on_issues_creation.png)
![Rate limits on issues creation](img/rate_limit_on_issues_creation_v13_1.png)
This limit is:

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -55,14 +55,19 @@ generates for you. GitLab supports the following scanners:
is only available for Node.js projects managed with `yarn`.
- [Container Scanning](../container_scanning/index.md).
When an automatic solution is available, the button in the header will show "Resolve with merge request":
![Resolve with Merge Request button](img/standalone_vulnerability_page_merge_request_button_v13_1.png)
Selecting the button will create a merge request with the automatic solution.
### Manually applying a suggested patch
To apply a patch automatically generated by GitLab to fix a vulnerability:
To manually apply the patch that was generated by GitLab for a vulnerability, select the dropdown arrow on the "Resolve
with merge request" button, then select the "Download patch to resolve" option:
1. Open the issue created in [Create issue](#creating-an-issue-for-a-vulnerability).
1. In the **Issue description**, scroll to **Solution** and download the linked patch file.
1. Ensure your local project has the same commit checked out that was used to generate the patch.
1. Run `git apply remediation.patch` to apply the patch.
1. Verify and commit the changes to your branch.
![Resolve with Merge Request button dropdown](img/standalone_vulnerability_page_merge_request_button_dropdown_v13_1.png)
![Apply patch for dependency scanning](../img/vulnerability_solution.png)
This will change the button text to "Download patch to resolve". Click on it to download the patch:
![Download patch button](img/standalone_vulnerability_page_download_patch_button_v13_1.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Some files were not shown because too many files have changed in this diff Show More