Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-06-14 18:10:28 +00:00
parent 81f257d72e
commit f69bc1dab5
104 changed files with 1982 additions and 1115 deletions

View File

@ -375,7 +375,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- ee/spec/requests/api/commits_spec.rb
- ee/spec/requests/api/dora/metrics_spec.rb
- ee/spec/requests/api/epics_spec.rb
- ee/spec/requests/api/external_approval_rules_spec.rb
- ee/spec/requests/api/geo_spec.rb
- ee/spec/requests/api/graphql/boards/epic_board_list_epics_query_spec.rb
- ee/spec/requests/api/graphql/current_user/todos_query_spec.rb
@ -439,9 +438,9 @@ RSpec/EmptyLineAfterFinalLetItBe:
- ee/spec/services/dast_scanner_profiles/destroy_service_spec.rb
- ee/spec/services/dast_scanner_profiles/update_service_spec.rb
- ee/spec/services/dast_site_profiles/destroy_service_spec.rb
- ee/spec/services/external_approval_rules/create_service_spec.rb
- ee/spec/services/external_approval_rules/destroy_service_spec.rb
- ee/spec/services/external_approval_rules/update_service_spec.rb
- ee/spec/services/external_status_checks/create_service_spec.rb
- ee/spec/services/external_status_checks/destroy_service_spec.rb
- ee/spec/services/external_status_checks/update_service_spec.rb
- ee/spec/services/gitlab_subscriptions/activate_service_spec.rb
- ee/spec/services/gitlab_subscriptions/apply_trial_service_spec.rb
- ee/spec/services/incident_management/incidents/upload_metric_service_spec.rb
@ -2829,7 +2828,7 @@ Gitlab/FeatureAvailableUsage:
- 'ee/app/views/shared/promotions/_promote_repository_features.html.haml'
- 'ee/app/workers/analytics/code_review_metrics_worker.rb'
- 'ee/app/workers/group_saml_group_sync_worker.rb'
- 'ee/lib/api/external_approval_rules.rb'
- 'ee/lib/api/external_status_checks.rb'
- 'ee/lib/ee/api/entities/approval_state.rb'
- 'ee/lib/ee/api/entities/board.rb'
- 'ee/lib/ee/api/entities/issue.rb'

View File

@ -82,7 +82,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ruby (MRI) 2.7.2
- Git 2.31+
- Redis 5.0+
- PostgreSQL 11+
- PostgreSQL 12+
For more information please see the [architecture](https://docs.gitlab.com/ee/development/architecture.html) and [requirements](https://docs.gitlab.com/ee/install/requirements.html) documentation.

View File

@ -14,9 +14,9 @@ export class CiSchemaExtension extends EditorLiteExtension {
* @param {Object} opts
* @param {String} opts.projectNamespace
* @param {String} opts.projectPath
* @param {String?} opts.ref - Current ref. Defaults to master
* @param {String?} opts.ref - Current ref. Defaults to main
*/
registerCiSchema({ projectNamespace, projectPath, ref = 'master' } = {}) {
registerCiSchema({ projectNamespace, projectPath, ref } = {}) {
const ciSchemaPath = Api.buildUrl(Api.projectFileSchemaPath)
.replace(':namespace_path', projectNamespace)
.replace(':project_path', projectPath)

View File

@ -24,7 +24,6 @@ import DependencyRow from './dependency_row.vue';
import InstallationCommands from './installation_commands.vue';
import PackageFiles from './package_files.vue';
import PackageHistory from './package_history.vue';
import PackageTitle from './package_title.vue';
export default {
name: 'PackagesApp',
@ -36,7 +35,9 @@ export default {
GlTab,
GlTabs,
GlSprintf,
PackageTitle,
PackageTitle: () => import('./package_title.vue'),
TerraformTitle: () =>
import('~/packages_and_registries/infrastructure_registry/components/details_title.vue'),
PackagesListLoader,
PackageListRow,
DependencyRow,
@ -50,6 +51,12 @@ export default {
GlModal: GlModalDirective,
},
mixins: [Tracking.mixin()],
inject: {
titleComponent: {
default: 'PackageTitle',
from: 'titleComponent',
},
},
trackingActions: { ...TrackingActions },
data() {
return {
@ -160,7 +167,7 @@ export default {
/>
<div v-else class="packages-app">
<package-title>
<component :is="titleComponent">
<template #delete-button>
<gl-button
v-if="canDelete"
@ -173,7 +180,7 @@ export default {
{{ __('Delete') }}
</gl-button>
</template>
</package-title>
</component>
<gl-tabs>
<gl-tab :title="__('Detail')">

View File

@ -1,5 +1,6 @@
<script>
import { PackageType } from '../../shared/constants';
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
import { PackageType, TERRAFORM_PACKAGE_TYPE } from '../../shared/constants';
import ComposerInstallation from './composer_installation.vue';
import ConanInstallation from './conan_installation.vue';
import MavenInstallation from './maven_installation.vue';
@ -16,6 +17,7 @@ export default {
[PackageType.NUGET]: NugetInstallation,
[PackageType.PYPI]: PypiInstallation,
[PackageType.COMPOSER]: ComposerInstallation,
[TERRAFORM_PACKAGE_TYPE]: TerraformInstallation,
},
props: {
packageEntity: {

View File

@ -11,6 +11,9 @@ export const PackageType = {
GENERIC: 'generic',
};
// we want this separated from the main dictionary to avoid it being pulled in the search of package
export const TERRAFORM_PACKAGE_TYPE = 'terraform_module';
export const TrackingActions = {
DELETE_PACKAGE: 'delete_package',
REQUEST_DELETE_PACKAGE: 'request_delete_package',

View File

@ -0,0 +1,82 @@
<script>
import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
import { mapState, mapGetters } from 'vuex';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { __ } from '~/locale';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
export default {
name: 'DetailsTitle',
components: {
TitleArea,
GlIcon,
GlSprintf,
MetadataItem,
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [timeagoMixin],
i18n: {
packageInfo: __('v%{version} published %{timeAgo}'),
},
computed: {
...mapState(['packageEntity', 'packageFiles']),
...mapGetters(['packagePipeline']),
totalSize() {
return numberToHumanSize(this.packageFiles.reduce((acc, p) => acc + p.size, 0));
},
},
methods: {
dynamicSlotName(index) {
return `metadata-tag${index}`;
},
},
};
</script>
<template>
<title-area :title="packageEntity.name" data-qa-selector="package_title">
<template #sub-header>
<gl-icon name="eye" class="gl-mr-3" />
<gl-sprintf :message="$options.i18n.packageInfo">
<template #version>
{{ packageEntity.version }}
</template>
<template #timeAgo>
<span v-gl-tooltip :title="tooltipTitle(packageEntity.created_at)">
&nbsp;{{ timeFormatted(packageEntity.created_at) }}
</span>
</template>
</gl-sprintf>
</template>
<template #metadata-type>
<metadata-item data-testid="package-type" icon="infrastructure-registry" text="Terraform" />
</template>
<template #metadata-size>
<metadata-item data-testid="package-size" icon="disk" :text="totalSize" />
</template>
<template v-if="packagePipeline" #metadata-pipeline>
<metadata-item
data-testid="pipeline-project"
icon="review-list"
:text="packagePipeline.project.name"
:link="packagePipeline.project.web_url"
/>
</template>
<template v-if="packagePipeline" #metadata-ref>
<metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" />
</template>
<template #right-actions>
<slot name="delete-button"></slot>
</template>
</title-area>
</template>

View File

@ -0,0 +1,66 @@
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { mapState } from 'vuex';
import { s__ } from '~/locale';
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
export default {
name: 'ConanInstallation',
components: {
CodeInstruction,
GlLink,
GlSprintf,
},
computed: {
...mapState(['packageEntity', 'terraformHelpPath', 'projectPath']),
provisionInstructions() {
// eslint-disable-next-line @gitlab/require-i18n-strings
return `module "${this.packageEntity.name}" {
source = "${this.projectPath}/${this.packageEntity.name}"
version = "${this.packageEntity.version}"
}`;
},
registrySetup() {
return `credentials "gitlab.com" {
token = "<TOKEN>"
}`;
},
},
i18n: {
helpText: s__(
'InfrastructureRegistry|For more information on the Terraform registry, %{linkStart}see our documentation%{linkEnd}.',
),
},
};
</script>
<template>
<div>
<h3 class="gl-font-lg">{{ __('Provision instructions') }}</h3>
<code-instruction
:label="
s__(
'InfrastructureRegistry|Copy and paste into your Terraform configuration, insert the variables, and run Terraform init:',
)
"
:instruction="provisionInstructions"
:copy-text="s__('InfrastructureRegistry|Copy Terraform Command')"
multiline
/>
<h3 class="gl-font-lg">{{ __('Registry setup') }}</h3>
<code-instruction
:label="s__('InfrastructureRegistry|To authorize access to the Terraform registry:')"
:instruction="registrySetup"
:copy-text="s__('InfrastructureRegistry|Copy Terraform Setup Command')"
multiline
/>
<gl-sprintf :message="$options.i18n.helpText">
<template #link="{ content }">
<gl-link :href="terraformHelpPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</div>
</template>

View File

@ -22,6 +22,9 @@ export default () => {
return new Vue({
el,
store,
provide: {
titleComponent: 'TerraformTitle',
},
render(createElement) {
return createElement(PackagesApp);
},

View File

@ -10,7 +10,7 @@ export default {
EditorLite,
},
mixins: [glFeatureFlagMixin()],
inject: ['ciConfigPath', 'projectPath', 'projectNamespace'],
inject: ['ciConfigPath', 'projectPath', 'projectNamespace', 'defaultBranch'],
inheritAttrs: false,
data() {
return {
@ -34,7 +34,7 @@ export default {
editorInstance.registerCiSchema({
projectPath: this.projectPath,
projectNamespace: this.projectNamespace,
ref: this.commitSha,
ref: this.commitSha || this.defaultBranch,
});
}
},

View File

@ -6,7 +6,7 @@ module MembershipActions
def create
create_params = params.permit(:user_ids, :access_level, :expires_at)
result = Members::CreateService.new(current_user, create_params.merge({ source: membershipable, invite_source: "#{source_type}-members-page" })).execute
result = Members::CreateService.new(current_user, create_params.merge({ source: membershipable, invite_source: "#{plain_source_type}-members-page" })).execute
if result[:status] == :success
redirect_to members_page_url, notice: _('Users were successfully added.')
@ -175,6 +175,10 @@ module MembershipActions
end
end
def plain_source_type
raise NotImplementedError
end
def requested_relations
case params[:with_inherited_permissions].presence
when 'exclude'

View File

@ -78,6 +78,10 @@ class Groups::GroupMembersController < Groups::ApplicationController
def membershipable_members
group.members
end
def plain_source_type
'group'
end
end
Groups::GroupMembersController.prepend_mod_with('Groups::GroupMembersController')

View File

@ -62,6 +62,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController
def membershipable_members
project.members
end
def plain_source_type
'project'
end
end
Projects::ProjectMembersController.prepend_mod_with('Projects::ProjectMembersController')

View File

@ -20,7 +20,7 @@ class UsersController < ApplicationController
skip_before_action :authenticate_user!
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
before_action :user, except: [:exists, :suggests, :ssh_keys]
before_action :user, except: [:exists, :ssh_keys]
before_action :authorize_read_user_profile!,
only: [:calendar, :calendar_activities, :groups, :projects, :contributed, :starred, :snippets, :followers, :following]
@ -153,14 +153,6 @@ class UsersController < ApplicationController
render json: { exists: !!Namespace.find_by_path_or_name(params[:username]) }
end
def suggests
namespace_path = params[:username]
exists = !!Namespace.find_by_path_or_name(namespace_path)
suggestions = exists ? [Namespace.clean_path(namespace_path)] : []
render json: { exists: exists, suggests: suggestions }
end
def follow
current_user.follow(user)

View File

@ -95,6 +95,14 @@ module Packages
mount_file_store_uploader Packages::Debian::DistributionReleaseFileUploader
def component_names
components.pluck(:name).sort
end
def architecture_names
architectures.pluck(:name).sort
end
def needs_update?
!file.exists? || time_duration_expired?
end

View File

@ -389,11 +389,23 @@ class MergeRequestDiff < ApplicationRecord
def diffs_in_batch(batch_page, batch_size, diff_options:)
fetching_repository_diffs(diff_options) do |comparison|
reorder_diff_files!
diffs_batch = diffs_in_batch_collection(batch_page, batch_size, diff_options: diff_options)
if comparison
comparison.diffs_in_batch(batch_page, batch_size, diff_options: diff_options)
if diff_options[:paths].blank? && !without_files?
# Return the empty MergeRequestDiffBatch for an out of bound batch request
break diffs_batch if diffs_batch.diff_file_paths.blank?
diff_options.merge!(
paths: diffs_batch.diff_file_paths,
pagination_data: diffs_batch.pagination_data
)
end
comparison.diffs(diff_options)
else
reorder_diff_files!
diffs_in_batch_collection(batch_page, batch_size, diff_options: diff_options)
diffs_batch
end
end
end

View File

@ -24,9 +24,15 @@ module MergeRequests
merge_request.project.execute_hooks(merge_data, :merge_request_hooks)
merge_request.project.execute_services(merge_data, :merge_request_hooks)
execute_external_hooks(merge_request, merge_data)
enqueue_jira_connect_messages_for(merge_request)
end
def execute_external_hooks(merge_request, merge_data)
# Implemented in EE
end
def handle_changes(merge_request, options)
old_associations = options.fetch(:old_associations, {})
old_assignees = old_associations.fetch(:assignees, [])

View File

@ -38,14 +38,19 @@ module Packages
append_errors(distribution)
return error unless errors.empty?
distribution.transaction do
if distribution.save
create_components
create_architectures
result = distribution.transaction do
next unless distribution.save
success
end
end || error
create_components
create_architectures
success
end
result ||= error
::Packages::Debian::GenerateDistributionWorker.perform_async(distribution.class.container_type, distribution.reset.id) if result.success?
result
end
def create_components

View File

@ -1,33 +0,0 @@
# frozen_string_literal: true
module Packages
module Debian
class DestroyDistributionService
def initialize(distribution)
@distribution = distribution
end
def execute
destroy_distribution
end
private
def destroy_distribution
if @distribution.destroy
success
else
error("Unable to destroy Debian #{@distribution.model_name.human.downcase}")
end
end
def success
ServiceResponse.success
end
def error(message)
ServiceResponse.error(message: message, payload: { distribution: @distribution })
end
end
end
end

View File

@ -31,7 +31,7 @@ module Packages
end
def update_distribution
distribution.transaction do
result = distribution.transaction do
if distribution.update(params)
update_components if components
update_architectures if architectures
@ -41,7 +41,13 @@ module Packages
append_errors(distribution)
error
end
end || error
end
result ||= error
::Packages::Debian::GenerateDistributionWorker.perform_async(distribution.class.container_type, distribution.id) if result.success?
result
end
def update_components

View File

@ -105,22 +105,6 @@ module Packages
end
def with_zip_file(&block)
if ::Feature.enabled?(:packages_nuget_archive_new_file_reader, project, default_enabled: :yaml)
with_new_file_reader(&block)
else
with_legacy_file_reader(&block)
end
end
def with_legacy_file_reader
package_file.file.use_file do |file_path|
Zip::File.open(file_path) do |zip_file|
yield(zip_file)
end
end
end
def with_new_file_reader
package_file.file.use_open_file do |open_file|
zip_file = Zip::File.new(open_file, false, true)
yield(zip_file)

View File

@ -10,4 +10,6 @@
can_delete: can?(current_user, :destroy_package, @project).to_s,
svg_path: image_path('illustrations/no-packages.svg'),
project_name: @project.name,
project_path: expose_url(@project.full_path),
terraform_help_path: help_page_path('user/infrastructure/index'),
project_list_url: project_infrastructure_registry_index_path(@project)} }

View File

@ -1,3 +1,5 @@
- return if @hide_search_settings
- container_class = local_assigns.fetch(:container_class, 'gl-mt-5')
%div{ class: container_class }

View File

@ -1,8 +0,0 @@
---
name: packages_nuget_archive_new_file_reader
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62471
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331799
milestone: '13.13'
type: development
group: group::package
default_enabled: false

View File

@ -49,7 +49,6 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get :followers
get :following
get :exists
get :suggests
get :activity
post :follow
post :unfollow

View File

@ -0,0 +1,42 @@
# frozen_string_literal: true
class CreateExternalStatusChecksTable < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
create_table_with_constraints :external_status_checks, if_not_exists: true do |t|
t.references :project, foreign_key: { on_delete: :cascade }, null: false, index: false
t.timestamps_with_timezone
t.text :external_url, null: false
t.text_limit :external_url, 255
t.text :name, null: false
t.text_limit :name, 255
t.index([:project_id, :name],
unique: true,
name: 'idx_on_external_status_checks_project_id_name')
t.index([:project_id, :external_url],
unique: true,
name: 'idx_on_external_status_checks_project_id_external_url')
end
create_table :external_status_checks_protected_branches do |t|
t.bigint :external_status_check_id, null: false
t.bigint :protected_branch_id, null: false
t.index :external_status_check_id, name: 'index_esc_protected_branches_on_external_status_check_id'
t.index :protected_branch_id, name: 'index_esc_protected_branches_on_protected_branch_id'
end
end
def down
with_lock_retries do
drop_table :external_status_checks_protected_branches, force: :cascade, if_exists: true
end
with_lock_retries do
drop_table :external_status_checks, force: :cascade, if_exists: true
end
end
end

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
class RenameStatusCheckResponsesApprovalRule < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
execute('DELETE FROM status_check_responses')
unless column_exists?(:status_check_responses, :external_status_check_id)
add_column :status_check_responses, :external_status_check_id, :bigint, null: false # rubocop:disable Rails/NotNullColumn
end
add_concurrent_foreign_key :status_check_responses, :external_status_checks, column: :external_status_check_id, on_delete: :cascade
add_concurrent_foreign_key :status_check_responses, :merge_requests, column: :merge_request_id, on_delete: :cascade
add_concurrent_index :status_check_responses, :external_status_check_id
# Setting this to true so that we can remove the column in a future release once the column has been removed. It has been ignored in 14.0
change_column_null :status_check_responses, :external_approval_rule_id, true
with_lock_retries do
remove_foreign_key :status_check_responses, :external_approval_rules
end
end
def down
change_column_null :status_check_responses, :external_approval_rule_id, false
with_lock_retries do
add_foreign_key :status_check_responses, :external_approval_rules
end
remove_column :status_check_responses, :external_status_check_id
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddStatusCheckForeignKeyToExternalStatusCheckId < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
add_concurrent_foreign_key :external_status_checks_protected_branches, :external_status_checks, column: :external_status_check_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :external_status_checks_protected_branches, column: :external_status_check_id
end
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddStatusCheckForeignKeyToProtectedBranchId < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
add_concurrent_foreign_key :external_status_checks_protected_branches, :protected_branches, column: :protected_branch_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :external_status_checks_protected_branches, column: :protected_branch_id
end
end
end

View File

@ -0,0 +1 @@
f4191b4b8ae7c282c0012f533a01ebe341d62cb0418e39ad543d06ed2dac63a4

View File

@ -0,0 +1 @@
8b6e1c7bacf2cbc05ba94e3fea2ab20e30b78ccaa6833949c11f89d1bdec8110

View File

@ -0,0 +1 @@
b6c503eddc1c5e36957b59efc8fc5dd75da18104499667c3fcc435fcbd739af3

View File

@ -0,0 +1 @@
09771c6f56e54a4d3dc0caab4891cbaf2a1d5685ccb1161d141ce38e44d6cfdb

View File

@ -12893,6 +12893,41 @@ CREATE SEQUENCE external_pull_requests_id_seq
ALTER SEQUENCE external_pull_requests_id_seq OWNED BY external_pull_requests.id;
CREATE TABLE external_status_checks (
id bigint NOT NULL,
project_id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
external_url text NOT NULL,
name text NOT NULL,
CONSTRAINT check_7e3b9eb41a CHECK ((char_length(name) <= 255)),
CONSTRAINT check_ae0dec3f61 CHECK ((char_length(external_url) <= 255))
);
CREATE SEQUENCE external_status_checks_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE external_status_checks_id_seq OWNED BY external_status_checks.id;
CREATE TABLE external_status_checks_protected_branches (
id bigint NOT NULL,
external_status_check_id bigint NOT NULL,
protected_branch_id bigint NOT NULL
);
CREATE SEQUENCE external_status_checks_protected_branches_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE external_status_checks_protected_branches_id_seq OWNED BY external_status_checks_protected_branches.id;
CREATE TABLE feature_gates (
id integer NOT NULL,
feature_key character varying NOT NULL,
@ -18127,8 +18162,9 @@ ALTER SEQUENCE sprints_id_seq OWNED BY sprints.id;
CREATE TABLE status_check_responses (
id bigint NOT NULL,
merge_request_id bigint NOT NULL,
external_approval_rule_id bigint NOT NULL,
sha bytea NOT NULL
external_approval_rule_id bigint,
sha bytea NOT NULL,
external_status_check_id bigint NOT NULL
);
CREATE SEQUENCE status_check_responses_id_seq
@ -19863,6 +19899,10 @@ ALTER TABLE ONLY external_approval_rules_protected_branches ALTER COLUMN id SET
ALTER TABLE ONLY external_pull_requests ALTER COLUMN id SET DEFAULT nextval('external_pull_requests_id_seq'::regclass);
ALTER TABLE ONLY external_status_checks ALTER COLUMN id SET DEFAULT nextval('external_status_checks_id_seq'::regclass);
ALTER TABLE ONLY external_status_checks_protected_branches ALTER COLUMN id SET DEFAULT nextval('external_status_checks_protected_branches_id_seq'::regclass);
ALTER TABLE ONLY feature_gates ALTER COLUMN id SET DEFAULT nextval('feature_gates_id_seq'::regclass);
ALTER TABLE ONLY features ALTER COLUMN id SET DEFAULT nextval('features_id_seq'::regclass);
@ -21174,6 +21214,12 @@ ALTER TABLE ONLY external_approval_rules_protected_branches
ALTER TABLE ONLY external_pull_requests
ADD CONSTRAINT external_pull_requests_pkey PRIMARY KEY (id);
ALTER TABLE ONLY external_status_checks
ADD CONSTRAINT external_status_checks_pkey PRIMARY KEY (id);
ALTER TABLE ONLY external_status_checks_protected_branches
ADD CONSTRAINT external_status_checks_protected_branches_pkey PRIMARY KEY (id);
ALTER TABLE ONLY feature_gates
ADD CONSTRAINT feature_gates_pkey PRIMARY KEY (id);
@ -22388,6 +22434,10 @@ CREATE UNIQUE INDEX idx_on_external_approval_rules_project_id_external_url ON ex
CREATE UNIQUE INDEX idx_on_external_approval_rules_project_id_name ON external_approval_rules USING btree (project_id, name);
CREATE UNIQUE INDEX idx_on_external_status_checks_project_id_external_url ON external_status_checks USING btree (project_id, external_url);
CREATE UNIQUE INDEX idx_on_external_status_checks_project_id_name ON external_status_checks USING btree (project_id, name);
CREATE INDEX idx_packages_build_infos_on_package_id ON packages_build_infos USING btree (package_id);
CREATE INDEX idx_packages_debian_group_component_files_on_architecture_id ON packages_debian_group_component_files USING btree (architecture_id);
@ -23278,6 +23328,10 @@ CREATE INDEX index_epics_on_start_date_sourcing_epic_id ON epics USING btree (st
CREATE INDEX index_epics_on_start_date_sourcing_milestone_id ON epics USING btree (start_date_sourcing_milestone_id);
CREATE INDEX index_esc_protected_branches_on_external_status_check_id ON external_status_checks_protected_branches USING btree (external_status_check_id);
CREATE INDEX index_esc_protected_branches_on_protected_branch_id ON external_status_checks_protected_branches USING btree (protected_branch_id);
CREATE INDEX index_events_on_action ON events USING btree (action);
CREATE INDEX index_events_on_author_id_and_created_at ON events USING btree (author_id, created_at);
@ -24668,6 +24722,8 @@ CREATE INDEX index_sprints_on_title_trigram ON sprints USING gin (title gin_trgm
CREATE INDEX index_status_check_responses_on_external_approval_rule_id ON status_check_responses USING btree (external_approval_rule_id);
CREATE INDEX index_status_check_responses_on_external_status_check_id ON status_check_responses USING btree (external_status_check_id);
CREATE INDEX index_status_check_responses_on_merge_request_id ON status_check_responses USING btree (merge_request_id);
CREATE UNIQUE INDEX index_status_page_published_incidents_on_issue_id ON status_page_published_incidents USING btree (issue_id);
@ -25449,9 +25505,6 @@ ALTER TABLE ONLY ci_unit_test_failures
ALTER TABLE ONLY project_pages_metadata
ADD CONSTRAINT fk_0fd5b22688 FOREIGN KEY (pages_deployment_id) REFERENCES pages_deployments(id) ON DELETE SET NULL;
ALTER TABLE ONLY status_check_responses
ADD CONSTRAINT fk_116e7e7369 FOREIGN KEY (external_approval_rule_id) REFERENCES external_approval_rules(id) ON DELETE CASCADE;
ALTER TABLE ONLY group_deletion_schedules
ADD CONSTRAINT fk_11e3ebfcdd FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
@ -25623,6 +25676,9 @@ ALTER TABLE ONLY clusters_applications_prometheus
ALTER TABLE ONLY terraform_states
ADD CONSTRAINT fk_558901b030 FOREIGN KEY (locked_by_user_id) REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE ONLY status_check_responses
ADD CONSTRAINT fk_55bd2abc83 FOREIGN KEY (external_status_check_id) REFERENCES external_status_checks(id) ON DELETE CASCADE;
ALTER TABLE ONLY merge_request_metrics
ADD CONSTRAINT fk_56067dcb44 FOREIGN KEY (target_project_id) REFERENCES projects(id) ON DELETE CASCADE;
@ -25911,6 +25967,9 @@ ALTER TABLE ONLY bulk_import_entities
ALTER TABLE ONLY compliance_management_frameworks
ADD CONSTRAINT fk_b74c45b71f FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY external_status_checks_protected_branches
ADD CONSTRAINT fk_b7d788e813 FOREIGN KEY (protected_branch_id) REFERENCES protected_branches(id) ON DELETE CASCADE;
ALTER TABLE ONLY issue_assignees
ADD CONSTRAINT fk_b7d881734a FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
@ -25971,6 +26030,9 @@ ALTER TABLE ONLY external_approval_rules_protected_branches
ALTER TABLE ONLY external_approval_rules_protected_branches
ADD CONSTRAINT fk_ca2ffb55e6 FOREIGN KEY (protected_branch_id) REFERENCES protected_branches(id) ON DELETE CASCADE;
ALTER TABLE ONLY external_status_checks_protected_branches
ADD CONSTRAINT fk_cc0dcc36d1 FOREIGN KEY (external_status_check_id) REFERENCES external_status_checks(id) ON DELETE CASCADE;
ALTER TABLE ONLY dast_profiles_pipelines
ADD CONSTRAINT fk_cc206a8c13 FOREIGN KEY (dast_profile_id) REFERENCES dast_profiles(id) ON DELETE CASCADE;
@ -26358,6 +26420,9 @@ ALTER TABLE ONLY boards_epic_board_positions
ALTER TABLE ONLY geo_repository_created_events
ADD CONSTRAINT fk_rails_1f49e46a61 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY external_status_checks
ADD CONSTRAINT fk_rails_1f5a8aa809 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY dora_daily_metrics
ADD CONSTRAINT fk_rails_1fd07aff6f FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE;

View File

@ -56,7 +56,8 @@ Geo provides:
### Gitaly Cluster
Geo should not be confused with [Gitaly Cluster](../gitaly/praefect.md). For more information about
the difference between Geo and Gitaly Cluster, see [Gitaly Cluster compared to Geo](../gitaly/index.md#gitaly-cluster-compared-to-geo).
the difference between Geo and Gitaly Cluster, see
[How does Gitaly Cluster compare to Geo?](../gitaly/faq.md#how-does-gitaly-cluster-compare-to-geo).
## How it works

View File

@ -728,6 +728,10 @@ For each Patroni instance on the secondary site:
postgresql['sql_replication_password'] = 'POSTGRESQL_REPLICATION_PASSWORD_HASH'
postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
postgresql['listen_address'] = '0.0.0.0' # You can use a public or VPC address here instead
gitlab_rails['dbpassword'] = 'POSTGRESQL_PASSWORD'
gitlab_rails['enable'] = true
gitlab_rails['auto_migrate'] = false
```
1. Reconfigure GitLab for the changes to take effect.
@ -882,6 +886,7 @@ For each Patroni instance on the secondary site for the tracking database:
# GitLab database settings
gitlab_rails['db_database'] = 'gitlabhq_geo_production'
gitlab_rails['db_username'] = 'gitlab_geo'
gitlab_rails['enable'] = true
# Disable automatic database migrations
gitlab_rails['auto_migrate'] = false

View File

@ -0,0 +1,90 @@
---
stage: Create
group: Gitaly
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/#assignments
type: reference
---
# Frequently asked questions **(FREE SELF)**
The following are answers to frequently asked questions about Gitaly and Gitaly Cluster.
## How does Gitaly Cluster compare to Geo?
Gitaly Cluster and [Geo](../geo/index.md) both provide redundancy. However the redundancy of:
- Gitaly Cluster provides fault tolerance for data storage and is invisible to the user. Users are
not aware when Gitaly Cluster is used.
- Geo provides [replication](../geo/index.md) and [disaster recovery](../geo/disaster_recovery/index.md) for
an entire instance of GitLab. Users know when they are using Geo for
[replication](../geo/index.md). Geo [replicates multiple data types](../geo/replication/datatypes.md#limitations-on-replicationverification),
including Git data.
The following table outlines the major differences between Gitaly Cluster and Geo:
| Tool | Nodes | Locations | Latency tolerance | Failover | Consistency | Provides redundancy for |
|:---------------|:---------|:----------|:-------------------|:----------------------------------------------------------------------------|:-----------------------------------------|:------------------------|
| Gitaly Cluster | Multiple | Single | Approximately 1 ms | [Automatic](praefect.md#automatic-failover-and-primary-election-strategies) | [Strong](praefect.md#strong-consistency) | Data storage in Git |
| Geo | Multiple | Multiple | Up to one minute | [Manual](../geo/disaster_recovery/index.md) | Eventual | Entire GitLab instance |
For more information, see:
- Geo [use cases](../geo/index.md#use-cases).
- Geo [architecture](../geo/index.md#architecture).
## Are there instructions for migrating to Gitaly Cluster?
Yes! For more information, see [Migrate to Gitaly Cluster](praefect.md#migrate-to-gitaly-cluster).
## What are some repository storage recommendations?
The size of the required storage can vary between instances and depends on the set
[replication factor](praefect.md#replication-factor). You might want to include implementing
repository storage redundancy.
For a replication factor:
- Of `1`: NFS, Gitaly, and Gitaly Cluster have roughly the same storage requirements.
- More than `1`: The amount of required storage is `used space * replication factor`. `used space`
should include any planned future growth.
## What are some Praefect database storage requirements?
The requirements are relatively low because the database contains only metadata of:
- Where repositories are located.
- Some queued work.
It depends on the number of repositories, but a useful minimum is 5-10 GB, similar to the main
GitLab application database.
## Can the GitLab application database and the Praefect database be on the same servers?
Yes, however Praefect should have it's own database server when using Omnibus GitLab PostgreSQL. If
there is a failover, Praefect isn't aware and starts to fail as the database it's trying to use would
either:
- Be unavailable.
- In read-only mode.
A future solution may allow for Praefect and Omnibus GitLab databases on the same PostgreSQL server.
For more information, see the relevant:
- [Omnibus GitLab issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5919).
- [Gitaly issue](https://gitlab.com/gitlab-org/gitaly/-/issues/3398).
## Is PgBouncer required for the Praefect database?
No, because the number of connections Praefect makes is low. You can use the same PgBouncer instance
for both the GitLab application database and the Praefect database if you wish.
## Are there any special considerations for Gitaly Cluster when PostgreSQL is upgraded?
There are no special requirements. Gitaly Cluster requires PostgreSQL version 11 or later.
## Praefect database tables are empty?
These tables are created per the [specific configuration section](praefect.md#postgresql).
If you find you have an empty Praefect database table, see the
[relevant troubleshooting section](index.md#relation-does-not-exist-errors).

View File

@ -235,29 +235,6 @@ A hybrid approach can be used in these instances, where each shard is configured
cluster. [Variable replication factor](https://gitlab.com/groups/gitlab-org/-/epics/3372) is planned
to provide greater flexibility for extremely large GitLab instances.
### Gitaly Cluster compared to Geo
Gitaly Cluster and [Geo](../geo/index.md) both provide redundancy. However the redundancy of:
- Gitaly Cluster provides fault tolerance for data storage and is invisible to the user. Users are
not aware when Gitaly Cluster is used.
- Geo provides [replication](../geo/index.md) and [disaster recovery](../geo/disaster_recovery/index.md) for
an entire instance of GitLab. Users know when they are using Geo for
[replication](../geo/index.md). Geo [replicates multiple data types](../geo/replication/datatypes.md#limitations-on-replicationverification),
including Git data.
The following table outlines the major differences between Gitaly Cluster and Geo:
| Tool | Nodes | Locations | Latency tolerance | Failover | Consistency | Provides redundancy for |
|:---------------|:---------|:----------|:-------------------|:----------------------------------------------------------------------------|:-----------------------------------------|:------------------------|
| Gitaly Cluster | Multiple | Single | Approximately 1 ms | [Automatic](praefect.md#automatic-failover-and-primary-election-strategies) | [Strong](praefect.md#strong-consistency) | Data storage in Git |
| Geo | Multiple | Multiple | Up to one minute | [Manual](../geo/disaster_recovery/index.md) | Eventual | Entire GitLab instance |
For more information, see:
- Geo [use cases](../geo/index.md#use-cases).
- Geo [architecture](../geo/index.md#architecture).
### Architecture
Praefect is a router and transaction manager for Gitaly, and a required
@ -407,30 +384,31 @@ We welcome your feedback on this process: raise a support ticket, or [comment on
Refer to the information below when troubleshooting Gitaly and Gitaly Cluster.
Before troubleshooting, see the Gitaly and Gitaly Cluster
[frequently asked questions](faq.md).
### Troubleshoot Gitaly
The following sections provide possible solutions to Gitaly errors.
See also:
- [Gitaly timeout](../../user/admin_area/settings/gitaly_timeouts.md) settings.
- [Gitaly troubleshooting information](../reference_architectures/troubleshooting.md#troubleshooting-gitaly)
in reference architecture documentation.
See also [Gitaly timeout](../../user/admin_area/settings/gitaly_timeouts.md) settings.
#### Check versions when using standalone Gitaly servers
When using standalone Gitaly servers, you must make sure they are the same version
as GitLab to ensure full compatibility. Check **Admin Area > Overview > Gitaly Servers** on
your GitLab instance and confirm all Gitaly servers indicate that they are up to date.
as GitLab to ensure full compatibility:
#### `gitaly-debug`
1. Go to **Admin Area > Overview > Gitaly Servers** on your GitLab instance.
1. Confirm all Gitaly servers indicate that they are up to date.
#### Use `gitaly-debug`
The `gitaly-debug` command provides "production debugging" tools for Gitaly and Git
performance. It is intended to help production engineers and support
engineers investigate Gitaly performance problems.
If you're using GitLab 11.6 or newer, this tool should be installed on
your GitLab / Gitaly server already at `/opt/gitlab/embedded/bin/gitaly-debug`.
your GitLab or Gitaly server already at `/opt/gitlab/embedded/bin/gitaly-debug`.
If you're investigating an older GitLab version you can compile this
tool offline and copy the executable to your server:
@ -452,13 +430,13 @@ gitaly-debug -h
remote: GitLab: 401 Unauthorized
```
You need to sync your `gitlab-secrets.json` file with your Gitaly clients (GitLab
app nodes).
You need to sync your `gitlab-secrets.json` file with your GitLab
application nodes.
#### Client side gRPC logs
Gitaly uses the [gRPC](https://grpc.io/) RPC framework. The Ruby gRPC
client has its own log file which may contain debugging information when
client has its own log file which may contain useful information when
you are seeing Gitaly errors. You can control the log level of the
gRPC client with the `GRPC_LOG_LEVEL` environment variable. The
default level is `WARN`.
@ -510,12 +488,13 @@ so, there's not that much visibility into what goes on inside
If you have Prometheus set up to scrape your Gitaly process, you can see
request rates and error codes for individual RPCs in `gitaly-ruby` by
querying `grpc_client_handled_total`. Strictly speaking, this metric does
not differentiate between `gitaly-ruby` and other RPCs. However from GitLab 11.9,
all gRPC calls made by Gitaly itself are internal calls from the main Gitaly process to one of its
`gitaly-ruby` sidecars.
querying `grpc_client_handled_total`.
Assuming your `grpc_client_handled_total` counter observes only Gitaly,
- In theory, this metric does not differentiate between `gitaly-ruby` and other RPCs.
- In practice from GitLab 11.9, all gRPC calls made by Gitaly itself are internal calls from the
main Gitaly process to one of its `gitaly-ruby` sidecars.
Assuming your `grpc_client_handled_total` counter only observes Gitaly,
the following query shows you RPCs are (most likely) internally
implemented as calls to `gitaly-ruby`:
@ -549,7 +528,7 @@ Confirm the following are all true:
- When any user adds or modifies a file from the repository using the GitLab
UI, it immediately fails with a red `401 Unauthorized` banner.
- Creating a new project and [initializing it with a README](../../user/project/working_with_projects.md#blank-projects)
successfully creates the project, but doesn't create the README.
successfully creates the project but doesn't create the README.
- When [tailing the logs](https://docs.gitlab.com/omnibus/settings/logs.html#tail-logs-in-a-console-on-the-server)
on a Gitaly client and reproducing the error, you get `401` errors
when reaching the [`/api/v4/internal/allowed`](../../development/internal_api.md) endpoint:
@ -631,22 +610,24 @@ Verify you can reach Gitaly by using TCP:
sudo gitlab-rake gitlab:tcp_check[GITALY_SERVER_IP,GITALY_LISTEN_PORT]
```
If the TCP connection fails, check your network settings and your firewall rules.
If the TCP connection succeeds, your networking and firewall rules are correct.
If the TCP connection:
If you use proxy servers in your command line environment, such as Bash, these
can interfere with your gRPC traffic.
- Fails, check your network settings and your firewall rules.
- Succeeds, your networking and firewall rules are correct.
If you use Bash or a compatible command line environment, run the following commands
to determine whether you have proxy servers configured:
If you use proxy servers in your command line environment such as Bash, these can interfere with
your gRPC traffic.
If you use Bash or a compatible command line environment, run the following commands to determine
whether you have proxy servers configured:
```shell
echo $http_proxy
echo $https_proxy
```
If either of these variables have a value, your Gitaly CLI connections may be
getting routed through a proxy which cannot connect to Gitaly.
If either of these variables have a value, your Gitaly CLI connections may be getting routed through
a proxy which cannot connect to Gitaly.
To remove the proxy setting, run the following commands (depending on which variables had values):
@ -683,6 +664,22 @@ it's likely that the Gitaly servers are experiencing
Ensure the Gitaly clients and servers are synchronized, and use an NTP time
server to keep them synchronized.
#### Gitaly not listening on new address after reconfiguring
When updating the `gitaly['listen_addr']` or `gitaly['prometheus_listen_addr']` values, Gitaly may
continue to listen on the old address after a `sudo gitlab-ctl reconfigure`.
When this occurs, run `sudo gitlab-ctl restart` to resolve the issue. This should no longer be
necessary because [this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/2521) is resolved.
#### Permission denied errors appearing in Gitaly logs when accessing repositories from a standalone Gitaly node
If this error occurs even though file permissions are correct, it's likely that the Gitaly node is
experiencing [clock drift](https://en.wikipedia.org/wiki/Clock_drift).
Please ensure that the GitLab and Gitaly nodes are synchronized and use an NTP time
server to keep them synchronized if possible.
### Troubleshoot Praefect (Gitaly Cluster)
The following sections provide possible solutions to Gitaly Cluster errors.
@ -737,7 +734,7 @@ For example:
{"level":"error","msg":"Error updating node: pq: relation \"node_status\" does not exist","pid":210882,"praefectName":"gitlab1x4m:0.0.0.0:2305","time":"2021-04-01T19:26:19.473Z","virtual_storage":"praefect-cluster-1"}
```
To solve this, the database schema migration can be done using `sql-migrate` subcommand of
To solve this, the database schema migration can be done using `sql-migrate` sub-command of
the `praefect` command:
```shell

View File

@ -1485,15 +1485,8 @@ or to move from single Gitaly nodes, the basic process involves:
1. Create and configure Gitaly Cluster.
1. [Move the repositories](#move-repositories).
The size of the required storage can vary between instances and depends on the set
[replication factor](#replication-factor). The migration to Gitaly Cluster might include
implementing repository storage redundancy.
For a replication factor:
- Of `1`: NFS, Gitaly, and Gitaly Cluster have roughly the same storage requirements.
- More than `1`: The amount of required storage is `used space * replication factor`. `used space`
should include any planned future growth.
When creating the storage, see some
[repository storage recommendations](faq.md#what-are-some-repository-storage-recommendations).
### Move Repositories

View File

@ -206,7 +206,7 @@ stop;
After configuring your local PlantUML server, you're ready to enable the PlantUML integration:
1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user.
1. In the top menu, click **{admin}** **Admin Area**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, go to **Settings > General** and expand the **PlantUML** section.
1. Select the **Enable PlantUML** check box.
1. Set the PlantUML instance as `https://gitlab.example.com/-/plantuml/`,

View File

@ -21,6 +21,42 @@ including adjusting log retention, log forwarding,
switching logs from JSON to plain text logging, and more.
- [How to parse and analyze JSON logs](troubleshooting/log_parsing.md).
## Log Rotation
The logs for a given service may be managed and rotated by:
- `logrotate`
- `svlogd` (`runit`'s service logging daemon)
- `logrotate` and `svlogd`
- Or not at all
The table below includes information about what is responsible for managing and rotating logs for
the included services. Logs
[managed by `svlogd`](https://docs.gitlab.com/omnibus/settings/logs.html#runit-logs)
are written to a file called `current`. The `logrotate` service built into GitLab
[manages all logs](https://docs.gitlab.com/omnibus/settings/logs.html#logrotate)
except those captured by `runit`.
| Log Type | Managed by logrotate | Managed by svlogd/runit |
| ----------------------------------------------- | -------------------- | ----------------------- |
| [Alertmanager Logs](#alertmanager-logs) | N | Y |
| [Crond Logs](#crond-logs) | N | Y |
| [Gitaly](#gitaly-logs) | Y | Y |
| [GitLab Exporter For Omnibus](#gitlab-exporter) | N | Y |
| [GitLab Pages Logs](#pages-logs) | Y | Y |
| GitLab Rails | Y | N |
| [GitLab Shell Logs](#gitlab-shelllog) | Y | N |
| [Grafana Logs](#grafana-logs) | N | Y |
| [LogRotate Logs](#logrotate-logs) | N | Y |
| [Mailroom](#mail_room_jsonlog-default) | Y | Y |
| [NGINX](#nginx-logs) | Y | Y |
| [PostgreSQL Logs](#postgresql-logs) | N | Y |
| [Prometheus Logs](#prometheus-logs) | N | Y |
| [Puma](#puma-logs) | Y | Y |
| [Redis Logs](#redis-logs) | N | Y |
| [Registry Logs](#registry-logs) | N | Y |
| [Workhorse Logs](#workhorse-logs) | Y | Y |
## `production_json.log`
This file lives in `/var/log/gitlab/gitlab-rails/production_json.log` for

View File

@ -8,8 +8,7 @@ type: reference
# Using NFS with GitLab **(FREE SELF)**
NFS can be used as an alternative for object storage but this isn't typically
recommended for performance reasons. Note however it is required for [GitLab
Pages](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/196).
recommended for performance reasons.
For data objects such as LFS, Uploads, Artifacts, etc., an [Object Storage service](object_storage.md)
is recommended over NFS where possible, due to better performance.
@ -17,7 +16,7 @@ is recommended over NFS where possible, due to better performance.
File system performance can impact overall GitLab performance, especially for
actions that read or write to Git repositories. For steps you can use to test
file system performance, see
[File system Performance Benchmarking](operations/filesystem_benchmarking.md).
[File System Performance Benchmarking](operations/filesystem_benchmarking.md).
## Gitaly and NFS deprecation

View File

@ -206,211 +206,8 @@ To make sure your configuration is correct:
## Troubleshooting Gitaly
If you have any problems when using standalone Gitaly nodes, first
[check all the versions are up to date](../gitaly/index.md#check-versions-when-using-standalone-gitaly-servers).
### `gitaly-debug`
The `gitaly-debug` command provides "production debugging" tools for Gitaly and Git
performance. It is intended to help production engineers and support
engineers investigate Gitaly performance problems.
If you're using GitLab 11.6 or newer, this tool should be installed on
your GitLab / Gitaly server already at `/opt/gitlab/embedded/bin/gitaly-debug`.
If you're investigating an older GitLab version you can compile this
tool offline and copy the executable to your server:
```shell
git clone https://gitlab.com/gitlab-org/gitaly.git
cd cmd/gitaly-debug
GOOS=linux GOARCH=amd64 go build -o gitaly-debug
```
To see the help page of `gitaly-debug` for a list of supported sub-commands, run:
```shell
gitaly-debug -h
```
### Commits, pushes, and clones return a 401
```plaintext
remote: GitLab: 401 Unauthorized
```
You will need to sync your `gitlab-secrets.json` file with your GitLab
app nodes.
### Client side gRPC logs
Gitaly uses the [gRPC](https://grpc.io/) RPC framework. The Ruby gRPC
client has its own log file which may contain useful information when
you are seeing Gitaly errors. You can control the log level of the
gRPC client with the `GRPC_LOG_LEVEL` environment variable. The
default level is `WARN`.
You can run a gRPC trace with:
```shell
sudo GRPC_TRACE=all GRPC_VERBOSITY=DEBUG gitlab-rake gitlab:gitaly:check
```
### Observing `gitaly-ruby` traffic
[`gitaly-ruby`](../gitaly/configure_gitaly.md#gitaly-ruby) is an internal implementation detail of Gitaly,
so, there's not that much visibility into what goes on inside
`gitaly-ruby` processes.
If you have Prometheus set up to scrape your Gitaly process, you can see
request rates and error codes for individual RPCs in `gitaly-ruby` by
querying `grpc_client_handled_total`. Strictly speaking, this metric does
not differentiate between `gitaly-ruby` and other RPCs, but in practice
(as of GitLab 11.9), all gRPC calls made by Gitaly itself are internal
calls from the main Gitaly process to one of its `gitaly-ruby` sidecars.
Assuming your `grpc_client_handled_total` counter only observes Gitaly,
the following query shows you RPCs are (most likely) internally
implemented as calls to `gitaly-ruby`:
```prometheus
sum(rate(grpc_client_handled_total[5m])) by (grpc_method) > 0
```
### Repository changes fail with a `401 Unauthorized` error
If you're running Gitaly on its own server and notice that users can
successfully clone and fetch repositories (via both SSH and HTTPS), but can't
push to them or make changes to the repository in the web UI without getting a
`401 Unauthorized` message, then it's possible Gitaly is failing to authenticate
with the other nodes due to having the wrong secrets file.
Confirm the following are all true:
- When any user performs a `git push` to any repository on this Gitaly node, it
fails with the following error (note the `401 Unauthorized`):
```shell
remote: GitLab: 401 Unauthorized
To <REMOTE_URL>
! [remote rejected] branch-name -> branch-name (pre-receive hook declined)
error: failed to push some refs to '<REMOTE_URL>'
```
- When any user adds or modifies a file from the repository using the GitLab
UI, it immediately fails with a red `401 Unauthorized` banner.
- Creating a new project and [initializing it with a README](../../user/project/working_with_projects.md#blank-projects)
successfully creates the project but doesn't create the README.
- When [tailing the logs](https://docs.gitlab.com/omnibus/settings/logs.html#tail-logs-in-a-console-on-the-server) on an app node and reproducing the error, you get `401` errors
when reaching the [`/api/v4/internal/allowed`](../../development/internal_api.md) endpoint:
```shell
# api_json.log
{
"time": "2019-07-18T00:30:14.967Z",
"severity": "INFO",
"duration": 0.57,
"db": 0,
"view": 0.57,
"status": 401,
"method": "POST",
"path": "\/api\/v4\/internal\/allowed",
"params": [
{
"key": "action",
"value": "git-receive-pack"
},
{
"key": "changes",
"value": "REDACTED"
},
{
"key": "gl_repository",
"value": "REDACTED"
},
{
"key": "project",
"value": "\/path\/to\/project.git"
},
{
"key": "protocol",
"value": "web"
},
{
"key": "env",
"value": "{\"GIT_ALTERNATE_OBJECT_DIRECTORIES\":[],\"GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE\":[],\"GIT_OBJECT_DIRECTORY\":null,\"GIT_OBJECT_DIRECTORY_RELATIVE\":null}"
},
{
"key": "user_id",
"value": "2"
},
{
"key": "secret_token",
"value": "[FILTERED]"
}
],
"host": "gitlab.example.com",
"ip": "REDACTED",
"ua": "Ruby",
"route": "\/api\/:version\/internal\/allowed",
"queue_duration": 4.24,
"gitaly_calls": 0,
"gitaly_duration": 0,
"correlation_id": "XPUZqTukaP3"
}
# nginx_access.log
[IP] - - [18/Jul/2019:00:30:14 +0000] "POST /api/v4/internal/allowed HTTP/1.1" 401 30 "" "Ruby"
```
To fix this problem, confirm that your `gitlab-secrets.json` file
on the Gitaly node matches the one on all other nodes. If it doesn't match,
update the secrets file on the Gitaly node to match the others, then
[reconfigure the node](../restart_gitlab.md#omnibus-gitlab-reconfigure).
### Command line tools cannot connect to Gitaly
If you are having trouble connecting to a Gitaly node with command line (CLI) tools, and certain actions result in a `14: Connect Failed` error message, it means that gRPC cannot reach your Gitaly node.
Verify that you can reach Gitaly via TCP:
```shell
sudo gitlab-rake gitlab:tcp_check[GITALY_SERVER_IP,GITALY_LISTEN_PORT]
```
If the TCP connection fails, check your network settings and your firewall rules. If the TCP connection succeeds, your networking and firewall rules are correct.
If you use proxy servers in your command line environment, such as Bash, these can interfere with your gRPC traffic.
If you use Bash or a compatible command line environment, run the following commands to determine whether you have proxy servers configured:
```shell
echo $http_proxy
echo $https_proxy
```
If either of these variables have a value, your Gitaly CLI connections may be getting routed through a proxy which cannot connect to Gitaly.
To remove the proxy setting, run the following commands (depending on which variables had values):
```shell
unset http_proxy
unset https_proxy
```
### Gitaly not listening on new address after reconfiguring
When updating the `gitaly['listen_addr']` or `gitaly['prometheus_listen_addr']` values, Gitaly may continue to listen on the old address after a `sudo gitlab-ctl reconfigure`.
When this occurs, performing a `sudo gitlab-ctl restart` will resolve the issue. This will no longer be necessary after [this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/2521) is resolved.
### Permission denied errors appearing in Gitaly logs when accessing repositories from a standalone Gitaly node
If this error occurs even though file permissions are correct, it's likely that
the Gitaly node is experiencing
[clock drift](https://en.wikipedia.org/wiki/Clock_drift).
Please ensure that the GitLab and Gitaly nodes are synchronized and use an NTP time
server to keep them synchronized if possible.
For troubleshooting information, see Gitaly and Gitaly Cluster
[troubleshooting information](../gitaly/index.md).
## Troubleshooting the GitLab Rails application

View File

@ -503,120 +503,6 @@ DELETE /projects/:id/approval_rules/:approval_rule_id
| `id` | integer | yes | The ID of a project |
| `approval_rule_id` | integer | yes | The ID of a approval rule
## External Project-level MR approvals **(ULTIMATE)**
Configuration for approvals on a specific Merge Request which makes a call to an external HTTP resource.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3869) in GitLab 13.10.
> - It's [deployed behind a feature flag](../user/feature_flags.md), disabled by default.
> - It's disabled on GitLab.com.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-external-project-level-mr-approvals). **(ULTIMATE SELF)**
### Get project external approval rules **(ULTIMATE)**
You can request information about a project's external approval rules using the following endpoint:
```plaintext
GET /projects/:id/external_approval_rules
```
**Parameters:**
| Attribute | Type | Required | Description |
|---------------------|---------|----------|---------------------|
| `id` | integer | yes | The ID of a project |
```json
[
{
"id": 1,
"name": "Compliance Check",
"project_id": 6,
"external_url": "https://gitlab.com/example/test.json",
"protected_branches": [
{
"id": 14,
"project_id": 6,
"name": "master",
"created_at": "2020-10-12T14:04:50.787Z",
"updated_at": "2020-10-12T14:04:50.787Z",
"code_owner_approval_required": false
}
]
}
]
```
### Create external approval rule **(ULTIMATE)**
You can create a new external approval rule for a project using the following endpoint:
```plaintext
POST /projects/:id/external_approval_rules
```
| Attribute | Type | Required | Description |
|------------------------|----------------|----------|----------------------------------------------------|
| `id` | integer | yes | The ID of a project |
| `name` | string | yes | Display name of approval rule |
| `external_url` | string | yes | URL of external approval resource |
| `protected_branch_ids` | `array<Integer>` | no | The ids of protected branches to scope the rule by |
### Delete external approval rule **(ULTIMATE)**
You can delete an external approval rule for a project using the following endpoint:
```plaintext
DELETE /projects/:id/external_approval_rules/:rule_id
```
| Attribute | Type | Required | Description |
|------------------------|----------------|----------|----------------------------------------------------|
| `rule_id` | integer | yes | The ID of an approval rule |
| `id` | integer | yes | The ID of a project |
### Update external approval rule **(ULTIMATE)**
You can update an existing external approval rule for a project using the following endpoint:
```plaintext
PUT /projects/:id/external_approval_rules/:rule_id
```
| Attribute | Type | Required | Description |
|------------------------|----------------|----------|----------------------------------------------------|
| `id` | integer | yes | The ID of a project |
| `rule_id` | integer | yes | The ID of an external approval rule |
| `name` | string | no | Display name of approval rule |
| `external_url` | string | no | URL of external approval resource |
| `protected_branch_ids` | `array<Integer>` | no | The ids of protected branches to scope the rule by |
### Enable or disable External Project-level MR approvals **(ULTIMATE SELF)**
Enable or disable External Project-level MR approvals is under development and not ready for production use. It is
deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../user/feature_flags.md)
can enable it.
To enable it:
```ruby
# For the instance
Feature.enable(:ff_compliance_approval_gates)
# For a single project
Feature.enable(:ff_compliance_approval_gates, Project.find(<project id>))
```
To disable it:
```ruby
# For the instance
Feature.disable(:ff_compliance_approval_gates)
# For a single project
Feature.disable(:ff_compliance_approval_gates, Project.find(<project id>))
```
## Merge Request-level MR approvals
Configuration for approvals on a specific Merge Request. Must be authenticated for all endpoints.

View File

@ -74,6 +74,110 @@ deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
can enable it.
## Get project external status checks **(ULTIMATE)**
You can request information about a project's external status checks using the following endpoint:
```plaintext
GET /projects/:id/external_status_checks
```
**Parameters:**
| Attribute | Type | Required | Description |
|---------------------|---------|----------|---------------------|
| `id` | integer | yes | The ID of a project |
```json
[
{
"id": 1,
"name": "Compliance Check",
"project_id": 6,
"external_url": "https://gitlab.com/example/test.json",
"protected_branches": [
{
"id": 14,
"project_id": 6,
"name": "master",
"created_at": "2020-10-12T14:04:50.787Z",
"updated_at": "2020-10-12T14:04:50.787Z",
"code_owner_approval_required": false
}
]
}
]
```
### Create external status check **(ULTIMATE)**
You can create a new external status check for a project using the following endpoint:
```plaintext
POST /projects/:id/external_status_checks
```
| Attribute | Type | Required | Description |
|------------------------|----------------|----------|----------------------------------------------------|
| `id` | integer | yes | The ID of a project |
| `name` | string | yes | Display name of status check |
| `external_url` | string | yes | URL of status check resource |
| `protected_branch_ids` | `array<Integer>` | no | The ids of protected branches to scope the rule by |
### Delete external status check **(ULTIMATE)**
You can delete an external status check for a project using the following endpoint:
```plaintext
DELETE /projects/:id/external_status_checks/:check_id
```
| Attribute | Type | Required | Description |
|------------------------|----------------|----------|----------------------------------------------------|
| `rule_id` | integer | yes | The ID of an status check |
| `id` | integer | yes | The ID of a project |
### Update external status check **(ULTIMATE)**
You can update an existing external status check for a project using the following endpoint:
```plaintext
PUT /projects/:id/external_status_checks/:check_id
```
| Attribute | Type | Required | Description |
|------------------------|----------------|----------|----------------------------------------------------|
| `id` | integer | yes | The ID of a project |
| `rule_id` | integer | yes | The ID of an external status check |
| `name` | string | no | Display name of status check |
| `external_url` | string | no | URL of external status check resource |
| `protected_branch_ids` | `array<Integer>` | no | The ids of protected branches to scope the rule by |
### Enable or disable External Project-level MR status checks **(ULTIMATE SELF)**
Enable or disable External Project-level MR status checks is under development and not ready for production use. It is
deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../user/feature_flags.md)
can enable it.
To enable it:
```ruby
# For the instance
Feature.enable(:ff_compliance_approval_gates)
# For a single project
Feature.enable(:ff_compliance_approval_gates, Project.find(<project id>))
```
To disable it:
```ruby
# For the instance
Feature.disable(:ff_compliance_approval_gates)
# For a single project
Feature.disable(:ff_compliance_approval_gates, Project.find(<project id>))
```
To enable it:
```ruby

View File

@ -73,7 +73,7 @@ end-to-end:
- $CI_COMMIT_MESSAGE =~ /skip-end-to-end-tests/
```
You can use [parentheses](../variables/README.md#parentheses) with `&&` and `||`
You can use [parentheses](#group-variable-expressions-together-with-parentheses) with `&&` and `||`
to build more complicated variable expressions:
```yaml
@ -318,3 +318,114 @@ this feature flag again:
```ruby
Feature.enable(:allow_unsafe_ruby_regexp)
```
## CI/CD variable expressions
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/37397) in GitLab 10.7 for [the `only` and `except` CI keywords](../yaml/README.md#onlyvariables--exceptvariables)
> - [Expanded](https://gitlab.com/gitlab-org/gitlab/-/issues/27863) in GitLab 12.3 with [the `rules` keyword](../yaml/README.md#rules)
Use variable expressions to control which jobs are created in a pipeline after changes
are pushed to GitLab. You can use variable expressions with:
- [`rules:if`](../yaml/README.md#rules).
- [`only:variables` and `except:variables`](../yaml/README.md#onlyvariables--exceptvariables).
For example, with `rules:if`:
```yaml
job1:
variables:
VAR1: "variable1"
script:
- echo "Test variable comparison
rules:
- if: $VAR1 == "variable1"
```
### Compare a variable to a string
You can use the equality operators `==` and `!=` to compare a variable with a
string. Both single quotes and double quotes are valid. The order doesn't matter,
so the variable can be first, or the string can be first. For example:
- `if: $VARIABLE == "some value"`
- `if: $VARIABLE != "some value"`
- `if: "some value" == $VARIABLE`
### Compare two variables
You can compare the values of two variables. For example:
- `if: $VARIABLE_1 == $VARIABLE_2`
- `if: $VARIABLE_1 != $VARIABLE_2`
### Check if a variable is undefined
You can compare a variable to the `null` keyword to see if it is defined. For example:
- `if: $VARIABLE == null`
- `if: $VARIABLE != null`
### Check if a variable is empty
You can check if a variable is defined but empty. For example:
- `if: $VARIABLE == ""`
- `if: $VARIABLE != ""`
### Check if a variable exists
You can check for the existence of a variable by using just the variable name in
the expression. The variable must not be empty. For example:
- `if: $VARIABLE`
### Compare a variable to a regex pattern
You can do regex pattern matching on variable values with the `=~` and `!~` operators.
Variable pattern matching with regular expressions uses the
[RE2 regular expression syntax](https://github.com/google/re2/wiki/Syntax).
Expressions evaluate as `true` if:
- Matches are found when using `=~`.
- Matches are *not* found when using `!~`.
For example:
- `$VARIABLE =~ /^content.*/`
- `$VARIABLE_1 !~ /^content.*/`
Pattern matching is case-sensitive by default. Use the `i` flag modifier to make a
pattern case-insensitive. For example: `/pattern/i`.
### Join variable expressions together with `&&` or `||`
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62867) in GitLab 12.0
You can join multiple expressions using `&&` (and) or `||` (or), for example:
- `$VARIABLE1 =~ /^content.*/ && $VARIABLE2 == "something"`
- `$VARIABLE1 =~ /^content.*/ && $VARIABLE2 =~ /thing$/ && $VARIABLE3`
- `$VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$/ && $VARIABLE3`
The precedence of operators follows the [Ruby 2.5 standard](https://ruby-doc.org/core-2.5.0/doc/syntax/precedence_rdoc.html),
so `&&` is evaluated before `||`.
#### Group variable expressions together with parentheses
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230938) in GitLab 13.3.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/238174) in GitLab 13.5.
You can use parentheses to group expressions together. Parentheses take precedence over
`&&` and `||`, so expressions enclosed in parentheses are evaluated first, and the
result is used for the rest of the expression.
You can nest parentheses to create complex conditions, and the inner-most expressions
in parentheses are evaluated first.
For example:
- `($VARIABLE1 =~ /^content.*/ || $VARIABLE2) && ($VARIABLE3 =~ /thing$/ || $VARIABLE4)`
- `($VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$/) && $VARIABLE3`
- `$CI_COMMIT_BRANCH == "my-branch" || (($VARIABLE1 == "thing" || $VARIABLE2 == "thing") && $VARIABLE3)`

View File

@ -647,154 +647,6 @@ with `K8S_SECRET_`.
CI/CD variables with multi-line values are not supported.
## CI/CD variable expressions
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/37397) in GitLab 10.7 for [the `only` and `except` CI keywords](../yaml/README.md#onlyvariables--exceptvariables)
> - [Expanded](https://gitlab.com/gitlab-org/gitlab/-/issues/27863) in GitLab 12.3 with [the `rules` keyword](../yaml/README.md#rules)
Use variable expressions to limit which jobs are created
in a pipeline after changes are pushed to GitLab.
In `.gitlab-ci.yml`, variable expressions work with both:
- [`rules`](../yaml/README.md#rules), which is the recommended approach, and
- [`only` and `except`](../yaml/README.md#only--except), which are candidates for deprecation.
This is particularly useful in combination with variables and triggered
pipeline variables.
```yaml
deploy:
script: cap staging deploy
environment: staging
only:
variables:
- $RELEASE == "staging"
- $STAGING
```
Each expression provided is evaluated before a pipeline is created.
If any of the conditions in `variables` evaluates to true when using `only`,
a new job is created. If any of the expressions evaluates to true
when `except` is being used, a job is not created.
This follows the usual rules for [`only` / `except` policies](../yaml/README.md#onlyvariables--exceptvariables).
### Syntax of CI/CD variable expressions
Below you can find supported syntax reference.
#### Equality matching using a string
Examples:
- `$VARIABLE == "some value"`
- `$VARIABLE != "some value"` (introduced in GitLab 11.11)
You can use equality operator `==` or `!=` to compare a variable content to a
string. We support both, double quotes and single quotes to define a string
value, so both `$VARIABLE == "some value"` and `$VARIABLE == 'some value'`
are supported. `"some value" == $VARIABLE` is correct too.
#### Checking for an undefined value
Examples:
- `$VARIABLE == null`
- `$VARIABLE != null` (introduced in GitLab 11.11)
It sometimes happens that you want to check whether a variable is defined
or not. To do that, you can compare a variable to `null` keyword, like
`$VARIABLE == null`. This expression evaluates to true if
variable is not defined when `==` is used, or to false if `!=` is used.
#### Checking for an empty variable
Examples:
- `$VARIABLE == ""`
- `$VARIABLE != ""` (introduced in GitLab 11.11)
To check if a variable is defined but empty, compare it to:
- An empty string: `$VARIABLE == ''`
- A non-empty string: `$VARIABLE != ""`
#### Comparing two variables
Examples:
- `$VARIABLE_1 == $VARIABLE_2`
- `$VARIABLE_1 != $VARIABLE_2` (introduced in GitLab 11.11)
It is possible to compare two variables. This compares values
of these variables.
#### Variable presence check
Example: `$STAGING`
To create a job when there is some variable present, meaning it is defined and non-empty,
use the variable name as an expression, like `$STAGING`. If the `$STAGING` variable
is defined, and is non empty, expression evaluates to `true`.
`$STAGING` value needs to be a string, with length higher than zero.
Variable that contains only whitespace characters is not an empty variable.
#### Regex pattern matching
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/43601) in GitLab 11.0
Examples:
- `=~`: True if pattern is matched. Ex: `$VARIABLE =~ /^content.*/`
- `!~`: True if pattern is not matched. Ex: `$VARIABLE_1 !~ /^content.*/` ([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/61900) in GitLab 11.11)
Variable pattern matching with regular expressions uses the
[RE2 regular expression syntax](https://github.com/google/re2/wiki/Syntax).
Expressions evaluate as `true` if:
- Matches are found when using `=~`.
- Matches are *not* found when using `!~`.
Pattern matching is case-sensitive by default. Use `i` flag modifier, like
`/pattern/i` to make a pattern case-insensitive.
#### Conjunction / Disjunction
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62867) in GitLab 12.0
Examples:
- `$VARIABLE1 =~ /^content.*/ && $VARIABLE2 == "something"`
- `$VARIABLE1 =~ /^content.*/ && $VARIABLE2 =~ /thing$/ && $VARIABLE3`
- `$VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$/ && $VARIABLE3`
It is possible to join multiple conditions using `&&` or `||`. Any of the otherwise
supported syntax may be used in a conjunctive or disjunctive statement.
Precedence of operators follows the
[Ruby 2.5 standard](https://ruby-doc.org/core-2.5.0/doc/syntax/precedence_rdoc.html),
so `&&` is evaluated before `||`.
#### Parentheses
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230938) in GitLab 13.3.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/238174) in GitLab 13.5.
It is possible to use parentheses to group conditions. Parentheses have the highest
precedence of all operators. Expressions enclosed in parentheses are evaluated first,
and the result is used for the rest of the expression.
Many nested parentheses can be used to create complex conditions, and the inner-most
expressions in parentheses are evaluated first. For an expression to be valid an equal
number of `(` and `)` need to be used.
Examples:
- `($VARIABLE1 =~ /^content.*/ || $VARIABLE2) && ($VARIABLE3 =~ /thing$/ || $VARIABLE4)`
- `($VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$/) && $VARIABLE3`
- `$CI_COMMIT_BRANCH == "my-branch" || (($VARIABLE1 == "thing" || $VARIABLE2 == "thing") && $VARIABLE3)`
## Debug logging
> Introduced in GitLab Runner 1.7.

View File

@ -174,7 +174,7 @@ They are:
- Script execution shell.
- Not supported:
- For definitions where the ["Expansion place"](#gitlab-ciyml-file) is GitLab.
- In the `only` and `except` [variables expressions](README.md#cicd-variable-expressions).
- In the `only` and `except` [variables expressions](../jobs/job_control.md#cicd-variable-expressions).
Some of the persisted variables contain tokens and cannot be used by some definitions
due to security reasons.

View File

@ -1323,8 +1323,8 @@ Use `rules:if` clauses to specify when to add a job to a pipeline:
`rules:if` differs slightly from `only:variables` by accepting only a single
expression string per rule, rather than an array of them. Any set of expressions to be
evaluated can be [conjoined into a single expression](../variables/README.md#conjunction--disjunction)
by using `&&` or `||`, and the [variable matching operators (`==`, `!=`, `=~` and `!~`)](../variables/README.md#syntax-of-cicd-variable-expressions).
evaluated can be [conjoined into a single expression](../jobs/job_control.md#join-variable-expressions-together-with--or-)
by using `&&` or `||`, and the [variable matching operators (`==`, `!=`, `=~` and `!~`)](../jobs/job_control.md#cicd-variable-expressions).
Unlike variables in [`script`](../variables/README.md#use-cicd-variables-in-job-scripts)
sections, variables in rules expressions are always formatted as `$VARIABLE`.
@ -1598,7 +1598,7 @@ considered for their usage and behavior in this context. Future keyword improvem
are being discussed in our [epic for improving `rules`](https://gitlab.com/groups/gitlab-org/-/epics/2783),
where anyone can add suggestions or requests.
You can use [parentheses](../variables/README.md#parentheses) with `&&` and `||` to build more complicated variable expressions.
You can use [parentheses](../jobs/job_control.md#group-variable-expressions-together-with-parentheses) with `&&` and `||` to build more complicated variable expressions.
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230938) in GitLab 13.3:
```yaml
@ -1726,7 +1726,7 @@ to a pipeline, based on the status of [CI/CD variables](../variables/README.md).
**Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: An array of [CI/CD variable expressions](../variables/README.md#cicd-variable-expressions).
**Possible inputs**: An array of [CI/CD variable expressions](../jobs/job_control.md#cicd-variable-expressions).
**Example of `only:variables`**:

View File

@ -62,19 +62,19 @@ AND source_id = 13083;
```
Here PostgreSQL can perform the query quite efficiently if both columns are
indexed, but as the query gets more complex it may not be able to use these
indexes efficiently.
indexed. As the query gets more complex, it may not be able to use these
indexes effectively.
## Mixed Responsibilities
Similar to functions and classes a table should have a single responsibility:
Similar to functions and classes, a table should have a single responsibility:
storing data with a certain set of pre-defined columns. When using polymorphic
associations you are instead storing different types of data (possibly with
associations, you are storing different types of data (possibly with
different columns set) in the same table.
## The Solution
Fortunately there is a very simple solution to these problems: use a
Fortunately, there is a solution to these problems: use a
separate table for every type you would otherwise store in the same table. Using
a separate table allows you to use everything a database may provide to ensure
consistency and query data efficiently, without any additional application logic
@ -120,8 +120,8 @@ FROM pending_group_members
WHERE group_id = 4
```
If you want to get both you can use a UNION, though you need to be explicit
about what columns you want to SELECT as otherwise the result set uses the
If you want to get both you can use a `UNION`, though you need to be explicit
about what columns you want to `SELECT` as otherwise the result set uses the
columns of the first query. For example:
```sql

View File

@ -6396,7 +6396,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.user_preferences_group_overview_details`
Count of users who set personal preference to see Details on Group overview page
Count of users who set personal preference to see Details on Group information page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216182203_user_preferences_group_overview_details.yml)
@ -6408,7 +6408,7 @@ Tiers: `ultimate`
### `counts.user_preferences_group_overview_security_dashboard`
Count of users who set personal preference to see Security Dashboard on Group overview page
Count of users who set personal preference to see Security Dashboard on Group information page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216182205_user_preferences_group_overview_security_dashboard.yml)
@ -17440,7 +17440,7 @@ Tiers: `ultimate`
### `usage_activity_by_stage.secure.user_preferences_group_overview_security_dashboard`
Users who set personal preference to see Details on Group overview page
Users who set personal preference to see Details on Group information page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216182207_user_preferences_group_overview_security_dashboard.yml)
@ -19480,7 +19480,7 @@ Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.user_preferences_group_overview_security_dashboard`
Users who set personal preference to see Security Dashboard on Group overview page
Users who set personal preference to see Security Dashboard on Group information page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182209_user_preferences_group_overview_security_dashboard.yml)

View File

@ -292,7 +292,7 @@ sudo adduser --disabled-login --gecos 'GitLab' git
## 6. Database
NOTE:
In GitLab 12.1 and later, only PostgreSQL is supported. In GitLab 13.0 and later, we [require PostgreSQL 11+](requirements.md#postgresql-requirements).
In GitLab 12.1 and later, only PostgreSQL is supported. In GitLab 14.0 and later, we [require PostgreSQL 12+](requirements.md#postgresql-requirements).
1. Install the database packages.

View File

@ -116,6 +116,7 @@ the following table) as these were used for development and testing:
|----------------|----------------------------|
| 10.0 | 9.6 |
| 13.0 | 11 |
| 14.0 | 12 |
You must also ensure the following extensions are loaded into every
GitLab database. [Read more about this requirement, and troubleshooting](postgresql_extensions.md).

View File

@ -76,7 +76,8 @@ You can skip this step if you already have your GitLab repositories searchable i
### Configure your GitLab instance with Sourcegraph
1. In GitLab, go to **Admin Area > Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Sourcegraph** configuration section.
1. Check **Enable Sourcegraph**.
1. Set the Sourcegraph URL to your Sourcegraph instance, such as `https://sourcegraph.example.com`.

View File

@ -82,14 +82,19 @@ See [server hooks](../administration/server_hooks.md) for more information.
## Enabling push rules
NOTE:
GitLab administrators can set push rules globally under
**Admin Area > Push Rules** that all new projects inherit. You can later
override them in a project's settings. They can be also set on a [group level](../user/group/index.md#group-push-rules).
You can create push rules for all new projects to inherit, but they can be overridden
at the project level or the [group level](../user/group/index.md#group-push-rules).
1. Navigate to your project's **Settings > Repository** and expand **Push rules**
1. Set the rule you want
1. Click **Save Push Rules** for the changes to take effect
To create global push rules:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Push rules**.
To override global push rules in a project's settings:
1. Navigate to your project's **Settings > Repository** and expand **Push rules**.
1. Set the rule you want.
1. Select **Save Push Rules** for the changes to take effect.
The following options are available:

View File

@ -149,7 +149,7 @@ Remember to set `git -> bin_path` to `/usr/local/bin/git` in `config/gitlab.yml`
### 7. Update PostgreSQL
WARNING:
From GitLab 13.0, you must use at least PostgreSQL 11.
From GitLab 14.0, you must use at least PostgreSQL 12.
The latest version of GitLab might depend on a more recent PostgreSQL version
than what you're currently running. You may also need to enable some

View File

@ -24,7 +24,8 @@ This affects merge requests and branch comparison views.
To set the maximum diff patch size:
1. Go to the Admin Area (**{admin}**) and select **Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand **Diff limits**.
1. Enter a value for **Maximum diff patch size**, measured in bytes.
1. Select **Save changes**.

View File

@ -15,8 +15,8 @@ project level.
To enable merge request approval rules for an instance:
1. Navigate to **Admin Area >** **{push-rules}** **Push Rules** and expand **Merge
requests approvals**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **{push-rules}** **Push Rules**, and expand **Merge request (MR) approvals**.
1. Set the required rule.
1. Click **Save changes**.

View File

@ -9,18 +9,22 @@ type: reference
## Default projects limit
You can change the default maximum number of projects that users can create in their personal namespace.
Navigate to **Admin Area > Settings > General**, then expand **Account and Limit**.
You can increase or decrease that `Default projects limit` value.
You can change the default maximum number of projects that users can create in their personal namespace:
- If you set `Default projects limit` to 0, users are not allowed to create projects
in their users personal namespace. However, projects can still be created in a group.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease that **Default projects limit** value.
If you set **Default projects limit** to 0, users are not allowed to create projects
in their users personal namespace. However, projects can still be created in a group.
## Max attachment size
You can change the maximum file size for attachments in comments and replies in GitLab.
Navigate to **Admin Area > Settings > General**, then expand **Account and Limit**.
From here, you can increase or decrease by changing the value in `Maximum attachment size (MB)`.
You can change the maximum file size for attachments in comments and replies in GitLab:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease by changing the value in **Maximum attachment size (MB)**.
NOTE:
If you choose a size larger than the configured value for the web server,
@ -29,9 +33,11 @@ details.
## Max push size
You can change the maximum push size for your repository.
Navigate to **Admin Area > Settings > General**, then expand **Account and Limit**.
From here, you can increase or decrease by changing the value in `Maximum push size (MB)`.
You can change the maximum push size for your repository:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease by changing the value in **Maximum push size (MB)**.
NOTE:
When you [add files to a repository](../../project/repository/web_editor.md#create-a-file)
@ -42,9 +48,11 @@ Use [Git LFS](../../../topics/git/lfs/index.md) to add large files to a reposito
## Max import size
You can change the maximum file size for imports in GitLab.
Navigate to **Admin Area > Settings > General**, then expand **Account and Limit**.
From here, you can increase or decrease by changing the value in `Maximum import size (MB)`.
You can change the maximum file size for imports in GitLab:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease by changing the value in **Maximum import size (MB)**.
NOTE:
If you choose a size larger than the configured value for the web server,
@ -62,7 +70,8 @@ A prefix can help you identify PATs visually, as well as with automation tools.
Only a GitLab administrator can set the prefix, which is a global setting applied
to any PAT generated in the system by any user:
1. Navigate to **Admin Area > Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Personal Access Token prefix** field.
1. Click **Save changes**.
@ -104,7 +113,8 @@ These settings can be found in:
1. Fill in the **Repository size limit (MB)** field in the **Naming, visibility** section.
1. Click **Save changes**.
- GitLab global settings:
1. From the Dashboard, navigate to **Admin Area > Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Size limit per repository (MB)** field.
1. Click **Save changes**.
@ -150,7 +160,8 @@ GitLab administrators can choose to customize the session duration (in minutes)
To set a limit on how long these sessions are valid:
1. Navigate to **Admin Area > Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Session duration for Git operations when 2FA is enabled (minutes)** field.
1. Click **Save changes**.
@ -174,7 +185,8 @@ there are no restrictions.
To set a lifetime on how long personal access tokens are valid:
1. Navigate to **Admin Area > Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Maximum allowable lifetime for personal access tokens (days)** field.
1. Click **Save changes**.
@ -196,7 +208,8 @@ By default, expired SSH keys **are not usable**.
To allow the use of expired SSH keys:
1. Navigate to **Admin Area > Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Uncheck the **Enforce SSH key expiration** checkbox.
@ -212,7 +225,8 @@ You can allow the use of expired PATs with the following steps:
To do this:
1. Navigate to **Admin Area > Settings > General**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Uncheck the **Enforce personal access token expiration** checkbox.
@ -224,8 +238,9 @@ To maintain integrity of user details in [Audit Events](../../../administration/
To do this:
1. Navigate to **Admin Area > Settings > General**, then expand **Account and Limit**.
1. Check the **Prevent users from changing their profile name** checkbox.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Select the **Prevent users from changing their profile name** checkbox.
NOTE:
When this ability is disabled, GitLab administrators can still use the

View File

@ -9,13 +9,16 @@ type: index
As an administrator of a GitLab self-managed instance, you can manage the behavior of your deployment. To do so, select **Admin Area > Settings**.
The admin area is not accessible on GitLab.com, and settings can only be changed by the
The Admin Area is not accessible on GitLab.com, and settings can only be changed by the
GitLab.com administrators. See the [GitLab.com settings](../../gitlab_com/index.md)
documentation for all current settings and limits on the GitLab.com instance.
## General
Access the default page for Admin Area settings by navigating to **Admin Area > Settings > General**:
To access the default page for Admin Area settings:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
| Option | Description |
| ------ | ----------- |
@ -116,6 +119,11 @@ Access the default page for Admin Area settings by navigating to **Admin Area >
| [Gitaly timeouts](gitaly_timeouts.md) | Configure Gitaly timeouts. |
| Localization | [Default first day of the week](../../profile/preferences.md) and [Time tracking](../../project/time_tracking.md#limit-displayed-units-to-hours). |
NOTE:
You can change the [Default first day of the week](../../profile/preferences.md) for the entire GitLab instance
in the **Localization** section of **Admin Area > Settings > Preferences**.
### Default first day of the week
You can change the [Default first day of the week](../../profile/preferences.md)
for the entire GitLab instance:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Preferences**.
1. Scroll to the **Localization** section, and select your desired first day of the week.

View File

@ -17,12 +17,17 @@ while the project remains secure.
## Configuration
As an administrator, navigate to **Admin Area > Settings > Templates** and
select the project to serve as the custom template repository.
To select a project to serve as the custom template repository:
![File templates in the Admin Area](img/file_template_admin_area.png)
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Templates**.
1. Select the project:
After that, you can add custom templates to the selected repository and use them for the entire instance.
![File templates in the Admin Area](img/file_template_admin_area.png)
1. Add custom templates to the selected repository.
After you add templates, you can use them for the entire instance.
They are available in the [Web Editor's dropdown](../../project/repository/web_editor.md#template-dropdowns)
and through the [API settings](../../../api/settings.md).

View File

@ -23,9 +23,14 @@ branches), only 1 bulk push event is created instead of 1,000 push
events. This helps in maintaining good system performance and preventing spam on
the activity feed.
This setting can be modified in **Admin Area > Settings > Network > Performance Optimization**.
This can also be configured via the [Application settings API](../../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls)
as `push_event_activities_limit`. The default value is 3, but it can be greater
than or equal 0.
To modify this setting:
- In the Admin Area:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Network**, then expand **Performance optimization**.
- Through the [Application settings API](../../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls)
as `push_event_activities_limit`.
The default value is 3, but it can be greater than or equal 0.
![Push event activities limit](img/push_event_activities_limit_v12_4.png)

View File

@ -11,8 +11,9 @@ GitLab allows administrators to enforce specific controls.
To access the visibility and access control options:
1. Sign in to GitLab as a user with Administrator [permissions](../../permissions.md).
1. Go to **Admin Area > Settings > General**.
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
## Default branch protection

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -175,6 +175,10 @@ We recommend users do this prior to turning on sync, because while synchronizati
New users and existing users on subsequent visits can access the group through the identify provider's dashboard or by visiting links directly.
[In GitLab 14.0 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/325712), GitLab users created with a SCIM identity display with an **Enterprise** badge in the **Members** view.
![Enterprise badge for users created with a SCIM identity](img/member_enterprise_badge_v14_0.png)
For role information, please see the [Group SAML page](index.md#user-access-and-management)
### Blocking access

View File

@ -15,9 +15,8 @@ as a Terraform module registry.
To authenticate to the Terraform module registry, you need either:
- A [personal access token](../../../api/README.md#personalproject-access-tokens).
- A [personal access token](../../../api/README.md#personalproject-access-tokens) with at least `read_api` rights.
- A [CI/CD job token](../../../api/README.md#gitlab-cicd-job-token).
- A [deploy token](../../project/deploy_tokens/index.md).
## Publish a Terraform Module
@ -78,9 +77,9 @@ Example response:
Prerequisites:
- You need to [authenticate with the API](../../../api/README.md#authentication). If authenticating with a deploy token, it must be configured with the `read_package_registry` and/or `write_package_registry` scope.
- You need to [authenticate with the API](../../../api/README.md#authentication). If authenticating with a personal access token, it must be configured with the `read_api` scope.
Authentication tokens (Deploy Token, Job Token, or Personal Access Token) can be provided for `terraform` in your `~/.terraformrc` file:
Authentication tokens (Job Token or Personal Access Token) can be provided for `terraform` in your `~/.terraformrc` file:
```plaintext
credentials "gitlab.com" {
@ -116,3 +115,10 @@ upload:
script:
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file path/to/file.tgz "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/terraform/modules/my-module/my-system/0.0.1/file"'
```
## Example projects
For examples of the Terraform module registry, check the projects below:
- The [_GitLab local file_ project](https://gitlab.com/mattkasa/gitlab-local-file) creates a minimal Terraform module and uploads it into the Terraform module registry using GitLab CI/CD.
- The [_Terraform module test_ project](https://gitlab.com/mattkasa/terraform-module-test) uses the module from the previous example.

View File

@ -97,36 +97,6 @@ Without the approvals, the work cannot merge. Required approvals enable multiple
- [Require approval from a security team](../../../application_security/index.md#security-approvals-in-merge-requests)
before merging code that could introduce a vulnerability. **(ULTIMATE)**
## Notify external services **(ULTIMATE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3869) in GitLab Ultimate 13.10.
> - [Deployed behind a feature flag](../../../feature_flags.md), disabled by default.
> - Disabled on GitLab.com.
> - Not recommended for production use.
> - To use in GitLab self-managed instances, ask a GitLab administrator to [enable it](../../../../api/merge_request_approvals.md#enable-or-disable-external-project-level-mr-approvals). **(ULTIMATE SELF)**
WARNING:
This feature might not be available to you. Check the **version history** note above for details.
You can create an external approval rule to integrate approvals with third-party tools.
When users create, change, or close merge requests, GitLab sends a notification.
The users of the third-party tools can then approve merge requests from outside of GitLab.
With this integration, you can integrate with third-party workflow tools, like
[ServiceNow](https://www.servicenow.co.uk/), or the custom tool of your choice.
You can modify your external approval rules
[by using the REST API](../../../../api/merge_request_approvals.md#external-project-level-mr-approvals).
The lack of an external approval doesn't block the merging of a merge request.
When [approval rule overrides](settings.md#prevent-overrides-of-default-approvals) are allowed,
changes to default approval rules will **not** be applied to existing
merge requests, except for changes to the [target branch](rules.md#approvals-for-protected-branches)
of the rule.
To learn more about use cases, feature discovery, and development timelines,
see the [External API approval rules epic](https://gitlab.com/groups/gitlab-org/-/epics/3869).
## Related links
- [Merge request approvals API](../../../../api/merge_request_approvals.md)

View File

@ -65,7 +65,8 @@ GitLab [administrators](../../../permissions.md) of self-managed instances can
customize the initial branch for projects hosted on that instance. Individual
groups and subgroups can override this instance-wide setting for their projects.
1. Go to **Admin Area > Settings > Repository**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Repository**.
1. Expand **Default initial branch name**.
1. Change the default initial branch to a custom name of your choice.
1. Select **Save changes**.

View File

@ -267,7 +267,7 @@ a `main` entry point inside the Web IDE.
Live Preview is enabled for all projects on GitLab.com. If you are an administrator
of a self-managed GitLab instance, and you want to enable Live Preview:
1. In the top navigation bar, go to **Admin Area**.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > General**.
1. Scroll to **Web IDE** and select **Expand**:
![Administrator Live Preview setting](img/admin_live_preview_v13_0.png)

View File

@ -228,6 +228,7 @@ module API
mount ::API::PagesDomains
mount ::API::ProjectClusters
mount ::API::ProjectContainerRepositories
mount ::API::ProjectDebianDistributions
mount ::API::ProjectEvents
mount ::API::ProjectExport
mount ::API::ProjectImport

View File

@ -0,0 +1,152 @@
# frozen_string_literal: true
module API
module Concerns
module Packages
module DebianDistributionEndpoints
extend ActiveSupport::Concern
included do
include PaginationParams
feature_category :package_registry
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
include ::API::Helpers::Authentication
namespace 'debian_distributions' do
helpers do
params :optional_distribution_params do
optional :suite, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Suite'
optional :origin, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Origin'
optional :label, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Label'
optional :version, type: String, regexp: Gitlab::Regex.debian_version_regex, desc: 'The Debian Version'
optional :description, type: String, desc: 'The Debian Description'
optional :valid_time_duration_seconds, type: Integer, desc: 'The duration before the Release file should be considered expired by the client'
optional :components, type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
regexp: Gitlab::Regex.debian_component_regex,
desc: 'The list of Components'
optional :architectures, type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
regexp: Gitlab::Regex.debian_architecture_regex,
desc: 'The list of Architectures'
end
end
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
.sent_through(:http_basic_auth)
end
content_type :json, 'application/json'
format :json
# POST {projects|groups}/:id/debian_distributions
desc 'Create a Debian Distribution' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
post '/' do
authorize_create_package!(project_or_group)
distribution_params = declared_params(include_missing: false)
result = ::Packages::Debian::CreateDistributionService.new(project_or_group, current_user, distribution_params).execute
distribution = result.payload[:distribution]
if result.success?
present distribution, with: ::API::Entities::Packages::Debian::Distribution
else
render_validation_error!(distribution)
end
end
# GET {projects|groups}/:id/debian_distributions
desc 'Get a list of Debian Distributions' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
use :pagination
optional :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
get '/' do
distribution_params = declared_params(include_missing: false)
distributions = ::Packages::Debian::DistributionsFinder.new(project_or_group, distribution_params).execute
present paginate(distributions), with: ::API::Entities::Packages::Debian::Distribution
end
# GET {projects|groups}/:id/debian_distributions/:codename
desc 'Get a Debian Distribution' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
end
get '/:codename' do
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
present distribution, with: ::API::Entities::Packages::Debian::Distribution
end
# PUT {projects|groups}/:id/debian_distributions/:codename
desc 'Update a Debian Distribution' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
put '/:codename' do
authorize_create_package!(project_or_group)
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
distribution_params = declared_params(include_missing: false).except(:codename)
result = ::Packages::Debian::UpdateDistributionService.new(distribution, distribution_params).execute
distribution = result.payload[:distribution]
if result.success?
present distribution, with: ::API::Entities::Packages::Debian::Distribution
else
render_validation_error!(distribution)
end
end
# DELETE {projects|groups}/:id/debian_distributions/:codename
desc 'Delete a Debian Distribution' do
detail 'This feature was introduced in 14.0'
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
delete '/:codename' do
authorize_destroy_package!(project_or_group)
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
accepted! if distribution.destroy
render_api_error!('Failed to delete distribution', 400)
end
end
end
end
end
end
end

View File

@ -3,7 +3,7 @@
module API
module Concerns
module Packages
module DebianEndpoints
module DebianPackageEndpoints
extend ActiveSupport::Concern
DISTRIBUTION_REGEX = %r{[a-zA-Z0-9][a-zA-Z0-9.-]*}.freeze
@ -32,23 +32,17 @@ module API
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
format :txt
content_type :txt, 'text/plain'
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
before do
require_packages_enabled!
end
include ::API::Helpers::Authentication
namespace 'packages/debian' do
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
.sent_through(:http_basic_auth)
end
format :txt
content_type :txt, 'text/plain'
params do
requires :distribution, type: String, desc: 'The Debian Codename', regexp: Gitlab::Regex.debian_distribution_regex
end
@ -59,7 +53,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
route_setting :authentication, authenticate_non_public: true
get 'Release.gpg' do
not_found!
end
@ -69,7 +63,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
route_setting :authentication, authenticate_non_public: true
get 'Release' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Release'
@ -80,7 +74,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
route_setting :authentication, authenticate_non_public: true
get 'InRelease' do
not_found!
end
@ -96,7 +90,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
route_setting :authentication, authenticate_non_public: true
get 'Packages' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Packages'
@ -119,7 +113,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true
route_setting :authentication, authenticate_non_public: true
get ':file_name', requirements: FILE_NAME_REQUIREMENTS do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO File'

View File

@ -7,6 +7,14 @@ module API
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
before do
require_packages_enabled!
@ -16,7 +24,7 @@ module API
end
namespace ':id/-' do
include ::API::Concerns::Packages::DebianEndpoints
include ::API::Concerns::Packages::DebianPackageEndpoints
end
end
end

View File

@ -7,7 +7,15 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
after_validation do
require_packages_enabled!
not_found! unless ::Feature.enabled?(:debian_packages, user_project)
@ -16,13 +24,20 @@ module API
end
namespace ':id' do
include ::API::Concerns::Packages::DebianEndpoints
helpers do
def project_or_group
user_project
end
end
include ::API::Concerns::Packages::DebianPackageEndpoints
params do
requires :file_name, type: String, desc: 'The file name'
end
namespace 'packages/debian/:file_name', requirements: FILE_NAME_REQUIREMENTS do
format :txt
content_type :json, Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
# PUT {projects|groups}/:id/packages/debian/:file_name
@ -35,8 +50,6 @@ module API
authorize_upload!(authorized_user_project)
bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:debian_max_file_size, params[:file].size)
track_package_event('push_package', :debian, user: current_user, project: authorized_user_project, namespace: authorized_user_project.namespace)
file_params = {
file: params['file'],
file_name: params['file_name'],
@ -52,6 +65,7 @@ module API
::Packages::Debian::ProcessChangesWorker.perform_async(package_file.id, current_user.id) # rubocop:disable CodeReuse/Worker
end
track_package_event('push_package', :debian, user: current_user, project: authorized_user_project, namespace: authorized_user_project.namespace)
created!
rescue ObjectStorage::RemoteStoreError => e
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: authorized_user_project.id })

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module API
module Entities
module Packages
module Debian
class Distribution < Grape::Entity
expose :id
expose :codename
expose :suite
expose :origin
expose :label
expose :version
expose :description
expose :valid_time_duration_seconds
expose :component_names, as: :components
expose :architecture_names, as: :architectures
end
end
end
end
end

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
module API
class ProjectDebianDistributions < ::API::Base
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
after_validation do
require_packages_enabled!
not_found! unless ::Feature.enabled?(:debian_packages, user_project)
authorize_read_package!
end
namespace ':id' do
helpers do
def project_or_group
user_project
end
end
include ::API::Concerns::Packages::DebianDistributionEndpoints
end
end
end
end

View File

@ -14,7 +14,7 @@ module Gitlab
# Minimum PostgreSQL version requirement per documentation:
# https://docs.gitlab.com/ee/install/requirements.html#postgresql-requirements
MINIMUM_POSTGRES_VERSION = 11
MINIMUM_POSTGRES_VERSION = 12
# https://www.postgresql.org/docs/9.2/static/datatype-numeric.html
MAX_INT_VALUE = 2147483647

View File

@ -29,6 +29,7 @@ module Gitlab
sanitize_limit
select
select_one
select_rows
quote_column_name
).freeze

View File

@ -19,6 +19,7 @@ module Gitlab
@diffable = diffable
@include_stats = diff_options.delete(:include_stats)
@pagination_data = diff_options.delete(:pagination_data)
@project = project
@diff_options = diff_options
@diff_refs = diff_refs
@ -47,11 +48,7 @@ module Gitlab
end
def pagination_data
{
current_page: nil,
next_page: nil,
total_pages: nil
}
@pagination_data || empty_pagination_data
end
# This mutates `diff_files` lines.
@ -90,6 +87,14 @@ module Gitlab
private
def empty_pagination_data
{
current_page: nil,
next_page: nil,
total_pages: nil
}
end
def diff_stats_collection
strong_memoize(:diff_stats) do
next unless fetch_diff_stats?

View File

@ -21,9 +21,9 @@ module Gitlab
@paginated_collection = load_paginated_collection(batch_page, batch_size, diff_options)
@pagination_data = {
current_page: batch_gradual_load? ? nil : @paginated_collection.current_page,
next_page: batch_gradual_load? ? nil : @paginated_collection.next_page,
total_pages: batch_gradual_load? ? relation.size : @paginated_collection.total_pages
current_page: current_page,
next_page: next_page,
total_pages: total_pages
}
end
@ -62,6 +62,24 @@ module Gitlab
@merge_request_diff.merge_request_diff_files
end
def current_page
return if @paginated_collection.blank?
batch_gradual_load? ? nil : @paginated_collection.current_page
end
def next_page
return if @paginated_collection.blank?
batch_gradual_load? ? nil : @paginated_collection.next_page
end
def total_pages
return if @paginated_collection.blank?
batch_gradual_load? ? relation.size : @paginated_collection.total_pages
end
# rubocop: disable CodeReuse/ActiveRecord
def load_paginated_collection(batch_page, batch_size, diff_options)
batch_page ||= DEFAULT_BATCH_PAGE

View File

@ -12382,6 +12382,9 @@ msgstr ""
msgid "Enter your password to approve"
msgstr ""
msgid "Enterprise"
msgstr ""
msgid "Environment"
msgstr ""
@ -17441,6 +17444,18 @@ msgstr ""
msgid "Infrastructure Registry"
msgstr ""
msgid "InfrastructureRegistry|Copy Terraform Command"
msgstr ""
msgid "InfrastructureRegistry|Copy Terraform Setup Command"
msgstr ""
msgid "InfrastructureRegistry|Copy and paste into your Terraform configuration, insert the variables, and run Terraform init:"
msgstr ""
msgid "InfrastructureRegistry|For more information on the Terraform registry, %{linkStart}see our documentation%{linkEnd}."
msgstr ""
msgid "InfrastructureRegistry|Infrastructure Registry"
msgstr ""
@ -17453,6 +17468,9 @@ msgstr ""
msgid "InfrastructureRegistry|Terraform modules are the main way to package and reuse resource configurations with Terraform. Learn more about how to %{noPackagesLinkStart}create Terraform modules%{noPackagesLinkEnd} in GitLab."
msgstr ""
msgid "InfrastructureRegistry|To authorize access to the Terraform registry:"
msgstr ""
msgid "InfrastructureRegistry|You have no Terraform modules in your project"
msgstr ""
@ -26594,6 +26612,9 @@ msgstr ""
msgid "Provider"
msgstr ""
msgid "Provision instructions"
msgstr ""
msgid "Provisioned by:"
msgstr ""

View File

@ -74,6 +74,7 @@ RSpec.describe 'Database schema' do
slack_integrations: %w[team_id user_id],
snippets: %w[author_id],
spam_logs: %w[user_id],
status_check_responses: %w[external_approval_rule_id],
subscriptions: %w[user_id subscribable_id],
suggestions: %w[commit_id],
taggings: %w[tag_id taggable_id tagger_id],

View File

@ -4,6 +4,8 @@ import { EXTENSION_CI_SCHEMA_FILE_NAME_MATCH } from '~/editor/constants';
import EditorLite from '~/editor/editor_lite';
import { CiSchemaExtension } from '~/editor/extensions/editor_ci_schema_ext';
const mockRef = 'AABBCCDD';
describe('~/editor/editor_ci_config_ext', () => {
const defaultBlobPath = '.gitlab-ci.yml';
@ -75,8 +77,6 @@ describe('~/editor/editor_ci_config_ext', () => {
});
it('with an schema uri that contains project and ref', () => {
const mockRef = 'AABBCCDD';
instance.registerCiSchema({
projectNamespace: mockProjectNamespace,
projectPath: mockProjectPath,
@ -95,10 +95,11 @@ describe('~/editor/editor_ci_config_ext', () => {
instance.registerCiSchema({
projectNamespace: mockProjectNamespace,
projectPath: mockProjectPath,
ref: mockRef,
});
expect(getConfiguredYmlSchema()).toEqual({
uri: `${TEST_HOST}/${mockProjectNamespace}/${mockProjectPath}/-/schema/master/${EXTENSION_CI_SCHEMA_FILE_NAME_MATCH}`,
uri: `${TEST_HOST}/${mockProjectNamespace}/${mockProjectPath}/-/schema/${mockRef}/${EXTENSION_CI_SCHEMA_FILE_NAME_MATCH}`,
fileMatch: ['another-ci-filename.yml'],
});
});

View File

@ -30,6 +30,7 @@ export const member = {
usingLicense: false,
groupSso: false,
groupManagedAccount: false,
provisionedByThisGroup: false,
validRoles: {
Guest: 10,
Reporter: 20,

View File

@ -1,5 +1,6 @@
import { GlEmptyState } from '@gitlab/ui';
import { mount, createLocalVue } from '@vue/test-utils';
import { nextTick } from 'vue';
import Vuex from 'vuex';
import stubChildren from 'helpers/stub_children';
@ -109,9 +110,11 @@ describe('PackagesApp', () => {
window.location = location;
});
it('renders the app and displays the package title', () => {
it('renders the app and displays the package title', async () => {
createComponent();
await nextTick();
expect(packageTitle().exists()).toBe(true);
});

View File

@ -7,6 +7,7 @@ import MavenInstallation from '~/packages/details/components/maven_installation.
import NpmInstallation from '~/packages/details/components/npm_installation.vue';
import NugetInstallation from '~/packages/details/components/nuget_installation.vue';
import PypiInstallation from '~/packages/details/components/pypi_installation.vue';
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
import {
conanPackage,
@ -15,6 +16,7 @@ import {
nugetPackage,
pypiPackage,
composerPackage,
terraformModule,
} from '../../mock_data';
describe('InstallationCommands', () => {
@ -32,6 +34,7 @@ describe('InstallationCommands', () => {
const nugetInstallation = () => wrapper.find(NugetInstallation);
const pypiInstallation = () => wrapper.find(PypiInstallation);
const composerInstallation = () => wrapper.find(ComposerInstallation);
const terraformInstallation = () => wrapper.findComponent(TerraformInstallation);
afterEach(() => {
wrapper.destroy();
@ -46,6 +49,7 @@ describe('InstallationCommands', () => {
${nugetPackage} | ${nugetInstallation}
${pypiPackage} | ${pypiInstallation}
${composerPackage} | ${composerInstallation}
${terraformModule} | ${terraformInstallation}
`('renders', ({ packageEntity, selector }) => {
it(`${packageEntity.package_type} instructions exist`, () => {
createComponent({ packageEntity });

View File

@ -178,6 +178,20 @@ export const composerPackage = {
version: '1.0.0',
};
export const terraformModule = {
created_at: '2015-12-10',
id: 2,
name: 'Test/system-22',
package_type: 'terraform_module',
project_path: 'foo/bar/baz',
projectPathName: 'foo/bar/baz',
project_id: 1,
updated_at: '2015-12-10',
version: '0.1',
versions: [],
_links,
};
export const mockTags = [
{
name: 'foo-1',

View File

@ -0,0 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TerraformInstallation renders all the messages 1`] = `
<div>
<h3
class="gl-font-lg"
>
Provision instructions
</h3>
<code-instruction-stub
copytext="Copy Terraform Command"
instruction="module \\"Test/system-22\\" {
source = \\"foo/Test/system-22\\"
version = \\"0.1\\"
}"
label="Copy and paste into your Terraform configuration, insert the variables, and run Terraform init:"
multiline="true"
trackingaction=""
trackinglabel=""
/>
<h3
class="gl-font-lg"
>
Registry setup
</h3>
<code-instruction-stub
copytext="Copy Terraform Setup Command"
instruction="credentials \\"gitlab.com\\" {
token = \\"<TOKEN>\\"
}"
label="To authorize access to the Terraform registry:"
multiline="true"
trackingaction=""
trackinglabel=""
/>
<gl-sprintf-stub
message="For more information on the Terraform registry, %{linkStart}see our documentation%{linkEnd}."
/>
</div>
`;

View File

@ -0,0 +1,93 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { terraformModule, mavenFiles, npmPackage } from 'jest/packages/mock_data';
import component from '~/packages_and_registries/infrastructure_registry/components/details_title.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('PackageTitle', () => {
let wrapper;
let store;
function createComponent({ packageFiles = mavenFiles, packageEntity = terraformModule } = {}) {
store = new Vuex.Store({
state: {
packageEntity,
packageFiles,
},
getters: {
packagePipeline: ({ packageEntity: { pipeline = null } }) => pipeline,
},
});
wrapper = shallowMount(component, {
localVue,
store,
stubs: {
TitleArea,
},
});
return wrapper.vm.$nextTick();
}
const findTitleArea = () => wrapper.findComponent(TitleArea);
const packageSize = () => wrapper.find('[data-testid="package-size"]');
const pipelineProject = () => wrapper.find('[data-testid="pipeline-project"]');
const packageRef = () => wrapper.find('[data-testid="package-ref"]');
afterEach(() => {
wrapper.destroy();
});
describe('module title', () => {
it('is correctly bound', async () => {
await createComponent();
expect(findTitleArea().props('title')).toBe(terraformModule.name);
});
});
describe('calculates the package size', () => {
it('correctly calculates the size', async () => {
await createComponent();
expect(packageSize().props('text')).toBe('300 bytes');
});
});
describe('package ref', () => {
it('does not display the ref if missing', async () => {
await createComponent();
expect(packageRef().exists()).toBe(false);
});
it('correctly shows the package ref if there is one', async () => {
await createComponent({ packageEntity: npmPackage });
expect(packageRef().props()).toMatchObject({
text: npmPackage.pipeline.ref,
icon: 'branch',
});
});
});
describe('pipeline project', () => {
it('does not display the project if missing', async () => {
await createComponent();
expect(pipelineProject().exists()).toBe(false);
});
it('correctly shows the pipeline project if there is one', async () => {
await createComponent({ packageEntity: npmPackage });
expect(pipelineProject().props()).toMatchObject({
text: npmPackage.pipeline.project.name,
icon: 'review-list',
link: npmPackage.pipeline.project.web_url,
});
});
});
});

View File

@ -0,0 +1,61 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { terraformModule as packageEntity } from 'jest/packages/mock_data';
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('TerraformInstallation', () => {
let wrapper;
const store = new Vuex.Store({
state: {
packageEntity,
projectPath: 'foo',
},
});
const findCodeInstructions = () => wrapper.findAllComponents(CodeInstructions);
function createComponent() {
wrapper = shallowMount(TerraformInstallation, {
localVue,
store,
});
}
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('renders all the messages', () => {
expect(wrapper.element).toMatchSnapshot();
});
describe('installation commands', () => {
it('renders the correct command', () => {
expect(findCodeInstructions().at(0).props('instruction')).toMatchInlineSnapshot(`
"module \\"Test/system-22\\" {
source = \\"foo/Test/system-22\\"
version = \\"0.1\\"
}"
`);
});
});
describe('setup commands', () => {
it('renders the correct command', () => {
expect(findCodeInstructions().at(1).props('instruction')).toMatchInlineSnapshot(`
"credentials \\"gitlab.com\\" {
token = \\"<TOKEN>\\"
}"
`);
});
});
});

View File

@ -9,6 +9,7 @@ import {
mockCommitSha,
mockProjectPath,
mockProjectNamespace,
mockDefaultBranch,
} from '../../mock_data';
describe('Pipeline Editor | Text editor component', () => {
@ -38,6 +39,7 @@ describe('Pipeline Editor | Text editor component', () => {
projectPath: mockProjectPath,
projectNamespace: mockProjectNamespace,
ciConfigPath: mockCiConfigPath,
defaultBranch: mockDefaultBranch,
glFeatures,
},
attrs: {

View File

@ -125,10 +125,10 @@ RSpec.describe Gitlab::Database do
expect(described_class.postgresql_minimum_supported_version?).to eq(false)
end
it 'returns true when using PostgreSQL 11' do
it 'returns false when using PostgreSQL 11' do
allow(described_class).to receive(:version).and_return('11')
expect(described_class.postgresql_minimum_supported_version?).to eq(true)
expect(described_class.postgresql_minimum_supported_version?).to eq(false)
end
it 'returns true when using PostgreSQL 12' do

View File

@ -342,7 +342,7 @@ container_repositories:
- project
- name
project:
- external_approval_rules
- external_status_checks
- taggings
- base_tags
- topic_taggings

View File

@ -418,8 +418,8 @@ RSpec.describe MergeRequestDiff do
shared_examples_for 'fetching full diffs' do
it 'returns diffs from repository comparison' do
expect_next_instance_of(Compare) do |comparison|
expect(comparison).to receive(:diffs_in_batch)
.with(1, 10, diff_options: diff_options)
expect(comparison).to receive(:diffs)
.with(diff_options)
.and_call_original
end
@ -448,13 +448,13 @@ RSpec.describe MergeRequestDiff do
end
it_behaves_like 'fetching full diffs'
end
context 'when diff_options include ignore_whitespace_change' do
it_behaves_like 'fetching full diffs' do
context 'when diff_options include ignore_whitespace_change' do
let(:diff_options) do
{ ignore_whitespace_change: true }
end
it_behaves_like 'fetching full diffs'
end
end
@ -485,6 +485,51 @@ RSpec.describe MergeRequestDiff do
'files/whitespace'
])
end
context 'when diff_options include ignore_whitespace_change' do
let(:diff_options) do
{ ignore_whitespace_change: true }
end
it 'returns a Gitlab::Diff::FileCollection::Compare with paginated diffs' do
diffs = diff_with_commits.diffs_in_batch(1, 10, diff_options: diff_options)
expect(diffs).to be_a(Gitlab::Diff::FileCollection::Compare)
expect(diffs.diff_files.size).to eq 10
expect(diffs.pagination_data).to eq(current_page: 1, next_page: 2, total_pages: 2)
end
it 'returns an empty MergeRequestBatch with empty pagination data when the batch is empty' do
diffs = diff_with_commits.diffs_in_batch(3, 10, diff_options: diff_options)
expect(diffs).to be_a(Gitlab::Diff::FileCollection::MergeRequestDiffBatch)
expect(diffs.diff_files.size).to eq 0
expect(diffs.pagination_data).to eq(current_page: nil, next_page: nil, total_pages: nil)
end
context 'with gradual load enabled' do
before do
stub_feature_flags(diffs_gradual_load: true)
end
it 'returns pagination data from MergeRequestDiffBatch' do
diffs = diff_with_commits.diffs_in_batch(1, 10, diff_options: diff_options)
file_count = diff_with_commits.merge_request_diff_files.count
expect(diffs).to be_a(Gitlab::Diff::FileCollection::Compare)
expect(diffs.diff_files.size).to eq 10
expect(diffs.pagination_data).to eq(current_page: nil, next_page: nil, total_pages: file_count)
end
it 'returns an empty MergeRequestBatch with empty pagination data when the batch is empty' do
diffs = diff_with_commits.diffs_in_batch(30, 10, diff_options: diff_options)
expect(diffs).to be_a(Gitlab::Diff::FileCollection::MergeRequestDiffBatch)
expect(diffs.diff_files.size).to eq 0
expect(diffs.pagination_data).to eq(current_page: nil, next_page: nil, total_pages: nil)
end
end
end
end
end

View File

@ -7,33 +7,33 @@ RSpec.describe API::DebianGroupPackages do
include_context 'Debian repository shared context', :group, false do
describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release.gpg' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/Release.gpg" }
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/Release.gpg" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/Release" }
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/Release" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Release'
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Release$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/InRelease' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/InRelease" }
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/InRelease" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/#{component}/binary-#{architecture}/Packages" }
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component}/binary-#{architecture}/Packages" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Packages'
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Packages$/
end
describe 'GET groups/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name' do
let(:url) { "/groups/#{container.id}/-/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO File'
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO File$/
end
end
end

View File

@ -7,33 +7,33 @@ RSpec.describe API::DebianProjectPackages do
include_context 'Debian repository shared context', :project, true do
describe 'GET projects/:id/packages/debian/dists/*distribution/Release.gpg' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/Release.gpg" }
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/Release.gpg" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end
describe 'GET projects/:id/packages/debian/dists/*distribution/Release' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/Release" }
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/Release" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Release'
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Release$/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/InRelease' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/InRelease" }
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/InRelease" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/#{component}/binary-#{architecture}/Packages" }
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component}/binary-#{architecture}/Packages" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Packages'
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Packages$/
end
describe 'GET projects/:id/packages/debian/pool/:component/:letter/:source_package/:file_name' do
let(:url) { "/projects/#{container.id}/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO File'
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO File$/
end
describe 'PUT projects/:id/packages/debian/:file_name' do

View File

@ -0,0 +1,66 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::ProjectDebianDistributions do
include HttpBasicAuthHelpers
include WorkhorseHelpers
include_context 'Debian repository shared context', :project, true do
describe 'POST projects/:id/debian_distributions' do
let(:method) { :post }
let(:url) { "/projects/#{container.id}/debian_distributions" }
let(:api_params) { { 'codename': 'my-codename' } }
it_behaves_like 'Debian repository write endpoint', 'POST distribution request', :created, /^{.*"codename":"my-codename",.*"components":\["main"\],.*"architectures":\["all","amd64"\]/, authenticate_non_public: false
context 'with invalid parameters' do
let(:api_params) { { codename: distribution.codename } }
it_behaves_like 'Debian repository write endpoint', 'GET request', :bad_request, /^{"message":{"codename":\["has already been taken"\]}}$/, authenticate_non_public: false
end
end
describe 'GET projects/:id/debian_distributions' do
let(:url) { "/projects/#{container.id}/debian_distributions" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^\[{.*"codename":"existing-codename\",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/, authenticate_non_public: false
end
describe 'GET projects/:id/debian_distributions/:codename' do
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^{.*"codename":"existing-codename\",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/, authenticate_non_public: false
end
describe 'PUT projects/:id/debian_distributions/:codename' do
let(:method) { :put }
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
let(:api_params) { { suite: 'my-suite' } }
it_behaves_like 'Debian repository write endpoint', 'PUT distribution request', :success, /^{.*"codename":"existing-codename",.*"suite":"my-suite",/, authenticate_non_public: false
context 'with invalid parameters' do
let(:api_params) { { suite: distribution.codename } }
it_behaves_like 'Debian repository write endpoint', 'GET request', :bad_request, /^{"message":{"suite":\["has already been taken as Codename"\]}}$/, authenticate_non_public: false
end
end
describe 'DELETE projects/:id/debian_distributions/:codename' do
let(:method) { :delete }
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
it_behaves_like 'Debian repository maintainer write endpoint', 'DELETE distribution request', :success, /^{\"message\":\"202 Accepted\"}$/, authenticate_non_public: false
context 'when destroy fails' do
before do
allow_next_found_instance_of(::Packages::Debian::ProjectDistribution) do |distribution|
expect(distribution).to receive(:destroy).and_return(false)
end
end
it_behaves_like 'Debian repository maintainer write endpoint', 'GET request', :bad_request, /^{"message":"Failed to delete distribution"}$/, authenticate_non_public: false
end
end
end
end

View File

@ -675,48 +675,6 @@ RSpec.describe UsersController do
end
end
describe 'GET #suggests' do
context 'when user exists' do
it 'returns JSON indicating the user exists and a suggestion' do
get user_suggests_url user.username
expected_json = { exists: true, suggests: ["#{user.username}1"] }.to_json
expect(response.body).to eq(expected_json)
end
context 'when the casing is different' do
let(:user) { create(:user, username: 'CamelCaseUser') }
it 'returns JSON indicating the user exists and a suggestion' do
get user_suggests_url user.username.downcase
expected_json = { exists: true, suggests: ["#{user.username.downcase}1"] }.to_json
expect(response.body).to eq(expected_json)
end
end
end
context 'when the user does not exist' do
it 'returns JSON indicating the user does not exist' do
get user_suggests_url 'foo'
expected_json = { exists: false, suggests: [] }.to_json
expect(response.body).to eq(expected_json)
end
context 'when a user changed their username' do
let(:redirect_route) { user.namespace.redirect_routes.create!(path: 'old-username') }
it 'returns JSON indicating a user by that username does not exist' do
get user_suggests_url 'old-username'
expected_json = { exists: false, suggests: [] }.to_json
expect(response.body).to eq(expected_json)
end
end
end
end
describe '#ensure_canonical_path' do
before do
sign_in(user)

View File

@ -4,8 +4,12 @@ require 'spec_helper'
RSpec.describe Packages::Debian::CreateDistributionService do
RSpec.shared_examples 'Create Debian Distribution' do |expected_message, expected_components, expected_architectures|
let_it_be(:container) { create(container_type) } # rubocop:disable Rails/SaveBang
it 'returns ServiceResponse', :aggregate_failures do
if expected_message.nil?
expect(::Packages::Debian::GenerateDistributionWorker).to receive(:perform_async).with(container_type, an_instance_of(Integer))
expect { response }
.to change { container.debian_distributions.klass.all.count }
.from(0).to(1)
@ -18,6 +22,7 @@ RSpec.describe Packages::Debian::CreateDistributionService do
.and not_change { Packages::Debian::ProjectComponentFile.count }
.and not_change { Packages::Debian::GroupComponentFile.count }
else
expect(::Packages::Debian::GenerateDistributionWorker).not_to receive(:perform_async)
expect { response }
.to not_change { container.debian_distributions.klass.all.count }
.and not_change { container.debian_distributions.count }
@ -109,13 +114,13 @@ RSpec.describe Packages::Debian::CreateDistributionService do
let(:response) { subject.execute }
context 'within a projet' do
let_it_be(:container) { create(:project) }
let_it_be(:container_type) { :project }
it_behaves_like 'Debian Create Distribution Service'
end
context 'within a group' do
let_it_be(:container) { create(:group) }
let_it_be(:container_type) { :group }
it_behaves_like 'Debian Create Distribution Service'
end

View File

@ -1,78 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Debian::DestroyDistributionService do
RSpec.shared_examples 'Destroy Debian Distribution' do |expected_message|
it 'returns ServiceResponse', :aggregate_failures do
if expected_message.nil?
expect { response }
.to change { container.debian_distributions.klass.all.count }
.from(1).to(0)
.and change { container.debian_distributions.count }
.from(1).to(0)
.and change { component1.class.all.count }
.from(2).to(0)
.and change { architecture1.class.all.count }
.from(3).to(0)
.and change { component_file1.class.all.count }
.from(4).to(0)
else
expect { response }
.to not_change { container.debian_distributions.klass.all.count }
.and not_change { container.debian_distributions.count }
.and not_change { component1.class.all.count }
.and not_change { architecture1.class.all.count }
.and not_change { component_file1.class.all.count }
end
expect(response).to be_a(ServiceResponse)
expect(response.success?).to eq(expected_message.nil?)
expect(response.error?).to eq(!expected_message.nil?)
expect(response.message).to eq(expected_message)
if expected_message.nil?
expect(response.payload).to eq({})
else
expect(response.payload).to eq(distribution: distribution)
end
end
end
RSpec.shared_examples 'Debian Destroy Distribution Service' do |container_type, can_freeze|
context "with a Debian #{container_type} distribution" do
let_it_be(:container, freeze: can_freeze) { create(container_type) } # rubocop:disable Rails/SaveBang
let_it_be(:distribution, freeze: can_freeze) { create("debian_#{container_type}_distribution", container: container) }
let_it_be(:component1, freeze: can_freeze) { create("debian_#{container_type}_component", distribution: distribution, name: 'component1') }
let_it_be(:component2, freeze: can_freeze) { create("debian_#{container_type}_component", distribution: distribution, name: 'component2') }
let_it_be(:architecture0, freeze: true) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'all') }
let_it_be(:architecture1, freeze: can_freeze) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'architecture1') }
let_it_be(:architecture2, freeze: can_freeze) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'architecture2') }
let_it_be(:component_file1, freeze: can_freeze) { create("debian_#{container_type}_component_file", :source, component: component1) }
let_it_be(:component_file2, freeze: can_freeze) { create("debian_#{container_type}_component_file", component: component1, architecture: architecture1) }
let_it_be(:component_file3, freeze: can_freeze) { create("debian_#{container_type}_component_file", :source, component: component2) }
let_it_be(:component_file4, freeze: can_freeze) { create("debian_#{container_type}_component_file", component: component2, architecture: architecture2) }
subject { described_class.new(distribution) }
let(:response) { subject.execute }
context 'with a distribution' do
it_behaves_like 'Destroy Debian Distribution'
end
context 'when destroy fails' do
let(:distribution) { create("debian_#{container_type}_distribution", container: container) }
before do
expect(distribution).to receive(:destroy).and_return(false)
end
it_behaves_like 'Destroy Debian Distribution', "Unable to destroy Debian #{container_type} distribution"
end
end
end
it_behaves_like 'Debian Destroy Distribution Service', :project, true
it_behaves_like 'Debian Destroy Distribution Service', :group, false
end

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