Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-09-15 09:09:47 +00:00
parent 034e7d969a
commit 33f96e8df0
49 changed files with 1213 additions and 195 deletions

View file

@ -1 +1 @@
14.2.2 14.3.1

View file

@ -120,7 +120,7 @@ gem 'carrierwave', '~> 1.3'
gem 'mini_magick', '~> 4.10.1' gem 'mini_magick', '~> 4.10.1'
# for backups # for backups
gem 'fog-aws', '~> 3.9' gem 'fog-aws', '~> 3.12'
# Locked until fog-google resolves https://github.com/fog/fog-google/issues/421. # Locked until fog-google resolves https://github.com/fog/fog-google/issues/421.
# Also see config/initializers/fog_core_patch.rb. # Also see config/initializers/fog_core_patch.rb.
gem 'fog-core', '= 2.1.0' gem 'fog-core', '= 2.1.0'

View file

@ -395,7 +395,7 @@ GEM
fog-json fog-json
ipaddress (~> 0.8) ipaddress (~> 0.8)
xml-simple (~> 1.1) xml-simple (~> 1.1)
fog-aws (3.9.0) fog-aws (3.12.0)
fog-core (~> 2.1) fog-core (~> 2.1)
fog-json (~> 1.1) fog-json (~> 1.1)
fog-xml (~> 0.1) fog-xml (~> 0.1)
@ -1452,7 +1452,7 @@ DEPENDENCIES
flipper-active_support_cache_store (~> 0.21.0) flipper-active_support_cache_store (~> 0.21.0)
flowdock (~> 0.7) flowdock (~> 0.7)
fog-aliyun (~> 0.3) fog-aliyun (~> 0.3)
fog-aws (~> 3.9) fog-aws (~> 3.12)
fog-core (= 2.1.0) fog-core (= 2.1.0)
fog-google (~> 1.15) fog-google (~> 1.15)
fog-local (~> 0.6) fog-local (~> 0.6)

View file

@ -202,7 +202,7 @@ export default {
data-testid="resolved-discussion" data-testid="resolved-discussion"
@error="$emit('onDesignDiscussionError', $event)" @error="$emit('onDesignDiscussionError', $event)"
@updateNoteError="$emit('updateNoteError', $event)" @updateNoteError="$emit('updateNoteError', $event)"
@openForm="updateDiscussionWithOpenForm" @open-form="updateDiscussionWithOpenForm"
@click.native.stop="updateActiveDiscussion(discussion.notes[0].id)" @click.native.stop="updateActiveDiscussion(discussion.notes[0].id)"
/> />
</gl-collapse> </gl-collapse>

View file

@ -1,5 +1,13 @@
<script> <script>
import { GlButton, GlFormSelect, GlToggle, GlLoadingIcon, GlSprintf } from '@gitlab/ui'; import {
GlButton,
GlFormSelect,
GlToggle,
GlLoadingIcon,
GlSprintf,
GlFormInput,
GlLink,
} from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
@ -14,6 +22,8 @@ export default {
GlToggle, GlToggle,
GlLoadingIcon, GlLoadingIcon,
GlSprintf, GlSprintf,
GlFormInput,
GlLink,
}, },
props: { props: {
isEnabled: { isEnabled: {
@ -148,17 +158,37 @@ export default {
<span class="sr-only">{{ __('Fetching incoming email') }}</span> <span class="sr-only">{{ __('Fetching incoming email') }}</span>
</template> </template>
<template v-if="hasProjectKeySupport">
<label for="service-desk-project-suffix" class="mt-3"> <label for="service-desk-project-suffix" class="mt-3">
{{ __('Project name suffix') }} {{ __('Project name suffix') }}
</label> </label>
<input id="service-desk-project-suffix" v-model.trim="projectKey" class="form-control" /> <gl-form-input
<span class="form-text text-muted"> v-if="hasProjectKeySupport"
{{ id="service-desk-project-suffix"
__('A string appended to the project path to form the Service Desk email address.') v-model.trim="projectKey"
}} data-testid="project-suffix"
class="form-control"
/>
<span v-if="hasProjectKeySupport" class="form-text text-muted">
{{ __('A string appended to the project path to form the Service Desk email address.') }}
</span> </span>
<span v-else class="form-text text-muted">
<gl-sprintf
:message="
__(
'Please set up a Service Desk email address in order to add a custom suffix. %{linkStart}Learn more%{linkEnd}.',
)
"
>
<template #link="{ content }">
<gl-link
href="https://docs.gitlab.com/ee/user/project/service_desk.html#using-a-custom-email-address"
target="_blank"
class="gl-text-blue-600 font-size-inherit"
>{{ content }}
</gl-link>
</template> </template>
</gl-sprintf>
</span>
<label for="service-desk-template-select" class="mt-3"> <label for="service-desk-template-select" class="mt-3">
{{ __('Template to append to all Service Desk issues') }} {{ __('Template to append to all Service Desk issues') }}

View file

@ -24,14 +24,16 @@ class Projects::ServiceDeskController < Projects::ApplicationController
private private
def setting_params def setting_params
params.permit(:issue_template_key, :outgoing_name, :project_key) params.permit(*allowed_update_attributes)
end end
def json_response def allowed_update_attributes
respond_to do |format| %i(issue_template_key outgoing_name project_key)
end
def service_desk_attributes
service_desk_settings = project.service_desk_setting service_desk_settings = project.service_desk_setting
service_desk_attributes =
{ {
service_desk_address: project.service_desk_address, service_desk_address: project.service_desk_address,
service_desk_enabled: project.service_desk_enabled, service_desk_enabled: project.service_desk_enabled,
@ -40,8 +42,13 @@ class Projects::ServiceDeskController < Projects::ApplicationController
outgoing_name: service_desk_settings&.outgoing_name, outgoing_name: service_desk_settings&.outgoing_name,
project_key: service_desk_settings&.project_key project_key: service_desk_settings&.project_key
} }
end
def json_response
respond_to do |format|
format.json { render json: service_desk_attributes } format.json { render json: service_desk_attributes }
end end
end end
end end
Projects::ServiceDeskController.prepend_mod

View file

@ -27,11 +27,10 @@ class Environment < ApplicationRecord
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :environment has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :environment
has_one :last_deployment, -> { success.distinct_on_environment }, class_name: 'Deployment', inverse_of: :environment has_one :last_deployment, -> { success.distinct_on_environment }, class_name: 'Deployment', inverse_of: :environment
has_one :last_deployable, through: :last_deployment, source: 'deployable', source_type: 'CommitStatus'
has_one :last_pipeline, through: :last_deployable, source: 'pipeline'
has_one :last_visible_deployment, -> { visible.distinct_on_environment }, inverse_of: :environment, class_name: 'Deployment' has_one :last_visible_deployment, -> { visible.distinct_on_environment }, inverse_of: :environment, class_name: 'Deployment'
has_one :last_visible_deployable, through: :last_visible_deployment, source: 'deployable', source_type: 'CommitStatus' has_one :last_visible_deployable, through: :last_visible_deployment, source: 'deployable', source_type: 'CommitStatus', disable_joins: -> { ::Feature.enabled?(:environment_last_visible_pipeline_disable_joins, default_enabled: :yaml) }
has_one :last_visible_pipeline, through: :last_visible_deployable, source: 'pipeline' has_one :last_visible_pipeline, through: :last_visible_deployable, source: 'pipeline', disable_joins: -> { ::Feature.enabled?(:environment_last_visible_pipeline_disable_joins, default_enabled: :yaml) }
has_one :upcoming_deployment, -> { running.distinct_on_environment }, class_name: 'Deployment', inverse_of: :environment has_one :upcoming_deployment, -> { running.distinct_on_environment }, class_name: 'Deployment', inverse_of: :environment
has_one :latest_opened_most_severe_alert, -> { order_severity_with_open_prometheus_alert }, class_name: 'AlertManagement::Alert', inverse_of: :environment has_one :latest_opened_most_severe_alert, -> { order_severity_with_open_prometheus_alert }, class_name: 'AlertManagement::Alert', inverse_of: :environment
@ -182,6 +181,35 @@ class Environment < ApplicationRecord
end end
end end
def last_deployable
last_deployment&.deployable
end
# NOTE: Below assocation overrides is a workaround for issue https://gitlab.com/gitlab-org/gitlab/-/issues/339908
# It helps to avoid cross joins with the CI database.
# Caveat: It also overrides and losses the default AR caching mechanism.
# Read - https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68870#note_677227727
# NOTE: Association Preloads does not use the overriden definitions below.
# Association Preloads when preloading uses the original definitions from the relationships above.
# https://github.com/rails/rails/blob/75ac626c4e21129d8296d4206a1960563cc3d4aa/activerecord/lib/active_record/associations/preloader.rb#L158
# But after preloading, when they are called it is using the overriden methods below.
# So we are checking for `association_cached?(:association_name)` in the overridden methods and calling `super` which inturn fetches the preloaded values.
# Overriding association
def last_visible_deployable
return super if association_cached?(:last_visible_deployable) || ::Feature.disabled?(:environment_last_visible_pipeline_disable_joins, default_enabled: :yaml)
last_visible_deployment&.deployable
end
# Overriding association
def last_visible_pipeline
return super if association_cached?(:last_visible_pipeline) || ::Feature.disabled?(:environment_last_visible_pipeline_disable_joins, default_enabled: :yaml)
last_visible_deployable&.pipeline
end
def clear_prometheus_reactive_cache!(query_name) def clear_prometheus_reactive_cache!(query_name)
cluster_prometheus_adapter&.clear_prometheus_reactive_cache!(query_name, self) cluster_prometheus_adapter&.clear_prometheus_reactive_cache!(query_name, self)
end end

View file

@ -33,7 +33,6 @@ class Release < ApplicationRecord
includes(:author, :evidences, :milestones, :links, :sorted_links, includes(:author, :evidences, :milestones, :links, :sorted_links,
project: [:project_feature, :route, { namespace: :route }]) project: [:project_feature, :route, { namespace: :route }])
} }
scope :with_project_and_namespace, -> { includes(project: :namespace) }
scope :recent, -> { sorted.limit(MAX_NUMBER_TO_DISPLAY) } scope :recent, -> { sorted.limit(MAX_NUMBER_TO_DISPLAY) }
scope :without_evidence, -> { left_joins(:evidences).where(::Releases::Evidence.arel_table[:id].eq(nil)) } scope :without_evidence, -> { left_joins(:evidences).where(::Releases::Evidence.arel_table[:id].eq(nil)) }
scope :released_within_2hrs, -> { where(released_at: Time.zone.now - 1.hour..Time.zone.now + 1.hour) } scope :released_within_2hrs, -> { where(released_at: Time.zone.now - 1.hour..Time.zone.now + 1.hour) }

View file

@ -191,8 +191,12 @@ class Repository
end end
def find_tag(name) def find_tag(name)
if @tags.blank? && Feature.enabled?(:find_tag_via_gitaly, project, default_enabled: :yaml)
raw_repository.find_tag(name)
else
tags.find { |tag| tag.name == name } tags.find { |tag| tag.name == name }
end end
end
def ambiguous_ref?(ref) def ambiguous_ref?(ref)
tag_exists?(ref) && branch_exists?(ref) tag_exists?(ref) && branch_exists?(ref)

View file

@ -19,7 +19,11 @@ class ServiceDeskSetting < ApplicationRecord
strong_memoize(:issue_template_content) do strong_memoize(:issue_template_content) do
next unless issue_template_key.present? next unless issue_template_key.present?
Gitlab::Template::IssueTemplate.find(issue_template_key, project).content TemplateFinder.new(
:issues, project,
name: issue_template_key,
source_template_project: source_template_project
).execute.content
rescue ::Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError rescue ::Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError
end end
end end
@ -42,6 +46,10 @@ class ServiceDeskSetting < ApplicationRecord
private private
def source_template_project
nil
end
def projects_with_same_slug_and_key_exists? def projects_with_same_slug_and_key_exists?
return false unless project_key return false unless project_key
@ -53,3 +61,5 @@ class ServiceDeskSetting < ApplicationRecord
end end
end end
end end
ServiceDeskSetting.prepend_mod

View file

@ -1,56 +1,68 @@
= form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-ip-limits-settings'), html: { class: 'fieldset-form' } do |f| = gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-ip-limits-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting) = form_errors(@application_setting)
%fieldset %fieldset
%h5 %legend.h5.gl-border-none
= _('Unauthenticated request rate limit') = _('Unauthenticated API request rate limit')
.form-group .form-group
.form-check = f.gitlab_ui_checkbox_component :throttle_unauthenticated_api_enabled,
= f.check_box :throttle_unauthenticated_enabled, class: 'form-check-input', data: { qa_selector: 'throttle_unauthenticated_checkbox' } _("Enable unauthenticated API request rate limit"),
= f.label :throttle_unauthenticated_enabled, class: 'form-check-label label-bold' do help_text: _("Helps reduce request volume (e.g. from crawlers or abusive bots)"),
= _("Enable unauthenticated request rate limit") checkbox_options: { data: { qa_selector: 'throttle_unauthenticated_api_checkbox' } }
%span.form-text.text-muted
= _("Helps reduce request volume (e.g. from crawlers or abusive bots)")
.form-group .form-group
= f.label :throttle_unauthenticated_requests_per_period, _('Max unauthenticated requests per period per IP'), class: 'label-bold' = f.label :throttle_unauthenticated_api_requests_per_period, _('Max unauthenticated API requests per period per IP'), class: 'label-bold'
= f.number_field :throttle_unauthenticated_api_requests_per_period, class: 'form-control gl-form-input'
.form-group
= f.label :throttle_unauthenticated_api_period_in_seconds, _('Unauthenticated API rate limit period in seconds'), class: 'label-bold'
= f.number_field :throttle_unauthenticated_api_period_in_seconds, class: 'form-control gl-form-input'
%fieldset
%legend.h5.gl-border-none
= _('Unauthenticated web request rate limit')
.form-group
= f.gitlab_ui_checkbox_component :throttle_unauthenticated_enabled,
_("Enable unauthenticated web request rate limit"),
help_text: _("Helps reduce request volume (e.g. from crawlers or abusive bots)"),
checkbox_options: { data: { qa_selector: 'throttle_unauthenticated_web_checkbox' } }
.form-group
= f.label :throttle_unauthenticated_requests_per_period, _('Max unauthenticated web requests per period per IP'), class: 'label-bold'
= f.number_field :throttle_unauthenticated_requests_per_period, class: 'form-control gl-form-input' = f.number_field :throttle_unauthenticated_requests_per_period, class: 'form-control gl-form-input'
.form-group .form-group
= f.label :throttle_unauthenticated_period_in_seconds, _('Unauthenticated rate limit period in seconds'), class: 'label-bold' = f.label :throttle_unauthenticated_period_in_seconds, _('Unauthenticated web rate limit period in seconds'), class: 'label-bold'
= f.number_field :throttle_unauthenticated_period_in_seconds, class: 'form-control gl-form-input' = f.number_field :throttle_unauthenticated_period_in_seconds, class: 'form-control gl-form-input'
%hr
%h5 %fieldset
%legend.h5.gl-border-none
= _('Authenticated API request rate limit') = _('Authenticated API request rate limit')
.form-group .form-group
.form-check = f.gitlab_ui_checkbox_component :throttle_authenticated_api_enabled,
= f.check_box :throttle_authenticated_api_enabled, class: 'form-check-input', data: { qa_selector: 'throttle_authenticated_api_checkbox' } _("Enable authenticated API request rate limit"),
= f.label :throttle_authenticated_api_enabled, class: 'form-check-label label-bold' do help_text: _("Helps reduce request volume (e.g. from crawlers or abusive bots)"),
= _("Enable authenticated API request rate limit") checkbox_options: { data: { qa_selector: 'throttle_authenticated_api_checkbox' }}
%span.form-text.text-muted
= _("Helps reduce request volume (e.g. from crawlers or abusive bots)")
.form-group .form-group
= f.label :throttle_authenticated_api_requests_per_period, _('Max authenticated API requests per period per user'), class: 'label-bold' = f.label :throttle_authenticated_api_requests_per_period, _('Max authenticated API requests per period per user'), class: 'label-bold'
= f.number_field :throttle_authenticated_api_requests_per_period, class: 'form-control gl-form-input' = f.number_field :throttle_authenticated_api_requests_per_period, class: 'form-control gl-form-input'
.form-group .form-group
= f.label :throttle_authenticated_api_period_in_seconds, _('Authenticated API rate limit period in seconds'), class: 'label-bold' = f.label :throttle_authenticated_api_period_in_seconds, _('Authenticated API rate limit period in seconds'), class: 'label-bold'
= f.number_field :throttle_authenticated_api_period_in_seconds, class: 'form-control gl-form-input' = f.number_field :throttle_authenticated_api_period_in_seconds, class: 'form-control gl-form-input'
%hr
%h5 %fieldset
%legend.h5.gl-border-none
= _('Authenticated web request rate limit') = _('Authenticated web request rate limit')
.form-group .form-group
.form-check = f.gitlab_ui_checkbox_component :throttle_authenticated_web_enabled,
= f.check_box :throttle_authenticated_web_enabled, class: 'form-check-input', data: { qa_selector: 'throttle_authenticated_web_checkbox' } _("Enable authenticated web request rate limit"),
= f.label :throttle_authenticated_web_enabled, class: 'form-check-label label-bold' do help_text: _("Helps reduce request volume (e.g. from crawlers or abusive bots)"),
Enable authenticated web request rate limit checkbox_options: { data: { qa_selector: 'throttle_authenticated_web_checkbox' } }
%span.form-text.text-muted
Helps reduce request volume (e.g. from crawlers or abusive bots)
.form-group .form-group
= f.label :throttle_authenticated_web_requests_per_period, _('Max authenticated web requests per period per user'), class: 'label-bold' = f.label :throttle_authenticated_web_requests_per_period, _('Max authenticated web requests per period per user'), class: 'label-bold'
= f.number_field :throttle_authenticated_web_requests_per_period, class: 'form-control gl-form-input' = f.number_field :throttle_authenticated_web_requests_per_period, class: 'form-control gl-form-input'
.form-group .form-group
= f.label :throttle_authenticated_web_period_in_seconds, _('Authenticated web rate limit period in seconds'), class: 'label-bold' = f.label :throttle_authenticated_web_period_in_seconds, _('Authenticated web rate limit period in seconds'), class: 'label-bold'
= f.number_field :throttle_authenticated_web_period_in_seconds, class: 'form-control gl-form-input' = f.number_field :throttle_authenticated_web_period_in_seconds, class: 'form-control gl-form-input'
%hr
%h5 %fieldset
%legend.h5.gl-border-none
= _('Response text') = _('Response text')
.form-group .form-group
= f.label :rate_limiting_response_text, class: 'label-bold' do = f.label :rate_limiting_response_text, class: 'label-bold' do

View file

@ -0,0 +1,8 @@
---
name: environment_last_visible_pipeline_disable_joins
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68870
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340283
milestone: '14.3'
type: development
group: group::release
default_enabled: true

View file

@ -1,8 +1,8 @@
--- ---
name: get_tag_signatures name: find_tag_via_gitaly
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67000 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70181
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/337842 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340899
milestone: '14.2' milestone: '14.3'
type: development type: development
group: group::gitaly group: group::source code
default_enabled: false default_enabled: false

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
class SetDefaultJobTokenScopeFalse < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
def up
with_lock_retries do
change_column_default :project_ci_cd_settings, :job_token_scope_enabled, from: true, to: false
end
end
def down
with_lock_retries do
change_column_default :project_ci_cd_settings, :job_token_scope_enabled, from: false, to: true
end
end
end

View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
class DropTemporaryColumnsAndTriggersForCiBuildTraceChunks < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
TABLE = 'ci_build_trace_chunks'
COLUMN = 'build_id'
# rubocop:disable Migration/WithLockRetriesDisallowedMethod
def up
with_lock_retries do
cleanup_conversion_of_integer_to_bigint(TABLE, COLUMN)
end
end
# rubocop:enable Migration/WithLockRetriesDisallowedMethod
def down
restore_conversion_of_integer_to_bigint(TABLE, COLUMN)
end
end

View file

@ -0,0 +1,52 @@
# frozen_string_literal: true
class DisableJobTokenScopeWhenUnused < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
class ProjectCiCdSetting < ApplicationRecord
include EachBatch
self.table_name = 'project_ci_cd_settings'
end
module Ci
module JobToken
class ProjectScopeLink < ApplicationRecord
self.table_name = 'ci_job_token_project_scope_links'
end
end
end
def up
# Disabling job token scope after db/migrate/20210902171808_set_default_job_token_scope_false.rb
# if users haven't configured it.
ProjectCiCdSetting.each_batch(of: 10_000) do |settings|
with_enabled_but_unused_scope(settings).each_batch(of: 500) do |settings_to_update|
settings_to_update.update_all(job_token_scope_enabled: false)
end
end
end
def down
# irreversible data migration
# The migration relies on the state of `job_token_scope_enabled` and
# updates it based on whether the feature is used or not.
#
# The inverse migration would be to set `job_token_scope_enabled: true`
# for those projects that have the feature disabled and unused. But there
# could be also existing cases where the feature is disabled and unused.
# For example, old projects.
end
private
# The presence of ProjectScopeLinks means that the job token scope
# is configured and we need to leave it enabled. Unused job token scope
# can be disabled since they weren't configured.
def with_enabled_but_unused_scope(settings)
settings
.where(job_token_scope_enabled: true)
.where.not(project_id: Ci::JobToken::ProjectScopeLink.select(:source_project_id))
end
end

View file

@ -0,0 +1 @@
09b482e4716a2b0808ad83770222baed8e863a8f94f85f77ed2d557eaa348df4

View file

@ -0,0 +1 @@
b7329d4ff7ee651b56cb86c7091e0d933c4f43a77125323fb6c283eedcb737c2

View file

@ -0,0 +1 @@
399e35197111c257786a2bdf5dac990a26f48d2cc8493de642dcfa47ddececd2

View file

@ -108,15 +108,6 @@ BEGIN
END; END;
$$; $$;
CREATE FUNCTION trigger_cf2f9e35f002() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW."build_id_convert_to_bigint" := NEW."build_id";
RETURN NEW;
END;
$$;
CREATE TABLE audit_events ( CREATE TABLE audit_events (
id bigint NOT NULL, id bigint NOT NULL,
author_id integer NOT NULL, author_id integer NOT NULL,
@ -11277,7 +11268,6 @@ ALTER SEQUENCE ci_build_report_results_build_id_seq OWNED BY ci_build_report_res
CREATE TABLE ci_build_trace_chunks ( CREATE TABLE ci_build_trace_chunks (
id bigint NOT NULL, id bigint NOT NULL,
build_id_convert_to_bigint integer DEFAULT 0 NOT NULL,
chunk_index integer NOT NULL, chunk_index integer NOT NULL,
data_store integer NOT NULL, data_store integer NOT NULL,
raw_data bytea, raw_data bytea,
@ -17729,7 +17719,7 @@ CREATE TABLE project_ci_cd_settings (
auto_rollback_enabled boolean DEFAULT false NOT NULL, auto_rollback_enabled boolean DEFAULT false NOT NULL,
keep_latest_artifact boolean DEFAULT true NOT NULL, keep_latest_artifact boolean DEFAULT true NOT NULL,
restrict_user_defined_variables boolean DEFAULT false NOT NULL, restrict_user_defined_variables boolean DEFAULT false NOT NULL,
job_token_scope_enabled boolean DEFAULT true NOT NULL job_token_scope_enabled boolean DEFAULT false NOT NULL
); );
CREATE SEQUENCE project_ci_cd_settings_id_seq CREATE SEQUENCE project_ci_cd_settings_id_seq
@ -27329,8 +27319,6 @@ CREATE TRIGGER trigger_91dc388a5fe6 BEFORE INSERT OR UPDATE ON dep_ci_build_trac
CREATE TRIGGER trigger_aebe8b822ad3 BEFORE INSERT OR UPDATE ON taggings FOR EACH ROW EXECUTE FUNCTION trigger_aebe8b822ad3(); CREATE TRIGGER trigger_aebe8b822ad3 BEFORE INSERT OR UPDATE ON taggings FOR EACH ROW EXECUTE FUNCTION trigger_aebe8b822ad3();
CREATE TRIGGER trigger_cf2f9e35f002 BEFORE INSERT OR UPDATE ON ci_build_trace_chunks FOR EACH ROW EXECUTE FUNCTION trigger_cf2f9e35f002();
CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON integrations FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker(); CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON integrations FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker();
CREATE TRIGGER trigger_has_external_issue_tracker_on_insert AFTER INSERT ON integrations FOR EACH ROW WHEN ((((new.category)::text = 'issue_tracker'::text) AND (new.active = true) AND (new.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker(); CREATE TRIGGER trigger_has_external_issue_tracker_on_insert AFTER INSERT ON integrations FOR EACH ROW WHEN ((((new.category)::text = 'issue_tracker'::text) AND (new.active = true) AND (new.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker();

View file

@ -415,9 +415,15 @@ listed in the descriptions of the relevant settings.
| `throttle_authenticated_web_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_web_period_in_seconds` and `throttle_authenticated_web_requests_per_period`) Enable authenticated web request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). | | `throttle_authenticated_web_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_web_period_in_seconds` and `throttle_authenticated_web_requests_per_period`) Enable authenticated web request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). |
| `throttle_authenticated_web_period_in_seconds` | integer | required by:<br>`throttle_authenticated_web_enabled` | Rate limit period in seconds. | | `throttle_authenticated_web_period_in_seconds` | integer | required by:<br>`throttle_authenticated_web_enabled` | Rate limit period in seconds. |
| `throttle_authenticated_web_requests_per_period` | integer | required by:<br>`throttle_authenticated_web_enabled` | Max requests per period per user. | | `throttle_authenticated_web_requests_per_period` | integer | required by:<br>`throttle_authenticated_web_enabled` | Max requests per period per user. |
| `throttle_unauthenticated_enabled` | boolean | no | (**If enabled, requires:** `throttle_unauthenticated_period_in_seconds` and `throttle_unauthenticated_requests_per_period`) Enable unauthenticated request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). | | `throttle_unauthenticated_enabled` | boolean | no | ([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/335300) in GitLab 14.3. Use `throttle_unauthenticated_web_enabled` or `throttle_unauthenticated_api_enabled` instead.) (**If enabled, requires:** `throttle_unauthenticated_period_in_seconds` and `throttle_unauthenticated_requests_per_period`) Enable unauthenticated web request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). |
| `throttle_unauthenticated_period_in_seconds` | integer | required by:<br>`throttle_unauthenticated_enabled` | Rate limit period in seconds. | | `throttle_unauthenticated_period_in_seconds` | integer | required by:<br>`throttle_unauthenticated_enabled` | ([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/335300) in GitLab 14.3. Use `throttle_unauthenticated_web_period_in_seconds` or `throttle_unauthenticated_api_period_in_seconds` instead.) Rate limit period in seconds. |
| `throttle_unauthenticated_requests_per_period` | integer | required by:<br>`throttle_unauthenticated_enabled` | Max requests per period per IP. | | `throttle_unauthenticated_requests_per_period` | integer | required by:<br>`throttle_unauthenticated_enabled` | ([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/335300) in GitLab 14.3. Use `throttle_unauthenticated_web_requests_per_period` or `throttle_unauthenticated_api_requests_per_period` instead.) Max requests per period per IP. |
| `throttle_unauthenticated_api_enabled` | boolean | no | (**If enabled, requires:** `throttle_unauthenticated_api_period_in_seconds` and `throttle_unauthenticated_api_requests_per_period`) Enable unauthenticated API request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). |
| `throttle_unauthenticated_api_period_in_seconds` | integer | required by:<br>`throttle_unauthenticated_api_enabled` | Rate limit period in seconds. |
| `throttle_unauthenticated_api_requests_per_period` | integer | required by:<br>`throttle_unauthenticated_api_enabled` | Max requests per period per IP. |
| `throttle_unauthenticated_web_enabled` | boolean | no | (**If enabled, requires:** `throttle_unauthenticated_web_period_in_seconds` and `throttle_unauthenticated_web_requests_per_period`) Enable unauthenticated web request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). |
| `throttle_unauthenticated_web_period_in_seconds` | integer | required by:<br>`throttle_unauthenticated_web_enabled` | Rate limit period in seconds. |
| `throttle_unauthenticated_web_requests_per_period` | integer | required by:<br>`throttle_unauthenticated_web_enabled` | Max requests per period per IP. |
| `time_tracking_limit_to_hours` | boolean | no | Limit display of time tracking units to hours. Default is `false`. | | `time_tracking_limit_to_hours` | boolean | no | Limit display of time tracking units to hours. Default is `false`. |
| `two_factor_grace_period` | integer | required by: `require_two_factor_authentication` | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication. | | `two_factor_grace_period` | integer | required by: `require_two_factor_authentication` | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication. |
| `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple IPs. | | `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple IPs. |

View file

@ -0,0 +1,118 @@
---
stage: Enablement
group: Distribution
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
---
# Convert Community Edition to Enterprise Edition **(FREE SELF)**
To convert an existing GitLab Community Edition (CE) server installed using the Omnibus GitLab
packages to GitLab [Enterprise Edition](https://about.gitlab.com/pricing/) (EE), you install the EE
package on top of CE.
Converting from the same version of CE to EE is not explicitly necessary, and any standard upgrade
(for example, CE 12.0 to EE 12.1) should work. However, in the following steps we assume that
you are upgrading the same version (for example, CE 12.1 to EE 12.1), which is **recommended**.
WARNING:
When updating to EE from CE, avoid reverting back to CE if you plan on going to EE again in the
future. Reverting back to CE can cause
[database issues](index.md#500-error-when-accessing-project--settings--repository)
that may require Support intervention.
The steps can be summed up to:
1. Find the currently installed GitLab version:
**For Debian/Ubuntu**
```shell
sudo apt-cache policy gitlab-ce | grep Installed
```
The output should be similar to: `Installed: 13.0.4-ce.0`. In that case,
the equivalent Enterprise Edition version will be: `13.0.4-ee.0`. Write this
value down.
**For CentOS/RHEL**
```shell
sudo rpm -q gitlab-ce
```
The output should be similar to: `gitlab-ce-13.0.4-ce.0.el8.x86_64`. In that
case, the equivalent Enterprise Edition version will be:
`gitlab-ee-13.0.4-ee.0.el8.x86_64`. Write this value down.
1. Add the `gitlab-ee` [Apt or Yum repository](https://packages.gitlab.com/gitlab/gitlab-ee/install):
**For Debian/Ubuntu**
```shell
curl --silent "https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh" | sudo bash
```
**For CentOS/RHEL**
```shell
curl --silent "https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.rpm.sh" | sudo bash
```
The above command will find your OS version and automatically set up the
repository. If you are not comfortable installing the repository through a
piped script, you can first
[check its contents](https://packages.gitlab.com/gitlab/gitlab-ee/install).
1. Next, install the `gitlab-ee` package. Note that this will automatically
uninstall the `gitlab-ce` package on your GitLab server. `reconfigure`
Omnibus right after the `gitlab-ee` package is installed. **Make sure that you
install the exact same GitLab version**:
**For Debian/Ubuntu**
```shell
## Make sure the repositories are up-to-date
sudo apt-get update
## Install the package using the version you wrote down from step 1
sudo apt-get install gitlab-ee=13.0.4-ee.0
## Reconfigure GitLab
sudo gitlab-ctl reconfigure
```
**For CentOS/RHEL**
```shell
## Install the package using the version you wrote down from step 1
sudo yum install gitlab-ee-13.0.4-ee.0.el8.x86_64
## Reconfigure GitLab
sudo gitlab-ctl reconfigure
```
1. Now go to the GitLab admin panel of your server (`/admin/license/new`) and
upload your license file.
1. After you confirm that GitLab is working as expected, you may remove the old
Community Edition repository:
**For Debian/Ubuntu**
```shell
sudo rm /etc/apt/sources.list.d/gitlab_gitlab-ce.list
```
**For CentOS/RHEL**
```shell
sudo rm /etc/yum.repos.d/gitlab_gitlab-ce.repo
```
That's it! You can now use GitLab Enterprise Edition! To update to a newer
version, follow [Update using the official repositories](index.md#upgrade-using-the-official-repositories).
NOTE:
If you want to use `dpkg`/`rpm` instead of `apt-get`/`yum`, go through the first
step to find the current GitLab version and then follow
[Update using a manually-downloaded package](index.md#upgrade-using-a-manually-downloaded-package).

View file

@ -0,0 +1,83 @@
---
stage: Enablement
group: Distribution
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
---
# Downgrade **(FREE SELF)**
This section contains general information on how to revert to an earlier version
of a package.
WARNING:
You must at least have a database backup created under the version you are
downgrading to. Ideally, you should have a
[full backup archive](../../raketasks/backup_restore.md#back-up-gitlab)
on hand.
The example below demonstrates the downgrade procedure when downgrading between minor
and patch versions (for example, from 13.0.6 to 13.0.5).
When downgrading between major versions, take into account the
[specific version changes](index.md#version-specific-changes) that occurred when you upgraded
to the major version you are downgrading from.
These steps consist of:
- Stopping GitLab
- Removing the current package
- Installing the old package
- Reconfiguring GitLab
- Restoring the backup
- Starting GitLab
Steps:
1. Stop GitLab and remove the current package:
```shell
# If running Puma
sudo gitlab-ctl stop puma
# Stop sidekiq
sudo gitlab-ctl stop sidekiq
# If on Ubuntu: remove the current package
sudo dpkg -r gitlab-ee
# If on Centos: remove the current package
sudo yum remove gitlab-ee
```
1. Identify the GitLab version you want to downgrade to:
```shell
# (Replace with gitlab-ce if you have GitLab FOSS installed)
# Ubuntu
sudo apt-cache madison gitlab-ee
# CentOS:
sudo yum --showduplicates list gitlab-ee
```
1. Downgrade GitLab to the desired version (for example, to GitLab 13.0.5):
```shell
# (Replace with gitlab-ce if you have GitLab FOSS installed)
# Ubuntu
sudo apt install gitlab-ee=13.0.5-ee.0
# CentOS:
sudo yum install gitlab-ee-13.0.5-ee.0.el8
```
1. Reconfigure GitLab:
```shell
sudo gitlab-ctl reconfigure
```
1. [Restore GitLab](../../raketasks/backup_restore.md#restore-for-omnibus-gitlab-installations)
to complete the downgrade.

278
doc/update/package/index.md Normal file
View file

@ -0,0 +1,278 @@
---
stage: Enablement
group: Distribution
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
---
# Upgrade GitLab using the GitLab Package **(FREE SELF)**
This section describes how to upgrade GitLab to a new version using the
GitLab package.
We recommend performing upgrades between major and minor releases no more than once per
week, to allow time for background migrations to finish. Decrease the time required to
complete these migrations by increasing the number of
[Sidekiq workers](../../administration/operations/extra_sidekiq_processes.md)
that can process jobs in the `background_migration` queue.
If you don't follow the steps in [zero downtime upgrades](../zero_downtime.md),
your GitLab application will not be available to users while an upgrade is in progress.
They either see a "Deploy in progress" message or a "502" error in their web browser.
Prerequisites:
- [Supported upgrade paths](../index.md#upgrade-paths)
has suggestions on when to upgrade. Upgrade paths are enforced for version upgrades by
default. This restricts performing direct upgrades that skip major versions (for
example 10.3 to 12.7 in one jump) that **can break GitLab
installations** due to multiple reasons like deprecated or removed configuration
settings, upgrade of internal tools and libraries, and so on.
- If you are upgrading from a non-Package installation to a GitLab Package installation, see
[Upgrading from a non-Package installation to a GitLab Package installation](https://docs.gitlab.com/omnibus/convert_to_omnibus.html).
- It's important to ensure that any
[background migrations](../index.md#checking-for-background-migrations-before-upgrading)
have been fully completed before upgrading to a new major version. Upgrading
before background migrations have finished may lead to data corruption.
- Gitaly servers must be upgraded to the newer version prior to upgrading the application server.
This prevents the gRPC client on the application server from sending RPCs that the old Gitaly version
does not support.
You can upgrade the GitLab Package using one of the following methods:
- [Using the official repositories](#upgrade-using-the-official-repositories).
- [Using a manually-downloaded package](#upgrade-using-a-manually-downloaded-package).
Both automatically back up the GitLab database before installing a newer
GitLab version. You may skip this automatic database backup by creating an empty file
at `/etc/gitlab/skip-auto-backup`:
```shell
sudo touch /etc/gitlab/skip-auto-backup
```
For safety reasons, you should maintain an up-to-date backup on your own if you plan to use this flag.
## Version-specific changes
Updating to major versions might need some manual intervention. For more information,
check the version your are upgrading to:
- [GitLab 14](https://docs.gitlab.com/omnibus/gitlab_14_changes.html)
- [GitLab 13](https://docs.gitlab.com/omnibus/gitlab_13_changes.html)
- [GitLab 12](https://docs.gitlab.com/omnibus/gitlab_12_changes.html)
- [GitLab 11](https://docs.gitlab.com/omnibus/gitlab_11_changes.html)
## Upgrade using the official repositories
All GitLab packages are posted to the GitLab [package server](https://packages.gitlab.com/gitlab/).
Five repositories are maintained:
- [GitLab EE](https://packages.gitlab.com/gitlab/gitlab-ee): for official
[Enterprise Edition](https://about.gitlab.com/pricing/) releases.
- [GitLab CE](https://packages.gitlab.com/gitlab/gitlab-ce): for official Community Edition releases.
- [Unstable](https://packages.gitlab.com/gitlab/unstable): for release candidates and other unstable versions.
- [Nighty Builds](https://packages.gitlab.com/gitlab/nightly-builds): for nightly builds.
- [Raspberry Pi](https://packages.gitlab.com/gitlab/raspberry-pi2): for official Community Edition releases built for [Raspberry Pi](https://www.raspberrypi.org) packages.
If you have installed Omnibus GitLab [Community Edition](https://about.gitlab.com/install/?version=ce)
or [Enterprise Edition](https://about.gitlab.com/install/), then the
official GitLab repository should have already been set up for you.
To upgrade to the newest GitLab version, run:
- For GitLab [Enterprise Edition](https://about.gitlab.com/pricing/):
```shell
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install gitlab-ee
# Centos/RHEL
sudo yum install gitlab-ee
```
- For GitLab Community Edition:
```shell
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install gitlab-ce
# Centos/RHEL
sudo yum install gitlab-ce
```
### Upgrade to a specific version using the official repositories
Linux package managers default to installing the latest available version of a
package for installation and upgrades. Upgrading directly to the latest major
version can be problematic for older GitLab versions that require a multi-stage
[upgrade path](../index.md#upgrade-paths). An upgrade path can span multiple
versions, so you must specify the specific GitLab package with each upgrade.
To specify the intended GitLab version number in your package manager's install
or upgrade command:
1. First, identify the GitLab version number in your package manager:
```shell
# Ubuntu/Debian
sudo apt-cache madison gitlab-ee
# RHEL/CentOS 6 and 7
yum --showduplicates list gitlab-ee
# RHEL/CentOS 8
dnf search gitlab-ee*
```
1. Then install the specific GitLab package:
```shell
# Ubuntu/Debian
sudo apt install gitlab-ee=12.0.12-ee.0
# RHEL/CentOS 6 and 7
yum install gitlab-ee-12.0.12-ee.0.el7
# RHEL/CentOS 8
dnf install gitlab-ee-12.0.12-ee.0.el8
# SUSE
zypper install gitlab-ee=12.0.12-ee.0
```
## Upgrade using a manually-downloaded package
NOTE:
The [package repository](#upgrade-using-the-official-repositories) is recommended over
a manual installation.
If for some reason you don't use the official repositories, you can
download the package and install it manually. This method can be used to either
install GitLab for the first time or update it.
To download and install GitLab:
1. Visit the [official repository](#upgrade-using-the-official-repositories) of your package.
1. Browse to the repository for the type of package you would like to see the
list of packages that are available. Multiple packages exist for a
single version, one for each supported distribution type. Next to the filename
is a label indicating the distribution, as the file names may be the same.
1. Find the package version you wish to install and click on it.
1. Click the **Download** button in the upper right corner to download the package.
1. After the GitLab package is downloaded, install it using the following commands:
- For GitLab [Enterprise Edition](https://about.gitlab.com/pricing/):
```shell
# Debian/Ubuntu
dpkg -i gitlab-ee-<version>.deb
# CentOS/RHEL
rpm -Uvh gitlab-ee-<version>.rpm
```
- For GitLab Community Edition:
```shell
# GitLab Community Edition
# Debian/Ubuntu
dpkg -i gitlab-ce-<version>.deb
# CentOS/RHEL
rpm -Uvh gitlab-ce-<version>.rpm
```
## Troubleshooting
### GitLab 13.7 and later unavailable on Amazon Linux 2
Amazon Linux 2 is not an [officially supported operating system](https://docs.gitlab.com/omnibus/package-information/deprecated_os.html#supported-operating-systems).
However, in past the [official package installation script](https://packages.gitlab.com/gitlab/gitlab-ee/install)
installed the `el/6` package repository if run on Amazon Linux. From GitLab 13.7, we no longer
provide `el/6` packages so administrators must run the [installation script](https://packages.gitlab.com/gitlab/gitlab-ee/install)
again to update the repository to `el/7`:
```shell
curl --silent "https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.rpm.sh" | sudo bash
```
See the [epic on support for GitLab on Amazon Linux 2](https://gitlab.com/groups/gitlab-org/-/epics/2195) for the latest details on official Amazon Linux 2 support.
### Get the status of a GitLab installation
```shell
sudo gitlab-ctl status
sudo gitlab-rake gitlab:check SANITIZE=true
```
- Information on using `gitlab-ctl` to perform [maintenance tasks](https://docs.gitlab.com/omnibus/maintenance/index.html).
- Information on using `gitlab-rake` to [check the configuration](../../administration/raketasks/maintenance.md#check-gitlab-configuration).
### RPM 'package is already installed' error
If you are using RPM and you are upgrading from GitLab Community Edition to GitLab Enterprise Edition you may get an error like this:
```shell
package gitlab-7.5.2_omnibus.5.2.1.ci-1.el7.x86_64 (which is newer than gitlab-7.5.2_ee.omnibus.5.2.1.ci-1.el7.x86_64) is already installed
```
You can override this version check with the `--oldpackage` option:
```shell
sudo rpm -Uvh --oldpackage gitlab-7.5.2_ee.omnibus.5.2.1.ci-1.el7.x86_64.rpm
```
### Package obsoleted by installed package
CE and EE packages are marked as obsoleting and replacing each other so that both aren't installed and running at the same time.
If you are using local RPM files to switch from CE to EE or vice versa, use `rpm` for installing the package rather than `yum`. If you try to use yum, then you may get an error like this:
```plaintext
Cannot install package gitlab-ee-11.8.3-ee.0.el6.x86_64. It is obsoleted by installed package gitlab-ce-11.8.3-ce.0.el6.x86_64
```
To avoid this issue, either:
- Use the same instructions provided in the
[Upgrade using a manually-downloaded package](#upgrade-using-a-manually-downloaded-package) section.
- Temporarily disable this checking in yum by adding `--setopt=obsoletes=0` to the options given to the command.
### 500 error when accessing Project > Settings > Repository
When GitLab is migrated from CE > EE > CE, and then back to EE, you
might get the following error when viewing a project's repository settings:
```shell
Processing by Projects::Settings::RepositoryController#show as HTML
Parameters: {"namespace_id"=>"<namespace_id>", "project_id"=>"<project_id>"}
Completed 500 Internal Server Error in 62ms (ActiveRecord: 4.7ms | Elasticsearch: 0.0ms | Allocations: 14583)
NoMethodError (undefined method `commit_message_negative_regex' for #<PushRule:0x00007fbddf4229b8>
Did you mean? commit_message_regex_change):
```
This error is caused by an EE feature being added to a CE instance on the initial move to EE.
After the instance is moved back to CE and then is upgraded to EE again, the
`push_rules` table already exists in the database. Therefore, a migration is
unable to add the `commit_message_regex_change` column.
This results in the [backport migration of EE tables](https://gitlab.com/gitlab-org/gitlab/-/blob/cf00e431024018ddd82158f8a9210f113d0f4dbc/db/migrate/20190402150158_backport_enterprise_schema.rb#L1619) not working correctly.
The backport migration assumes that certain tables in the database do not exist when running CE.
To fix this issue, manually add the missing `commit_message_negative_regex` column and restart GitLab:
```shell
# Access psql
sudo gitlab-rails dbconsole
# Add the missing column
ALTER TABLE push_rules ADD COLUMN commit_message_negative_regex VARCHAR;
# Exit psql
\q
# Restart GitLab
sudo gitlab-ctl restart
```
### Error `Failed to connect to the internal GitLab API` on a separate GitLab Pages server
Please see [GitLab Pages troubleshooting](../../administration/pages/index.md#failed-to-connect-to-the-internal-gitlab-api).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View file

@ -13,7 +13,8 @@ of a web application. For more details, see
The following limits are disabled by default: The following limits are disabled by default:
- Unauthenticated requests - Unauthenticated API requests
- Unauthenticated web requests
- Authenticated API requests - Authenticated API requests
- Authenticated web requests - Authenticated web requests
@ -21,7 +22,7 @@ To enforce any or all of them:
1. On the top bar, select **Menu > Admin**. 1. On the top bar, select **Menu > Admin**.
1. On the left sidebar, select **Settings > Network**, and expand **User and IP rate limits**: 1. On the left sidebar, select **Settings > Network**, and expand **User and IP rate limits**:
![user-and-ip-rate-limits](img/user_and_ip_rate_limits.png) ![user-and-ip-rate-limits](img/user_and_ip_rate_limits_v14_3.png)
NOTE: NOTE:
By default, all Git operations are first tried unauthenticated. Because of this, HTTP Git operations By default, all Git operations are first tried unauthenticated. Because of this, HTTP Git operations
@ -129,6 +130,10 @@ a comma-separated list of throttle names.
The possible names are: The possible names are:
- `throttle_unauthenticated` - `throttle_unauthenticated`
- [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/335300) in GitLab 14.3. Use `throttle_unauthenticated_api` or `throttle_unauthenticated_web` instead.
`throttle_unauthenticated` is still supported and selects both of them.
- `throttle_unauthenticated_api`
- `throttle_unauthenticated_web`
- `throttle_authenticated_api` - `throttle_authenticated_api`
- `throttle_authenticated_web` - `throttle_authenticated_web`
- `throttle_unauthenticated_protected_paths` - `throttle_unauthenticated_protected_paths`

View file

@ -10,7 +10,7 @@ module API
# in the future we can only return the filename here without the leading # in the future we can only return the filename here without the leading
# directory path. # directory path.
# https://gitlab.com/gitlab-org/gitlab/issues/34521 # https://gitlab.com/gitlab-org/gitlab/issues/34521
expose :filename, &:path expose :path, as: :filename
expose :id expose :id
expose :ref expose :ref
expose :startline expose :startline

View file

@ -127,6 +127,13 @@ module Gitlab
end end
end end
def find_tag(name)
wrapped_gitaly_errors do
gitaly_ref_client.find_tag(name)
end
rescue CommandError
end
def local_branches(sort_by: nil, pagination_params: nil) def local_branches(sort_by: nil, pagination_params: nil)
wrapped_gitaly_errors do wrapped_gitaly_errors do
gitaly_ref_client.local_branches(sort_by: sort_by, pagination_params: pagination_params) gitaly_ref_client.local_branches(sort_by: sort_by, pagination_params: pagination_params)
@ -604,10 +611,6 @@ module Gitlab
end end
end end
def find_tag(name)
tags.find { |tag| tag.name == name }
end
def merge_to_ref(user, **kwargs) def merge_to_ref(user, **kwargs)
wrapped_gitaly_errors do wrapped_gitaly_errors do
gitaly_operation_client.user_merge_to_ref(user, **kwargs) gitaly_operation_client.user_merge_to_ref(user, **kwargs)

View file

@ -129,6 +129,21 @@ module Gitlab
Gitlab::Git::Branch.new(@repository, encode!(branch.name.dup), branch.target_commit.id, target_commit) Gitlab::Git::Branch.new(@repository, encode!(branch.name.dup), branch.target_commit.id, target_commit)
end end
def find_tag(tag_name)
return if tag_name.blank?
request = Gitaly::FindTagRequest.new(
repository: @gitaly_repo,
tag_name: encode_binary(tag_name)
)
response = GitalyClient.call(@repository.storage, :ref_service, :find_tag, request, timeout: GitalyClient.medium_timeout)
tag = response.tag
return unless tag
Gitlab::Git::Tag.new(@repository, tag)
end
def delete_refs(refs: [], except_with_prefixes: []) def delete_refs(refs: [], except_with_prefixes: [])
request = Gitaly::DeleteRefsRequest.new( request = Gitaly::DeleteRefsRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,

View file

@ -7,12 +7,7 @@ module Gitlab
def initialize(repository, tag) def initialize(repository, tag)
@repository = repository @repository = repository
@tag = tag @tag = tag
if Feature.enabled?(:get_tag_signatures)
@signature_data = Gitlab::Git::Tag.extract_signature_lazily(repository, tag.id) if repository @signature_data = Gitlab::Git::Tag.extract_signature_lazily(repository, tag.id) if repository
else
@signature_data = [signature_text_of_message.b, signed_text_of_message.b]
end
end end
def signature def signature
@ -26,22 +21,5 @@ module Gitlab
def signed_text def signed_text
@signature_data&.fetch(1) @signature_data&.fetch(1)
end end
private
def signature_text_of_message
@tag.message.slice(@tag.message.index("-----BEGIN SIGNED MESSAGE-----")..-1)
rescue StandardError
nil
end
def signed_text_of_message
%{object #{@tag.target_commit.id}
type commit
tag #{@tag.name}
tagger #{@tag.tagger.name} <#{@tag.tagger.email}> #{@tag.tagger.date.seconds} #{@tag.tagger.timezone}
#{@tag.message.gsub(/-----BEGIN SIGNED MESSAGE-----(.*)-----END SIGNED MESSAGE-----/m, "")}}
end
end end
end end

View file

@ -12493,6 +12493,9 @@ msgstr ""
msgid "Enable authenticated Git LFS request rate limit" msgid "Enable authenticated Git LFS request rate limit"
msgstr "" msgstr ""
msgid "Enable authenticated web request rate limit"
msgstr ""
msgid "Enable authentication" msgid "Enable authentication"
msgstr "" msgstr ""
@ -12598,7 +12601,7 @@ msgstr ""
msgid "Enable unauthenticated API request rate limit" msgid "Enable unauthenticated API request rate limit"
msgstr "" msgstr ""
msgid "Enable unauthenticated request rate limit" msgid "Enable unauthenticated web request rate limit"
msgstr "" msgstr ""
msgid "Enable user deactivation emails" msgid "Enable user deactivation emails"
@ -18937,7 +18940,7 @@ msgstr ""
msgid "Iterations|Create cadence" msgid "Iterations|Create cadence"
msgstr "" msgstr ""
msgid "Iterations|Create your first iteration" msgid "Iterations|Create iteration"
msgstr "" msgstr ""
msgid "Iterations|Delete cadence" msgid "Iterations|Delete cadence"
@ -18982,12 +18985,18 @@ msgstr ""
msgid "Iterations|New iteration cadence" msgid "Iterations|New iteration cadence"
msgstr "" msgstr ""
msgid "Iterations|No closed iterations."
msgstr ""
msgid "Iterations|No iteration cadences to show." msgid "Iterations|No iteration cadences to show."
msgstr "" msgstr ""
msgid "Iterations|No iterations in cadence." msgid "Iterations|No iterations in cadence."
msgstr "" msgstr ""
msgid "Iterations|No open iterations."
msgstr ""
msgid "Iterations|Number of future iterations you would like to have scheduled" msgid "Iterations|Number of future iterations you would like to have scheduled"
msgstr "" msgstr ""
@ -20726,7 +20735,10 @@ msgstr ""
msgid "Max session time" msgid "Max session time"
msgstr "" msgstr ""
msgid "Max unauthenticated requests per period per IP" msgid "Max unauthenticated API requests per period per IP"
msgstr ""
msgid "Max unauthenticated web requests per period per IP"
msgstr "" msgstr ""
msgid "MaxBuilds" msgid "MaxBuilds"
@ -25291,6 +25303,9 @@ msgstr ""
msgid "Please set a new password before proceeding." msgid "Please set a new password before proceeding."
msgstr "" msgstr ""
msgid "Please set up a Service Desk email address in order to add a custom suffix. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience." msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
msgstr "" msgstr ""
@ -35927,18 +35942,21 @@ msgstr ""
msgid "Unassigned" msgid "Unassigned"
msgstr "" msgstr ""
msgid "Unauthenticated API rate limit period in seconds"
msgstr ""
msgid "Unauthenticated API request rate limit" msgid "Unauthenticated API request rate limit"
msgstr "" msgstr ""
msgid "Unauthenticated rate limit period in seconds"
msgstr ""
msgid "Unauthenticated request rate limit"
msgstr ""
msgid "Unauthenticated requests" msgid "Unauthenticated requests"
msgstr "" msgstr ""
msgid "Unauthenticated web rate limit period in seconds"
msgstr ""
msgid "Unauthenticated web request rate limit"
msgstr ""
msgid "Undo" msgid "Undo"
msgstr "" msgstr ""

View file

@ -7,16 +7,18 @@ module QA
module Component module Component
class IpLimits < Page::Base class IpLimits < Page::Base
view 'app/views/admin/application_settings/_ip_limits.html.haml' do view 'app/views/admin/application_settings/_ip_limits.html.haml' do
element :throttle_unauthenticated_checkbox element :throttle_unauthenticated_api_checkbox
element :throttle_unauthenticated_web_checkbox
element :throttle_authenticated_api_checkbox element :throttle_authenticated_api_checkbox
element :throttle_authenticated_web_checkbox element :throttle_authenticated_web_checkbox
element :save_changes_button element :save_changes_button
end end
def enable_throttles def enable_throttles
check_element(:throttle_unauthenticated_checkbox) check_element(:throttle_unauthenticated_api_checkbox, true)
check_element(:throttle_authenticated_api_checkbox) check_element(:throttle_unauthenticated_web_checkbox, true)
check_element(:throttle_authenticated_web_checkbox) check_element(:throttle_authenticated_api_checkbox, true)
check_element(:throttle_authenticated_web_checkbox, true)
end end
def save_settings def save_settings

View file

@ -546,6 +546,50 @@ RSpec.describe 'Admin updates settings' do
expect(current_settings.dns_rebinding_protection_enabled).to be false expect(current_settings.dns_rebinding_protection_enabled).to be false
end end
it 'changes User and IP Rate Limits settings' do
visit network_admin_application_settings_path
page.within('.as-ip-limits') do
check 'Enable unauthenticated API request rate limit'
fill_in 'Max unauthenticated API requests per period per IP', with: 100
fill_in 'Unauthenticated API rate limit period in seconds', with: 200
check 'Enable unauthenticated web request rate limit'
fill_in 'Max unauthenticated web requests per period per IP', with: 300
fill_in 'Unauthenticated web rate limit period in seconds', with: 400
check 'Enable authenticated API request rate limit'
fill_in 'Max authenticated API requests per period per user', with: 500
fill_in 'Authenticated API rate limit period in seconds', with: 600
check 'Enable authenticated web request rate limit'
fill_in 'Max authenticated web requests per period per user', with: 700
fill_in 'Authenticated web rate limit period in seconds', with: 800
fill_in 'A plain-text response to show to clients that hit the rate limit.', with: 'Custom message'
click_button 'Save changes'
end
expect(page).to have_content "Application settings saved successfully"
expect(current_settings).to have_attributes(
throttle_unauthenticated_api_enabled: true,
throttle_unauthenticated_api_requests_per_period: 100,
throttle_unauthenticated_api_period_in_seconds: 200,
throttle_unauthenticated_enabled: true,
throttle_unauthenticated_requests_per_period: 300,
throttle_unauthenticated_period_in_seconds: 400,
throttle_authenticated_api_enabled: true,
throttle_authenticated_api_requests_per_period: 500,
throttle_authenticated_api_period_in_seconds: 600,
throttle_authenticated_web_enabled: true,
throttle_authenticated_web_requests_per_period: 700,
throttle_authenticated_web_period_in_seconds: 800,
rate_limiting_response_text: 'Custom message'
)
end
it 'changes Issues rate limits settings' do it 'changes Issues rate limits settings' do
visit network_admin_application_settings_path visit network_admin_application_settings_path

View file

@ -38,7 +38,6 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache do
expect(project.service_desk_enabled).to be_truthy expect(project.service_desk_enabled).to be_truthy
expect(project.service_desk_address).to be_present expect(project.service_desk_address).to be_present
expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_incoming_address) expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_incoming_address)
expect(page).not_to have_selector('#service-desk-project-suffix')
end end
end end

View file

@ -107,6 +107,29 @@ describe('ServiceDeskSetting', () => {
}); });
}); });
describe('project suffix', () => {
it('input is hidden', () => {
wrapper = createComponent({
props: { customEmailEnabled: false },
});
const input = wrapper.findByTestId('project-suffix');
expect(input.exists()).toBe(false);
});
it('input is enabled', () => {
wrapper = createComponent({
props: { customEmailEnabled: true },
});
const input = wrapper.findByTestId('project-suffix');
expect(input.exists()).toBe(true);
expect(input.attributes('disabled')).toBeUndefined();
});
});
describe('customEmail is the same as incomingEmail', () => { describe('customEmail is the same as incomingEmail', () => {
const email = 'foo@bar.com'; const email = 'foo@bar.com';

View file

@ -56,32 +56,17 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do
let(:templates) do let(:templates) do
{ {
"" => [ "" => [
{ name: "another_issue_template", id: "another_issue_template" }, { name: "another_issue_template", id: "another_issue_template", project_id: project.id },
{ name: "custom_issue_template", id: "custom_issue_template" } { name: "custom_issue_template", id: "custom_issue_template", project_id: project.id }
] ]
} }
end end
it 'returns project templates only' do it 'returns project templates' do
expect(helper.issuable_templates_names(Issue.new)).to eq(%w[another_issue_template custom_issue_template]) expect(helper.issuable_templates_names(Issue.new)).to eq(%w[another_issue_template custom_issue_template])
end end
end end
context 'without matching project templates' do
let(:templates) do
{
"Project Templates" => [
{ name: "another_issue_template", id: "another_issue_template", project_id: non_existing_record_id },
{ name: "custom_issue_template", id: "custom_issue_template", project_id: non_existing_record_id }
]
}
end
it 'returns empty array' do
expect(helper.issuable_templates_names(Issue.new)).to eq([])
end
end
context 'when there are not templates in the project' do context 'when there are not templates in the project' do
let(:templates) { {} } let(:templates) { {} }

View file

@ -353,13 +353,4 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
expect { receiver.execute rescue nil }.not_to change { Issue.count } expect { receiver.execute rescue nil }.not_to change { Issue.count }
end end
end end
def email_fixture(path)
fixture_file(path).gsub('project_id', project.project_id.to_s)
end
def service_desk_fixture(path, slug: nil, key: 'mykey')
slug ||= project.full_path_slug.to_s
fixture_file(path).gsub('project_slug', slug).gsub('project_key', key)
end
end end

View file

@ -38,7 +38,7 @@ RSpec.describe Gitlab::Git::Tag, :seed_helper do
it { expect(tag.tagger.timezone).to eq("+0200") } it { expect(tag.tagger.timezone).to eq("+0200") }
end end
shared_examples 'signed tag' do describe 'signed tag' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:tag) { project.repository.find_tag('v1.1.1') } let(:tag) { project.repository.find_tag('v1.1.1') }
@ -54,18 +54,6 @@ RSpec.describe Gitlab::Git::Tag, :seed_helper do
it { expect(tag.tagger.timezone).to eq("+0100") } it { expect(tag.tagger.timezone).to eq("+0100") }
end end
context 'with :get_tag_signatures enabled' do
it_behaves_like 'signed tag'
end
context 'with :get_tag_signatures disabled' do
before do
stub_feature_flags(get_tag_signatures: false)
end
it_behaves_like 'signed tag'
end
it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) } it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
end end

View file

@ -92,6 +92,36 @@ RSpec.describe Gitlab::GitalyClient::RefService do
end end
end end
describe '#find_branch' do
it 'sends a find_branch message' do
expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_branch)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return(double(branch: Gitaly::Branch.new(name: 'name', target_commit: build(:gitaly_commit))))
client.find_branch('name')
end
end
describe '#find_tag' do
it 'sends a find_tag message' do
expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_tag)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return(double(tag: Gitaly::Tag.new))
client.find_tag('name')
end
context 'when tag is empty' do
it 'does not send a fing_tag message' do
expect_any_instance_of(Gitaly::RefService::Stub).not_to receive(:find_tag)
expect(client.find_tag('')).to be_nil
end
end
end
describe '#default_branch_name' do describe '#default_branch_name' do
it 'sends a find_default_branch_name message' do it 'sends a find_default_branch_name message' do
expect_any_instance_of(Gitaly::RefService::Stub) expect_any_instance_of(Gitaly::RefService::Stub)

View file

@ -771,3 +771,5 @@ push_rule:
- group - group
bulk_import_export: bulk_import_export:
- group - group
service_desk_setting:
- file_template_project

View file

@ -8,7 +8,7 @@ RSpec.describe Gitlab::X509::Tag do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') } let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
shared_examples 'signed tag' do describe 'signed tag' do
let(:tag) { project.repository.find_tag('v1.1.1') } let(:tag) { project.repository.find_tag('v1.1.1') }
let(:certificate_attributes) do let(:certificate_attributes) do
{ {
@ -33,24 +33,10 @@ RSpec.describe Gitlab::X509::Tag do
it { expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) } it { expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) }
end end
shared_examples 'unsigned tag' do describe 'unsigned tag' do
let(:tag) { project.repository.find_tag('v1.0.0') } let(:tag) { project.repository.find_tag('v1.0.0') }
it { expect(signature).to be_nil } it { expect(signature).to be_nil }
end end
context 'with :get_tag_signatures enabled' do
it_behaves_like 'signed tag'
it_behaves_like 'unsigned tag'
end
context 'with :get_tag_signatures disabled' do
before do
stub_feature_flags(get_tag_signatures: false)
end
it_behaves_like 'signed tag'
it_behaves_like 'unsigned tag'
end
end end
end end

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!('drop_temporary_columns_and_triggers_for_ci_build_trace_chunks')
RSpec.describe DropTemporaryColumnsAndTriggersForCiBuildTraceChunks do
let(:ci_build_trace_chunks_table) { table(:ci_build_trace_chunks) }
it 'correctly migrates up and down' do
reversible_migration do |migration|
migration.before -> {
expect(ci_build_trace_chunks_table.column_names).to include('build_id_convert_to_bigint')
}
migration.after -> {
ci_build_trace_chunks_table.reset_column_information
expect(ci_build_trace_chunks_table.column_names).not_to include('build_id_convert_to_bigint')
}
end
end
end

View file

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe DisableJobTokenScopeWhenUnused do
let(:ci_cd_settings) { table(:project_ci_cd_settings) }
let(:links) { table(:ci_job_token_project_scope_links) }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:namespace) { namespaces.create!(name: 'test', path: 'path', type: 'Group') }
let(:project_with_used_scope) { projects.create!(namespace_id: namespace.id) }
let!(:used_scope_settings) { ci_cd_settings.create!(project_id: project_with_used_scope.id, job_token_scope_enabled: true) }
let(:target_project) { projects.create!(namespace_id: namespace.id) }
let!(:link) { links.create!(source_project_id: project_with_used_scope.id, target_project_id: target_project.id) }
let(:project_with_unused_scope) { projects.create!(namespace_id: namespace.id) }
let!(:unused_scope_settings) { ci_cd_settings.create!(project_id: project_with_unused_scope.id, job_token_scope_enabled: true) }
let(:project_with_disabled_scope) { projects.create!(namespace_id: namespace.id) }
let!(:disabled_scope_settings) { ci_cd_settings.create!(project_id: project_with_disabled_scope.id, job_token_scope_enabled: false) }
describe '#up' do
it 'sets job_token_scope_enabled to false for projects not having job token scope configured' do
migrate!
expect(unused_scope_settings.reload.job_token_scope_enabled).to be_falsey
end
it 'keeps the scope enabled for projects that are using it' do
migrate!
expect(used_scope_settings.reload.job_token_scope_enabled).to be_truthy
end
it 'keeps the scope disabled for projects having it disabled' do
migrate!
expect(disabled_scope_settings.reload.job_token_scope_enabled).to be_falsey
end
end
end

View file

@ -912,8 +912,8 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
subject { cluster.kubernetes_namespace_for(environment, deployable: build) } subject { cluster.kubernetes_namespace_for(environment, deployable: build) }
let(:environment_name) { 'the-environment-name' } let(:environment_name) { 'the-environment-name' }
let(:environment) { create(:environment, name: environment_name, project: cluster.project, last_deployable: build) } let(:environment) { create(:environment, name: environment_name, project: cluster.project) }
let(:build) { create(:ci_build, environment: environment_name, project: cluster.project) } let(:build) { create(:ci_build, environment: environment, project: cluster.project) }
let(:cluster) { create(:cluster, :project, managed: managed_cluster) } let(:cluster) { create(:cluster, :project, managed: managed_cluster) }
let(:managed_cluster) { true } let(:managed_cluster) { true }
let(:default_namespace) { Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: cluster.project).from_environment_slug(environment.slug) } let(:default_namespace) { Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: cluster.project).from_environment_slug(environment.slug) }

View file

@ -691,6 +691,28 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end end
end end
describe '#last_deployable' do
subject { environment.last_deployable }
context 'does not join across databases' do
let(:pipeline_a) { create(:ci_pipeline, project: project) }
let(:pipeline_b) { create(:ci_pipeline, project: project) }
let(:ci_build_a) { create(:ci_build, project: project, pipeline: pipeline_a) }
let(:ci_build_b) { create(:ci_build, project: project, pipeline: pipeline_b) }
before do
create(:deployment, :success, project: project, environment: environment, deployable: ci_build_a)
create(:deployment, :failed, project: project, environment: environment, deployable: ci_build_b)
end
it 'when called' do
with_cross_joins_prevented do
expect(subject.id).to eq(ci_build_a.id)
end
end
end
end
describe '#last_visible_deployment' do describe '#last_visible_deployment' do
subject { environment.last_visible_deployment } subject { environment.last_visible_deployment }
@ -733,6 +755,86 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end end
end end
describe '#last_visible_deployable' do
subject { environment.last_visible_deployable }
context 'does not join across databases' do
let(:pipeline_a) { create(:ci_pipeline, project: project) }
let(:pipeline_b) { create(:ci_pipeline, project: project) }
let(:ci_build_a) { create(:ci_build, project: project, pipeline: pipeline_a) }
let(:ci_build_b) { create(:ci_build, project: project, pipeline: pipeline_b) }
before do
create(:deployment, :success, project: project, environment: environment, deployable: ci_build_a)
create(:deployment, :failed, project: project, environment: environment, deployable: ci_build_b)
end
it 'for direct call' do
with_cross_joins_prevented do
expect(subject.id).to eq(ci_build_b.id)
end
end
it 'for preload' do
environment.reload
with_cross_joins_prevented do
ActiveRecord::Associations::Preloader.new.preload(environment, [last_visible_deployable: []])
expect(subject.id).to eq(ci_build_b.id)
end
end
end
context 'call after preload' do
it 'fetches from association cache' do
pipeline = create(:ci_pipeline, project: project)
ci_build = create(:ci_build, project: project, pipeline: pipeline)
create(:deployment, :failed, project: project, environment: environment, deployable: ci_build)
environment.reload
ActiveRecord::Associations::Preloader.new.preload(environment, [last_visible_deployable: []])
query_count = ActiveRecord::QueryRecorder.new do
expect(subject.id).to eq(ci_build.id)
end.count
expect(query_count).to eq(0)
end
end
context 'when the feature for disable_join is disabled' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:ci_build) { create(:ci_build, project: project, pipeline: pipeline) }
before do
stub_feature_flags(environment_last_visible_pipeline_disable_joins: false)
create(:deployment, :failed, project: project, environment: environment, deployable: ci_build)
end
context 'for preload' do
it 'executes the original association instead of override' do
environment.reload
ActiveRecord::Associations::Preloader.new.preload(environment, [last_visible_deployable: []])
expect_any_instance_of(Deployment).not_to receive(:deployable)
query_count = ActiveRecord::QueryRecorder.new do
expect(subject.id).to eq(ci_build.id)
end.count
expect(query_count).to eq(0)
end
end
context 'for direct call' do
it 'executes the original association instead of override' do
expect_any_instance_of(Deployment).not_to receive(:deployable)
expect(subject.id).to eq(ci_build.id)
end
end
end
end
describe '#last_visible_pipeline' do describe '#last_visible_pipeline' do
let(:user) { create(:user) } let(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
@ -777,6 +879,35 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
expect(last_pipeline).to eq(failed_pipeline) expect(last_pipeline).to eq(failed_pipeline)
end end
context 'does not join across databases' do
let(:pipeline_a) { create(:ci_pipeline, project: project) }
let(:pipeline_b) { create(:ci_pipeline, project: project) }
let(:ci_build_a) { create(:ci_build, project: project, pipeline: pipeline_a) }
let(:ci_build_b) { create(:ci_build, project: project, pipeline: pipeline_b) }
before do
create(:deployment, :success, project: project, environment: environment, deployable: ci_build_a)
create(:deployment, :failed, project: project, environment: environment, deployable: ci_build_b)
end
subject { environment.last_visible_pipeline }
it 'for direct call' do
with_cross_joins_prevented do
expect(subject.id).to eq(pipeline_b.id)
end
end
it 'for preload' do
environment.reload
with_cross_joins_prevented do
ActiveRecord::Associations::Preloader.new.preload(environment, [last_visible_pipeline: []])
expect(subject.id).to eq(pipeline_b.id)
end
end
end
context 'for the environment' do context 'for the environment' do
it 'returns the last pipeline' do it 'returns the last pipeline' do
pipeline = create(:ci_pipeline, project: project, user: user, sha: commit.sha) pipeline = create(:ci_pipeline, project: project, user: user, sha: commit.sha)
@ -815,6 +946,57 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end end
end end
end end
context 'call after preload' do
it 'fetches from association cache' do
pipeline = create(:ci_pipeline, project: project)
ci_build = create(:ci_build, project: project, pipeline: pipeline)
create(:deployment, :failed, project: project, environment: environment, deployable: ci_build)
environment.reload
ActiveRecord::Associations::Preloader.new.preload(environment, [last_visible_pipeline: []])
query_count = ActiveRecord::QueryRecorder.new do
expect(environment.last_visible_pipeline.id).to eq(pipeline.id)
end.count
expect(query_count).to eq(0)
end
end
context 'when the feature for disable_join is disabled' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:ci_build) { create(:ci_build, project: project, pipeline: pipeline) }
before do
stub_feature_flags(environment_last_visible_pipeline_disable_joins: false)
create(:deployment, :failed, project: project, environment: environment, deployable: ci_build)
end
subject { environment.last_visible_pipeline }
context 'for preload' do
it 'executes the original association instead of override' do
environment.reload
ActiveRecord::Associations::Preloader.new.preload(environment, [last_visible_pipeline: []])
expect_any_instance_of(Ci::Build).not_to receive(:pipeline)
query_count = ActiveRecord::QueryRecorder.new do
expect(subject.id).to eq(pipeline.id)
end.count
expect(query_count).to eq(0)
end
end
context 'for direct call' do
it 'executes the original association instead of override' do
expect_any_instance_of(Ci::Build).not_to receive(:pipeline)
expect(subject.id).to eq(pipeline.id)
end
end
end
end end
describe '#upcoming_deployment' do describe '#upcoming_deployment' do

View file

@ -21,12 +21,6 @@ RSpec.describe ProjectCiCdSetting do
end end
end end
describe '#job_token_scope_enabled' do
it 'is true by default' do
expect(described_class.new.job_token_scope_enabled).to be_truthy
end
end
describe '#default_git_depth' do describe '#default_git_depth' do
let(:default_value) { described_class::DEFAULT_GIT_DEPTH } let(:default_value) { described_class::DEFAULT_GIT_DEPTH }

View file

@ -2366,6 +2366,42 @@ RSpec.describe Repository do
end end
end end
describe '#find_tag' do
before do
allow(Gitlab::GitalyClient).to receive(:call).and_call_original
end
it 'finds a tag with specified name by performing FindTag request' do
expect(Gitlab::GitalyClient)
.to receive(:call).with(anything, :ref_service, :find_tag, anything, anything).and_call_original
expect(repository.find_tag('v1.1.0').name).to eq('v1.1.0')
end
it 'does not perform Gitaly call when tags are preloaded' do
repository.tags
expect(Gitlab::GitalyClient).not_to receive(:call)
expect(repository.find_tag('v1.1.0').name).to eq('v1.1.0')
end
it 'returns nil when tag does not exists' do
expect(repository.find_tag('does-not-exist')).to be_nil
end
context 'when find_tag_via_gitaly is disabled' do
it 'fetches all tags' do
stub_feature_flags(find_tag_via_gitaly: false)
expect(Gitlab::GitalyClient)
.to receive(:call).with(anything, :ref_service, :find_all_tags, anything, anything).and_call_original
expect(repository.find_tag('v1.1.0').name).to eq('v1.1.0')
end
end
end
describe '#avatar' do describe '#avatar' do
it 'returns nil if repo does not exist' do it 'returns nil if repo does not exist' do
allow(repository).to receive(:root_ref).and_raise(Gitlab::Git::Repository::NoRepository) allow(repository).to receive(:root_ref).and_raise(Gitlab::Git::Repository::NoRepository)

View file

@ -18,6 +18,15 @@ RSpec.shared_context :email_shared_context do
end end
end end
def email_fixture(path)
fixture_file(path).gsub('project_id', project.project_id.to_s)
end
def service_desk_fixture(path, slug: nil, key: 'mykey')
slug ||= project.full_path_slug.to_s
fixture_file(path).gsub('project_slug', slug).gsub('project_key', key)
end
RSpec.shared_examples :reply_processing_shared_examples do RSpec.shared_examples :reply_processing_shared_examples do
context 'when the user could not be found' do context 'when the user could not be found' do
before do before do