Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
388e0fbbd0
commit
9be457ffc1
|
|
@ -63,10 +63,17 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
|
|||
# This entry must occur before `/scripts/` in order to be matched first
|
||||
/scripts/remote_development/
|
||||
|
||||
[Engineering Productivity] @gl-quality/eng-prod
|
||||
# This entry must occur before `/scripts/glfm/**/*`/`/scripts/lib/glfm/**/*` in order to be matched first
|
||||
/scripts/glfm/**/*.js @gitlab-org/maintainers/frontend
|
||||
/scripts/lib/glfm/**/*.js @gitlab-org/maintainers/frontend
|
||||
/scripts/glfm/**/* @gitlab-org/maintainers/rails-backend
|
||||
/scripts/lib/glfm/**/* @gitlab-org/maintainers/rails-backend
|
||||
|
||||
[Pipeline configuration] @gl-quality/eng-prod
|
||||
/.gitlab-ci.yml
|
||||
/.gitlab/ci/
|
||||
/.gitlab/ci/docs.gitlab-ci.yml @gl-quality/eng-prod @gl-docsteam
|
||||
/.gitlab/ci/frontend.gitlab-ci.yml @gl-quality/eng-prod @gitlab-org/maintainers/frontend
|
||||
/.gitlab/ci/package-and-test/ @gl-quality/eng-prod @gl-quality/qe-maintainers
|
||||
/.gitlab/ci/qa.gitlab-ci.yml @gl-quality/eng-prod @gl-quality/qe-maintainers
|
||||
/.gitlab/ci/qa-common/ @gl-quality/eng-prod @gl-quality/qe-maintainers
|
||||
|
|
@ -74,14 +81,29 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
|
|||
/.gitlab/ci/reports.gitlab-ci.yml @gl-quality/eng-prod @gitlab-com/gl-security/appsec
|
||||
/.gitlab/ci/review-apps/qa.gitlab-ci.yml @gl-quality/eng-prod @gl-quality/qe-maintainers
|
||||
/.gitlab/ci/test-on-gdk/ @gl-quality/eng-prod @gl-quality/qe-maintainers
|
||||
/gems/gem.gitlab-ci.yml
|
||||
|
||||
[Tooling] @gl-quality/eng-prod
|
||||
/.gitlab/CODEOWNERS
|
||||
Dangerfile
|
||||
/danger/
|
||||
/gems/gem.gitlab-ci.yml
|
||||
/tooling/danger/
|
||||
/scripts/
|
||||
/scripts/**/*.rb @gl-quality/eng-prod @gitlab-org/maintainers/rails-backend
|
||||
/scripts/**/*.js @gl-quality/eng-prod @gitlab-org/maintainers/frontend
|
||||
/scripts/frontend/ @gl-quality/eng-prod @gitlab-org/maintainers/frontend
|
||||
/scripts/review_apps/seed-dast-test-data.sh @gl-quality/eng-prod @dappelt @ngeorge1
|
||||
.editorconfig
|
||||
/.codeclimate.yml
|
||||
/.dockerignore
|
||||
/.editorconfig
|
||||
/.gitpod.yml
|
||||
/.haml-lint_todo.yml
|
||||
/.haml-lint.yml
|
||||
/.nvmrc
|
||||
/.ruby-version
|
||||
/.tool-versions
|
||||
/lefthook.yml
|
||||
/tests.yml
|
||||
|
||||
^[Backend Static Code Analysis] @gl-quality/eng-prod @dstull @splattael
|
||||
.rubocop*.yml
|
||||
|
|
|
|||
|
|
@ -760,6 +760,10 @@ No changes.
|
|||
- [Add schema_version in the commits index mapping](gitlab-org/gitlab@e75b94903b69e1e1588e251217926882875555a8) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123435)) **GitLab Enterprise Edition**
|
||||
- [Allow to set labels for Redis calls](gitlab-org/gitlab@8ccfff9e2d250eb22afaa7d0243e707b536a5436) ([merge request](gitlab-org/gitlab!122340))
|
||||
|
||||
## 16.1.4 (2023-08-03)
|
||||
|
||||
No changes.
|
||||
|
||||
## 16.1.3 (2023-08-01)
|
||||
|
||||
### Added (1 change)
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -404,7 +404,7 @@ group :development, :test do
|
|||
gem 'parser', '~> 3.2', '>= 3.2.2.3'
|
||||
gem 'pry-byebug'
|
||||
gem 'pry-rails', '~> 0.3.9'
|
||||
gem 'pry-shell', '~> 0.6.1'
|
||||
gem 'pry-shell', '~> 0.6.4'
|
||||
|
||||
gem 'awesome_print', require: false
|
||||
|
||||
|
|
|
|||
|
|
@ -461,7 +461,7 @@
|
|||
{"name":"pry","version":"0.14.2","platform":"ruby","checksum":"c4fe54efedaca1d351280b45b8849af363184696fcac1c72e0415f9bdac4334d"},
|
||||
{"name":"pry-byebug","version":"3.10.1","platform":"ruby","checksum":"c8f975c32255bfdb29e151f5532130be64ff3d0042dc858d0907e849125581f8"},
|
||||
{"name":"pry-rails","version":"0.3.9","platform":"ruby","checksum":"468662575abb6b67f4a9831219f99290d5eae7bf186e64dd810d0a3e4a8cc4b1"},
|
||||
{"name":"pry-shell","version":"0.6.1","platform":"ruby","checksum":"a99a6b3dffe4df274ea1751866816906861a23851f13346e10a8e8f61b53360c"},
|
||||
{"name":"pry-shell","version":"0.6.4","platform":"ruby","checksum":"ad024882d29912b071a7de65ebea538b242d2dc1498c60c7c2352ef94769f208"},
|
||||
{"name":"public_suffix","version":"5.0.0","platform":"ruby","checksum":"26ee4fbce33ada25eb117ac71f2c24bf4d8b3414ab6b34f05b4708a3e90f1c6b"},
|
||||
{"name":"puma","version":"6.3.0","platform":"java","checksum":"5e2ff95953608d1ba0350b80a3961a43e9bbb78ec60ebd5e4db1940c2921d5d8"},
|
||||
{"name":"puma","version":"6.3.0","platform":"ruby","checksum":"b0e35b4fe7ae440237a9ff1647c6bb252a1c0951ff356020670d2e62c1aeeeec"},
|
||||
|
|
|
|||
|
|
@ -1217,7 +1217,7 @@ GEM
|
|||
pry (>= 0.13, < 0.15)
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
pry-shell (0.6.1)
|
||||
pry-shell (0.6.4)
|
||||
pry (>= 0.13.0)
|
||||
tty-markdown
|
||||
tty-prompt
|
||||
|
|
@ -1941,7 +1941,7 @@ DEPENDENCIES
|
|||
prometheus-client-mmap (~> 0.27)
|
||||
pry-byebug
|
||||
pry-rails (~> 0.3.9)
|
||||
pry-shell (~> 0.6.1)
|
||||
pry-shell (~> 0.6.4)
|
||||
puma (~> 6.3)
|
||||
rack (~> 2.2.7)
|
||||
rack-attack (~> 6.6.1)
|
||||
|
|
|
|||
|
|
@ -687,11 +687,23 @@ export function redirectTo(url) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Navigates to a URL
|
||||
* @param {*} url - url to navigate to
|
||||
* Navigates to a URL.
|
||||
*
|
||||
* If destination is a querystring, it will be automatically transformed into a fully qualified URL.
|
||||
* If the URL is not a safe URL (see isSafeURL implementation), this function will log an exception into Sentry.
|
||||
*
|
||||
* @param {*} destination - url to navigate to. This can be a fully qualified URL or a querystring.
|
||||
* @param {*} external - if true, open a new page or tab
|
||||
*/
|
||||
export function visitUrl(url, external = false) {
|
||||
export function visitUrl(destination, external = false) {
|
||||
let url = destination;
|
||||
|
||||
if (destination.startsWith('?')) {
|
||||
const currentUrl = new URL(window.location.href);
|
||||
currentUrl.search = destination;
|
||||
url = currentUrl.toString();
|
||||
}
|
||||
|
||||
if (!isSafeURL(url)) {
|
||||
// For now log this to Sentry and do not block the execution.
|
||||
// See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121551#note_1408873600
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import $ from 'jquery';
|
||||
import Visibility from 'visibilityjs';
|
||||
import Vue from 'vue';
|
||||
import actionCable from '~/actioncable_consumer';
|
||||
import Api from '~/api';
|
||||
import { createAlert, VARIANT_INFO } from '~/alert';
|
||||
import { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issuable/constants';
|
||||
|
|
@ -151,7 +152,30 @@ export const initPolling = ({ state, dispatch, getters, commit }) => {
|
|||
|
||||
dispatch('setLastFetchedAt', getters.getNotesDataByProp('lastFetchedAt'));
|
||||
|
||||
dispatch('poll');
|
||||
if (gon.features?.actionCableNotes) {
|
||||
actionCable.subscriptions.create(
|
||||
{
|
||||
channel: 'Noteable::NotesChannel',
|
||||
project_id: state.notesData.projectId,
|
||||
group_id: state.notesData.groupId,
|
||||
noteable_type: state.notesData.noteableType,
|
||||
noteable_id: state.notesData.noteableId,
|
||||
},
|
||||
{
|
||||
connected() {
|
||||
dispatch('fetchUpdatedNotes');
|
||||
},
|
||||
received(data) {
|
||||
if (data.event === 'updated') {
|
||||
dispatch('fetchUpdatedNotes');
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
} else {
|
||||
dispatch('poll');
|
||||
}
|
||||
|
||||
commit(types.SET_IS_POLLING_INITIALIZED, true);
|
||||
};
|
||||
|
||||
|
|
@ -491,7 +515,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
|
|||
{"commands_changes":{},"valid":false,"errors":{"commands_only":["Commands applied"]}}
|
||||
*/
|
||||
if (hasQuickActions && message) {
|
||||
eTagPoll.makeRequest();
|
||||
if (eTagPoll) eTagPoll.makeRequest();
|
||||
|
||||
// synchronizing the quick action with the sidebar widget
|
||||
// this is a temporary solution until we have confidentiality real-time updates
|
||||
|
|
@ -592,6 +616,21 @@ const getFetchDataParams = (state) => {
|
|||
return { endpoint, options };
|
||||
};
|
||||
|
||||
export const fetchUpdatedNotes = ({ commit, state, getters, dispatch }) => {
|
||||
const { endpoint, options } = getFetchDataParams(state);
|
||||
|
||||
return axios
|
||||
.get(endpoint, options)
|
||||
.then(({ data }) => {
|
||||
pollSuccessCallBack(data, commit, state, getters, dispatch);
|
||||
})
|
||||
.catch(() => {
|
||||
createAlert({
|
||||
message: __('Something went wrong while fetching latest comments.'),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const poll = ({ commit, state, getters, dispatch }) => {
|
||||
const notePollOccurrenceTracking = create();
|
||||
let alert;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Noteable
|
||||
class NotesChannel < ApplicationCable::Channel
|
||||
def subscribed
|
||||
project = Project.find(params[:project_id]) if params[:project_id].present?
|
||||
|
||||
noteable = NotesFinder.new(current_user, {
|
||||
project: project,
|
||||
group_id: params[:group_id],
|
||||
target_type: params[:noteable_type],
|
||||
target_id: params[:noteable_id]
|
||||
}).target
|
||||
|
||||
return reject if noteable.nil?
|
||||
return reject if Feature.disabled?(:action_cable_notes, project || noteable.try(:group))
|
||||
|
||||
stream_for noteable
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
reject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -21,7 +21,7 @@ module WebIdeCSP
|
|||
|
||||
default_src = Array(request.content_security_policy.directives['default-src'] || [])
|
||||
request.content_security_policy.directives['frame-src'] ||= default_src
|
||||
request.content_security_policy.directives['frame-src'].concat([webpack_url, 'https://*.vscode-cdn.net/'])
|
||||
request.content_security_policy.directives['frame-src'].concat([webpack_url, 'https://*.web-ide.gitlab-static.net/'])
|
||||
|
||||
request.content_security_policy.directives['worker-src'] ||= default_src
|
||||
request.content_security_policy.directives['worker-src'].concat([webpack_url])
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
push_frontend_feature_flag(:epic_widget_edit_confirmation, project)
|
||||
push_frontend_feature_flag(:moved_mr_sidebar, project)
|
||||
push_frontend_feature_flag(:move_close_into_dropdown, project)
|
||||
push_frontend_feature_flag(:action_cable_notes, project)
|
||||
end
|
||||
|
||||
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
push_frontend_feature_flag(:mr_activity_filters, current_user)
|
||||
push_frontend_feature_flag(:review_apps_redeploy_mr_widget, project)
|
||||
push_frontend_feature_flag(:ci_job_failures_in_mr, project)
|
||||
push_frontend_feature_flag(:action_cable_notes, project)
|
||||
end
|
||||
|
||||
before_action only: [:edit] do
|
||||
|
|
|
|||
|
|
@ -318,6 +318,7 @@ module ApplicationSettingsHelper
|
|||
:max_export_size,
|
||||
:max_import_size,
|
||||
:max_import_remote_file_size,
|
||||
:max_decompressed_archive_size,
|
||||
:max_pages_size,
|
||||
:max_pages_custom_domains_per_project,
|
||||
:max_terraform_state_size_bytes,
|
||||
|
|
|
|||
|
|
@ -178,6 +178,10 @@ module NotesHelper
|
|||
|
||||
def notes_data(issuable)
|
||||
data = {
|
||||
noteableType: @noteable.class.underscore,
|
||||
noteableId: @noteable.id,
|
||||
projectId: @project&.id,
|
||||
groupId: @group&.id,
|
||||
discussionsPath: discussions_path(issuable),
|
||||
registerPath: new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'),
|
||||
newSessionPath: new_session_path(:user, redirect_to_referer: 'yes'),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ class DeviseMailer < Devise::Mailer
|
|||
|
||||
helper EmailsHelper
|
||||
helper ApplicationHelper
|
||||
helper RegistrationsHelper
|
||||
|
||||
def password_change_by_admin(record, opts = {})
|
||||
devise_mail(record, :password_change_by_admin, opts)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class Notify < ApplicationMailer
|
|||
helper GitlabRoutingHelper
|
||||
helper IssuablesHelper
|
||||
helper InProductMarketingHelper
|
||||
helper RegistrationsHelper
|
||||
|
||||
def test_email(recipient_email, subject, body)
|
||||
mail_with_locale(
|
||||
|
|
|
|||
|
|
@ -263,6 +263,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
presence: true,
|
||||
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||
|
||||
validates :max_decompressed_archive_size,
|
||||
presence: true,
|
||||
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||
|
||||
validates :max_pages_size,
|
||||
presence: true,
|
||||
numericality: {
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ module ApplicationSettingImplementation
|
|||
max_export_size: 0,
|
||||
max_import_size: 0,
|
||||
max_import_remote_file_size: 10240,
|
||||
max_decompressed_archive_size: 25600,
|
||||
max_terraform_state_size_bytes: 0,
|
||||
max_yaml_size_bytes: 1.megabyte,
|
||||
max_yaml_depth: 100,
|
||||
|
|
|
|||
|
|
@ -171,9 +171,9 @@ module Noteable
|
|||
return unless etag_caching_enabled?
|
||||
|
||||
# TODO: We need to figure out a way to make ETag caching work for group-level work items
|
||||
return if is_a?(Issue) && project.nil?
|
||||
Gitlab::EtagCaching::Store.new.touch(note_etag_key) unless is_a?(Issue) && project.nil?
|
||||
|
||||
Gitlab::EtagCaching::Store.new.touch(note_etag_key)
|
||||
Noteable::NotesChannel.broadcast_to(self, event: 'updated') if Feature.enabled?(:action_cable_notes, project || try(:group))
|
||||
end
|
||||
|
||||
def note_etag_key
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
module WebHooks
|
||||
module AutoDisabling
|
||||
extend ActiveSupport::Concern
|
||||
include ::Gitlab::Loggable
|
||||
|
||||
ENABLED_HOOK_TYPES = %w[ProjectHook].freeze
|
||||
MAX_FAILURES = 100
|
||||
|
|
@ -86,17 +87,14 @@ module WebHooks
|
|||
recent_failures > FAILURE_THRESHOLD && disabled_until.blank?
|
||||
end
|
||||
|
||||
def disable!
|
||||
return if !auto_disabling_enabled? || permanently_disabled?
|
||||
|
||||
update_attribute(:recent_failures, EXCEEDED_FAILURE_THRESHOLD)
|
||||
end
|
||||
|
||||
def enable!
|
||||
return unless auto_disabling_enabled?
|
||||
return if recent_failures == 0 && disabled_until.nil? && backoff_count == 0
|
||||
|
||||
assign_attributes(recent_failures: 0, disabled_until: nil, backoff_count: 0)
|
||||
attrs = { recent_failures: 0, disabled_until: nil, backoff_count: 0 }
|
||||
|
||||
assign_attributes(attrs)
|
||||
logger.info(hook_id: id, action: 'enable', **attrs)
|
||||
save(validate: false)
|
||||
end
|
||||
|
||||
|
|
@ -114,14 +112,21 @@ module WebHooks
|
|||
end
|
||||
|
||||
assign_attributes(attrs)
|
||||
save(validate: false) if changed?
|
||||
|
||||
return unless changed?
|
||||
|
||||
logger.info(hook_id: id, action: 'backoff', **attrs)
|
||||
save(validate: false)
|
||||
end
|
||||
|
||||
def failed!
|
||||
return unless auto_disabling_enabled?
|
||||
return unless recent_failures < MAX_FAILURES
|
||||
|
||||
assign_attributes(disabled_until: nil, backoff_count: 0, recent_failures: next_failure_count)
|
||||
attrs = { disabled_until: nil, backoff_count: 0, recent_failures: next_failure_count }
|
||||
|
||||
assign_attributes(**attrs)
|
||||
logger.info(hook_id: id, action: 'disable', **attrs)
|
||||
save(validate: false)
|
||||
end
|
||||
|
||||
|
|
@ -147,6 +152,10 @@ module WebHooks
|
|||
|
||||
private
|
||||
|
||||
def logger
|
||||
@logger ||= Gitlab::WebHooks::Logger.build
|
||||
end
|
||||
|
||||
def next_failure_count
|
||||
recent_failures.succ.clamp(1, MAX_FAILURES)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ class Integration < ApplicationRecord
|
|||
raise ArgumentError, "Unknown field storage: #{storage}"
|
||||
end
|
||||
|
||||
boolean_accessor(name) if attrs[:type] == 'checkbox' && storage != :attribute
|
||||
boolean_accessor(name) if attrs[:type] == :checkbox && storage != :attribute
|
||||
end
|
||||
# :nocov:
|
||||
|
||||
|
|
@ -472,7 +472,7 @@ class Integration < ApplicationRecord
|
|||
# use `#secret?` here.
|
||||
# See: https://gitlab.com/groups/gitlab-org/-/epics/7652
|
||||
def secret_fields
|
||||
fields.select { |f| f[:type] == 'password' }.pluck(:name)
|
||||
fields.select { |f| f[:type] == :password }.pluck(:name)
|
||||
end
|
||||
|
||||
# Expose a list of fields in the JSON endpoint.
|
||||
|
|
@ -517,7 +517,7 @@ class Integration < ApplicationRecord
|
|||
end
|
||||
|
||||
def api_field_names
|
||||
fields.reject { _1[:type] == 'password' || _1[:name] == 'webhook' }.pluck(:name)
|
||||
fields.reject { _1[:type] == :password || _1[:name] == 'webhook' }.pluck(:name)
|
||||
end
|
||||
|
||||
def form_fields
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ module Integrations
|
|||
field :app_store_private_key, api_only: true
|
||||
|
||||
field :app_store_protected_refs,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
title: -> { s_('AppleAppStore|Protected branches and tags only') },
|
||||
checkbox_label: -> { s_('AppleAppStore|Only set variables on protected branches and tags') }
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module Integrations
|
|||
validates :api_key, presence: true, if: :activated?
|
||||
|
||||
field :api_key,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: 'API key',
|
||||
help: -> { s_('AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user.') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new API key') },
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Integrations
|
|||
validates :token, presence: true, if: :activated?
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
|
||||
placeholder: '',
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ module Integrations
|
|||
help: -> { s_('BambooService|The user with API access to the Bamboo server.') }
|
||||
|
||||
field :password,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new password') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current password') }
|
||||
|
||||
|
|
|
|||
|
|
@ -78,27 +78,27 @@ module Integrations
|
|||
def default_fields
|
||||
[
|
||||
{
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
name: 'notify_only_broken_pipelines',
|
||||
help: 'Do not send notifications for successful pipelines.'
|
||||
}.freeze,
|
||||
{
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
name: 'branches_to_be_notified',
|
||||
title: s_('Integrations|Branches for which notifications are to be sent'),
|
||||
choices: self.class.branch_choices
|
||||
}.freeze,
|
||||
{
|
||||
type: 'text',
|
||||
type: :text,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
name: 'labels_to_be_notified',
|
||||
placeholder: '~backend,~frontend',
|
||||
help: 'Send notifications for issue, merge request, and comment events with the listed labels only. Leave blank to receive notifications for all events.'
|
||||
}.freeze,
|
||||
{
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
name: 'labels_to_be_notified_behavior',
|
||||
choices: [
|
||||
|
|
@ -110,8 +110,8 @@ module Integrations
|
|||
next unless requires_webhook?
|
||||
|
||||
fields.unshift(
|
||||
{ type: 'text', name: 'webhook', help: webhook_help, required: true }.freeze,
|
||||
{ type: 'text', name: 'username', placeholder: 'GitLab-integration' }.freeze
|
||||
{ type: :text, name: 'webhook', help: webhook_help, required: true }.freeze,
|
||||
{ type: :text, name: 'username', placeholder: 'GitLab-integration' }.freeze
|
||||
)
|
||||
end.freeze
|
||||
end
|
||||
|
|
@ -264,7 +264,7 @@ module Integrations
|
|||
|
||||
def build_event_channels
|
||||
event_channel_names.map do |channel_field|
|
||||
{ type: 'text', name: channel_field, placeholder: default_channel_placeholder }
|
||||
{ type: :text, name: channel_field, placeholder: default_channel_placeholder }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { _('Token') },
|
||||
help: -> do
|
||||
s_('ProjectService|The token you get after you create a Buildkite pipeline with a GitLab repository.')
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module Integrations
|
|||
format: { with: SUBDOMAIN_REGEXP }, length: { in: 1..63 }
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { _('Campfire token') },
|
||||
help: -> { s_('CampfireService|API authentication token from Campfire.') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ module Integrations
|
|||
help: -> { s_('DatadogIntegration|(Advanced) The full URL for your Datadog site.') }
|
||||
|
||||
field :api_key,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { _('API key') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new API key') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current API key') },
|
||||
|
|
@ -48,7 +48,7 @@ module Integrations
|
|||
|
||||
field :archive_trace_events,
|
||||
storage: :attribute,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
title: -> { _('Logs') },
|
||||
checkbox_label: -> { _('Enable logs collection') },
|
||||
help: -> { s_('When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces.') }
|
||||
|
|
@ -73,7 +73,7 @@ module Integrations
|
|||
end
|
||||
|
||||
field :datadog_tags,
|
||||
type: 'textarea',
|
||||
type: :textarea,
|
||||
title: -> { s_('DatadogIntegration|Tags') },
|
||||
placeholder: "tag:value\nanother_tag:value",
|
||||
help: -> do
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: -> { branch_choices }
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
help: -> { s_('ProjectService|Token for the Drone project.') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module Integrations
|
|||
validate :number_of_recipients_within_limit, if: :validate_recipients?
|
||||
|
||||
field :send_from_committer_email,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
title: -> { s_("EmailsOnPushService|Send from committer") },
|
||||
help: -> do
|
||||
@help ||= begin
|
||||
|
|
@ -21,17 +21,17 @@ module Integrations
|
|||
end
|
||||
|
||||
field :disable_diffs,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
title: -> { s_("EmailsOnPushService|Disable code diffs") },
|
||||
help: -> { s_("EmailsOnPushService|Don't include possibly sensitive code diffs in notification body.") }
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: branch_choices
|
||||
|
||||
field :recipients,
|
||||
type: 'textarea',
|
||||
type: :textarea,
|
||||
placeholder: -> { s_('EmailsOnPushService|tanuki@example.com gitlab@example.com') },
|
||||
help: -> { s_('EmailsOnPushService|Emails separated by whitespace.') }
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ module Integrations
|
|||
non_empty_password_title
|
||||
].concat(BOOLEAN_ATTRIBUTES).freeze
|
||||
|
||||
TYPES = %w[text textarea password checkbox select].freeze
|
||||
TYPES = %i[text textarea password checkbox select].freeze
|
||||
|
||||
attr_reader :name, :integration_class
|
||||
|
||||
def initialize(name:, integration_class:, type: 'text', is_secret: false, api_only: false, **attributes)
|
||||
def initialize(name:, integration_class:, type: :text, is_secret: false, api_only: false, **attributes)
|
||||
@name = name.to_s.freeze
|
||||
@integration_class = integration_class
|
||||
|
||||
attributes[:type] = is_secret ? 'password' : type
|
||||
attributes[:type] = is_secret ? :password : type
|
||||
attributes[:api_only] = api_only
|
||||
attributes[:is_secret] = is_secret
|
||||
@attributes = attributes.freeze
|
||||
|
|
@ -42,7 +42,7 @@ module Integrations
|
|||
end
|
||||
|
||||
def secret?
|
||||
self[:type] == 'password'
|
||||
self[:type] == :password
|
||||
end
|
||||
|
||||
ATTRIBUTES.each do |name|
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: -> { branch_choices }
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :password,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { s_('HarborIntegration|Harbor password') },
|
||||
help: -> { s_('HarborIntegration|Password for your Harbor username.') },
|
||||
non_empty_password_title: -> { s_('HarborIntegration|Enter new Harbor password') },
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module Integrations
|
|||
placeholder: 'irc://irc.network.net:6697/'
|
||||
|
||||
field :recipients,
|
||||
type: 'textarea',
|
||||
type: :textarea,
|
||||
title: -> { s_('IrkerService|Recipients') },
|
||||
placeholder: 'irc[s]://irc.network.net[:port]/#channel',
|
||||
required: true,
|
||||
|
|
@ -45,7 +45,7 @@ module Integrations
|
|||
end
|
||||
|
||||
field :colorize_messages,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
title: -> { _('Colorize messages') }
|
||||
|
||||
# NOTE: This field is only used internally to store the parsed
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module Integrations
|
|||
help: -> { s_('The username for the Jenkins server.') }
|
||||
|
||||
field :password,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
help: -> { s_('The password for the Jenkins server.') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new password.') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current password.') }
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ module Integrations
|
|||
exposes_secrets: true
|
||||
|
||||
field :jira_auth_type,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
required: true,
|
||||
section: SECTION_TYPE_CONNECTION,
|
||||
title: -> { s_('JiraService|Authentication type') },
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Integrations
|
|||
include Ci::TriggersHelper
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
|
||||
placeholder: ''
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
help: 'If selected, successful pipelines do not trigger a notification event.'
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: -> { branch_choices }
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { _('Token') },
|
||||
help: -> { _('Enter your Packagist token.') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@ module Integrations
|
|||
validate :number_of_recipients_within_limit, if: :validate_recipients?
|
||||
|
||||
field :recipients,
|
||||
type: 'textarea',
|
||||
type: :textarea,
|
||||
help: -> { _('Comma-separated list of email addresses.') },
|
||||
required: true
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
type: 'checkbox'
|
||||
type: :checkbox
|
||||
|
||||
field :notify_only_default_branch,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
api_only: true
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: branch_choices
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module Integrations
|
|||
validates :token, presence: true, if: :activated?
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
help: -> { s_('PivotalTrackerService|Pivotal Tracker API token. User must have access to the story. All comments are attributed to this user.') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module Integrations
|
|||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
field :manual_configuration,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
title: -> { s_('PrometheusService|Active') },
|
||||
help: -> { s_('PrometheusService|Select this checkbox to override the auto configuration settings with your own settings.') },
|
||||
required: true
|
||||
|
|
@ -24,7 +24,7 @@ module Integrations
|
|||
required: false
|
||||
|
||||
field :google_iap_service_account_json,
|
||||
type: 'textarea',
|
||||
type: :textarea,
|
||||
title: 'Google IAP Service Account JSON',
|
||||
placeholder: -> { s_('PrometheusService|{ "type": "service_account", "project_id": ... }') },
|
||||
help: -> { s_('PrometheusService|The contents of the credentials.json file of your service account.') },
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
help: 'If selected, successful pipelines do not trigger a notification event.'
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: -> { branch_choices }
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module Integrations
|
|||
validates :api_key, :user_key, :priority, presence: true, if: :activated?
|
||||
|
||||
field :api_key,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { _('API key') },
|
||||
help: -> { s_('PushoverService|Enter your application key.') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new API key') },
|
||||
|
|
@ -16,7 +16,7 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :user_key,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { _('User key') },
|
||||
help: -> { s_('PushoverService|Enter your user key.') },
|
||||
non_empty_password_title: -> { s_('PushoverService|Enter new user key') },
|
||||
|
|
@ -30,7 +30,7 @@ module Integrations
|
|||
placeholder: ''
|
||||
|
||||
field :priority,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
required: true,
|
||||
choices: -> do
|
||||
[
|
||||
|
|
@ -42,7 +42,7 @@ module Integrations
|
|||
end
|
||||
|
||||
field :sound,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
choices: -> do
|
||||
[
|
||||
['Device default sound', nil],
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Integrations
|
|||
include Ci::TriggersHelper
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
|
||||
placeholder: ''
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { s_('SquashTmIntegration|Secret token (optional)') },
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new token') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module Integrations
|
|||
help: -> { s_('ProjectService|Must have permission to trigger a manual build in TeamCity.') }
|
||||
|
||||
field :password,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
non_empty_password_title: -> { s_('ProjectService|Enter new password') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current password') }
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: -> { branch_choices }
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ module Integrations
|
|||
required: true
|
||||
|
||||
field :notify_only_broken_pipelines,
|
||||
type: 'checkbox',
|
||||
type: :checkbox,
|
||||
section: SECTION_TYPE_CONFIGURATION
|
||||
|
||||
field :branches_to_be_notified,
|
||||
type: 'select',
|
||||
type: :select,
|
||||
section: SECTION_TYPE_CONFIGURATION,
|
||||
title: -> { s_('Integrations|Branches for which notifications are to be sent') },
|
||||
choices: -> { branch_choices }
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module Integrations
|
|||
exposes_secrets: true
|
||||
|
||||
field :api_token,
|
||||
type: 'password',
|
||||
type: :password,
|
||||
title: -> { s_('ZentaoIntegration|ZenTao API token') },
|
||||
non_empty_password_title: -> { s_('ZentaoIntegration|Enter new ZenTao API token') },
|
||||
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') },
|
||||
|
|
|
|||
|
|
@ -197,9 +197,7 @@ class Note < ApplicationRecord
|
|||
# Syncs `confidential` with `internal` as we rename the column.
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/367923
|
||||
before_create :set_internal_flag
|
||||
after_destroy :expire_etag_cache
|
||||
after_save :keep_around_commit, if: :for_project_noteable?, unless: -> { importing? || skip_keep_around_commits }
|
||||
after_save :expire_etag_cache, unless: :importing?
|
||||
after_save :touch_noteable, unless: :importing?
|
||||
after_commit :notify_after_create, on: :create
|
||||
after_commit :notify_after_destroy, on: :destroy
|
||||
|
|
@ -207,6 +205,7 @@ class Note < ApplicationRecord
|
|||
after_commit :trigger_note_subscription_create, on: :create
|
||||
after_commit :trigger_note_subscription_update, on: :update
|
||||
after_commit :trigger_note_subscription_destroy, on: :destroy
|
||||
after_commit :expire_etag_cache, unless: :importing?
|
||||
|
||||
def trigger_note_subscription_create
|
||||
return unless trigger_note_subscription?
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectAuthorization < ApplicationRecord
|
||||
BATCH_SIZE = 1000
|
||||
SLEEP_DELAY = 0.1
|
||||
|
||||
extend SuppressCompositePrimaryKeyWarning
|
||||
include FromUnion
|
||||
|
||||
|
|
@ -28,57 +25,6 @@ class ProjectAuthorization < ApplicationRecord
|
|||
def self.insert_all(attributes)
|
||||
super(attributes, unique_by: connection.schema_cache.primary_keys(table_name))
|
||||
end
|
||||
|
||||
def self.insert_all_in_batches(attributes, per_batch = BATCH_SIZE)
|
||||
add_delay = add_delay_between_batches?(entire_size: attributes.size, batch_size: per_batch)
|
||||
log_details(entire_size: attributes.size, batch_size: per_batch) if add_delay
|
||||
|
||||
attributes.each_slice(per_batch) do |attributes_batch|
|
||||
insert_all(attributes_batch)
|
||||
perform_delay if add_delay
|
||||
end
|
||||
end
|
||||
|
||||
def self.delete_all_in_batches_for_project(project:, user_ids:, per_batch: BATCH_SIZE)
|
||||
add_delay = add_delay_between_batches?(entire_size: user_ids.size, batch_size: per_batch)
|
||||
log_details(entire_size: user_ids.size, batch_size: per_batch) if add_delay
|
||||
|
||||
user_ids.each_slice(per_batch) do |user_ids_batch|
|
||||
project.project_authorizations.where(user_id: user_ids_batch).delete_all
|
||||
perform_delay if add_delay
|
||||
end
|
||||
end
|
||||
|
||||
def self.delete_all_in_batches_for_user(user:, project_ids:, per_batch: BATCH_SIZE)
|
||||
add_delay = add_delay_between_batches?(entire_size: project_ids.size, batch_size: per_batch)
|
||||
log_details(entire_size: project_ids.size, batch_size: per_batch) if add_delay
|
||||
|
||||
project_ids.each_slice(per_batch) do |project_ids_batch|
|
||||
user.project_authorizations.where(project_id: project_ids_batch).delete_all
|
||||
perform_delay if add_delay
|
||||
end
|
||||
end
|
||||
|
||||
private_class_method def self.add_delay_between_batches?(entire_size:, batch_size:)
|
||||
# The reason for adding a delay is to give the replica database enough time to
|
||||
# catch up with the primary when large batches of records are being added/removed.
|
||||
# Hance, we add a delay only if the GitLab installation has a replica database configured.
|
||||
entire_size > batch_size &&
|
||||
!::Gitlab::Database::LoadBalancing.primary_only?
|
||||
end
|
||||
|
||||
private_class_method def self.log_details(entire_size:, batch_size:)
|
||||
Gitlab::AppLogger.info(
|
||||
entire_size: entire_size,
|
||||
total_delay: (entire_size / batch_size.to_f).ceil * SLEEP_DELAY,
|
||||
message: 'Project authorizations refresh performed with delay',
|
||||
**Gitlab::ApplicationContext.current
|
||||
)
|
||||
end
|
||||
|
||||
private_class_method def self.perform_delay
|
||||
sleep(SLEEP_DELAY)
|
||||
end
|
||||
end
|
||||
|
||||
ProjectAuthorization.prepend_mod_with('ProjectAuthorization')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProjectAuthorizations
|
||||
# How to use this class
|
||||
# authorizations_to_add:
|
||||
# Rows to insert in the form `[{ user_id: user_id, project_id: project_id, access_level: access_level}, ...]
|
||||
#
|
||||
# ProjectAuthorizations::Changes.new do |changes|
|
||||
# changes.add(authorizations_to_add)
|
||||
# changes.remove_users_in_project(project, user_ids)
|
||||
# changes.remove_projects_for_user(user, project_ids)
|
||||
# end.apply!
|
||||
class Changes
|
||||
attr_reader :projects_to_remove, :users_to_remove, :authorizations_to_add
|
||||
|
||||
BATCH_SIZE = 1000
|
||||
SLEEP_DELAY = 0.1
|
||||
|
||||
def initialize
|
||||
@authorizations_to_add = []
|
||||
yield self
|
||||
end
|
||||
|
||||
def add(authorizations_to_add)
|
||||
@authorizations_to_add += authorizations_to_add
|
||||
end
|
||||
|
||||
def remove_users_in_project(project, user_ids)
|
||||
@users_to_remove = { user_ids: user_ids, scope: project }
|
||||
end
|
||||
|
||||
def remove_projects_for_user(user, project_ids)
|
||||
@projects_to_remove = { project_ids: project_ids, scope: user }
|
||||
end
|
||||
|
||||
def apply!
|
||||
delete_authorizations_for_user if should_delete_authorizations_for_user?
|
||||
delete_authorizations_for_project if should_delete_authorizations_for_project?
|
||||
add_authorizations if should_add_authorization?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def should_add_authorization?
|
||||
authorizations_to_add.present?
|
||||
end
|
||||
|
||||
def should_delete_authorizations_for_user?
|
||||
user && project_ids.present?
|
||||
end
|
||||
|
||||
def should_delete_authorizations_for_project?
|
||||
project && user_ids.present?
|
||||
end
|
||||
|
||||
def add_authorizations
|
||||
insert_all_in_batches(authorizations_to_add)
|
||||
end
|
||||
|
||||
def delete_authorizations_for_user
|
||||
delete_all_in_batches(resource: user,
|
||||
ids_to_remove: project_ids,
|
||||
column_name_of_ids_to_remove: :project_id)
|
||||
end
|
||||
|
||||
def delete_authorizations_for_project
|
||||
delete_all_in_batches(resource: project,
|
||||
ids_to_remove: user_ids,
|
||||
column_name_of_ids_to_remove: :user_id)
|
||||
end
|
||||
|
||||
def delete_all_in_batches(resource:, ids_to_remove:, column_name_of_ids_to_remove:)
|
||||
add_delay = add_delay_between_batches?(entire_size: ids_to_remove.size, batch_size: BATCH_SIZE)
|
||||
log_details(entire_size: ids_to_remove.size, batch_size: BATCH_SIZE) if add_delay
|
||||
|
||||
ids_to_remove.each_slice(BATCH_SIZE) do |ids_batch|
|
||||
resource.project_authorizations.where(column_name_of_ids_to_remove => ids_batch).delete_all
|
||||
perform_delay if add_delay
|
||||
end
|
||||
end
|
||||
|
||||
def insert_all_in_batches(attributes)
|
||||
add_delay = add_delay_between_batches?(entire_size: attributes.size, batch_size: BATCH_SIZE)
|
||||
log_details(entire_size: attributes.size, batch_size: BATCH_SIZE) if add_delay
|
||||
|
||||
attributes.each_slice(BATCH_SIZE) do |attributes_batch|
|
||||
ProjectAuthorization.insert_all(attributes_batch)
|
||||
perform_delay if add_delay
|
||||
end
|
||||
end
|
||||
|
||||
def add_delay_between_batches?(entire_size:, batch_size:)
|
||||
# The reason for adding a delay is to give the replica database enough time to
|
||||
# catch up with the primary when large batches of records are being added/removed.
|
||||
# Hence, we add a delay only if the GitLab installation has a replica database configured.
|
||||
entire_size > batch_size &&
|
||||
!::Gitlab::Database::LoadBalancing.primary_only?
|
||||
end
|
||||
|
||||
def log_details(entire_size:, batch_size:)
|
||||
Gitlab::AppLogger.info(
|
||||
entire_size: entire_size,
|
||||
total_delay: (entire_size / batch_size.to_f).ceil * SLEEP_DELAY,
|
||||
message: 'Project authorizations refresh performed with delay',
|
||||
**Gitlab::ApplicationContext.current
|
||||
)
|
||||
end
|
||||
|
||||
def perform_delay
|
||||
sleep(SLEEP_DELAY)
|
||||
end
|
||||
|
||||
def user
|
||||
projects_to_remove&.[](:scope)
|
||||
end
|
||||
|
||||
def project_ids
|
||||
projects_to_remove&.[](:project_ids)
|
||||
end
|
||||
|
||||
def project
|
||||
users_to_remove&.[](:scope)
|
||||
end
|
||||
|
||||
def user_ids
|
||||
users_to_remove&.[](:user_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -67,7 +67,13 @@ class ProjectStatistics < ApplicationRecord
|
|||
end
|
||||
|
||||
def update_repository_size
|
||||
self.repository_size = project.repository.size * 1.megabyte
|
||||
size = if Feature.enabled?(:recent_objects_for_project_statistics, project)
|
||||
project.repository.recent_objects_size
|
||||
else
|
||||
project.repository.size
|
||||
end
|
||||
|
||||
self.repository_size = size.megabytes
|
||||
end
|
||||
|
||||
def update_wiki_size
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class Repository
|
|||
#
|
||||
# For example, for entry `:commit_count` there's a method called `commit_count` which
|
||||
# stores its data in the `commit_count` cache key.
|
||||
CACHED_METHODS = %i(size commit_count readme_path contribution_guide
|
||||
CACHED_METHODS = %i(size recent_objects_size commit_count readme_path contribution_guide
|
||||
changelog license_blob license_gitaly gitignore
|
||||
gitlab_ci_yml branch_names tag_names branch_count
|
||||
tag_count avatar exists? root_ref merged_branch_names
|
||||
|
|
@ -363,7 +363,7 @@ class Repository
|
|||
end
|
||||
|
||||
def expire_statistics_caches
|
||||
expire_method_caches(%i(size commit_count))
|
||||
expire_method_caches(%i(size recent_objects_size commit_count))
|
||||
end
|
||||
|
||||
def expire_all_method_caches
|
||||
|
|
@ -579,6 +579,12 @@ class Repository
|
|||
end
|
||||
cache_method :size, fallback: 0.0
|
||||
|
||||
# The recent objects size of this repository in mebibytes.
|
||||
def recent_objects_size
|
||||
exists? ? raw_repository.recent_objects_size : 0.0
|
||||
end
|
||||
cache_method :recent_objects_size, fallback: 0.0
|
||||
|
||||
def commit_count
|
||||
root_ref ? raw_repository.commit_count(root_ref) : 0
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
module Ci
|
||||
class BridgePolicy < CommitStatusPolicy
|
||||
include Ci::DeployablePolicy
|
||||
|
||||
condition(:can_update_downstream_branch) do
|
||||
::Gitlab::UserAccess.new(@user, container: @subject.downstream_project)
|
||||
.can_update_branch?(@subject.target_revision_ref)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
module Ci
|
||||
class BuildPolicy < CommitStatusPolicy
|
||||
include Ci::DeployablePolicy
|
||||
|
||||
delegate { @subject.project }
|
||||
|
||||
condition(:protected_ref) do
|
||||
|
|
@ -22,15 +24,6 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
# overridden in EE
|
||||
condition(:protected_environment) do
|
||||
false
|
||||
end
|
||||
|
||||
condition(:outdated_deployment) do
|
||||
@subject.outdated_deployment?
|
||||
end
|
||||
|
||||
condition(:owner_of_job) do
|
||||
@subject.triggered_by?(@user)
|
||||
end
|
||||
|
|
@ -83,17 +76,15 @@ module Ci
|
|||
# Authorizing the user to access to protected entities.
|
||||
# There is a "jailbreak" mode to exceptionally bypass the authorization,
|
||||
# however, you should NEVER allow it, rather suspect it's a wrong feature/product design.
|
||||
rule { ~can?(:jailbreak) & (archived | (protected_ref & ~admin) | protected_environment) }.policy do
|
||||
rule { ~can?(:jailbreak) & (archived | (protected_ref & ~admin)) }.policy do
|
||||
prevent :update_commit_status
|
||||
end
|
||||
|
||||
rule { ~can?(:jailbreak) & (archived | protected_ref | protected_environment) }.policy do
|
||||
rule { ~can?(:jailbreak) & (archived | protected_ref) }.policy do
|
||||
prevent :update_build
|
||||
prevent :erase_build
|
||||
end
|
||||
|
||||
rule { outdated_deployment }.prevent :update_build
|
||||
|
||||
rule { can?(:admin_build) | (can?(:update_build) & owner_of_job & unprotected_ref) }.enable :erase_build
|
||||
|
||||
rule { can?(:public_access) & branch_allows_collaboration }.policy do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
module DeployablePolicy
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
prepend_mod_with('Ci::DeployablePolicy') # rubocop: disable Cop/InjectEnterpriseEditionModule
|
||||
|
||||
condition(:outdated_deployment) do
|
||||
@subject.outdated_deployment?
|
||||
end
|
||||
|
||||
rule { outdated_deployment }.prevent :update_build
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,12 +5,16 @@ module Integrations
|
|||
include RequestAwareEntity
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
expose :section, :type, :name, :placeholder, :required, :choices, :checkbox_label
|
||||
expose :section, :name, :placeholder, :required, :choices, :checkbox_label
|
||||
|
||||
expose :title do |field|
|
||||
non_empty_password?(field) ? field[:non_empty_password_title] : field[:title]
|
||||
end
|
||||
|
||||
expose :type do |field|
|
||||
field[:type].to_s
|
||||
end
|
||||
|
||||
expose :help do |field|
|
||||
non_empty_password?(field) ? field[:non_empty_password_help] : field[:help]
|
||||
end
|
||||
|
|
@ -20,7 +24,7 @@ module Integrations
|
|||
|
||||
if non_empty_password?(field)
|
||||
'true'
|
||||
elsif field[:type] == 'checkbox'
|
||||
elsif field[:type] == :checkbox
|
||||
ActiveRecord::Type::Boolean.new.deserialize(value).to_s
|
||||
elsif field[:name] == 'webhook' && integration.chat?
|
||||
BaseChatNotification::SECRET_MASK if value.present?
|
||||
|
|
@ -44,7 +48,7 @@ module Integrations
|
|||
|
||||
def non_empty_password?(field)
|
||||
strong_memoize(:non_empty_password) do
|
||||
field[:type] == 'password' && value_for(field).present?
|
||||
field[:type] == :password && value_for(field).present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ module Admin
|
|||
|
||||
add_history_to_params!
|
||||
|
||||
plan_limits.assign_attributes(parsed_params)
|
||||
|
||||
validate_storage_limits
|
||||
|
||||
return error(plan_limits.errors.full_messages, :bad_request) if plan_limits.errors.any?
|
||||
|
||||
if plan_limits.update(parsed_params)
|
||||
success
|
||||
else
|
||||
|
|
@ -26,6 +32,8 @@ module Admin
|
|||
|
||||
attr_accessor :current_user, :params, :plan, :plan_limits
|
||||
|
||||
delegate :notification_limit, :storage_size_limit, :enforcement_limit, to: :plan_limits
|
||||
|
||||
def can_update?
|
||||
current_user.can_admin_all_resources?
|
||||
end
|
||||
|
|
@ -35,6 +43,39 @@ module Admin
|
|||
parsed_params.merge!(limits_history: formatted_limits_history) unless formatted_limits_history.empty?
|
||||
end
|
||||
|
||||
def validate_storage_limits
|
||||
validate_notification_limit
|
||||
validate_enforcement_limit
|
||||
validate_storage_size_limit
|
||||
end
|
||||
|
||||
def validate_notification_limit
|
||||
return unless parsed_params.include?(:notification_limit)
|
||||
return if notification_limit >= storage_size_limit && notification_limit <= enforcement_limit
|
||||
|
||||
plan_limits.errors.add(:notification_limit, "must be greater than or equal to " \
|
||||
"storage_size_limit (Dashboard limit): #{storage_size_limit} " \
|
||||
"and less than or equal to enforcement_limit: #{enforcement_limit}")
|
||||
end
|
||||
|
||||
def validate_enforcement_limit
|
||||
return unless parsed_params.include?(:enforcement_limit)
|
||||
return if enforcement_limit >= storage_size_limit && enforcement_limit >= notification_limit
|
||||
|
||||
plan_limits.errors.add(:enforcement_limit, "must be greater than or equal to " \
|
||||
"storage_size_limit (Dashboard limit): #{storage_size_limit} and " \
|
||||
"greater than or equal to notification_limit: #{notification_limit}")
|
||||
end
|
||||
|
||||
def validate_storage_size_limit
|
||||
return unless parsed_params.include?(:storage_size_limit)
|
||||
return if storage_size_limit <= enforcement_limit && storage_size_limit <= notification_limit
|
||||
|
||||
plan_limits.errors.add(:storage_size_limit, "(Dashboard limit) must be less than or equal to " \
|
||||
"enforcement_limit: #{enforcement_limit} " \
|
||||
"and notification_limit: #{notification_limit}")
|
||||
end
|
||||
|
||||
# Overridden in EE
|
||||
def parsed_params
|
||||
params
|
||||
|
|
|
|||
|
|
@ -64,13 +64,10 @@ module AuthorizedProjectUpdate
|
|||
end
|
||||
|
||||
def refresh_authorizations
|
||||
if user_ids_to_remove.any?
|
||||
ProjectAuthorization.delete_all_in_batches_for_project(
|
||||
project: project,
|
||||
user_ids: user_ids_to_remove)
|
||||
end
|
||||
|
||||
ProjectAuthorization.insert_all_in_batches(authorizations_to_create) if authorizations_to_create.any?
|
||||
ProjectAuthorizations::Changes.new do |changes|
|
||||
changes.add(authorizations_to_create)
|
||||
changes.remove_users_in_project(project, user_ids_to_remove)
|
||||
end.apply!
|
||||
end
|
||||
|
||||
def apply_scopes(project_authorizations)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ module Metrics
|
|||
STAGES = ::Gitlab::Metrics::Dashboard::Stages
|
||||
SEQUENCE = [
|
||||
STAGES::CommonMetricsInserter,
|
||||
STAGES::VariableEndpointInserter,
|
||||
STAGES::PanelIdsInserter,
|
||||
STAGES::TrackPanelType,
|
||||
STAGES::UrlValidator
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Responsible for returning a filtered system dashboard
|
||||
# containing only the default embedded metrics. This class
|
||||
# operates by selecting metrics directly from the system
|
||||
# dashboard.
|
||||
#
|
||||
# Why isn't this filtering in a processing stage? By filtering
|
||||
# here, we ensure the dynamically-determined dashboard is cached.
|
||||
#
|
||||
# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards.
|
||||
module Metrics
|
||||
module Dashboard
|
||||
class DefaultEmbedService < ::Metrics::Dashboard::BaseEmbedService
|
||||
# For the default filtering for embedded metrics,
|
||||
# uses the 'id' key in dashboard-yml definition for
|
||||
# identification.
|
||||
DEFAULT_EMBEDDED_METRICS_IDENTIFIERS = %w(
|
||||
system_metrics_kubernetes_container_memory_total
|
||||
system_metrics_kubernetes_container_cores_total
|
||||
).freeze
|
||||
|
||||
class << self
|
||||
def valid_params?(params)
|
||||
embedded?(params[:embedded])
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a new dashboard with only the matching
|
||||
# metrics from the system dashboard, stripped of groups.
|
||||
# @return [Hash]
|
||||
def get_raw_dashboard
|
||||
panels = panel_groups.each_with_object([]) do |group, panels|
|
||||
matched_panels = group['panels'].select { |panel| matching_panel?(panel) }
|
||||
|
||||
panels.concat(matched_panels)
|
||||
end
|
||||
|
||||
{ 'panel_groups' => [{ 'panels' => panels }] }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns an array of the panels groups on the
|
||||
# system dashboard
|
||||
def panel_groups
|
||||
::Metrics::Dashboard::SystemDashboardService
|
||||
.new(project, nil)
|
||||
.raw_dashboard['panel_groups']
|
||||
end
|
||||
|
||||
# Identifies a panel as "matching" if any metric ids in
|
||||
# the panel is in the list of identifiers to collect.
|
||||
def matching_panel?(panel)
|
||||
panel['metrics'].any? do |metric|
|
||||
metric_identifiers.include?(metric['id'])
|
||||
end
|
||||
end
|
||||
|
||||
def metric_identifiers
|
||||
DEFAULT_EMBEDDED_METRICS_IDENTIFIERS
|
||||
end
|
||||
|
||||
def identifiers
|
||||
metric_identifiers.join('|')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,6 @@ module Metrics
|
|||
DASHBOARD_NAME = nil
|
||||
|
||||
SEQUENCE = [
|
||||
STAGES::VariableEndpointInserter,
|
||||
STAGES::PanelIdsInserter
|
||||
].freeze
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ module Metrics
|
|||
STAGES::CommonMetricsInserter,
|
||||
STAGES::CustomMetricsInserter,
|
||||
STAGES::CustomMetricsDetailsInserter,
|
||||
STAGES::VariableEndpointInserter,
|
||||
STAGES::PanelIdsInserter
|
||||
].freeze
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Projects
|
|||
include ::Gitlab::Utils::StrongMemoize
|
||||
|
||||
STAT_TO_CACHED_METHOD = {
|
||||
repository_size: :size,
|
||||
repository_size: [:size, :recent_objects_size],
|
||||
commit_count: :commit_count
|
||||
}.freeze
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ module Projects
|
|||
|
||||
def method_caches_to_expire
|
||||
strong_memoize(:method_caches_to_expire) do
|
||||
statistics.map { |stat| STAT_TO_CACHED_METHOD[stat] }.compact
|
||||
statistics.flat_map { |stat| STAT_TO_CACHED_METHOD[stat] }.compact
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,10 @@ module Users
|
|||
def update_authorizations(remove = [], add = [])
|
||||
log_refresh_details(remove, add)
|
||||
|
||||
ProjectAuthorization.delete_all_in_batches_for_user(user: user, project_ids: remove) if remove.any?
|
||||
ProjectAuthorization.insert_all_in_batches(add) if add.any?
|
||||
ProjectAuthorizations::Changes.new do |changes|
|
||||
changes.add(add)
|
||||
changes.remove_projects_for_user(user, remove)
|
||||
end.apply!
|
||||
|
||||
# Since we batch insert authorization rows, Rails' associations may get
|
||||
# out of sync. As such we force a reload of the User object.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
.form-group
|
||||
= f.label :bulk_import_max_download_file_size, s_('BulkImport|Direct transfer maximum download file size (MB)'), class: 'label-light'
|
||||
= f.number_field :bulk_import_max_download_file_size, class: 'form-control gl-form-input', title: s_('BulkImport|Maximum download file size when importing from source GitLab instances by direct transfer.'), data: { toggle: 'tooltip', container: 'body' }
|
||||
.form-group
|
||||
= f.label :max_decompressed_archive_size, s_('Import|Maximum decompressed size (MiB)'), class: 'label-light'
|
||||
= f.number_field :max_decompressed_archive_size, class: 'form-control gl-form-input', title: s_('Import|Maximum size of decompressed archive.'), data: { toggle: 'tooltip', container: 'body' }
|
||||
%span.form-text.text-muted= _('Set to 0 for no size limit.')
|
||||
.form-group
|
||||
= f.label :session_expire_delay, _('Session duration (minutes)'), class: 'label-light'
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
= render "layouts/bizible"
|
||||
= render "layouts/google_tag_manager_body"
|
||||
|
||||
= render_if_exists 'devise/shared/delete_unconfirmed_users_flash'
|
||||
|
||||
.well-confirmation.gl-text-center.gl-mb-6
|
||||
%h1.gl-mt-0
|
||||
= _("Almost there...")
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
- confirmation_link = confirmation_url(@resource, confirmation_token: @token)
|
||||
|
||||
- if @resource.unconfirmed_email.present? || !@resource.created_recently?
|
||||
#content
|
||||
= email_default_heading(@email)
|
||||
%p= _('Click the link below to confirm your email address.')
|
||||
#cta
|
||||
= render_if_exists 'devise/shared/delete_unconfirmed_users'
|
||||
= link_to _('Confirm your email address'), confirmation_link
|
||||
- else
|
||||
#content
|
||||
|
|
@ -13,4 +15,5 @@
|
|||
= email_default_heading(_("Welcome, %{name}!") % { name: @resource.name })
|
||||
%p= _("To get started, click the link below to confirm your account.")
|
||||
#cta
|
||||
= render_if_exists 'devise/shared/delete_unconfirmed_users'
|
||||
= link_to _('Confirm your account'), confirmation_link
|
||||
|
|
|
|||
|
|
@ -10,4 +10,6 @@
|
|||
<%= _('To get started, use the link below to confirm your account.') %>
|
||||
<% end %>
|
||||
|
||||
<%= render_if_exists 'devise/shared/delete_unconfirmed_users_text' %>
|
||||
|
||||
<%= confirmation_url(@resource, confirmation_token: @token) %>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ class WebHookWorker
|
|||
# present in the request header so the hook can pass this same header value in its request.
|
||||
Gitlab::WebHooks::RecursionDetection.set_request_uuid(params[:recursion_detection_request_uuid])
|
||||
|
||||
WebHookService.new(hook, data, hook_name, jid).execute
|
||||
WebHookService.new(hook, data, hook_name, jid).execute.tap do |response|
|
||||
log_extra_metadata_on_done(:response_status, response.status)
|
||||
log_extra_metadata_on_done(:http_status, response[:http_status])
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Scalability/IdempotentWorker
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: action_cable_notes
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127964
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/412823
|
||||
milestone: '16.3'
|
||||
type: development
|
||||
group: group::project management
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: recent_objects_for_project_statistics
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127867
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420125
|
||||
milestone: '16.3'
|
||||
type: development
|
||||
group: group::utilization
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddMaxDecompressionArchiveSizeToApplicationSettings < Gitlab::Database::Migration[2.1]
|
||||
def change
|
||||
add_column :application_settings, :max_decompressed_archive_size, :integer, default: 25600, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddApplicationSettingsMaxDecompressionSizeConstraint < Gitlab::Database::Migration[2.1]
|
||||
CONSTRAINT_NAME = 'app_settings_max_decompressed_archive_size_positive'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_check_constraint :application_settings, 'max_decompressed_archive_size >= 0', CONSTRAINT_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_check_constraint :application_settings, CONSTRAINT_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
1bc56bc33ef336f4c97d15c8b726dad319a5775b8f8efa759bb14bb9a4db44eb
|
||||
|
|
@ -0,0 +1 @@
|
|||
1b158b3191749032084d69f68e02f8aaddeb640ee10db4f1bb43041e4fd2d4ac
|
||||
|
|
@ -11861,12 +11861,14 @@ CREATE TABLE application_settings (
|
|||
bulk_import_max_download_file_size bigint DEFAULT 5120 NOT NULL,
|
||||
max_import_remote_file_size bigint DEFAULT 10240 NOT NULL,
|
||||
protected_paths_for_get_request text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
max_decompressed_archive_size integer DEFAULT 25600 NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
|
||||
CONSTRAINT app_settings_git_rate_limit_users_alertlist_max_usernames CHECK ((cardinality(git_rate_limit_users_alertlist) <= 100)),
|
||||
CONSTRAINT app_settings_git_rate_limit_users_allowlist_max_usernames CHECK ((cardinality(git_rate_limit_users_allowlist) <= 100)),
|
||||
CONSTRAINT app_settings_max_decompressed_archive_size_positive CHECK ((max_decompressed_archive_size >= 0)),
|
||||
CONSTRAINT app_settings_max_pages_custom_domains_per_project_check CHECK ((max_pages_custom_domains_per_project >= 0)),
|
||||
CONSTRAINT app_settings_max_terraform_state_size_bytes_check CHECK ((max_terraform_state_size_bytes >= 0)),
|
||||
CONSTRAINT app_settings_p_cleanup_package_file_worker_capacity_positive CHECK ((packages_cleanup_package_file_worker_capacity >= 0)),
|
||||
|
|
|
|||
|
|
@ -820,6 +820,23 @@ This file is located at:
|
|||
This structured log file records internal activity in the `mail_room` gem.
|
||||
Its name and path are configurable, so the name and path may not match the above.
|
||||
|
||||
## `web_hooks.log`
|
||||
|
||||
> Introduced in GitLab 16.3.
|
||||
|
||||
This file is located at:
|
||||
|
||||
- `/var/log/gitlab/gitlab-rails/web_hooks.log` on Linux package installations.
|
||||
- `/home/git/gitlab/log/web_hooks.log` on self-compiled installations.
|
||||
|
||||
The back-off, disablement, and re-enablement events for Webhook are recorded in this file. For example:
|
||||
|
||||
```json
|
||||
{"severity":"INFO","time":"2020-11-24T02:30:59.860Z","hook_id":12,"action":"backoff","disabled_until":"2020-11-24T04:30:59.860Z","backoff_count":2,"recent_failures":2}
|
||||
{"severity":"INFO","time":"2020-11-24T02:30:59.860Z","hook_id":12,"action":"disable","disabled_until":null,"backoff_count":5,"recent_failures":100}
|
||||
{"severity":"INFO","time":"2020-11-24T02:30:59.860Z","hook_id":12,"action":"enable","disabled_until":null,"backoff_count":0,"recent_failures":0}
|
||||
```
|
||||
|
||||
## Reconfigure logs
|
||||
|
||||
Reconfigure log files are in `/var/log/gitlab/reconfigure` for Linux package installations. Self-compiled installations
|
||||
|
|
|
|||
|
|
@ -135,6 +135,26 @@ To modify the maximum download file size for imports by direct transfer:
|
|||
1. Expand **Account and limit**.
|
||||
1. Increase or decrease by changing the value in **Direct transfer maximum download file size (MB)**. Set to `0` to set no download file size limit.
|
||||
|
||||
## Maximum decompressed file size for imported archives
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128218) in GitLab 16.3.
|
||||
|
||||
When you [import a project](../../user/project/settings/import_export.md), you can specify the maximum decompressed file size for imported archives. The default value is 25 GB.
|
||||
|
||||
When you import a compressed file, the decompressed size cannot exceed the maximum decompressed file size limit. If the decompressed size exceeds the configured limit, the following error is returned:
|
||||
|
||||
```plaintext
|
||||
Decompressed archive size validation failed.
|
||||
```
|
||||
|
||||
To modify the maximum decompressed file size for imports in GitLab:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
1. Select **Admin Area**.
|
||||
1. Select **Settings > General**.
|
||||
1. Expand **Account and limit**.
|
||||
1. Set another value for **Maximum decompressed size (MiB)**.
|
||||
|
||||
## Personal access token prefix
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20968) in GitLab 13.7.
|
||||
|
|
|
|||
|
|
@ -6888,6 +6888,7 @@ Input type: `UserAddOnAssignmentCreateInput`
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationuseraddonassignmentcreateaddonpurchase"></a>`addOnPurchase` | [`AddOnPurchase`](#addonpurchase) | AddOnPurchase state after mutation. |
|
||||
| <a id="mutationuseraddonassignmentcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationuseraddonassignmentcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
|
||||
|
|
|
|||
|
|
@ -324,7 +324,8 @@ Example response:
|
|||
"version": "1.3.0.17",
|
||||
"tags": "",
|
||||
"packageContent": "https://gitlab.example.com/api/v4/projects/1/packages/nuget/download/MyNuGetPkg/1.3.0.17/helloworld.1.3.0.17.nupkg",
|
||||
"summary": "Summary of the package",
|
||||
"description": "Description of the package",
|
||||
"summary": "Description of the package",
|
||||
"published": "2023-05-08T17:23:25Z",
|
||||
}
|
||||
}
|
||||
|
|
@ -367,7 +368,8 @@ Example response:
|
|||
"version": "1.3.0.17",
|
||||
"tags": "",
|
||||
"packageContent": "https://gitlab.example.com/api/v4/projects/1/packages/nuget/download/MyNuGetPkg/1.3.0.17/helloworld.1.3.0.17.nupkg",
|
||||
"summary": "Summary of the package",
|
||||
"description": "Description of the package",
|
||||
"summary": "Description of the package",
|
||||
"published": "2023-05-08T17:23:25Z",
|
||||
}
|
||||
}
|
||||
|
|
@ -405,7 +407,8 @@ Example response:
|
|||
"authors": "Author1, Author2",
|
||||
"id": "MyNuGetPkg",
|
||||
"title": "MyNuGetPkg",
|
||||
"summary": "Summary of the package",
|
||||
"description": "Description of the package",
|
||||
"summary": "Description of the package",
|
||||
"totalDownloads": 0,
|
||||
"verified": true,
|
||||
"version": "1.3.0.17",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ Example response:
|
|||
"max_export_size": 50,
|
||||
"max_import_size": 50,
|
||||
"max_import_remote_file_size": 10240,
|
||||
"max_decompressed_archive_size": 25600,
|
||||
"user_oauth_applications" : true,
|
||||
"updated_at" : "2016-01-04T15:44:55.176Z",
|
||||
"session_expire_delay" : 10080,
|
||||
|
|
@ -185,6 +186,7 @@ Example response:
|
|||
"max_export_size": 50,
|
||||
"max_import_size": 50,
|
||||
"max_import_remote_file_size": 10240,
|
||||
"max_decompressed_archive_size": 25600,
|
||||
"session_expire_delay": 10080,
|
||||
"default_ci_config_path" : null,
|
||||
"default_project_visibility": "internal",
|
||||
|
|
@ -456,9 +458,10 @@ listed in the descriptions of the relevant settings.
|
|||
| `maintenance_mode` **(PREMIUM)** | boolean | no | When instance is in maintenance mode, non-administrative users can sign in with read-only access and make read-only API requests. |
|
||||
| `max_artifacts_size` | integer | no | Maximum artifacts size in MB. |
|
||||
| `max_attachment_size` | integer | no | Limit attachment size in MB. |
|
||||
| `max_decompressed_archive_size` | integer | no | Maximum decompressed file size for imported archives in MB. Set to `0` for unlimited. Default is `25600`. |
|
||||
| `max_export_size` | integer | no | Maximum export size in MB. 0 for unlimited. Default = 0 (unlimited). |
|
||||
| `max_import_size` | integer | no | Maximum import size in MB. 0 for unlimited. Default = 0 (unlimited). [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/251106) from 50 MB to 0 in GitLab 13.8. |
|
||||
| `max_import_remote_file_size` | integer | no | Maximum remote file size for imports from external object storages. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384976) in GitLab 16.3. |
|
||||
| `max_import_remote_file_size` | integer | no | Maximum remote file size for imports from external object storages. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384976) in GitLab 16.3. |
|
||||
| `max_pages_size` | integer | no | Maximum size of pages repositories in MB. |
|
||||
| `max_personal_access_token_lifetime` **(ULTIMATE SELF)** | integer | no | Maximum allowable lifetime for access tokens in days. When left blank, default value of 365 is applied. When set, value must be 365 or less. When changed, existing access tokens with an expiration date beyond the maximum allowable lifetime are revoked.|
|
||||
| `max_ssh_key_lifetime` **(ULTIMATE SELF)** | integer | no | Maximum allowable lifetime for SSH keys in days. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1007) in GitLab 14.6. |
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ AI is moving very quickly, and we need to be able to keep pace with changes in t
|
|||
|
||||
The following diagram from the [architecture blueprint](../architecture/blueprints/ai_gateway/index.md) shows a simplified view of how the different components in GitLab interact. The abstraction layer helps avoid code duplication within the REST APIs within the `AI API` block.
|
||||
|
||||

|
||||

|
||||
|
||||
## SaaS-based AI abstraction layer
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: none
|
||||
group: none
|
||||
stage: ModelOps
|
||||
group: AI Framework
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
@ -421,6 +421,52 @@ module EE
|
|||
end
|
||||
```
|
||||
|
||||
### Pairing requests with responses
|
||||
|
||||
Because multiple users' requests can be processed in parallel, when receiving responses,
|
||||
it can be difficult to pair a response with its original request. The `requestId`
|
||||
field can be used for this purpose, because both the request and response are assured
|
||||
to have the same `requestId` UUID.
|
||||
|
||||
### Caching
|
||||
|
||||
AI requests and responses can be cached. Cached conversation is being used to
|
||||
display user interaction with AI features. In the current implementation, this cache
|
||||
is not used to skip consecutive calls to the AI service when a user repeats
|
||||
their requests.
|
||||
|
||||
```graphql
|
||||
query {
|
||||
aiMessages {
|
||||
nodes {
|
||||
id
|
||||
requestId
|
||||
content
|
||||
role
|
||||
errors
|
||||
timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This cache is especially useful for chat functionality. For other services,
|
||||
caching is disabled. (It can be enabled for a service by using `skip_cache: false`
|
||||
option.)
|
||||
|
||||
Caching has following limitations:
|
||||
|
||||
- Messages are stored in Redis stream.
|
||||
- There is a single stream of messages per user. This means that all services
|
||||
currently share the same cache. If needed, this could be extended to multiple
|
||||
streams per user (after checking with the infrastructure team that Redis can handle
|
||||
the estimated amount of messages).
|
||||
- Only the last 50 messages (requests + responses) are kept.
|
||||
- Expiration time of the stream is 3 days since adding last message.
|
||||
- User can access only their own messages. There is no authorization on the caching
|
||||
level, and any authorization (if accessed by not current user) is expected on
|
||||
the service layer.
|
||||
|
||||
### Check if feature is allowed for this resource based on namespace settings
|
||||
|
||||
There are two settings allowed on root namespace level that restrict the use of AI features:
|
||||
|
|
|
|||
|
|
@ -1298,6 +1298,12 @@ Use lowercase for **runner managers**. These are a type of runner that can creat
|
|||
|
||||
Use lowercase for **runner workers**. This is the process created by the runner on the host computing platform to run jobs. See also [GitLab Runner](#gitlab-runner).
|
||||
|
||||
## runner authentication token
|
||||
|
||||
Use **runner authentication token** instead of variations like **runner token**, **authentication token**, or **token**.
|
||||
Runners are assigned runner authentication tokens when they are created, and use them to authenticate with GitLab when
|
||||
they execute jobs.
|
||||
|
||||
## (s)
|
||||
|
||||
Do not use **(s)** to make a word optionally plural. It can slow down comprehension. For example:
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 369 KiB |
|
|
@ -24,7 +24,7 @@ type: index
|
|||
- [Proxying images](asset_proxy.md)
|
||||
- [CI/CD variables](../ci/variables/index.md#cicd-variable-security)
|
||||
- [Token overview](token_overview.md)
|
||||
- [Project Import decompressed archive size limits](project_import_decompressed_archive_size_limits.md)
|
||||
- [Maximum decompressed file size for imported archives](../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives)
|
||||
- [Responding to security incidents](responding_to_security_incidents.md)
|
||||
|
||||
To harden your GitLab instance and minimize the risk of unwanted user account creation, consider access control features like [Sign up restrictions](../administration/settings/sign_up_restrictions.md) and [Authentication options](../topics/authentication/index.md). For more detailed information, refer to [Hardening](hardening.md).
|
||||
|
|
|
|||
|
|
@ -1,31 +1,11 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Authentication and Authorization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
type: reference, howto
|
||||
redirect_to: '../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives'
|
||||
remove_date: '2023-11-02'
|
||||
---
|
||||
|
||||
# Project import decompressed archive size limits **(FREE SELF)**
|
||||
This document was moved to [another location](../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives).
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31564) in GitLab 13.2.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63025) in GitLab 14.0.
|
||||
|
||||
When using [Project Import](../user/project/settings/import_export.md), the size of the decompressed project archive is limited to 10 Gb.
|
||||
|
||||
If decompressed size exceeds this limit, `Decompressed archive size validation failed` error is returned.
|
||||
|
||||
## Enable/disable size validation
|
||||
|
||||
If you have a project with decompressed size exceeding this limit,
|
||||
it is possible to disable the validation by turning off the
|
||||
`validate_import_decompressed_archive_size` feature flag.
|
||||
|
||||
Start a [Rails console](../administration/operations/rails_console.md#starting-a-rails-console-session).
|
||||
|
||||
```ruby
|
||||
# Disable
|
||||
Feature.disable(:validate_import_decompressed_archive_size)
|
||||
|
||||
# Enable
|
||||
Feature.enable(:validate_import_decompressed_archive_size)
|
||||
```
|
||||
<!-- This redirect file can be deleted after <2023-11-02>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -21,14 +21,7 @@ they confirm their email address.
|
|||
By default, a user can confirm their account within 24 hours after the confirmation email was sent.
|
||||
After 24 hours, the confirmation token becomes invalid.
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
## Automatically delete unconfirmed users **(PREMIUM SELF)**
|
||||
|
||||
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
||||
important to describe those, too. Think of things that may go wrong and include them here.
|
||||
This is important to minimize requests for support, and to avoid doc comments with
|
||||
questions that you know someone might ask.
|
||||
|
||||
Each scenario can be a third-level heading, for example `### Getting error message X`.
|
||||
If you have none to add when creating a doc, leave this section in place
|
||||
but commented out to help encourage others to add to it in the future. -->
|
||||
When email confirmation is turned on, administrators can enable the setting to
|
||||
[automatically delete unconfirmed users](../administration/moderate_users.md#automatically-delete-unconfirmed-users).
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ the default value [is the same as for self-managed instances](../../administrati
|
|||
| Maximum remote file size for imports from external object storages | 10 GB |
|
||||
| Maximum download file size when importing from source GitLab instances by direct transfer | 5 GB |
|
||||
| Maximum attachment size | 100 MB |
|
||||
| [Maximum decompressed file size for imported archives](../../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives) | 25 GB |
|
||||
|
||||
If you are near or over the repository size limit, you can either
|
||||
[reduce your repository size with Git](../project/repository/reducing_the_repo_size_using_git.md)
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ Keep in mind that restricting group access by IP address has the following impli
|
|||
- IP access restrictions for Git operations via SSH are supported on GitLab SaaS.
|
||||
IP access restrictions applied to self-managed instances are possible with [`gitlab-sshd`](../../administration/operations/gitlab_sshd.md)
|
||||
with [PROXY protocol](../../administration/operations/gitlab_sshd.md#proxy-protocol-support) enabled.
|
||||
- IP restriction is not applicable to shared resources belonging to a group. Any shared resource is accessible to a user even if that user is not able to access the group.
|
||||
|
||||
## Restrict group access by domain **(PREMIUM)**
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ Prerequisites:
|
|||
the [Composer specification](https://getcomposer.org/doc/04-schema.md#version).
|
||||
If the version is not valid, for example, it has three dots (`1.0.0.0`), an
|
||||
error (`Validation failed: Version is invalid`) occurs when you publish.
|
||||
- A valid `composer.json` file.
|
||||
- A valid `composer.json` file at the project root directory.
|
||||
- The Packages feature is enabled in a GitLab repository.
|
||||
- The project ID, which is on the project's home page.
|
||||
- One of the following token types:
|
||||
|
|
@ -324,6 +324,14 @@ If you committed your `composer.lock`, you could do a `composer install` in CI w
|
|||
In GitLab 14.10 and later, authorization is required for the [downloading a package archive](../../../api/packages/composer.md#download-a-package-archive) endpoint.
|
||||
If you encounter a credentials prompt when you are using `composer install`, follow the instructions in the [install a composer package](#install-a-composer-package) section to create an `auth.json` file.
|
||||
|
||||
### Publish fails with `The file composer.json was not found`
|
||||
|
||||
You might see an error that says `The file composer.json was not found`.
|
||||
|
||||
This issue occurs when [configuration requirements for publishing a package](#publish-a-composer-package-by-using-the-api) are not met.
|
||||
|
||||
To resolve the error, commit a `composer.json` file to the project root directory.
|
||||
|
||||
## Supported CLI commands
|
||||
|
||||
The GitLab Composer repository supports the following Composer CLI commands:
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ More details about the permissions for some project-level features follow.
|
|||
| Run CI/CD pipeline | | | | ✓ | ✓ | ✓ |
|
||||
| Run CI/CD pipeline for a protected branch | | | | ✓ (5) | ✓ (5) | ✓ |
|
||||
| Stop [environments](../ci/environments/index.md) | | | | ✓ | ✓ | ✓ |
|
||||
| Run deployment job for a protected environment | | | ✓ (5) | ✓ (6) | ✓ (6) | ✓ |
|
||||
| View a job with [debug logging](../ci/variables/index.md#enable-debug-logging) | | | | ✓ | ✓ | ✓ |
|
||||
| Use pipeline editor | | | | ✓ | ✓ | ✓ |
|
||||
| Run [interactive web terminals](../ci/interactive_web_terminal/index.md) | | | | ✓ | ✓ | ✓ |
|
||||
|
|
@ -307,6 +308,7 @@ More details about the permissions for some project-level features follow.
|
|||
- [In GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/35069) and later,
|
||||
run for a non-protected branch.
|
||||
5. If the user is [allowed to merge or push to the protected branch](../ci/pipelines/index.md#pipeline-security-on-protected-branches).
|
||||
6. If the user if [part of a group with at least the Reporter role](../ci/environments/protected_environments.md#deployment-only-access-to-protected-environments)
|
||||
|
||||
<!-- markdownlint-enable MD029 -->
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ module API
|
|||
expose :authors, documentation: { type: 'string', example: 'Authors' } do |metadatum|
|
||||
metadatum[:authors] || ''
|
||||
end
|
||||
expose :description, as: :summary, documentation: { type: 'string', example: 'Description' } do |metadatum|
|
||||
metadatum[:description] || ''
|
||||
with_options documentation: { type: 'string', example: 'Description' } do
|
||||
set_default = ->(metadatum) { metadatum[:description] || '' }
|
||||
expose :description, &set_default
|
||||
expose :description, as: :summary, &set_default
|
||||
end
|
||||
expose :project_url, as: :projectUrl, expose_nil: false, documentation: { type: 'string', example: 'http://sandbox.com/project' }
|
||||
expose :license_url, as: :licenseUrl, expose_nil: false, documentation: { type: 'string', example: 'http://sandbox.com/license' }
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ module API
|
|||
optional :max_export_size, type: Integer, desc: 'Maximum export size in MB'
|
||||
optional :max_import_size, type: Integer, desc: 'Maximum import size in MB'
|
||||
optional :max_import_remote_file_size, type: Integer, desc: 'Maximum remote file size in MB for imports from external object storages'
|
||||
optional :max_decompressed_archive_size, type: Integer, desc: 'Maximum decompressed size in MB'
|
||||
optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB'
|
||||
optional :max_pages_custom_domains_per_project, type: Integer, desc: 'Maximum number of GitLab Pages custom domains per project'
|
||||
optional :max_terraform_state_size_bytes, type: Integer, desc: "Maximum size in bytes of the Terraform state file. Set this to 0 for unlimited file size."
|
||||
|
|
|
|||
|
|
@ -11,12 +11,13 @@ module Gitlab
|
|||
include ::Gitlab::Config::Entry::Validatable
|
||||
include ::Gitlab::Config::Entry::Attributable
|
||||
|
||||
attributes :default, prefix: :input
|
||||
attributes :default, :type, prefix: :input
|
||||
|
||||
validations do
|
||||
validates :config, type: Hash, allowed_keys: [:default]
|
||||
validates :config, type: Hash, allowed_keys: [:default, :type]
|
||||
validates :key, alphanumeric: true
|
||||
validates :input_default, alphanumeric: true, allow_nil: true
|
||||
validates :input_type, allow_nil: true, allowed_values: ::Gitlab::Ci::Interpolation::Inputs.input_types
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,9 +8,15 @@ module Gitlab
|
|||
UnknownInputTypeError = Class.new(StandardError)
|
||||
|
||||
TYPES = [
|
||||
BooleanInput,
|
||||
NumberInput,
|
||||
StringInput
|
||||
].freeze
|
||||
|
||||
def self.input_types
|
||||
TYPES.map(&:type_name)
|
||||
end
|
||||
|
||||
def initialize(specs, args)
|
||||
@specs = specs.to_h
|
||||
@args = args.to_h
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue