Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
81f257d72e
commit
f69bc1dab5
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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')">
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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)">
|
||||
{{ 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -22,6 +22,9 @@ export default () => {
|
|||
return new Vue({
|
||||
el,
|
||||
store,
|
||||
provide: {
|
||||
titleComponent: 'TerraformTitle',
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(PackagesApp);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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, [])
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)} }
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
- return if @hide_search_settings
|
||||
|
||||
- container_class = local_assigns.fetch(:container_class, 'gl-mt-5')
|
||||
|
||||
%div{ class: container_class }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
f4191b4b8ae7c282c0012f533a01ebe341d62cb0418e39ad543d06ed2dac63a4
|
||||
|
|
@ -0,0 +1 @@
|
|||
8b6e1c7bacf2cbc05ba94e3fea2ab20e30b78ccaa6833949c11f89d1bdec8110
|
||||
|
|
@ -0,0 +1 @@
|
|||
b6c503eddc1c5e36957b59efc8fc5dd75da18104499667c3fcc435fcbd739af3
|
||||
|
|
@ -0,0 +1 @@
|
|||
09771c6f56e54a4d3dc0caab4891cbaf2a1d5685ccb1161d141ce38e44d6cfdb
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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/`,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)`
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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`**:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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**.
|
||||
|
|
|
|||
|
|
@ -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**.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||

|
||||
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.
|
||||

|
||||
|
||||
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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||

|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
For role information, please see the [Group SAML page](index.md#user-access-and-management)
|
||||
|
||||
### Blocking access
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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**.
|
||||
|
|
|
|||
|
|
@ -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**:
|
||||

|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ module Gitlab
|
|||
sanitize_limit
|
||||
select
|
||||
select_one
|
||||
select_rows
|
||||
quote_column_name
|
||||
).freeze
|
||||
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export const member = {
|
|||
usingLicense: false,
|
||||
groupSso: false,
|
||||
groupManagedAccount: false,
|
||||
provisionedByThisGroup: false,
|
||||
validRoles: {
|
||||
Guest: 10,
|
||||
Reporter: 20,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
`;
|
||||
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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>\\"
|
||||
}"
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ container_repositories:
|
|||
- project
|
||||
- name
|
||||
project:
|
||||
- external_approval_rules
|
||||
- external_status_checks
|
||||
- taggings
|
||||
- base_tags
|
||||
- topic_taggings
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue