Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-06-09 15:08:05 +00:00
parent ea054ec1c3
commit 6ff3eb60e3
112 changed files with 1794 additions and 428 deletions

1
.gitignore vendored
View File

@ -93,3 +93,4 @@ webpack-dev-server.json
.solargraph.yml
apollo.config.js
/tmp/matching_foss_tests.txt
ee/changelogs/unreleased-ee

View File

@ -43,6 +43,7 @@ const boardsStore = {
},
detail: {
issue: {},
list: {},
},
moving: {
issue: {},
@ -74,6 +75,7 @@ const boardsStore = {
this.filter.path = getUrlParamsArray().join('&');
this.detail = {
issue: {},
list: {},
};
},
showPage(page) {

View File

@ -2,7 +2,7 @@ import Service from '../../services';
import * as types from './mutation_types';
import createFlash from '~/flash';
import Poll from '~/lib/utils/poll';
import { __, sprintf } from '~/locale';
import { __ } from '~/locale';
let eTagPoll;
@ -31,17 +31,9 @@ export function startPolling({ state, commit, dispatch }) {
commit(types.SET_LOADING, false);
dispatch('stopPolling');
},
errorCallback: ({ response }) => {
let errorMessage = '';
if (response && response.data && response.data.message) {
errorMessage = response.data.message;
}
errorCallback: () => {
commit(types.SET_LOADING, false);
createFlash(
sprintf(__(`Failed to load errors from Sentry. Error message: %{errorMessage}`), {
errorMessage,
}),
);
createFlash(__('Failed to load errors from Sentry.'));
},
});

View File

@ -1,5 +1,5 @@
<script>
import { GlAlert } from '@gitlab/ui';
import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import DagGraph from './dag_graph.vue';
@ -12,6 +12,8 @@ export default {
components: {
DagGraph,
GlAlert,
GlLink,
GlSprintf,
},
props: {
graphUrl: {
@ -23,6 +25,7 @@ export default {
data() {
return {
showFailureAlert: false,
showBetaInfo: true,
failureType: null,
graphData: null,
};
@ -34,6 +37,11 @@ export default {
[DEFAULT]: __('An unknown error occurred while loading this graph.'),
},
computed: {
betaMessage() {
return __(
'This feature is currently in beta. We invite you to %{linkStart}give feedback%{linkEnd}.',
);
},
failure() {
switch (this.failureType) {
case LOAD_FAILURE:
@ -98,6 +106,9 @@ export default {
hideAlert() {
this.showFailureAlert = false;
},
hideBetaInfo() {
this.showBetaInfo = false;
},
reportFailure(type) {
this.showFailureAlert = true;
this.failureType = type;
@ -110,6 +121,16 @@ export default {
<gl-alert v-if="showFailureAlert" :variant="failure.variant" @dismiss="hideAlert">
{{ failure.text }}
</gl-alert>
<gl-alert v-if="showBetaInfo" @dismiss="hideBetaInfo">
<gl-sprintf :message="betaMessage">
<template #link="{ content }">
<gl-link href="https://gitlab.com/gitlab-org/gitlab/-/issues/220368" target="_blank">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</gl-alert>
<dag-graph v-if="shouldDisplayGraph" :graph-data="graphData" @onFailure="reportFailure" />
</div>
</template>

View File

@ -14,8 +14,6 @@
}
.broadcast-banner-message {
@extend .broadcast-message;
@extend .alert-warning;
text-align: center;
.broadcast-message-dismiss {
@ -24,8 +22,6 @@
}
.broadcast-notification-message {
@extend .broadcast-message;
position: fixed;
bottom: $gl-padding;
right: $gl-padding;

View File

@ -14,7 +14,7 @@ module WorkhorseImportExportUpload
authorized = ImportExportUploader.workhorse_authorize(
has_length: false,
maximum_size: ImportExportUpload::MAXIMUM_IMPORT_FILE_SIZE
maximum_size: Gitlab::CurrentSettings.max_import_size.megabytes
)
render json: authorized

View File

@ -13,7 +13,7 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:junit_pipeline_view, project)
push_frontend_feature_flag(:filter_pipelines_search, default_enabled: true)
push_frontend_feature_flag(:dag_pipeline_tab)
push_frontend_feature_flag(:dag_pipeline_tab, default_enabled: true)
push_frontend_feature_flag(:pipelines_security_report_summary, project)
end
before_action :ensure_pipeline, only: [:show]

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Types
class AccessLevelEnum < BaseEnum
graphql_name 'AccessLevelEnum'
description 'Access level to a resource'
value 'NO_ACCESS', value: Gitlab::Access::NO_ACCESS
value 'GUEST', value: Gitlab::Access::GUEST
value 'REPORTER', value: Gitlab::Access::REPORTER
value 'DEVELOPER', value: Gitlab::Access::DEVELOPER
value 'MAINTAINER', value: Gitlab::Access::MAINTAINER
value 'OWNER', value: Gitlab::Access::OWNER
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
class AccessLevelType < Types::BaseObject
graphql_name 'AccessLevel'
description 'Represents the access level of a relationship between a User and object that it is related to'
field :integer_value, GraphQL::INT_TYPE, null: true,
description: 'Integer representation of access level',
method: :to_i
field :string_value, Types::AccessLevelEnum, null: true,
description: 'String representation of access level',
method: :to_i
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
module Types
class GroupMemberType < BaseObject
expose_permissions Types::PermissionTypes::Group
authorize :read_group
implements MemberInterface
graphql_name 'GroupMember'
description 'Represents a Group Member'
field :group, Types::GroupType, null: true,
description: 'Group that a User is a member of',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.source_id).find }
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Types
module MemberInterface
include BaseInterface
field :access_level, Types::AccessLevelType, null: true,
description: 'GitLab::Access level'
field :created_by, Types::UserType, null: true,
description: 'User that authorized membership'
field :created_at, Types::TimeType, null: true,
description: 'Date and time the membership was created'
field :updated_at, Types::TimeType, null: true,
description: 'Date and time the membership was last updated'
field :expires_at, Types::TimeType, null: true,
description: 'Date and time the membership expires'
end
end

View File

@ -3,18 +3,23 @@
module Types
class ProjectMemberType < BaseObject
graphql_name 'ProjectMember'
description 'Member of a project'
description 'Represents a Project Member'
expose_permissions Types::PermissionTypes::Project
implements MemberInterface
authorize :read_project
field :id, GraphQL::ID_TYPE, null: false,
description: 'ID of the member'
field :access_level, GraphQL::INT_TYPE, null: false,
description: 'Access level of the member'
field :user, Types::UserType, null: false,
description: 'User that is associated with the member object',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.user_id).find }
field :project, Types::ProjectType, null: true,
description: 'Project that User is a member of',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, obj.source_id).find }
end
end

View File

@ -25,6 +25,12 @@ module Types
field :todos, Types::TodoType.connection_type, null: false,
resolver: Resolvers::TodoResolver,
description: 'Todos of the user'
field :group_memberships, Types::GroupMemberType.connection_type, null: true,
description: 'Group memberships of the user',
method: :group_members
field :project_memberships, Types::ProjectMemberType.connection_type, null: true,
description: 'Project memberships of the user',
method: :project_members
# Merge request field: MRs can be either authored or assigned:
field :authored_merge_requests, Types::MergeRequestType.connection_type, null: true,

View File

@ -228,6 +228,7 @@ module ApplicationSettingsHelper
:import_sources,
:max_artifacts_size,
:max_attachment_size,
:max_import_size,
:max_pages_size,
:metrics_method_call_threshold,
:minimum_password_length,

View File

@ -143,6 +143,10 @@ class ApplicationSetting < ApplicationRecord
presence: true,
numericality: { only_integer: true, greater_than: 0 }
validates :max_import_size,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :max_pages_size,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0,

View File

@ -86,6 +86,7 @@ module ApplicationSettingImplementation
local_markdown_version: 0,
max_artifacts_size: Settings.artifacts['max_size'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
max_import_size: 50,
mirror_available: true,
outbound_local_requests_whitelist: [],
password_authentication_enabled_for_git: true,

View File

@ -6,6 +6,10 @@ module Ci
extend Gitlab::ProcessMemoryCache::Helper
include Ci::NewHasVariable
include Ci::Maskable
include Limitable
self.limit_name = 'ci_instance_level_variables'
self.limit_scope = Limitable::GLOBAL_SCOPE
alias_attribute :secret_value, :value
@ -41,5 +45,13 @@ module Ci
end
end
end
private
def validate_plan_limit_not_exceeded
if Gitlab::Ci::Features.instance_level_variables_limit_enabled?
super
end
end
end
end

View File

@ -4,8 +4,6 @@ class ImportExportUpload < ApplicationRecord
include WithUploads
include ObjectStorage::BackgroundMove
MAXIMUM_IMPORT_FILE_SIZE = 50.megabytes.freeze
belongs_to :project
belongs_to :group

View File

@ -28,6 +28,10 @@
.form-group
= f.label :receive_max_input_size, _('Maximum push size (MB)'), class: 'label-light'
= f.number_field :receive_max_input_size, class: 'form-control qa-receive-max-input-size-field', title: _('Maximum size limit for a single commit.'), data: { toggle: 'tooltip', container: 'body' }
.form-group
= f.label :max_import_size, _('Maximum import size (MB)'), class: 'label-light'
= f.number_field :max_import_size, class: 'form-control qa-receive-max-import-size-field', title: _('Maximum size of import files.'), data: { toggle: 'tooltip', container: 'body' }
%span.form-text.text-muted= _('0 for unlimited, only effective with remote storage enabled.')
.form-group
= f.label :session_expire_delay, _('Session duration (minutes)'), class: 'label-light'
= f.number_field :session_expire_delay, class: 'form-control', title: _('Maximum duration of a session.'), data: { toggle: 'tooltip', container: 'body' }

View File

@ -1,4 +1,4 @@
.broadcast-banner-message.js-broadcast-banner-message-preview.mt-2{ style: broadcast_message_style(@broadcast_message), class: ('hidden' unless @broadcast_message.banner? ) }
.broadcast-message.broadcast-banner-message.alert-warning.js-broadcast-banner-message-preview.mt-2{ style: broadcast_message_style(@broadcast_message), class: ('hidden' unless @broadcast_message.banner? ) }
= sprite_icon('bullhorn', size: 16, css_class:'vertical-align-text-top')
.js-broadcast-message-preview
- if @broadcast_message.message.present?
@ -6,7 +6,7 @@
- else
Your message here
.d-flex.justify-content-center
.broadcast-notification-message.preview.js-broadcast-notification-message-preview.mt-2{ class: ('hidden' unless @broadcast_message.notification? ) }
.broadcast-message.broadcast-notification-message.preview.js-broadcast-notification-message-preview.mt-2{ class: ('hidden' unless @broadcast_message.notification? ) }
= sprite_icon('bullhorn', size: 16, css_class:'vertical-align-text-top')
.js-broadcast-message-preview
- if @broadcast_message.message.present?

View File

@ -10,6 +10,7 @@
%li.js-dag-tab-link
= link_to dag_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-dag', action: 'dag', toggle: 'tab' }, class: 'dag-tab' do
= _('DAG')
%span.badge-pill.gl-badge.sm.gl-bg-blue-500.gl-text-white.gl-ml-2= _('Beta')
%li.js-builds-tab-link
= link_to builds_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-builds', action: 'builds', toggle: 'tab' }, class: 'builds-tab' do
= _('Jobs')

View File

@ -1,4 +1,6 @@
%div{ class: "broadcast-#{message.broadcast_type}-message #{opts[:preview] && 'preview'} js-broadcast-notification-#{message.id} d-flex",
- is_banner = message.broadcast_type == 'banner'
%div{ class: "broadcast-message #{'alert-warning' if is_banner} broadcast-#{message.broadcast_type}-message #{opts[:preview] && 'preview'} js-broadcast-notification-#{message.id} gl-display-flex",
style: broadcast_message_style(message), dir: 'auto' }
.flex-grow-1.text-right.pr-2
= sprite_icon('bullhorn', size: 16, css_class: 'vertical-align-text-top')

View File

@ -0,0 +1,5 @@
---
title: Add DAG visualization MVC
merge_request: 33958
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Adds groupMembership and projectMembership to GraphQL API
merge_request: 33049
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add application limits to instance level CI/CD variables
merge_request: 32575
author:
type: added

View File

@ -0,0 +1,6 @@
---
title: Add number of database calls to Prometheus metrics and logs for sidekiq and
request
merge_request: 32131
author:
type: added

View File

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

View File

@ -0,0 +1,5 @@
---
title: Update text in error tracking list error message
merge_request: 33872
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add max import file size option
merge_request: 33215
author: Roger Meier
type: added

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddInstanceLevelVariablesColumnToPlanLimits < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :plan_limits, :ci_instance_level_variables, :integer, default: 25, null: false
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class AddMaxImportSize < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
add_column(:application_settings, :max_import_size, :integer, default: 50, null: false)
end
def down
remove_column(:application_settings, :max_import_size)
end
end

View File

@ -1,167 +0,0 @@
# 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
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.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

@ -458,6 +458,7 @@ CREATE TABLE public.application_settings (
spam_check_endpoint_enabled boolean DEFAULT false NOT NULL,
elasticsearch_pause_indexing boolean DEFAULT false NOT NULL,
repository_storages_weighted jsonb DEFAULT '{}'::jsonb NOT NULL,
max_import_size integer DEFAULT 50 NOT NULL,
CONSTRAINT check_d03919528d CHECK ((char_length(container_registry_vendor) <= 255)),
CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)),
CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255))
@ -4915,7 +4916,8 @@ CREATE TABLE public.plan_limits (
group_hooks integer DEFAULT 50 NOT NULL,
ci_project_subscriptions integer DEFAULT 2 NOT NULL,
ci_pipeline_schedules integer DEFAULT 10 NOT NULL,
offset_pagination_limit integer DEFAULT 50000 NOT NULL
offset_pagination_limit integer DEFAULT 50000 NOT NULL,
ci_instance_level_variables integer DEFAULT 25 NOT NULL
);
CREATE SEQUENCE public.plan_limits_id_seq
@ -13772,6 +13774,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200519074709
20200519101002
20200519115908
20200519141534
20200519171058
20200519194042
20200520103514
@ -13796,12 +13799,12 @@ COPY "schema_migrations" (version) FROM STDIN;
20200527151413
20200527152116
20200527152657
20200527211000
20200528054112
20200528123703
20200528125905
20200528171933
20200601210148
20200602143020
20200603073101
\.

View File

@ -1,8 +1,11 @@
---
# Warning: gitlab.Acronyms
#
# Checks for unexpanded acronyms.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: conditional
message: "'%s' has no definition."
message: '"%s" has no definition.'
link: https://about.gitlab.com/handbook/marketing/growth-marketing/content/editorial-team/#acronyms
level: warning
ignorecase: false
@ -60,4 +63,3 @@ exceptions:
- WIP
- XML
- YAML

View File

@ -1,7 +1,7 @@
---
# Error: gitlab.BadgeCapitalization
#
# Verifies that badges are not lower case, which won't render properly.
# Verifies that badges are not mixed case, which won't render properly.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence

View File

@ -1,11 +1,11 @@
---
# Error: gitlab.British
#
# Checks for use of some of the top misused terms at GitLab.
# Checks that US spelling is used over British spelling.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: substitution
message: 'Use the American spelling "%s" instead of the British "%s".'
message: 'Use the US spelling "%s" instead of the British "%s".'
link: https://about.gitlab.com/handbook/communication/#top-misused-terms
level: error
ignorecase: true

View File

@ -1,7 +1,7 @@
---
# Error: gitlab.CodeblockFences
#
# Ensures all codeblock fences use the full name for the language.
# Ensures all codeblock language tags use the full name, not aliases.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence

View File

@ -1,9 +1,11 @@
---
# Suggestion: gitlab.Contractions
#
# Checks for use of common and uncommon contractions.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: substitution
message: Use "%s" instead of "%s", for a friendly, informal tone.
message: 'Use "%s" instead of "%s", for a friendly, informal tone.'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language
level: suggestion
nonword: false

View File

@ -1,5 +1,5 @@
---
# Error: gitlab.CurlStringsQuoted
# Warning: gitlab.CurlStringsQuoted
#
# Ensures all codeblocks using curl quote any URL strings.
#

View File

@ -1,8 +1,11 @@
---
# Warning: gitlab.FirstPerson
#
# Checks for use of first person pronouns.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence
message: '`%s` is a first-person pronoun. Use second- or third-person pronouns (like we, you, us, one) instead.'
message: '"%s" is a first-person pronoun. Use second- or third-person pronouns (like we, you, us, one) instead.'
level: warning
ignorecase: true
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language

View File

@ -5,7 +5,7 @@
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence
message: Link %s must use the .md file extension.
message: 'Link "%s" must use the .md file extension.'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#links-to-internal-documentation
level: error
scope: raw

View File

@ -1,9 +1,11 @@
---
# Checks for use of latin terms..
# Warning: gitlab.LatinTerms
#
# Checks for use of latin terms.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: substitution
message: Use "%s" instead of "%s," but consider rewriting the sentence.
message: 'Use "%s" instead of "%s", but consider rewriting the sentence.'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language
level: warning
nonword: true

View File

@ -1,5 +1,5 @@
---
# Error: gitlab.MeaningfulLinkWords
# Warning: gitlab.MeaningfulLinkWords
#
# Checks for the presence of semantically unhelpful words in link text.
#

View File

@ -1,10 +1,12 @@
---
# Warning: gitlab.OxfordComma
#
# Checks for the lack of an Oxford comma. In some cases, will catch overly
# complex sentence structures with lots of commas.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence
message: Use a comma before the last "and" or "or" in a list of four or more items.
message: 'Use a comma before the last "and" or "or" in a list of four or more items.'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#punctuation
level: warning
raw:

View File

@ -5,7 +5,7 @@
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence
message: Link %s must be relative.
message: 'Link "%s" must be relative.'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#links-to-internal-documentation
level: error
scope: raw

View File

@ -1,9 +1,11 @@
---
# Warning: gitlab.SentenceLength
#
# Counts words in a sentence and alerts if a sentence exceeds 25 words.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: occurrence
message: "Shorter sentences improve readability (max 25 words)."
message: 'Shorter sentences improve readability (max 25 words).'
scope: sentence
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language
level: warning

View File

@ -1,3 +1,6 @@
---
# Warning: gitlab.Spelling
#
# Checks for possible spelling mistakes in content, not code. May find false positives
# due to links using angle brackets: <https://example.com>. These can be ignored.
#

View File

@ -1,4 +1,6 @@
---
# Warning: gitlab.SubstitutionWarning
#
# Warns against using common shorthand for terms.
# For substitutions flagged as errors, see Substitutions.yml
#

View File

@ -199,6 +199,24 @@ To set this limit on a self-managed installation, run the following in the
Plan.default.limits.update!(ci_pipeline_schedules: 100)
```
### Number of instance level variables
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216097) in GitLab 13.1.
The total number of instance level CI/CD variables is limited at the instance level.
This limit is checked each time a new instance level variable is created. If a new variable
would cause the total number of variables to exceed the limit, the new variable will not be created.
On self-managed instances this limit is defined for the `default` plan. By default,
this limit is set to `25`.
To update this limit to a new value on a self-managed installation, run the following in the
[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
```ruby
Plan.default.limits.update!(ci_instance_level_variables: 30)
```
## Instance monitoring and metrics
### Incident Management inbound alert limits

View File

@ -92,6 +92,9 @@ The following metrics are available:
| `gitlab_view_rendering_duration_seconds` | Histogram | 10.2 | Duration for views (histogram) | `controller`, `action`, `view` |
| `http_requests_total` | Counter | 9.4 | Rack request count | `method` |
| `http_request_duration_seconds` | Histogram | 9.4 | HTTP response time from rack middleware | `method`, `status` |
| `gitlab_transaction_db_count_total` | Counter | 13.1 | Counter for total number of sql calls | `controller`, `action` |
| `gitlab_transaction_db_write_count_total` | Counter | 13.1 | Counter for total number of write sql calls | `controller`, `action` |
| `gitlab_transaction_db_cached_count_total` | Counter | 13.1 | Counter for total number of cached sql calls | `controller`, `action` |
| `http_redis_requests_duration_seconds` | Histogram | 13.1 | Redis requests duration during web transactions | `controller`, `action` |
| `http_redis_requests_total` | Counter | 13.1 | Redis requests count during web transactions | `controller`, `action` |
| `http_elasticsearch_requests_duration_seconds` **(STARTER)** | Histogram | 13.1 | Elasticsearch requests duration during web transactions | `controller`, `action` |
@ -103,7 +106,7 @@ The following metrics are available:
| `failed_login_captcha_total` | Gauge | 11.0 | Counter of failed CAPTCHA attempts during login | |
| `successful_login_captcha_total` | Gauge | 11.0 | Counter of successful CAPTCHA attempts during login | |
| `auto_devops_pipelines_completed_total` | Counter | 12.7 | Counter of completed Auto DevOps pipelines, labeled by status | |
| `gitlab_metrics_dashboard_processing_time_ms` | Summary | 12.10 | Metrics dashboard processing time in milliseconds | service, stages |
| `gitlab_metrics_dashboard_processing_time_ms` | Summary | 12.10 | Metrics dashboard processing time in milliseconds | service, stages |
## Metrics controlled by a feature flag

View File

@ -0,0 +1,20 @@
# Troubleshooting a GitLab installation
Below are some resources to help you troubleshoot a GitLab installation
in case something goes wrong:
- [Debugging tips](debug.md)
- [Diagnostics tools](diagnostics_tools.md)
- [Elasticsearch](elasticsearch.md)
- [GitLab Rails console cheat sheet](gitlab_rails_cheat_sheet.md)
- [Group SAML and SCIM troubleshooting](group_saml_scim.md) **(SILVER ONLY)**
- [Kubernetes cheat sheet](kubernetes_cheat_sheet.md)
- [Linux cheat sheet](linux_cheat_sheet.md)
- [Parsing GitLab logs with `jq`](log_parsing.md)
- [Navigating GitLab via Rails console](navigating_gitlab_via_rails_console.md)
- [PostgreSQL](postgresql.md)
- [Sidekiq](sidekiq.md)
- [SSL](ssl.md)
If you need a testing environment to troubleshoot, see the
[apps for a testing environment](test_environments.md).

View File

@ -1,3 +1,30 @@
"""
Represents the access level of a relationship between a User and object that it is related to
"""
type AccessLevel {
"""
Integer representation of access level
"""
integerValue: Int
"""
String representation of access level
"""
stringValue: AccessLevelEnum
}
"""
Access level to a resource
"""
enum AccessLevelEnum {
DEVELOPER
GUEST
MAINTAINER
NO_ACCESS
OWNER
REPORTER
}
"""
Autogenerated input type of AddAwardEmoji
"""
@ -5012,6 +5039,81 @@ type Group {
webUrl: String!
}
"""
Represents a Group Member
"""
type GroupMember implements MemberInterface {
"""
GitLab::Access level
"""
accessLevel: AccessLevel
"""
Date and time the membership was created
"""
createdAt: Time
"""
User that authorized membership
"""
createdBy: User
"""
Date and time the membership expires
"""
expiresAt: Time
"""
Group that a User is a member of
"""
group: Group
"""
Date and time the membership was last updated
"""
updatedAt: Time
"""
Permissions for the current user on the resource
"""
userPermissions: GroupPermissions!
}
"""
The connection type for GroupMember.
"""
type GroupMemberConnection {
"""
A list of edges.
"""
edges: [GroupMemberEdge]
"""
A list of nodes.
"""
nodes: [GroupMember]
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"""
An edge in a connection.
"""
type GroupMemberEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of the edge.
"""
node: GroupMember
}
type GroupPermissions {
"""
Indicates the user can perform `read_group` on this resource
@ -6200,6 +6302,33 @@ type MarkAsSpamSnippetPayload {
snippet: Snippet
}
interface MemberInterface {
"""
GitLab::Access level
"""
accessLevel: AccessLevel
"""
Date and time the membership was created
"""
createdAt: Time
"""
User that authorized membership
"""
createdBy: User
"""
Date and time the membership expires
"""
expiresAt: Time
"""
Date and time the membership was last updated
"""
updatedAt: Time
}
type MergeRequest implements Noteable {
"""
Indicates if members of the target project can push to the fork
@ -9156,23 +9285,53 @@ type ProjectEdge {
}
"""
Member of a project
Represents a Project Member
"""
type ProjectMember {
type ProjectMember implements MemberInterface {
"""
Access level of the member
GitLab::Access level
"""
accessLevel: Int!
accessLevel: AccessLevel
"""
Date and time the membership was created
"""
createdAt: Time
"""
User that authorized membership
"""
createdBy: User
"""
Date and time the membership expires
"""
expiresAt: Time
"""
ID of the member
"""
id: ID!
"""
Project that User is a member of
"""
project: Project
"""
Date and time the membership was last updated
"""
updatedAt: Time
"""
User that is associated with the member object
"""
user: User!
"""
Permissions for the current user on the resource
"""
userPermissions: ProjectPermissions!
}
"""
@ -12626,6 +12785,31 @@ type User {
"""
avatarUrl: String
"""
Group memberships of the user
"""
groupMemberships(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): GroupMemberConnection
"""
ID of the user
"""
@ -12636,6 +12820,31 @@ type User {
"""
name: String!
"""
Project memberships of the user
"""
projectMemberships(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): ProjectMemberConnection
"""
Snippets authored by the user
"""

View File

@ -9,6 +9,94 @@
},
"subscriptionType": null,
"types": [
{
"kind": "OBJECT",
"name": "AccessLevel",
"description": "Represents the access level of a relationship between a User and object that it is related to",
"fields": [
{
"name": "integerValue",
"description": "Integer representation of access level",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "stringValue",
"description": "String representation of access level",
"args": [
],
"type": {
"kind": "ENUM",
"name": "AccessLevelEnum",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "AccessLevelEnum",
"description": "Access level to a resource",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": [
{
"name": "NO_ACCESS",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "GUEST",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "REPORTER",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "DEVELOPER",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "MAINTAINER",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "OWNER",
"description": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "AddAwardEmojiInput",
@ -13722,6 +13810,237 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "GroupMember",
"description": "Represents a Group Member",
"fields": [
{
"name": "accessLevel",
"description": "GitLab::Access level",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "AccessLevel",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createdAt",
"description": "Date and time the membership was created",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createdBy",
"description": "User that authorized membership",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "User",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "expiresAt",
"description": "Date and time the membership expires",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "group",
"description": "Group that a User is a member of",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Group",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updatedAt",
"description": "Date and time the membership was last updated",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "userPermissions",
"description": "Permissions for the current user on the resource",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "GroupPermissions",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
{
"kind": "INTERFACE",
"name": "MemberInterface",
"ofType": null
}
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "GroupMemberConnection",
"description": "The connection type for GroupMember.",
"fields": [
{
"name": "edges",
"description": "A list of edges.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "GroupMemberEdge",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "nodes",
"description": "A list of nodes.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "GroupMember",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pageInfo",
"description": "Information to aid in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "PageInfo",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "GroupMemberEdge",
"description": "An edge in a connection.",
"fields": [
{
"name": "cursor",
"description": "A cursor for use in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "node",
"description": "The item at the end of the edge.",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "GroupMember",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "GroupPermissions",
@ -17194,6 +17513,98 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INTERFACE",
"name": "MemberInterface",
"description": null,
"fields": [
{
"name": "accessLevel",
"description": "GitLab::Access level",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "AccessLevel",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createdAt",
"description": "Date and time the membership was created",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createdBy",
"description": "User that authorized membership",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "User",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "expiresAt",
"description": "Date and time the membership expires",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updatedAt",
"description": "Date and time the membership was last updated",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": [
{
"kind": "OBJECT",
"name": "GroupMember",
"ofType": null
},
{
"kind": "OBJECT",
"name": "ProjectMember",
"ofType": null
}
]
},
{
"kind": "OBJECT",
"name": "MergeRequest",
@ -26800,22 +27211,60 @@
{
"kind": "OBJECT",
"name": "ProjectMember",
"description": "Member of a project",
"description": "Represents a Project Member",
"fields": [
{
"name": "accessLevel",
"description": "Access level of the member",
"description": "GitLab::Access level",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
"kind": "OBJECT",
"name": "AccessLevel",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createdAt",
"description": "Date and time the membership was created",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createdBy",
"description": "User that authorized membership",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "User",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "expiresAt",
"description": "Date and time the membership expires",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
@ -26838,6 +27287,34 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "project",
"description": "Project that User is a member of",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Project",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updatedAt",
"description": "Date and time the membership was last updated",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "user",
"description": "User that is associated with the member object",
@ -26855,11 +27332,33 @@
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "userPermissions",
"description": "Permissions for the current user on the resource",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "ProjectPermissions",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
{
"kind": "INTERFACE",
"name": "MemberInterface",
"ofType": null
}
],
"enumValues": null,
"possibleTypes": null
@ -37234,6 +37733,59 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "groupMemberships",
"description": "Group memberships of the user",
"args": [
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "GroupMemberConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "ID of the user",
@ -37270,6 +37822,59 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "projectMemberships",
"description": "Project memberships of the user",
"args": [
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "ProjectMemberConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "snippets",
"description": "Snippets authored by the user",

View File

@ -16,6 +16,15 @@ fields and methods on a model are available via GraphQL.
CAUTION: **Caution:**
Fields that are deprecated are marked with **{warning-solid}**.
## AccessLevel
Represents the access level of a relationship between a User and object that it is related to
| Name | Type | Description |
| --- | ---- | ---------- |
| `integerValue` | Int | Integer representation of access level |
| `stringValue` | AccessLevelEnum | String representation of access level |
## AddAwardEmojiPayload
Autogenerated return type of AddAwardEmoji
@ -732,6 +741,20 @@ Autogenerated return type of EpicTreeReorder
| `visibility` | String | Visibility of the namespace |
| `webUrl` | String! | Web URL of the group |
## GroupMember
Represents a Group Member
| Name | Type | Description |
| --- | ---- | ---------- |
| `accessLevel` | AccessLevel | GitLab::Access level |
| `createdAt` | Time | Date and time the membership was created |
| `createdBy` | User | User that authorized membership |
| `expiresAt` | Time | Date and time the membership expires |
| `group` | Group | Group that a User is a member of |
| `updatedAt` | Time | Date and time the membership was last updated |
| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
## GroupPermissions
| Name | Type | Description |
@ -1289,13 +1312,19 @@ Information about pagination in a connection.
## ProjectMember
Member of a project
Represents a Project Member
| Name | Type | Description |
| --- | ---- | ---------- |
| `accessLevel` | Int! | Access level of the member |
| `accessLevel` | AccessLevel | GitLab::Access level |
| `createdAt` | Time | Date and time the membership was created |
| `createdBy` | User | User that authorized membership |
| `expiresAt` | Time | Date and time the membership expires |
| `id` | ID! | ID of the member |
| `project` | Project | Project that User is a member of |
| `updatedAt` | Time | Date and time the membership was last updated |
| `user` | User! | User that is associated with the member object |
| `userPermissions` | ProjectPermissions! | Permissions for the current user on the resource |
## ProjectPermissions

View File

@ -86,6 +86,10 @@ by `@`. For example:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "name=imported-group" --form "path=imported-group" --form "file=@/path/to/file" "https://gitlab.example.com/api/v4/groups/import"
```
NOTE: **Note:**
The maximum import file size can be set by the Administrator, default is 50MB.
As an administrator, you can modify the maximum import file size. To do so, use the `max_import_size` option in the [Application settings API](settings.md#change-application-settings) or the [Admin UI](../user/admin_area/settings/account_and_limit_settings.md).
## Important notes
Note the following:

View File

@ -67,8 +67,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
Create a new instance-level variable.
NOTE: **Note:**
The maximum number of instance-level variables is [planned to be 25](https://gitlab.com/gitlab-org/gitlab/-/issues/216097).
[Since GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/216097), the maximum number of allowed instance-level variables can be changed.
```plaintext
POST /admin/ci/variables

View File

@ -181,6 +181,10 @@ requests.post(url, headers=headers, data=data, files=files)
}
```
NOTE: **Note:**
The maximum import file size can be set by the Administrator, default is 50MB.
As an administrator, you can modify the maximum import file size. To do so, use the `max_import_size` option in the [Application settings API](settings.md#change-application-settings) or the [Admin UI](../user/admin_area/settings/account_and_limit_settings.md).
## Import status
Get the status of an import.

View File

@ -30,6 +30,7 @@ Example response:
"password_authentication_enabled_for_web" : true,
"after_sign_out_path" : null,
"max_attachment_size" : 10,
"max_import_size": 50,
"user_oauth_applications" : true,
"updated_at" : "2016-01-04T15:44:55.176Z",
"session_expire_delay" : 10080,
@ -118,6 +119,7 @@ Example response:
"default_branch_protection": 2,
"restricted_visibility_levels": [],
"max_attachment_size": 10,
"max_import_size": 50,
"session_expire_delay": 10080,
"default_ci_config_path" : null,
"default_project_visibility": "internal",
@ -280,6 +282,7 @@ are listed in the descriptions of the relevant settings.
| `local_markdown_version` | integer | no | Increase this value when any cached Markdown should be invalidated. |
| `max_artifacts_size` | integer | no | Maximum artifacts size in MB |
| `max_attachment_size` | integer | no | Limit attachment size in MB |
| `max_import_size` | integer | no | Maximum import size in MB. 0 for unlimited. Default = 50 |
| `max_pages_size` | integer | no | Maximum size of pages repositories in MB |
| `max_personal_access_token_lifetime` | integer | no | **(ULTIMATE ONLY)** Maximum allowable lifetime for personal access tokens in days |
| `metrics_method_call_threshold` | integer | no | A method call is only tracked when it takes longer than the given amount of milliseconds. |

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -78,3 +78,40 @@ are certain use cases that you may need to work around. For more information:
- [`needs` requirements and limitations](../yaml/README.md#requirements-and-limitations).
- Related epic [tracking planned improvements](https://gitlab.com/groups/gitlab-org/-/epics/1716).
## DAG Visualization
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215517) in GitLab 13.1 as a [Beta feature](https://about.gitlab.com/handbook/product/#beta).
> - It's deployed behind a feature flag, enabled by default.
> - It's enabled on GitLab.com.
> - It's not able to be enabled or disabled per-project
> - It's not recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-dag-visualization-core-only)
The DAG visualization makes it easier to visualize the relationships between dependent jobs in a DAG. This graph will display all the jobs in a pipeline that need or are needed by other jobs. Jobs with no relationships are not displayed in this view.
![DAG visualization example](img/dag_graph_example_v13_1.png)
Clicking a node will highlight all the job paths it depends on.
![DAG visualization with path highlight](img/dag_graph_example_clicked_v13_1.png)
### Enable or disable DAG Visualization **(CORE ONLY)**
DAG Visualization is under development and requires more testing, but is being made available as a beta features so users can check its limitations and uses.
It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can opt to disable it for your instance. It cannot be enabled or disabled per-project.
To disable it:
```ruby
Feature.disable(:dag_pipeline_tab)
```
To enable it:
```ruby
Feature.enable(:dag_pipeline_tab)
```

View File

@ -1,4 +1,7 @@
---
stage: Manage
group: Access
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
type: reference, howto
---

View File

@ -1,4 +1,7 @@
---
stage: Manage
group: Access
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
type: howto
---

View File

@ -1,4 +1,7 @@
---
stage: Manage
group: Access
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
type: howto
---

View File

@ -1,3 +1,10 @@
---
stage: Manage
group: Access
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
type: howto
---
# Credentials inventory **(ULTIMATE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20912) in GitLab 12.6.

View File

@ -1,4 +1,7 @@
---
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
type: reference
---

View File

@ -1,4 +1,7 @@
---
stage: Create
group: Source Code
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
type: reference
---

View File

@ -1,4 +1,7 @@
---
stage: Enablement
group: Geo
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
type: howto
---

View File

@ -1,4 +1,7 @@
---
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
type: reference
---

View File

@ -1,4 +1,7 @@
---
stage: Growth
group: Conversion
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
type: howto
---

View File

@ -1,4 +1,7 @@
---
stage: Create
group: Source Code
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
type: reference, concepts
---

View File

@ -15,6 +15,17 @@ If you choose a size larger than what is currently configured for the web server
you will likely get errors. See the [troubleshooting section](#troubleshooting) for more
details.
## Max import size
You can change the maximum file size for imports in GitLab.
Navigate to **Admin Area (wrench icon) > Settings > General**, then expand **Account and Limit**.
From here, you can increase or decrease by changing the value in `Maximum import size (MB)`.
NOTE: **Note:**
If you choose a size larger than what is currently configured for the web server,
you will likely get errors. See the [troubleshooting section](#troubleshooting) for more
details.
## Maximum namespace storage size
This sets a maximum size limit on each namespace. The following are included in the namespace size:

View File

@ -82,6 +82,7 @@ Below are the current settings regarding [GitLab CI/CD](../../ci/README.md).
| Scheduled Pipeline Cron | `*/5 * * * *` | `19 * * * *` |
| [Max jobs in active pipelines](../../administration/instance_limits.md#number-of-jobs-in-active-pipelines) | `500` for Free tier, unlimited otherwise | Unlimited
| [Max pipeline schedules in projects](../../administration/instance_limits.md#number-of-pipeline-schedules) | `10` for Free tier, `50` for all paid tiers | Unlimited |
| [Max number of instance level variables](../../administration/instance_limits.md#number-of-instance-level-variables) | `25` | `25` |
## Repository size limit

View File

@ -75,6 +75,10 @@ For more details on the specific data persisted in a group export, see the
1. Alternatively, you can come back to the project settings and download the
file from there by clicking **Download export**, or generate a new file by clicking **Regenerate export**.
NOTE: **Note:**
The maximum import file size can be set by the Administrator, default is 50MB.
As an administrator, you can modify the maximum import file size. To do so, use the `max_import_size` option in the [Application settings API](../../../api/settings.md#change-application-settings) or the [Admin UI](../../admin_area/settings/account_and_limit_settings.md).
### Between CE and EE
You can export groups from the [Community Edition to the Enterprise Edition](https://about.gitlab.com/install/ce-or-ee/) and vice versa.

View File

@ -158,6 +158,10 @@ If use of the `Internal` visibility level
[is restricted](../../../public_access/public_access.md#restricting-the-use-of-public-or-internal-projects),
all imported projects are given the visibility of `Private`.
NOTE: **Note:**
The maximum import file size can be set by the Administrator, default is 50MB.
As an administrator, you can modify the maximum import file size. To do so, use the `max_import_size` option in the [Application settings API](../../../api/settings.md#change-application-settings) or the [Admin UI](../../admin_area/settings/account_and_limit_settings.md).
## Rate limits
To help avoid abuse, users are rate limited to:

View File

@ -40,7 +40,7 @@ module API
ImportExportUploader.workhorse_authorize(
has_length: false,
maximum_size: ImportExportUpload::MAXIMUM_IMPORT_FILE_SIZE
maximum_size: Gitlab::CurrentSettings.max_import_size.megabytes
)
end

View File

@ -30,7 +30,10 @@ module API
status 200
content_type Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
ImportExportUploader.workhorse_authorize(has_length: false, maximum_size: MAXIMUM_FILE_SIZE)
ImportExportUploader.workhorse_authorize(
has_length: false,
maximum_size: Gitlab::CurrentSettings.max_import_size.megabytes
)
end
params do

View File

@ -83,6 +83,7 @@ module API
desc: 'Enabled sources for code import during project creation. OmniAuth must be configured for GitHub, Bitbucket, and GitLab.com'
optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts"
optional :max_attachment_size, type: Integer, desc: 'Maximum attachment size in MB'
optional :max_import_size, type: Integer, desc: 'Maximum import size in MB'
optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB'
optional :metrics_method_call_threshold, type: Integer, desc: 'A method call is only tracked when it takes longer to complete than the given amount of milliseconds.'
optional :password_authentication_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface' # support legacy names, can be removed in v5

View File

@ -17,6 +17,10 @@ module Gitlab
def self.job_heartbeats_runner?(project)
::Feature.enabled?(:ci_job_heartbeats_runner, project, default_enabled: true)
end
def self.instance_level_variables_limit_enabled?
::Feature.enabled?(:ci_instance_level_variables_limit, default_enabled: true)
end
end
end
end

View File

@ -7,6 +7,15 @@ module Gitlab
include Gitlab::ImportExport::CommandLineUtil
BATCH_SIZE = 100
SMALLER_BATCH_SIZE = 20
def self.batch_size(exportable)
if Feature.enabled?(:export_reduce_relation_batch_size, exportable)
SMALLER_BATCH_SIZE
else
BATCH_SIZE
end
end
class Raw < String
def to_json(*_args)
@ -60,7 +69,7 @@ module Gitlab
key_preloads = preloads&.dig(key)
records = records.preload(key_preloads) if key_preloads
records.find_each(batch_size: BATCH_SIZE) do |record|
records.find_each(batch_size: batch_size) do |record|
items << Raw.new(record.to_json(options))
end
end
@ -91,6 +100,10 @@ module Gitlab
def preloads
relations_schema[:preload]
end
def batch_size
@batch_size ||= self.class.batch_size(@exportable)
end
end
end
end

View File

@ -7,7 +7,7 @@ module Gitlab
def serialize(exportable, relations_tree)
Gitlab::ImportExport::FastHashSerializer
.new(exportable, relations_tree)
.new(exportable, relations_tree, batch_size: batch_size(exportable))
.execute
end
@ -18,6 +18,12 @@ module Gitlab
File.write(File.join(dir_path, filename), tree_json)
end
private
def batch_size(exportable)
Gitlab::ImportExport::JSON::StreamingSerializer.batch_size(exportable)
end
end
end
end

View File

@ -12,7 +12,6 @@ module Gitlab
params = event
.payload[:params]
.each_with_object([]) { |(k, v), array| array << { key: k, value: v } unless IGNORE_PARAMS.include?(k) }
payload = {
time: Time.now.utc.iso8601(3),
params: Gitlab::Utils::LogLimitedArray.log_limited_array(params, sentinel: LIMITED_ARRAY_SENTINEL),
@ -21,6 +20,7 @@ module Gitlab
username: event.payload[:username],
ua: event.payload[:ua]
}
add_db_counters!(payload)
payload.merge!(event.payload[:metadata]) if event.payload[:metadata]
@ -46,6 +46,16 @@ module Gitlab
payload
end
def self.add_db_counters!(payload)
current_transaction = Gitlab::Metrics::Transaction.current
if current_transaction
payload[:db_count] = current_transaction.get(:db_count, :counter).to_i
payload[:db_write_count] = current_transaction.get(:db_write_count, :counter).to_i
payload[:db_cached_count] = current_transaction.get(:db_cached_count, :counter).to_i
end
end
private_class_method :add_db_counters!
end
end
end

View File

@ -6,19 +6,30 @@ module Gitlab
#
# This middleware is intended to be used as a server-side middleware.
class SidekiqMiddleware
def call(worker, message, queue)
def call(worker, payload, queue)
trans = BackgroundTransaction.new(worker.class)
begin
# Old gitlad-shell messages don't provide enqueued_at/created_at attributes
trans.set(:sidekiq_queue_duration, Time.now.to_f - (message['enqueued_at'] || message['created_at'] || 0))
enqueued_at = payload['enqueued_at'] || payload['created_at'] || 0
trans.set(:sidekiq_queue_duration, Time.current.to_f - enqueued_at)
trans.run { yield }
rescue Exception => error # rubocop: disable Lint/RescueException
trans.add_event(:sidekiq_exception)
raise error
ensure
add_info_to_payload(payload, trans)
end
end
private
def add_info_to_payload(payload, trans)
payload[:db_count] = trans.get(:db_count, :counter).to_i
payload[:db_write_count] = trans.get(:db_write_count, :counter).to_i
payload[:db_cached_count] = trans.get(:db_cached_count, :counter).to_i
end
end
end
end

View File

@ -9,6 +9,7 @@ module Gitlab
attach_to :active_record
IGNORABLE_SQL = %w{BEGIN COMMIT}.freeze
DB_COUNTERS = %i{db_count db_write_count db_cached_count}.freeze
def sql(event)
return unless current_transaction
@ -19,8 +20,7 @@ module Gitlab
self.class.gitlab_sql_duration_seconds.observe(current_transaction.labels, event.duration / 1000.0)
current_transaction.increment(:sql_duration, event.duration, false)
current_transaction.increment(:sql_count, 1, false)
increment_db_counters(payload)
end
private
@ -31,6 +31,20 @@ module Gitlab
buckets [0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0]
end
def select_sql_command?(payload)
payload[:sql].match(/\A((?!(.*[^\w'"](DELETE|UPDATE|INSERT INTO)[^\w'"])))(WITH.*)?(SELECT)((?!(FOR UPDATE|FOR SHARE)).)*$/i)
end
def increment_db_counters(payload)
current_transaction.increment(:db_count, 1)
if payload.fetch(:cached, payload[:name] == 'CACHE')
current_transaction.increment(:db_cached_count, 1)
end
current_transaction.increment(:db_write_count, 1) unless select_sql_command?(payload)
end
def current_transaction
Transaction.current
end

View File

@ -16,7 +16,7 @@ module Gitlab
# The series to store events (e.g. Git pushes) in.
EVENT_SERIES = 'events'
attr_reader :tags, :method
attr_reader :method
def self.current
Thread.current[THREAD_KEY]
@ -28,8 +28,6 @@ module Gitlab
@started_at = nil
@finished_at = nil
@tags = {}
@memory_before = 0
@memory_after = 0
end
@ -94,6 +92,12 @@ module Gitlab
self.class.transaction_metric(name, :gauge).set(labels, value) if use_prometheus
end
def get(name, type, tags = {})
metric = self.class.transaction_metric(name, type)
metric.get(filter_tags(tags).merge(labels))
end
def labels
BASE_LABELS
end

View File

@ -36,6 +36,10 @@ module Gitlab
)
end
def add_db_counters!(job, output_payload)
output_payload.merge!(job.slice(*::Gitlab::Metrics::Subscribers::ActiveRecord::DB_COUNTERS))
end
def log_job_start(payload)
payload['message'] = "#{base_message(payload)}: start"
payload['job_status'] = 'start'
@ -50,6 +54,7 @@ module Gitlab
payload = payload.dup
add_instrumentation_keys!(job, payload)
add_logging_extras!(job, payload)
add_db_counters!(job, payload)
elapsed_time = elapsed(started_time)
add_time_keys!(elapsed_time, payload)

View File

@ -747,6 +747,9 @@ msgstr ""
msgid "0 for unlimited"
msgstr ""
msgid "0 for unlimited, only effective with remote storage enabled."
msgstr ""
msgid "1 %{type} addition"
msgid_plural "%{count} %{type} additions"
msgstr[0] ""
@ -3352,6 +3355,9 @@ msgstr ""
msgid "Below you will find all the groups that are public."
msgstr ""
msgid "Beta"
msgstr ""
msgid "Billing"
msgstr ""
@ -9335,7 +9341,7 @@ msgstr ""
msgid "Failed to load error details from Sentry."
msgstr ""
msgid "Failed to load errors from Sentry. Error message: %{errorMessage}"
msgid "Failed to load errors from Sentry."
msgstr ""
msgid "Failed to load group activity metrics. Please try again."
@ -13544,6 +13550,9 @@ msgstr ""
msgid "Maximum field length"
msgstr ""
msgid "Maximum import size (MB)"
msgstr ""
msgid "Maximum job timeout"
msgstr ""
@ -13583,6 +13592,9 @@ msgstr ""
msgid "Maximum size of Elasticsearch bulk indexing requests."
msgstr ""
msgid "Maximum size of import files."
msgstr ""
msgid "Maximum size of individual attachments in comments."
msgstr ""
@ -22624,6 +22636,9 @@ msgstr ""
msgid "This epic does not exist or you don't have sufficient permission."
msgstr ""
msgid "This feature is currently in beta. We invite you to %{linkStart}give feedback%{linkEnd}."
msgstr ""
msgid "This feature requires local storage to be enabled"
msgstr ""

View File

@ -41,7 +41,7 @@
"@babel/preset-env": "^7.8.4",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.137.0",
"@gitlab/ui": "16.3.0",
"@gitlab/ui": "16.4.1",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-1",
"@sentry/browser": "^5.10.2",

View File

@ -165,13 +165,6 @@ FactoryBot.define do
type { 'SlackService' }
end
factory :github_service do
project
type { 'GithubService' }
active { true }
token { 'github-token' }
end
factory :pipelines_email_service do
project
active { true }

View File

@ -105,6 +105,16 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
expect(page).to have_content "Application settings saved successfully"
end
it 'Change Maximum import size' do
page.within('.as-account-limit') do
fill_in 'Maximum import size (MB)', with: 15
click_button 'Save changes'
end
expect(current_settings.max_import_size).to eq 15
expect(page).to have_content "Application settings saved successfully"
end
it 'Change New users set to external', :js do
user_internal_regex = find('#application_setting_user_default_internal_regex', visible: :all)

View File

@ -1,4 +1,4 @@
import { shallowMount } from '@vue/test-utils';
import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import waitForPromises from 'helpers/wait_for_promises';
@ -18,17 +18,18 @@ describe('Pipeline DAG graph wrapper', () => {
let wrapper;
let mock;
const getAlert = () => wrapper.find(GlAlert);
const getAllAlerts = () => wrapper.findAll(GlAlert);
const getGraph = () => wrapper.find(DagGraph);
const getErrorText = type => wrapper.vm.$options.errorTexts[type];
const dataPath = '/root/test/pipelines/90/dag.json';
const createComponent = (propsData = {}) => {
const createComponent = (propsData = {}, method = shallowMount) => {
if (wrapper?.destroy) {
wrapper.destroy();
}
wrapper = shallowMount(Dag, {
wrapper = method(Dag, {
propsData,
data() {
return {
@ -100,15 +101,16 @@ describe('Pipeline DAG graph wrapper', () => {
describe('and the data fetch and parse succeeds', () => {
beforeEach(() => {
mock.onGet(dataPath).replyOnce(200, mockBaseData);
createComponent({ graphUrl: dataPath });
createComponent({ graphUrl: dataPath }, mount);
});
it('shows the graph and not the alert', () => {
it('shows the graph and not the beta alert', () => {
return wrapper.vm
.$nextTick()
.then(waitForPromises)
.then(() => {
expect(getAlert().exists()).toBe(false);
expect(getAllAlerts().length).toBe(1);
expect(getAlert().text()).toContain('This feature is currently in beta.');
expect(getGraph().exists()).toBe(true);
});
});

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
require 'spec_helper'
describe GitlabSchema.types['AccessLevelEnum'] do
specify { expect(described_class.graphql_name).to eq('AccessLevelEnum') }
it 'exposes all the existing access levels' do
expect(described_class.values.keys).to match_array(%w[NO_ACCESS GUEST REPORTER DEVELOPER MAINTAINER OWNER])
end
end

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
describe GitlabSchema.types['AccessLevel'] do
specify { expect(described_class.graphql_name).to eq('AccessLevel') }
specify { expect(described_class).to require_graphql_authorizations(nil) }
it 'has expected fields' do
expected_fields = [:integer_value, :string_value]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'spec_helper'
describe Types::GroupMemberType do
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Group) }
specify { expect(described_class.graphql_name).to eq('GroupMember') }
specify { expect(described_class).to require_graphql_authorizations(:read_group) }
it 'has the expected fields' do
expected_fields = %w[
access_level created_by created_at updated_at expires_at group
]
expect(described_class).to include_graphql_fields(*expected_fields)
end
end

View File

@ -2,14 +2,18 @@
require 'spec_helper'
describe GitlabSchema.types['ProjectMember'] do
describe Types::ProjectMemberType do
specify { expect(described_class).to expose_permissions_using(Types::PermissionTypes::Project) }
specify { expect(described_class.graphql_name).to eq('ProjectMember') }
it 'has the expected fields' do
expected_fields = %w[id accessLevel user]
expect(described_class).to have_graphql_fields(*expected_fields)
end
specify { expect(described_class).to require_graphql_authorizations(:read_project) }
it 'has the expected fields' do
expected_fields = %w[
access_level created_by created_at updated_at expires_at project user
]
expect(described_class).to include_graphql_fields(*expected_fields)
end
end

View File

@ -9,8 +9,19 @@ describe GitlabSchema.types['User'] do
it 'has the expected fields' do
expected_fields = %w[
id user_permissions snippets name username avatarUrl webUrl todos state
authoredMergeRequests assignedMergeRequests
id
user_permissions
snippets
name
username
avatarUrl
webUrl
todos
state
authoredMergeRequests
assignedMergeRequests
groupMemberships
projectMemberships
]
expect(described_class).to have_graphql_fields(*expected_fields)

View File

@ -65,9 +65,7 @@ describe Gitlab::Danger::Changelog do
context 'added files contain a changelog' do
[
'changelogs/unreleased/entry.yml',
'ee/changelogs/unreleased/entry.yml',
'changelogs/unreleased-ee/entry.yml',
'ee/changelogs/unreleased-ee/entry.yml'
'ee/changelogs/unreleased/entry.yml'
].each do |file_path|
let(:added_files) { [file_path] }

View File

@ -95,4 +95,26 @@ describe Gitlab::ImportExport::JSON::StreamingSerializer do
end
end
end
describe '.batch_size' do
context 'when export_reduce_relation_batch_size feature flag is enabled' do
before do
stub_feature_flags(export_reduce_relation_batch_size: true)
end
it 'returns 20' do
expect(described_class.batch_size(exportable)).to eq(described_class::SMALLER_BATCH_SIZE)
end
end
context 'when export_reduce_relation_batch_size feature flag is disabled' do
before do
stub_feature_flags(export_reduce_relation_batch_size: false)
end
it 'returns default batch size' do
expect(described_class.batch_size(exportable)).to eq(described_class::BATCH_SIZE)
end
end
end
end

View File

@ -8,17 +8,35 @@ describe Gitlab::ImportExport::LegacyRelationTreeSaver do
let(:tree) { {} }
describe '#serialize' do
let(:serializer) { instance_double(Gitlab::ImportExport::FastHashSerializer) }
shared_examples 'FastHashSerializer with batch size' do |batch_size|
let(:serializer) { instance_double(Gitlab::ImportExport::FastHashSerializer) }
it 'uses FastHashSerializer' do
expect(Gitlab::ImportExport::FastHashSerializer)
.to receive(:new)
.with(exportable, tree)
.and_return(serializer)
it 'uses FastHashSerializer' do
expect(Gitlab::ImportExport::FastHashSerializer)
.to receive(:new)
.with(exportable, tree, batch_size: batch_size)
.and_return(serializer)
expect(serializer).to receive(:execute)
expect(serializer).to receive(:execute)
relation_tree_saver.serialize(exportable, tree)
relation_tree_saver.serialize(exportable, tree)
end
end
context 'when export_reduce_relation_batch_size feature flag is enabled' do
before do
stub_feature_flags(export_reduce_relation_batch_size: true)
end
include_examples 'FastHashSerializer with batch size', Gitlab::ImportExport::JSON::StreamingSerializer::SMALLER_BATCH_SIZE
end
context 'when export_reduce_relation_batch_size feature flag is disabled' do
before do
stub_feature_flags(export_reduce_relation_batch_size: false)
end
include_examples 'FastHashSerializer with batch size', Gitlab::ImportExport::JSON::StreamingSerializer::BATCH_SIZE
end
end
end

View File

@ -44,6 +44,18 @@ describe Gitlab::Lograge::CustomOptions do
end
end
context 'with transaction' do
let(:transaction) { Gitlab::Metrics::WebTransaction.new({}) }
before do
allow(Gitlab::Metrics::Transaction).to receive(:current).and_return(transaction)
end
it 'adds db counters' do
expect(subject).to include(:db_count, :db_write_count, :db_cached_count)
end
end
it 'adds the user id' do
expect(subject[:user_id]).to eq('test')
end

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