Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-04-12 18:16:02 +00:00
parent bc89c8dcb1
commit 8da0fac362
166 changed files with 2482 additions and 1167 deletions

View File

@ -277,7 +277,7 @@ gem 're2', '2.7.0' # rubocop:todo Gemfile/MissingFeatureCategory
# Misc
gem 'semver_dialects', '~> 2.0', feature_category: :static_application_security_testing
gem 'semver_dialects', '~> 2.0', '>= 2.0.2', feature_category: :static_application_security_testing
gem 'version_sorter', '~> 2.3' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'csv_builder', path: 'gems/csv_builder' # rubocop:todo Gemfile/MissingFeatureCategory
@ -418,7 +418,7 @@ group :development do
gem 'ruby-lsp', "~> 0.14.6", require: false, feature_category: :tooling
gem 'ruby-lsp-rails', "~> 0.3.0", feature_category: :tooling
gem 'ruby-lsp-rails', "~> 0.3.3", feature_category: :tooling
gem 'ruby-lsp-rspec', "~> 0.1.10", require: false, feature_category: :tooling
@ -563,7 +563,7 @@ gem 'ssh_data', '~> 1.3' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'spamcheck', '~> 1.3.0' # rubocop:todo Gemfile/MissingFeatureCategory
# Gitaly GRPC protocol definitions
gem 'gitaly', '~> 16.10.1', feature_category: :gitaly
gem 'gitaly', '~> 16.11.0.pre.rc1', feature_category: :gitaly
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.4.0', feature_category: :deployment_management
@ -645,7 +645,7 @@ gem 'cvss-suite', '~> 3.0.1', require: 'cvss_suite' # rubocop:todo Gemfile/Missi
gem 'arr-pm', '~> 0.0.12' # rubocop:todo Gemfile/MissingFeatureCategory
# Remote Development
gem 'devfile', '~> 0.0.25.pre.alpha1', feature_category: :remote_development
gem 'devfile', '~> 0.0.26.pre.alpha1', feature_category: :remote_development
# Apple plist parsing
gem 'CFPropertyList', '~> 3.0.0' # rubocop:todo Gemfile/MissingFeatureCategory

View File

@ -112,9 +112,9 @@
{"name":"deprecation_toolkit","version":"1.5.1","platform":"ruby","checksum":"a8a1ab1a19ae40ea12560b65010e099f3459ebde390b76621ef0c21c516a04ba"},
{"name":"derailed_benchmarks","version":"2.1.2","platform":"ruby","checksum":"eaadc6206ceeb5538ff8f5e04a0023d54ebdd95d04f33e8960fb95a5f189a14f"},
{"name":"descendants_tracker","version":"0.0.4","platform":"ruby","checksum":"e9c41dd4cfbb85829a9301ea7e7c48c2a03b26f09319db230e6479ccdc780897"},
{"name":"devfile","version":"0.0.25.pre.alpha1","platform":"arm64-darwin","checksum":"cf8d5d16ad1ff1ff9ef6f086e58fbad17bdc95dad7fc0c46af3a833c659dd10e"},
{"name":"devfile","version":"0.0.25.pre.alpha1","platform":"ruby","checksum":"0ff071727acc6561766e115bd9aa63c4a52cb910ff64bf77129568a1c08621dc"},
{"name":"devfile","version":"0.0.25.pre.alpha1","platform":"x86_64-linux","checksum":"b448240d1cfeb62fbe32e447d62a69efc1d099beac6f6b1778926f72dcf5672f"},
{"name":"devfile","version":"0.0.26.pre.alpha1","platform":"arm64-darwin","checksum":"9865844fb87a616d3fa8f6bdc4b2c3fc7c8d67b7126b39afc7049ffa3dd419ba"},
{"name":"devfile","version":"0.0.26.pre.alpha1","platform":"ruby","checksum":"2012962fa924e51b5444f22c68055a6f02c72cb129c5180876468a0361dec9e4"},
{"name":"devfile","version":"0.0.26.pre.alpha1","platform":"x86_64-linux","checksum":"050e1a996fbae10ad6b9db00201b683bf9a11987d2869672172e7342003636ef"},
{"name":"device_detector","version":"1.0.0","platform":"ruby","checksum":"b800fb3150b00c23e87b6768011808ac1771fffaae74c3238ebaf2b782947a7d"},
{"name":"devise","version":"4.9.3","platform":"ruby","checksum":"480638d6c51b97f56da6e28d4f3e2a1b8e606681b316aa594b87c6ab94923488"},
{"name":"devise-two-factor","version":"4.1.1","platform":"ruby","checksum":"c95f5b07533e62217aaed3c386874d94e2d472fb5f2b6598afe8600fc17a8b95"},
@ -206,7 +206,7 @@
{"name":"gettext","version":"3.4.9","platform":"ruby","checksum":"292864fe6a15c224cee4125a4a72fab426fdbb280e4cff3cfe44935f549b009a"},
{"name":"gettext_i18n_rails","version":"1.12.0","platform":"ruby","checksum":"6ac4817731a9e2ce47e1e83381ac34f9142263bc2911aaaafb2526d2f1afc1be"},
{"name":"git","version":"1.18.0","platform":"ruby","checksum":"c9b80462e4565cd3d7a9ba8440c41d2c52244b17b0dad0bfddb46de70630c465"},
{"name":"gitaly","version":"16.10.1","platform":"ruby","checksum":"8f416e71d70fcea89941ca02ddd74b0938ec31e11d5d297bc99e8e3a8861df5a"},
{"name":"gitaly","version":"16.11.0.pre.rc1","platform":"ruby","checksum":"24334f5f3fd5b6c3d278eea9fe2b6732dd08e87a4146cd4374615506b1a6e7ae"},
{"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"},
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},
{"name":"gitlab-dangerfiles","version":"4.7.0","platform":"ruby","checksum":"2576876a8dcb7290853fc3aef8048001cfe593b87318dd0016959d42e0e145ca"},
@ -571,7 +571,7 @@
{"name":"rubocop-rspec","version":"2.25.0","platform":"ruby","checksum":"083f8a0481dbb9969b2a9eae85670a454fe91d46812e6ec97b34e7f6227b99f3"},
{"name":"ruby-fogbugz","version":"0.3.0","platform":"ruby","checksum":"5e04cde474648f498a71cf1e1a7ab42c66b953862fbe224f793ec0a7a1d5f657"},
{"name":"ruby-lsp","version":"0.14.6","platform":"ruby","checksum":"543bedcbe2f073b78285a88a46c9282ab6fd50eac2e922dcd21d7180c5534349"},
{"name":"ruby-lsp-rails","version":"0.3.1","platform":"ruby","checksum":"81e0aff084c54933cc150d8f544752da9a64b714cb312c196196fb5b8aec730c"},
{"name":"ruby-lsp-rails","version":"0.3.3","platform":"ruby","checksum":"03bc63aea84d6dc9a000396d2019121f646cfcd2dfefd1ec361b35bb751a2bc3"},
{"name":"ruby-lsp-rspec","version":"0.1.10","platform":"ruby","checksum":"71b638b46b08bfda425477aff705bcc0f48d703983afd1fde50e7b43425afd5a"},
{"name":"ruby-magic","version":"0.6.0","platform":"ruby","checksum":"7b2138877b7d23aff812c95564eba6473b74b815ef85beb0eb792e729a2b6101"},
{"name":"ruby-openai","version":"3.7.0","platform":"ruby","checksum":"fb735d4c055e282ade264cab9864944c05a8a10e0cddd45a0551e8a9851b1850"},
@ -591,7 +591,7 @@
{"name":"sd_notify","version":"0.1.1","platform":"ruby","checksum":"cbc7ac6caa7cedd26b30a72b5eeb6f36050dc0752df263452ea24fb5a4ad3131"},
{"name":"seed-fu","version":"2.3.7","platform":"ruby","checksum":"f19673443e9af799b730e3d4eca6a89b39e5a36825015dffd00d02ea3365cf74"},
{"name":"selenium-webdriver","version":"4.19.0","platform":"ruby","checksum":"4c8bd1d6016a456154b4ba71a3bb4d532a0ae185a38acf9cec0acbd38b4e5066"},
{"name":"semver_dialects","version":"2.0.0","platform":"ruby","checksum":"2199413894d88635f15f4ba55835af5b846db78e123ffa84a31207b44bb64587"},
{"name":"semver_dialects","version":"2.0.2","platform":"ruby","checksum":"60059c9f416f931b5212d862fad2879d6b9affb8e0b9afb0d91b793639c116fe"},
{"name":"sentry-rails","version":"5.10.0","platform":"ruby","checksum":"99aa2fac136c26942eb1897c65de65dac88ad43ac5eb183ff20711287a137ebd"},
{"name":"sentry-raven","version":"3.1.2","platform":"ruby","checksum":"103d3b122958810d34898ce2e705bcf549ddb9d855a70ce9a3970ee2484f364a"},
{"name":"sentry-ruby","version":"5.10.0","platform":"ruby","checksum":"115c24c0aee1309210f3a2988fb118e2bec1f11609feeda90e694388b1183619"},

View File

@ -482,7 +482,7 @@ GEM
thor (>= 0.19, < 2)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devfile (0.0.25.pre.alpha1)
devfile (0.0.26.pre.alpha1)
device_detector (1.0.0)
devise (4.9.3)
bcrypt (~> 3.0)
@ -687,7 +687,7 @@ GEM
git (1.18.0)
addressable (~> 2.8)
rchardet (~> 1.8)
gitaly (16.10.1)
gitaly (16.11.0.pre.rc1)
grpc (~> 1.0)
gitlab (4.19.0)
httparty (~> 0.20)
@ -1517,7 +1517,7 @@ GEM
language_server-protocol (~> 3.17.0)
prism (>= 0.22.0, < 0.25)
sorbet-runtime (>= 0.5.10782)
ruby-lsp-rails (0.3.1)
ruby-lsp-rails (0.3.3)
actionpack (>= 6.0)
activerecord (>= 6.0)
railties (>= 6.0)
@ -1560,7 +1560,7 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
semver_dialects (2.0.0)
semver_dialects (2.0.2)
deb_version (~> 1.0.1)
pastel (~> 0.8.0)
thor (~> 1.3)
@ -1871,7 +1871,7 @@ DEPENDENCIES
declarative_policy (~> 1.1.0)
deprecation_toolkit (~> 1.5.1)
derailed_benchmarks
devfile (~> 0.0.25.pre.alpha1)
devfile (~> 0.0.26.pre.alpha1)
device_detector
devise (~> 4.9.3)
devise-pbkdf2-encryptable (~> 0.0.0)!
@ -1907,7 +1907,7 @@ DEPENDENCIES
gdk-toogle (~> 0.9)
gettext (~> 3.4, >= 3.4.9)
gettext_i18n_rails (~> 1.12.0)
gitaly (~> 16.10.1)
gitaly (~> 16.11.0.pre.rc1)
gitlab-backup-cli!
gitlab-chronic (~> 0.10.5)
gitlab-dangerfiles (~> 4.7.0)
@ -2086,7 +2086,7 @@ DEPENDENCIES
rubocop
ruby-fogbugz (~> 0.3.0)
ruby-lsp (~> 0.14.6)
ruby-lsp-rails (~> 0.3.0)
ruby-lsp-rails (~> 0.3.3)
ruby-lsp-rspec (~> 0.1.10)
ruby-magic (~> 0.6)
ruby-openai (~> 3.7)
@ -2098,7 +2098,7 @@ DEPENDENCIES
sd_notify (~> 0.1.0)
seed-fu (~> 2.3.7)
selenium-webdriver (~> 4.19)
semver_dialects (~> 2.0)
semver_dialects (~> 2.0, >= 2.0.2)
sentry-rails (~> 5.10.0)
sentry-raven (~> 3.1)
sentry-ruby (~> 5.10.0)

View File

@ -44,6 +44,12 @@ export function createProject(projectData) {
});
}
export function updateProject(projectId, data) {
const url = buildApiUrl(PROJECT_PATH).replace(':id', projectId);
return axios.put(url, data);
}
export function deleteProject(projectId, params) {
const url = buildApiUrl(PROJECT_PATH).replace(':id', projectId);

View File

@ -1175,11 +1175,60 @@
]
},
"exists": {
"type": "array",
"markdownDescription": "Additional attributes will be provided to job if any of the provided paths matches an existing file in the repository. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#rulesexists).",
"items": {
"type": "string"
}
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "object",
"additionalProperties": false,
"required": [
"paths"
],
"properties": {
"paths": {
"type": "array",
"description": "List of file paths.",
"items": {
"type": "string"
}
},
"project": {
"type": "string",
"description": "Path of the project to search in."
}
}
},
{
"type": "object",
"additionalProperties": false,
"required": [
"paths",
"project"
],
"properties": {
"paths": {
"type": "array",
"description": "List of file paths.",
"items": {
"type": "string"
}
},
"project": {
"type": "string",
"description": "Path of the project to search in."
},
"ref": {
"type": "string",
"description": "Ref of the project to search in."
}
}
}
]
},
"timeout": {
"type": "string",

View File

@ -1,23 +1,74 @@
<script>
import { GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
import { __, s__ } from '~/locale';
import NewEditForm from '~/projects/components/new_edit_form.vue';
import { FORM_FIELD_NAME, FORM_FIELD_DESCRIPTION } from '~/projects/components/constants';
import { updateProject } from '~/rest_api';
import { visitUrlWithAlerts } from '~/lib/utils/url_utility';
import { createAlert } from '~/alert';
export default {
name: 'OrganizationProjectsEditApp',
components: { GlSprintf, NewEditForm },
i18n: {
pageTitle: __('Edit project: %{project_name}'),
errorMessage: s__('ProjectsEdit|An error occurred updating this project. Please try again.'),
successMessage: s__('ProjectsEdit|Project was successfully updated.'),
},
inject: ['projectsOrganizationPath', 'previewMarkdownPath', 'project'],
data() {
return {
loading: false,
serverValidations: {},
};
},
methods: {
async onSubmit() {
// Make API call. Coming in future MR
async onSubmit({ [FORM_FIELD_NAME]: name, [FORM_FIELD_DESCRIPTION]: description }) {
this.loading = true;
try {
await updateProject(this.project.id, {
name,
description,
});
visitUrlWithAlerts(window.location.href, [
{
id: 'organization-project-successfully-updated',
message: this.$options.i18n.successMessage,
variant: 'info',
},
]);
} catch (error) {
this.loading = false;
const fieldsToValidate = {
[FORM_FIELD_NAME]: s__('ProjectsNew|Project name'),
[FORM_FIELD_DESCRIPTION]: s__('ProjectsNewEdit|Project description'),
};
this.serverValidations = Object.entries(error?.response?.data?.message || {}).reduce(
(accumulator, [fieldName, errorMessages]) => {
const fieldLabel = fieldsToValidate[fieldName];
if (!fieldLabel || !errorMessages.length) {
return accumulator;
}
return {
...accumulator,
[fieldName]: `${fieldLabel} ${errorMessages[0]}`,
};
},
{},
);
if (!Object.keys(this.serverValidations).length) {
createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
}
}
},
onInputField({ name }) {
this.$delete(this.serverValidations, name);
},
},
};
@ -33,9 +84,11 @@ export default {
<new-edit-form
:loading="loading"
:initial-form-values="project"
:server-validations="serverValidations"
:preview-markdown-path="previewMarkdownPath"
:cancel-button-href="projectsOrganizationPath"
@submit="onSubmit"
@input-field="onInputField"
/>
</div>
</template>

View File

@ -45,6 +45,13 @@ export default {
};
},
},
serverValidations: {
type: Object,
required: false,
default() {
return {};
},
},
submitButtonText: {
type: String,
required: false,
@ -128,8 +135,10 @@ export default {
v-model="formValues"
:form-id="$options.formId"
:fields="fields"
:server-validations="serverValidations"
class="gl-display-flex gl-column-gap-5 gl-flex-wrap"
@submit="$emit('submit', formValues)"
@input-field="$emit('input-field', $event)"
>
<template #input(description)="{ id, value, input, blur }">
<div class="gl-md-form-input-xl">

View File

@ -898,17 +898,6 @@ $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio;
min-width: 180px;
}
.note-actions-item {
margin-left: 12px;
display: flex;
align-items: center;
&.more-actions {
// compensate for narrow icon
margin-left: 10px;
}
}
.discussion-toggle-button {
padding: 0 $gl-padding-8 0 0;
background-color: transparent;

View File

@ -21,9 +21,9 @@
.gl-display-flex.gl-flex-wrap.gl-mt-5.gl-gap-3{ class: button_wrapper_class }
- if @primary_button_text.present?
= render Pajamas::ButtonComponent.new(variant: :confirm, href: @primary_button_link, button_options: { class: 'gl-ml-0!' }) do
= render Pajamas::ButtonComponent.new(variant: :confirm, href: @primary_button_link, button_options: { class: 'gl-ml-0!', **@primary_button_options }) do
= @primary_button_text
- if @secondary_button_text.present?
= render Pajamas::ButtonComponent.new(variant: :default, href: @secondary_button_link, button_options: { class: ('gl-ml-0!' unless @primary_button_text.present?) }) do
= render Pajamas::ButtonComponent.new(variant: :default, href: @secondary_button_link, button_options: { class: ('gl-ml-0!' unless @primary_button_text.present?), **@secondary_button_options }) do
= @secondary_button_text

View File

@ -9,15 +9,19 @@ module Pajamas
# @param [String] primary_button_link
# @param [String] secondary_button_text
# @param [String] secondary_button_link
# @param [Hash] primary_button_options
# @param [Hash] secondary_button_options
# @param [Hash] empty_state_options
def initialize(
compact: false,
title: nil,
svg_path: nil,
primary_button_text: nil,
primary_button_options: {},
primary_button_link: nil,
secondary_button_text: nil,
secondary_button_link: nil,
secondary_button_options: {},
empty_state_options: {}
)
@compact = compact
@ -27,6 +31,8 @@ module Pajamas
@primary_button_link = primary_button_link
@secondary_button_text = secondary_button_text
@secondary_button_link = secondary_button_link
@primary_button_options = primary_button_options
@secondary_button_options = secondary_button_options
@empty_state_options = empty_state_options
end

View File

@ -33,12 +33,8 @@ class Projects::DiscussionsController < Projects::ApplicationController
private
def render_discussion
if serialize_notes?
prepare_notes_for_rendering(discussion.notes)
render_json_with_discussions_serializer
else
render_json_with_html
end
prepare_notes_for_rendering(discussion.notes)
render_json_with_discussions_serializer
end
def render_json_with_discussions_serializer
@ -47,14 +43,6 @@ class Projects::DiscussionsController < Projects::ApplicationController
.represent(discussion, context: self, render_truncated_diff_lines: true)
end
# Legacy method used to render discussions notes when not using Vue on views.
def render_json_with_html
render json: {
resolved_by: discussion.resolved_by.try(:name),
discussion_headline_html: view_to_html_string('discussions/_headline', discussion: discussion)
}
end
# rubocop: disable CodeReuse/ActiveRecord
def noteable
@noteable ||= noteable_finder_class.new(current_user, project_id: @project.id).find_by!(iid: params[:noteable_id])

View File

@ -207,11 +207,11 @@ module ApplicationHelper
def edited_time_ago_with_tooltip(editable_object, placement: 'top', html_class: 'time_ago', exclude_author: false)
return unless editable_object.edited?
content_tag :small, class: 'edited-text' do
content_tag :div, class: 'edited-text gl-mt-4 gl-text-gray-500 gl-font-sm' do
timeago = time_ago_with_tooltip(editable_object.last_edited_at, placement: placement, html_class: html_class)
if !exclude_author && editable_object.last_edited_by
author_link = link_to_member(editable_object.project, editable_object.last_edited_by, avatar: false, extra_class: 'gl-hover-text-decoration-underline', author_class: nil)
author_link = link_to_member(editable_object.project, editable_object.last_edited_by, avatar: false, extra_class: 'gl-hover-text-decoration-underline gl-text-gray-700', author_class: nil)
output = safe_format(_("Edited %{timeago} by %{author}"), timeago: timeago, author: author_link)
else
output = safe_format(_("Edited %{timeago}"), timeago: timeago)

View File

@ -197,10 +197,6 @@ module NotesHelper
data
end
def discussion_resolved_intro(discussion)
discussion.resolved_by_push? ? 'Automatically resolved' : 'Resolved'
end
def rendered_for_merge_request?
params[:from_merge_request].present?
end

View File

@ -27,7 +27,7 @@ module Ci
validates :version, :catalog_resource, :project, :name, presence: true
def include_path
"#{Gitlab.config.gitlab_ci.server_fqdn}/#{project.full_path}/#{name}@#{version.version}"
"#{Gitlab.config.gitlab_ci.server_fqdn}/#{project.full_path}/#{name}@#{version.name}"
end
end
end

View File

@ -9,9 +9,6 @@ module Ci
include BulkInsertableAssociations
include SemanticVersionable
semver_method :version
validate_semver
self.table_name = 'catalog_resource_versions'
belongs_to :release, inverse_of: :catalog_resource_version
@ -53,7 +50,7 @@ module Ci
end
def name
release.tag
semver.to_s
end
def commit

View File

@ -42,6 +42,8 @@ class Commit
MAX_DIFF_FILES_SETTING_UPPER_BOUND = 3_000
DIFF_SAFE_LIMIT_FACTOR = 10
CO_AUTHORED_TRAILER = "Co-authored-by"
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :full_title, pipeline: :single_line, limit: 1.kilobyte
cache_markdown_field :description, pipeline: :commit_description, limit: 1.megabyte

View File

@ -156,8 +156,22 @@ class CommitCollection
private
def committers_emails(with_merge_commits: false)
return commits.filter_map(&:committer_email).uniq if with_merge_commits
return committer_emails_for(commits) if with_merge_commits
without_merge_commits.filter_map(&:committer_email).uniq
committer_emails_for(without_merge_commits)
end
def committer_emails_for(commits)
if ::Feature.enabled?(:web_ui_commit_author_change, project)
commits.each(&:signature) # preload signatures
end
commits.filter_map do |commit|
if ::Feature.enabled?(:web_ui_commit_author_change, project) && commit.signature&.verified_system?
commit.author_email
else
commit.committer_email
end
end.uniq
end
end

View File

@ -4,50 +4,32 @@ module SemanticVersionable
extend ActiveSupport::Concern
included do
self.require_valid_semver = false
validate :semver_format, if: :require_valid_semver?
validates :semver,
format: { with: ::Gitlab::Regex::SemVer.optional_prefixed, message: 'must follow semantic version' }
scope :order_by_semantic_version_desc, -> { order(semver_major: :desc, semver_minor: :desc, semver_patch: :desc) }
scope :order_by_semantic_version_asc, -> { order(semver_major: :asc, semver_minor: :asc, semver_patch: :asc) }
private
def semver
return if [semver_major, semver_minor, semver_patch].any?(&:nil?)
def semver_format
return unless [semver_major, semver_minor, semver_patch].any?(&:nil?)
prefixed = respond_to?(:semver_prefixed) && semver_prefixed
errors.add(:base, _('must follow semantic version'))
Packages::SemVer.new(semver_major, semver_minor, semver_patch, semver_prerelease, prefixed: prefixed)
end
def require_valid_semver?
self.class.require_valid_semver
end
end
def semver=(version)
prefixed = version.start_with?('v')
class_methods do
attr_accessor :require_valid_semver
parsed_version = Packages::SemVer.parse(version, prefixed: prefixed)
def semver_method(name)
define_method(name) do
return if [semver_major, semver_minor, semver_patch].any?(&:nil?)
return if parsed_version.nil?
Packages::SemVer.new(semver_major, semver_minor, semver_patch, semver_prerelease)
end
define_method("#{name}=") do |version|
parsed = Packages::SemVer.parse(version)
return if parsed.nil?
self.semver_major = parsed.major
self.semver_minor = parsed.minor
self.semver_patch = parsed.patch
self.semver_prerelease = parsed.prerelease
end
end
def validate_semver
self.require_valid_semver = true
self.semver_major = parsed_version.major
self.semver_minor = parsed_version.minor
self.semver_patch = parsed_version.patch
self.semver_prerelease = parsed_version.prerelease
self.semver_prefixed = prefixed if respond_to?(:semver_prefixed)
end
end
end

View File

@ -6,9 +6,6 @@ module Ml
include Sortable
include SemanticVersionable
semver_method :semver
validate_semver
validates :project, :model, presence: true
validates :version,

View File

@ -3,6 +3,9 @@
class Packages::SemVer
attr_accessor :major, :minor, :patch, :prerelease, :build
# TODO: Move logic into the SemanticVersionable concern
# https://gitlab.com/gitlab-org/gitlab/-/issues/455670
def initialize(major = 0, minor = 0, patch = 0, prerelease = nil, build = nil, prefixed: false)
@major = major
@minor = minor

View File

@ -956,7 +956,8 @@ class Repository
def cherry_pick(
user, commit, branch_name, message,
start_branch_name: nil, start_project: project, dry_run: false)
start_branch_name: nil, start_project: project,
author_name: nil, author_email: nil, dry_run: false)
with_cache_hooks do
raw_repository.cherry_pick(
@ -966,6 +967,8 @@ class Repository
message: message,
start_branch_name: start_branch_name,
start_repository: start_project.repository.raw_repository,
author_name: author_name,
author_email: author_email,
dry_run: dry_run
)
end

View File

@ -36,7 +36,7 @@ module Ci
release: release,
catalog_resource: project.catalog_resource,
project: project,
version: release.tag
semver: release.tag
)
end

View File

@ -9,25 +9,18 @@ module Commits
@message = params[:message]
end
def commit_message
raise NotImplementedError
end
private
attr_reader :commit
def commit_change(action)
raise NotImplementedError unless repository.respond_to?(action)
message = @message || commit_message
# rubocop:disable GitlabSecurity/PublicSend
message =
@message || @commit.public_send(:"#{action}_message", current_user)
repository.public_send(
action,
current_user,
@commit,
@branch_name,
message,
start_project: @start_project,
start_branch_name: @start_branch,
dry_run: @dry_run
)
yield message
rescue Gitlab::Git::Repository::CreateTreeError => ex
type = @commit.change_type_title(current_user)

View File

@ -11,14 +11,28 @@ module Commits
def create_commit!
Gitlab::Git::CrossRepo.new(@project.repository, @source_project.repository).execute(@commit.id) do
commit_change(:cherry_pick).tap do |sha|
track_mr_picking(sha)
commit_sha = commit_change(:cherry_pick) do |message|
perform_cherry_pick(message)
end
track_mr_picking(commit_sha)
commit_sha
end
end
private
def commit_message
message = commit.cherry_pick_message(current_user)
return message unless ::Feature.enabled?(:web_ui_commit_author_change, project)
co_authored_trailer = "#{Commit::CO_AUTHORED_TRAILER}: #{commit.author_name} <#{commit.author_email}>"
"#{message}\n\n#{co_authored_trailer}"
end
def track_mr_picking(pick_sha)
merge_request = project.merge_requests.by_merge_commit_sha(@commit.sha).first
return unless merge_request
@ -29,5 +43,19 @@ module Commits
author: current_user
).picked_into_branch(@branch_name, pick_sha)
end
def perform_cherry_pick(message)
author_kwargs =
if Feature.enabled?(:web_ui_commit_author_change, project)
{ author_name: current_user.name, author_email: current_user.email }
else
{}
end
repository.cherry_pick(current_user, @commit, @branch_name, message,
start_project: @start_project, start_branch_name: @start_branch, dry_run: @dry_run,
**author_kwargs
)
end
end
end

View File

@ -3,7 +3,17 @@
module Commits
class RevertService < ChangeService
def create_commit!
commit_change(:revert)
commit_change(:revert) do |message|
repository.revert(current_user, @commit, @branch_name, message,
start_project: @start_project, start_branch_name: @start_branch, dry_run: @dry_run
)
end
end
private
def commit_message
commit.revert_message(current_user)
end
end
end

View File

@ -54,6 +54,13 @@ module Suggestions
author_email: author&.email
}
if ::Feature.enabled?(:web_ui_commit_author_change, project)
params.merge!({
author_name: current_user.name,
author_email: current_user.commit_email_or_default
})
end
::Files::MultiService.new(suggestion_set.source_project, current_user, params)
end

View File

@ -4,6 +4,7 @@
= render Pajamas::EmptyStateComponent.new(svg_path: 'illustrations/empty-state/empty-admin-apps-md.svg',
title: s_('AdminArea|No applications found'),
primary_button_text: _('Add new application'),
primary_button_options: { data: {testid: 'new-application-button'} },
primary_button_link: new_admin_application_path) do |c|
- c.with_description do

View File

@ -3,52 +3,9 @@
.timeline-entry-inner
.timeline-content
.discussion.js-toggle-container{ data: { discussion_id: discussion.id, is_expanded: expanded.to_s } }
.discussion-header.gl-display-flex.gl--flex-center
.timeline-icon.gl-flex-shrink-0
= link_to user_path(discussion.author) do
= render Pajamas::AvatarComponent.new(discussion.author, size: 32, class: 'gl-mr-3')
= link_to_member(@project, discussion.author, avatar: false)
.inline.discussion-headline-light.gl-mx-3
= discussion.author.to_reference
started a thread
- url = discussion_path(discussion)
- if discussion.for_commit? && @noteable != discussion.noteable
on
- commit = discussion.noteable
- if commit
commit
= link_to commit.short_id, url, class: 'commit-sha'
- else
a deleted commit
- elsif discussion.diff_discussion?
on
= conditional_link_to url.present?, url do
- if discussion.on_merge_request_commit?
- unless discussion.active?
an outdated change in
commit
%span.commit-sha= truncate_sha(discussion.commit_id)
- else
- unless discussion.active?
an old version of
the diff
= time_ago_with_tooltip(discussion.created_at, placement: "bottom", html_class: "note-created-ago")
= render "discussions/headline", discussion: discussion
.discussion-actions.gl-ml-auto
%button.note-action-button.discussion-toggle-button.js-toggle-button{ type: "button", class: ("js-toggle-lazy-diff" unless expanded) }
= sprite_icon('chevron-up', css_class: "js-sidebar-collapse #{'hidden' unless expanded}")
= sprite_icon('chevron-down', css_class: "js-sidebar-expand #{'hidden' if expanded}")
%span.js-sidebar-collapse{ class: "#{'hidden' unless expanded}" }= _('Hide thread')
%span.js-sidebar-expand{ class: "#{'hidden' if expanded}" }= _('Show thread')
.discussion-body.js-toggle-content{ class: ("hide" unless expanded) }
- if discussion.diff_discussion? && discussion.diff_file
= render "discussions/diff_with_notes", discussion: discussion
- else
.card
.card.discussion-wrapper
= render partial: "discussions/notes", locals: { discussion: discussion, disable_collapse_class: true }

View File

@ -1,16 +0,0 @@
- if discussion.resolved?
.discussion-headline-light.js-discussion-headline
= discussion_resolved_intro(discussion)
- if discussion.resolved_by
by
= link_to_member(@project, discussion.resolved_by, avatar: false)
- if discussion.resolved_by_push?
with a push
= time_ago_with_tooltip(discussion.resolved_at, placement: "bottom")
- elsif discussion.updated?
.discussion-headline-light.js-discussion-headline
Last updated
- if discussion.last_updated_by
by
= link_to_member(@project, discussion.last_updated_by, avatar: false)
= time_ago_with_tooltip(discussion.last_updated_at, placement: "bottom")

View File

@ -1,24 +1,24 @@
- access = note_human_max_access(note)
- if note.noteable_author?(@noteable)
= render Pajamas::BadgeComponent.new(_("Author"), variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100! note-role user-access-role has-tooltip gl-display-none gl-md-display-inline-block', title: _("This user is the author of this %{noteable}.") % { noteable: @noteable.human_class_name })
= render Pajamas::BadgeComponent.new(_("Author"), variant: 'neutral', class: 'has-tooltip gl-bg-transparent! gl-inset-border-1-gray-100! gl-display-none gl-md-display-inline-block gl-mr-3', title: _("This user is the author of this %{noteable}.") % { noteable: @noteable.human_class_name })
- if access
= render Pajamas::BadgeComponent.new(access, variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100! note-role user-access-role has-tooltip', title: _("This user has the %{access} role in the %{name} project.") % { access: access.downcase, name: note.project_name })
= render Pajamas::BadgeComponent.new(access, variant: 'neutral', class: 'has-tooltip gl-bg-transparent! gl-inset-border-1-gray-100! gl-display-none gl-md-display-inline-block gl-mr-3', title: _("This user has the %{access} role in the %{name} project.") % { access: access.downcase, name: note.project_name })
- elsif note.contributor?
= render Pajamas::BadgeComponent.new(_("Contributor"), variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100! note-role user-access-role has-tooltip', title: _("This user has previously committed to the %{name} project.") % { name: note.project_name })
= render Pajamas::BadgeComponent.new(_("Contributor"), variant: 'neutral', class: 'has-tooltip gl-bg-transparent! gl-inset-border-1-gray-100! gl-display-none gl-md-display-inline-block gl-mr-3', title: _("This user has previously committed to the %{name} project.") % { name: note.project_name })
- if can?(current_user, :award_emoji, note)
- if note.emoji_awardable?
.note-actions-item
= render Pajamas::ButtonComponent.new(category: :tertiary,
button_options: { title: _('Add reaction'), class: 'btn-icon add-reaction-button note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip', data: { position: 'right', container: 'body' }, 'aria-label': _('Add reaction') }) do
= sprite_icon('slight-smile', css_class: 'reaction-control-icon-neutral award-control-icon-neutral gl-button-icon gl-icon')
= sprite_icon('smiley', css_class: 'reaction-control-icon-positive award-control-icon-positive gl-button-icon gl-icon !gl-left-3')
= sprite_icon('smile', css_class: 'reaction-control-icon-super-positive award-control-icon-super-positive gl-button-icon gl-icon !gl-left-3 ')
= render Pajamas::ButtonComponent.new(category: :tertiary,
button_options: { title: _('Add reaction'), class: 'btn-icon add-reaction-button note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip', data: { position: 'right', container: 'body' }, 'aria-label': _('Add reaction') }) do
= sprite_icon('slight-smile', css_class: 'reaction-control-icon-neutral award-control-icon-neutral gl-button-icon gl-icon')
= sprite_icon('smiley', css_class: 'reaction-control-icon-positive award-control-icon-positive gl-button-icon gl-icon !gl-left-3')
= sprite_icon('smile', css_class: 'reaction-control-icon-super-positive award-control-icon-super-positive gl-button-icon gl-icon !gl-left-3 ')
- if note_editable
.note-actions-item.gl-ml-0
.gl-ml-0
= render Pajamas::ButtonComponent.new(category: :tertiary,
icon: 'pencil',
button_options: { class: 'note-action-button js-note-edit has-tooltip', data: { container: 'body', testid: 'edit-comment-button' }, title: _('Edit comment'), 'aria-label': _('Edit comment') })
button_options: { class: 'gl-display-none gl-sm-display-inline-block note-action-button js-note-edit has-tooltip', data: { testid: 'edit-comment-button' }, title: _('Edit comment'), 'aria-label': _('Edit comment') })
= render 'projects/notes/more_actions_dropdown', note: note, note_editable: note_editable

View File

@ -1,9 +1,13 @@
- is_current_user = current_user == note.author
- if note_editable || !is_current_user
%div{ class: "dropdown more-actions note-actions-item gl-ml-0!" }
= render Pajamas::ButtonComponent.new(icon: 'ellipsis_v', category: :tertiary, button_options: { class: 'note-action-button more-actions-toggle has-tooltip', data: { title: 'More actions', toggle: 'dropdown', container: 'body', testid: 'more-actions-dropdown' }})
.dropdown{ class: "more-actions gl-ml-0!" }
= render Pajamas::ButtonComponent.new(icon: 'ellipsis_v', category: :tertiary, button_options: { class: 'note-action-button more-actions-toggle', data: { title: 'More actions', toggle: 'dropdown', container: 'body', testid: 'more-actions-dropdown' }})
%ul.dropdown-menu.more-actions-dropdown.dropdown-open-left
- if note_editable
%li{ class: "gl-sm-display-none!" }
= render Pajamas::ButtonComponent.new(category: :tertiary, button_options: { class: 'menu-item note-action-button js-note-edit', data: { container: 'body', testid: 'edit-comment-button' } }) do
= _("Edit comment")
%li
= clipboard_button(text: noteable_note_url(note), title: _('Copy reference'), button_text: _('Copy link'), class: 'gl-rounded-0!', size: :medium, hide_tooltip: true, hide_button_icon: true)
- unless is_current_user

View File

@ -32,17 +32,17 @@
.note-header
.note-header-info
%a{ href: user_path(note.author) }
%span.note-header-author-name.bold
%span.note-header-author-name.gl-font-weight-bold
= note.author.name
= user_status(note.author)
%spannote-headline-light{ data: { testid: 'note-author-content' } }
= note.author.to_reference
%span.note-headline-ligh.note-headline-meta
%span.note-headline-light{ data: { testid: 'note-author-content' } }
= note.author.to_reference
%span.note-headline-light.note-headline-meta
- if note.system
%span.system-note-message
= markdown_field(note, :note)
- if note.created_at
%span.system-note-separator
%span.system-note-separator.gl-display-none.gl-sm-display-inline
&middot;
%a.system-note-separator{ href: "##{dom_id(note)}" }= time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago')
- unless note.system?
@ -51,30 +51,31 @@
= render 'snippets/notes/actions', note: note, note_editable: note_editable
- else
= render 'projects/notes/actions', note: note, note_editable: note_editable
.note-body{ class: note_editable ? 'js-task-list-container' : '' }
.note-text.md{ data: { testid: 'note-content' } }
= markdown_field(note, :note)
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago')
.original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore } }
#{note.note}
- if note_editable
= render 'shared/notes/edit', note: note
.note-awards
= render 'award_emoji/awards_block', awardable: note, inline: false
- if note.system
.system-note-commit-list-toggler.hide
= _("Toggle commit list")
= sprite_icon('chevron-down', css_class: 'js-chevron-down gl-ml-1 gl-vertical-align-text-bottom')
= sprite_icon('chevron-up', css_class: 'js-chevron-up gl-ml-1 gl-vertical-align-text-bottom gl-display-none')
- if note.attachment.url
.note-attachment
- if note.attachment.image?
= link_to note.attachment.url, target: '_blank' do
= image_tag note.attachment.url, class: 'note-image-attach col-lg-4'
.attachment
= link_to note.attachment.url, target: '_blank' do
= sprite_icon('paperclip')
= note.attachment_identifier
= link_to delete_attachment_project_note_path(note.project, note),
title: _('Delete this attachment'), method: :delete, remote: true, data: { confirm: _('Are you sure you want to remove the attachment?') }, class: 'danger js-note-attachment-delete' do
= sprite_icon('remove', css_class: 'cred')
.timeline-discussion-body
.note-body{ class: note_editable ? 'js-task-list-container' : '' }
.note-text.md{ data: { testid: 'note-content' } }
= markdown_field(note, :note)
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago')
.original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore } }
#{note.note}
- if note_editable
= render 'shared/notes/edit', note: note
.note-awards
= render 'award_emoji/awards_block', awardable: note, inline: false
- if note.system
.system-note-commit-list-toggler.hide
= _("Toggle commit list")
= sprite_icon('chevron-down', css_class: 'js-chevron-down gl-ml-1 gl-vertical-align-text-bottom')
= sprite_icon('chevron-up', css_class: 'js-chevron-up gl-ml-1 gl-vertical-align-text-bottom gl-display-none')
- if note.attachment.url
.note-attachment
- if note.attachment.image?
= link_to note.attachment.url, target: '_blank' do
= image_tag note.attachment.url, class: 'note-image-attach col-lg-4'
.attachment
= link_to note.attachment.url, target: '_blank' do
= sprite_icon('paperclip')
= note.attachment_identifier
= link_to delete_attachment_project_note_path(note.project, note),
title: _('Delete this attachment'), method: :delete, remote: true, data: { confirm: _('Are you sure you want to remove the attachment?') }, class: 'danger js-note-attachment-delete' do
= sprite_icon('remove', css_class: 'cred')

View File

@ -1,13 +1,12 @@
- if current_user
- if note.emoji_awardable?
.note-actions-item
= render Pajamas::ButtonComponent.new(category: :tertiary, button_options: { title: _('Add reaction'), class: 'btn-icon add-reaction-button note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip' }) do
= sprite_icon('slight-smile', css_class: 'reaction-control-icon-neutral award-control-icon-neutral gl-button-icon gl-icon')
= sprite_icon('smiley', css_class: 'reaction-control-icon-positive award-control-icon-positive gl-button-icon gl-icon !gl-left-3')
= sprite_icon('smile', css_class: 'reaction-control-icon-super-positive award-control-icon-super-positive gl-button-icon gl-icon !gl-left-3 ')
= render Pajamas::ButtonComponent.new(category: :tertiary, button_options: { title: _('Add reaction'), class: 'btn-icon add-reaction-button note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip' }) do
= sprite_icon('slight-smile', css_class: 'reaction-control-icon-neutral award-control-icon-neutral gl-button-icon gl-icon')
= sprite_icon('smiley', css_class: 'reaction-control-icon-positive award-control-icon-positive gl-button-icon gl-icon !gl-left-3')
= sprite_icon('smile', css_class: 'reaction-control-icon-super-positive award-control-icon-super-positive gl-button-icon gl-icon !gl-left-3 ')
- if note_editable
.note-actions-item.gl-ml-0
= render Pajamas::ButtonComponent.new(category: :tertiary, icon: 'pencil', button_options: { title: _('Edit comment'), class: 'note-action-button js-note-edit has-tooltip', data: { container: 'body', testid: 'edit-comment-button' } })
.gl-ml-0
= render Pajamas::ButtonComponent.new(category: :tertiary, icon: 'pencil', button_options: { title: _('Edit comment'), class: 'note-action-button js-note-edit has-tooltip gl-display-none gl-sm-display-block', data: { container: 'body', testid: 'edit-comment-button' } })
= render 'projects/notes/more_actions_dropdown', note: note, note_editable: note_editable

View File

@ -66,7 +66,7 @@ module ClickHouse
end
def enabled?
Gitlab::ClickHouse.globally_enabled_for_analytics? && Feature.enabled?(:event_sync_worker_for_click_house)
Gitlab::ClickHouse.globally_enabled_for_analytics?
end
def runtime_limiter

View File

@ -1,8 +0,0 @@
---
name: event_sync_worker_for_click_house
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128628
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421184
milestone: '16.3'
type: development
group: group::optimize
default_enabled: false

View File

@ -0,0 +1,9 @@
---
name: ci_support_rules_exists_paths_and_project
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386040
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/149326
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/453983
milestone: '16.11'
group: group::pipeline authoring
type: gitlab_com_derisk
default_enabled: false

View File

@ -2,8 +2,8 @@
name: jira_multiple_project_keys
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/440430
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146087
rollout_issue_url:
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/455259
milestone: '16.10'
group: group::import and integrate
type: wip
type: gitlab_com_derisk
default_enabled: false

View File

@ -1,8 +1,9 @@
---
name: clickhouse_data_collection
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127435
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420257
milestone: '16.3'
type: development
group: group::optimize
name: web_ui_commit_author_change
feature_issue_url:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148889
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/455288
milestone: '16.11'
group: group::source code
type: gitlab_com_derisk
default_enabled: false

View File

@ -1,6 +1,7 @@
---
table_name: external_status_checks_protected_branches
classes: []
classes:
- MergeRequests::ExternalStatusChecksProtectedBranch
feature_categories:
- compliance_management
description: Keeps relation between protected branches and external status checks

View File

@ -11,6 +11,7 @@ DETAILS:
**Offering:** GitLab.com, Self-managed
> - ClickHouse data collector [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/414610) in GitLab 16.3 [with a flag](../administration/feature_flags.md) named `clickhouse_data_collection`. Disabled by default.
> - Feature flag `clickhouse_data_collection` removed in GitLab 17.0 and replaced with an application setting.
The [contribution analytics](../user/group/contribution_analytics/index.md) report and [Value Streams Dashboard](../user/analytics/value_streams_dashboard.md#dashboard-metrics-and-drill-down-reports) contributors count metric can use ClickHouse as a data source.

View File

@ -18,7 +18,7 @@ This document describes how to:
This document is intended for environments using:
- [Linux package (Omnibus) and cloud-native hybrid reference architectures 3,000 users and up](../reference_architectures/index.md)
- [Linux package (Omnibus) and cloud-native hybrid reference architectures 60 RPS / 3,000 users and up](../reference_architectures/index.md)
- [Amazon RDS](https://aws.amazon.com/rds/) for PostgreSQL data
- [Amazon S3](https://aws.amazon.com/s3/) for object storage
- [Object storage](../object_storage.md) to store everything possible, including [blobs](backup_gitlab.md#blobs) and [container registry](backup_gitlab.md#container-registry)

View File

@ -23,7 +23,7 @@ DETAILS:
| Secondaries | One |
This runbook guides you through a planned failover of a multi-node Geo site
with one secondary. The following [2000 user reference architecture](../../../../administration/reference_architectures/2k_users.md) is assumed:
with one secondary. The following [40 RPS / 2,000 user reference architecture](../../../../administration/reference_architectures/2k_users.md) is assumed:
```mermaid
graph TD

View File

@ -31,7 +31,7 @@ these definitions yet.
| Primary site | A GitLab site whose data is being replicated by at least one secondary site. There can only be a single primary site. | Geo-specific | Geo deployment, Primary node |
| Secondary site | A GitLab site that is configured to replicate the data of a primary site. There can be one or more secondary sites. | Geo-specific | Geo deployment, Secondary node |
| Geo deployment | A collection of two or more GitLab sites with exactly one primary site being replicated by one or more secondary sites. | Geo-specific | |
| Reference architecture | A [specified configuration of GitLab for a number of users](../reference_architectures/index.md), possibly including multiple nodes and multiple sites. | GitLab | |
| Reference architecture | A [specified configuration of GitLab based on Requests per Second or user count](../reference_architectures/index.md), possibly including multiple nodes and multiple sites. | GitLab | |
| Promoting | Changing the role of a site from secondary to primary. | Geo-specific | |
| Demoting | Changing the role of a site from primary to secondary. | Geo-specific | |
| Failover | The entire process that shifts users from a primary Site to a secondary site. This includes promoting a secondary, but contains other parts as well. For example, scheduling maintenance. | Geo-specific | |

View File

@ -40,7 +40,7 @@ Depending on your GitLab deployment, [additional configuration](#additional-conf
### Multi-node Geo sites
If one or more of your sites is using the [2K reference architecture](../../reference_architectures/2k_users.md) or larger, see
If one or more of your sites is using the [40 RPS / 2,000 user reference architecture](../../reference_architectures/2k_users.md) or larger, see
[Configure Geo for multiple nodes](../replication/multiple_servers.md).
Depending on your GitLab deployment, [additional configuration](#additional-configuration) for LDAP, object storage, and the container registry might be required.

View File

@ -167,9 +167,9 @@ E --> F
### Configure Gitaly
Gitaly comes pre-configured with a Linux package installation, which is a configuration
[suitable for up to 1000 users](../reference_architectures/1k_users.md). For:
[suitable for up to 20 RPS / 1,000 users](../reference_architectures/1k_users.md). For:
- Linux package installations for up to 2000 users, see [specific Gitaly configuration instructions](../reference_architectures/2k_users.md#configure-gitaly).
- Linux package installations for up to 40 RPS / 2,000 users, see [specific Gitaly configuration instructions](../reference_architectures/2k_users.md#configure-gitaly).
- Self-compiled installations or custom Gitaly installations, see [Configure Gitaly](configure_gitaly.md).
GitLab installations for more than 2000 active users performing daily Git write operation may be

View File

@ -14,11 +14,11 @@ Configure Gitaly Cluster using either:
- Gitaly Cluster configuration instructions available as part of
[reference architectures](../reference_architectures/index.md) for installations of up to:
- [3000 users](../reference_architectures/3k_users.md#configure-gitaly-cluster).
- [5000 users](../reference_architectures/5k_users.md#configure-gitaly-cluster).
- [10,000 users](../reference_architectures/10k_users.md#configure-gitaly-cluster).
- [25,000 users](../reference_architectures/25k_users.md#configure-gitaly-cluster).
- [50,000 users](../reference_architectures/50k_users.md#configure-gitaly-cluster).
- [60 RPS or 3,000 users](../reference_architectures/3k_users.md#configure-gitaly-cluster).
- [100 RPS or 5,000 users](../reference_architectures/5k_users.md#configure-gitaly-cluster).
- [200 RPS or 10,000 users](../reference_architectures/10k_users.md#configure-gitaly-cluster).
- [500 RPS or 25,000 users](../reference_architectures/25k_users.md#configure-gitaly-cluster).
- [1000 RPS or 50,000 users](../reference_architectures/50k_users.md#configure-gitaly-cluster).
- The custom configuration instructions that follow on this page.
Smaller GitLab installations may need only [Gitaly itself](index.md).

View File

@ -13,7 +13,7 @@ DETAILS:
If you wish to have your database service hosted separately from your GitLab
application servers, you can do this using the PostgreSQL binaries packaged
together with the Linux package. This is recommended as part of our
[reference architecture for up to 2,000 users](../reference_architectures/2k_users.md).
[reference architecture for up to 40 RPS or 2,000 users](../reference_architectures/2k_users.md).
## Setting it up

View File

@ -4,14 +4,13 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: up to 10,000 users
# Reference architecture: 200 RPS or up to 10,000 users
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed for the load of up to 10,000 users
with notable headroom.
This page describes the GitLab reference architecture designed to target a peak load of 200 requests per second (RPS), the typical peak load of up to 10,000 users, both manual and automated, based on real data with headroom added.
For a full list of reference architectures, see
[Available reference architectures](index.md#available-reference-architectures).
@ -157,7 +156,7 @@ Before starting, see the [requirements](index.md#requirements) for reference arc
## Testing methodology
The 10k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Quality Engineering team
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 200 RPS
@ -179,7 +178,7 @@ The load balancers used for testing were HAProxy for Linux package environments
## Set up components
To set up GitLab and its components to accommodate up to 10,000 users:
To set up GitLab and its components to accommodate up to 200 RPS or 10,000 users:
1. [Configure the external load balancer](#configure-the-external-load-balancer)
to handle the load balancing of the GitLab application services nodes.
@ -2398,7 +2397,7 @@ Each Webservice pod consumes roughly 4 CPUs and 5 GB of memory using
the [recommended topology](#cluster-topology) because four worker processes
are created by default and each pod has other small processes running.
For 10,000 users we recommend a total Puma worker count of around 80.
For 200 RPS or 10,000 users we recommend a total Puma worker count of around 80.
With the [provided recommendations](#cluster-topology) this allows the deployment of up to 20
Webservice pods with 4 workers per pod and 5 pods per node. Expand available resources using
the ratio of 1 CPU to 1.25 GB of memory _per each worker process_ for each additional

View File

@ -4,14 +4,13 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: up to 1,000 users
# Reference architecture: 20 RPS or up to 1,000 users
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed for the load of up to 1,000 users
with notable headroom (non-HA standalone).
This page describes the GitLab reference architecture designed to target a peak load of 20 requests per second (RPS), the typical peak load of up to 1,000 users, both manual and automated, based on real data with headroom added.
For a full list of reference architectures, see
[Available reference architectures](index.md#available-reference-architectures).
@ -26,7 +25,7 @@ For a full list of reference architectures, see
| Users | Configuration | GCP | AWS | Azure |
|--------------|-------------------------|----------------|--------------|----------|
| Up to 1,000 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` |
| Up to 1,000 or 20 RPS | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` |
```plantuml
@startuml 1k
@ -74,7 +73,7 @@ If this applies to you, we strongly recommended referring to the linked document
## Testing methodology
The 1k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Quality Engineering team
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 20 RPS
@ -121,5 +120,5 @@ Cloud Native Hybrid Reference Architecture is an alternative approach where sele
components are deployed in Kubernetes via our official [Helm Charts](https://docs.gitlab.com/charts/),
and _stateful_ components are deployed in compute VMs with the Linux package.
The [2k GitLab Cloud Native Hybrid](2k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) (non HA) and [3k GitLab Cloud Native Hybrid](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) (HA) reference architectures are the smallest we recommend in Kubernetes.
For environments that serve fewer users, you can lower the node specs. Depending on your user count, you can lower all suggested node specs as desired. However, it's recommended that you don't go lower than the [general requirements](../../install/requirements.md).
The [2k or 40 RPS GitLab Cloud Native Hybrid](2k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) (non HA) and [3k or 60 RPS GitLab Cloud Native Hybrid](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) (HA) reference architectures are the smallest we recommend in Kubernetes.
For environments that serve fewer users or a lower RPS, you can lower the node specs. Depending on your user count, you can lower all suggested node specs as desired. However, it's recommended that you don't go lower than the [general requirements](../../install/requirements.md).

View File

@ -4,14 +4,13 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: up to 25,000 users
# Reference architecture: 500 RPS or up to 25,000 users
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed for the load of up to 25,000 users
with notable headroom.
This page describes the GitLab reference architecture designed to target a peak load of 500 requests per second (RPS) - The typical peak load of up to 25,000 users, both manual and automated, based on real data with headroom added.
For a full list of reference architectures, see
[Available reference architectures](index.md#available-reference-architectures).
@ -157,7 +156,7 @@ Before starting, see the [requirements](index.md#requirements) for reference arc
## Testing methodology
The 25k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Quality Engineering team
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 500 RPS
@ -179,7 +178,7 @@ The load balancers used for testing were HAProxy for Linux package environments
## Set up components
To set up GitLab and its components to accommodate up to 25,000 users:
To set up GitLab and its components to accommodate up to 500 RPS or 25,000 users:
1. [Configure the external load balancer](#configure-the-external-load-balancer)
to handle the load balancing of the GitLab application services nodes.
@ -2403,7 +2402,7 @@ Each Webservice pod consumes roughly 4 CPUs and 5 GB of memory using
the [recommended topology](#cluster-topology) because four worker processes
are created by default and each pod has other small processes running.
For 25,000 users we recommend a total Puma worker count of around 140.
For 500 RPS or 25,000 users we recommend a total Puma worker count of around 140.
With the [provided recommendations](#cluster-topology) this allows the deployment of up to 35
Webservice pods with 4 workers per pod and 5 pods per node. Expand available resources using
the ratio of 1 CPU to 1.25 GB of memory _per each worker process_ for each additional

View File

@ -4,21 +4,20 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: up to 2,000 users
# Reference architecture: 40 RPS or up to 2,000 users
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed for the load of up to 2,000 users
with notable headroom (non-HA).
This page describes the GitLab reference architecture designed to target a peak load of 40 requests per second (RPS), the typical peak load of up to 2,000 users, both manual and automated, based on real data with headroom added.
For a full list of reference architectures, see
[Available reference architectures](index.md#available-reference-architectures).
> - **Target Load:** API: 40 RPS, Web: 4 RPS, Git (Pull): 4 RPS, Git (Push): 1 RPS
> - **High Availability:** No. For a highly-available environment, you can
> follow a modified [3K reference architecture](3k_users.md#supported-modifications-for-lower-user-counts-ha).
> follow a modified [3K or 60 RPS reference architecture](3k_users.md#supported-modifications-for-lower-user-counts-ha).
> - **Estimated Costs:** [See cost table](index.md#cost-to-run)
> - **Cloud Native Hybrid:** [Yes](#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative)
> - **Unsure which Reference Architecture to use?** [Go to this guide for more info](index.md#deciding-which-architecture-to-use).
@ -100,7 +99,7 @@ Before starting, see the [requirements](index.md#requirements) for reference arc
## Testing methodology
The 2k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Quality Engineering team
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 40 RPS
@ -122,7 +121,7 @@ The load balancers used for testing were HAProxy for Linux package environments
## Set up components
To set up GitLab and its components to accommodate up to 2,000 users:
To set up GitLab and its components to accommodate up to 40 RPS or 2,000 users:
1. [Configure the external load balancing node](#configure-the-external-load-balancer)
to handle the load balancing of the GitLab application services nodes.
@ -1105,7 +1104,7 @@ section assumes this.
NOTE:
The 2,000 reference architecture is not a highly-available setup. To achieve HA,
you can follow a modified [3K reference architecture](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative).
you can follow a modified [3K or 60 RPS reference architecture](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative).
WARNING:
**Gitaly Cluster is not supported to be run in Kubernetes**.
@ -1200,7 +1199,7 @@ Each Webservice pod consumes roughly 4 CPUs and 5 GB of memory using
the [recommended topology](#cluster-topology) because two worker processes
are created by default and each pod has other small processes running.
For 2,000 users we recommend a total Puma worker count of around 12.
For 40 RPS or 2,000 users we recommend a total Puma worker count of around 12.
With the [provided recommendations](#cluster-topology) this allows the deployment of up to 3
Webservice pods with 4 workers per pod and 1 pod per node. Expand available resources using
the ratio of 1 CPU to 1.25 GB of memory _per each worker process_ for each additional

View File

@ -4,14 +4,13 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: up to 3,000 users
# Reference architecture: 60 RPS or up to 3,000 users
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed for the load of up to 3,000 users
with notable headroom.
This page describes the GitLab reference architecture designed to target a peak load of 60 requests per second (RPS), the typical peak load of up to 3,000 users, both manual and automated, based on real data with headroom added.
This architecture is the smallest one available with HA built in. If you require HA but
have a lower user count or total load the [Supported Modifications for lower user counts](#supported-modifications-for-lower-user-counts-ha)
@ -152,7 +151,7 @@ Before starting, see the [requirements](index.md#requirements) for reference arc
## Testing methodology
The 3k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Quality Engineering team
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 60 RPS
@ -174,7 +173,7 @@ The load balancers used for testing were HAProxy for Linux package environments
## Set up components
To set up GitLab and its components to accommodate up to 3,000 users:
To set up GitLab and its components to accommodate up to 60 RPS or 3,000 users:
1. [Configure the external load balancer](#configure-the-external-load-balancer)
to handle the load balancing of the GitLab application services nodes.
@ -2202,18 +2201,18 @@ cluster alongside your instance, read how to
## Supported modifications for lower user counts (HA)
The 3,000 user GitLab reference architecture is the smallest we recommend that achieves High Availability (HA).
However, for environments that need to serve fewer users but maintain HA, there are several
The 60 RPS or 3,000 users GitLab reference architecture is the smallest we recommend that achieves High Availability (HA).
However, for environments that need to serve fewer users or a lower RPS but maintain HA, there are several
supported modifications you can make to this architecture to reduce complexity and cost.
It should be noted that to achieve HA with GitLab, the 3,000 user architecture's makeup is ultimately what is
required. Each component has various considerations and rules to follow, and the 3,000 user architecture
It should be noted that to achieve HA with GitLab, the 60 RPS or 3,000 users architecture's makeup is ultimately what is
required. Each component has various considerations and rules to follow, and the architecture
meets all of these. Smaller versions of this architecture will be fundamentally the same,
but with smaller performance requirements, several modifications can be considered as follows:
- Lowering node specs: Depending on your user count, you can lower all suggested node specs as desired. However, it's recommended that you don't go lower than the [general requirements](../../install/requirements.md).
- Combining select nodes: Some nodes can be combined to reduce complexity at the cost of some performance:
- GitLab Rails and Sidekiq: Sidekiq nodes can be removed and the component instead enabled on the GitLab Rails nodes.
- GitLab Rails and Sidekiq: Sidekiq nodes can be removed, and the component instead enabled on the GitLab Rails nodes.
- PostgreSQL and PgBouncer: PgBouncer nodes could be removed and instead be enabled on PostgreSQL nodes with the Internal Load Balancer pointing to them. However, to enable [Database Load Balancing](../postgresql/database_load_balancing.md), a separate PgBouncer array is still required.
- Reducing the node counts: Some node types do not need consensus and can run with fewer nodes (but more than one for redundancy). This will also lead to reduced performance.
- GitLab Rails and Sidekiq: Stateless services don't have a minimum node count. Two are enough for redundancy.
@ -2381,7 +2380,7 @@ Each Webservice pod consumes roughly 4 CPUs and 5 GB of memory using
the [recommended topology](#cluster-topology) because four worker processes
are created by default and each pod has other small processes running.
For 3,000 users we recommend a total Puma worker count of around 16.
For 60 RPS or 3,000 users we recommend a total Puma worker count of around 16.
With the [provided recommendations](#cluster-topology) this allows the deployment of up to 4
Webservice pods with 4 workers per pod and 2 pods per node. Expand available resources using
the ratio of 1 CPU to 1.25 GB of memory _per each worker process_ for each additional

View File

@ -4,14 +4,13 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: up to 50,000 users
# Reference architecture: 1000 RPS or up to 50,000 users
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed for the load of up to 50,000 users
with notable headroom.
This page describes the GitLab reference architecture designed to target a peak load of 1000 requests per second (RPS), the typical peak load of up to 50,000 users, both manual and automated, based on real data with headroom added.
For a full list of reference architectures, see
[Available reference architectures](index.md#available-reference-architectures).
@ -156,7 +155,7 @@ Before starting, see the [requirements](index.md#requirements) for reference arc
## Testing methodology
The 50k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Quality Engineering team
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 1000 RPS
@ -178,7 +177,7 @@ The load balancers used for testing were HAProxy for Linux package environments
## Set up components
To set up GitLab and its components to accommodate up to 50,000 users:
To set up GitLab and its components to accommodate up to 1000 RPS or 50,000 users:
1. [Configure the external load balancer](#configure-the-external-load-balancer)
to handle the load balancing of the GitLab application services nodes.
@ -2417,7 +2416,7 @@ Each Webservice pod consumes roughly 4 CPUs and 5 GB of memory using
the [recommended topology](#cluster-topology) because four worker processes
are created by default and each pod has other small processes running.
For 50,000 users we recommend a total Puma worker count of around 320.
For 1000 RPS or 50,000 users we recommend a total Puma worker count of around 320.
With the [provided recommendations](#cluster-topology) this allows the deployment of up to 80
Webservice pods with 4 workers per pod and 5 pods per node. Expand available resources using
the ratio of 1 CPU to 1.25 GB of memory _per each worker process_ for each additional

View File

@ -4,14 +4,13 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: up to 5,000 users
# Reference architecture: 100 RPS or up to 5,000 users
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed for the load of up to 5,000 users
with notable headroom.
This page describes the GitLab reference architecture designed to target a peak load of 100 requests per second (RPS) - The typical peak load of up to 5,000 users, both manual and automated, based on real data with headroom added.
For a full list of reference architectures, see
[Available reference architectures](index.md#available-reference-architectures).
@ -152,7 +151,7 @@ Before starting, see the [requirements](index.md#requirements) for reference arc
## Testing methodology
The 5k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Quality Engineering team
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 100 RPS
@ -174,7 +173,7 @@ The load balancers used for testing were HAProxy for Linux package environments
## Set up components
To set up GitLab and its components to accommodate up to 5,000 users:
To set up GitLab and its components to accommodate up to 100 RPS or 5,000 users:
1. [Configure the external load balancer](#configure-the-external-load-balancer)
to handle the load balancing of the GitLab application services nodes.
@ -2356,7 +2355,7 @@ Each Webservice pod consumes roughly 4 CPUs and 5 GB of memory using
the [recommended topology](#cluster-topology) because four worker processes
are created by default and each pod has other small processes running.
For 5,000 users we recommend a total Puma worker count of around 40.
For 100 RPS or 5,000 users we recommend a total Puma worker count of around 40.
With the [provided recommendations](#cluster-topology) this allows the deployment of up to 10
Webservice pods with 4 workers per pod and 2 pods per node. Expand available resources using
the ratio of 1 CPU to 1.25 GB of memory _per each worker process_ for each additional

View File

@ -12,40 +12,41 @@ DETAILS:
**Offering:** Self-managed
The GitLab Reference Architectures have been designed and tested by the
GitLab Quality Engineering and Support teams to provide recommended deployments at scale.
GitLab Test Platform and Support teams to provide scalable recommended deployments for target loads.
## Available reference architectures
The following Reference Architectures are available as recommended starting points for your environment.
The architectures are named in terms of _total_ load, both manual and automated, correlated to user count and based on real data along with substantial headroom added to add additional coverage for most scenarios.
The architectures are named in terms of peak load, based on user count or Requests per Second (RPS). Where the latter has been calculated based on average real data of the former with headroom added.
However, it should be noted that in some cases, known heavy scenarios such as [large monorepos](#large-monorepos) or notable [additional workloads](#additional-workloads) may require adjustments to be made.
NOTE:
Each architecture has been designed to be [scalable and can be adjusted accordingly if required](#scaling-an-environment) by your specific workload. This may be likely in known heavy scenarios such as using [large monorepos](#large-monorepos) or notable [additional workloads](#additional-workloads).
For details about what each Reference Architecture has been tested against, see the "Testing Methodology" section of each page.
### GitLab package (Omnibus)
Below is a list of Linux package based architectures:
Below is the list of Linux package based reference architectures:
- [Up to 1,000 users](1k_users.md) <span style="color: darkgrey;">_API: 20 RPS, Web: 2 RPS, Git (Pull): 2 RPS, Git (Push): 1 RPS_</span>
- [Up to 2,000 users](2k_users.md) <span style="color: darkgrey;">_API: 40 RPS, Web: 4 RPS, Git (Pull): 4 RPS, Git (Push): 1 RPS_</span>
- [Up to 3,000 users](3k_users.md) <span style="color: darkgrey;">_API: 60 RPS, Web: 6 RPS, Git (Pull): 6 RPS, Git (Push): 1 RPS_</span>
- [Up to 5,000 users](5k_users.md) <span style="color: darkgrey;">_API: 100 RPS, Web: 10 RPS, Git (Pull): 10 RPS, Git (Push): 2 RPS_</span>
- [Up to 10,000 users](10k_users.md) <span style="color: darkgrey;">_API: 200 RPS, Web: 20 RPS, Git (Pull): 20 RPS, Git (Push): 4 RPS_</span>
- [Up to 25,000 users](25k_users.md) <span style="color: darkgrey;">_API: 500 RPS, Web: 50 RPS, Git (Pull): 50 RPS, Git (Push): 10 RPS_</span>
- [Up to 50,000 users](50k_users.md) <span style="color: darkgrey;">_API: 1000 RPS, Web: 100 RPS, Git (Pull): 100 RPS, Git (Push): 20 RPS_</span>
- [Up to 20 RPS or 1,000 users](1k_users.md) <span style="color: darkgrey;">_API: 20 RPS, Web: 2 RPS, Git (Pull): 2 RPS, Git (Push): 1 RPS_</span>
- [Up to 40 RPS or 2,000 users](2k_users.md) <span style="color: darkgrey;">_API: 40 RPS, Web: 4 RPS, Git (Pull): 4 RPS, Git (Push): 1 RPS_</span>
- [Up to 60 RPS or 3,000 users](3k_users.md) <span style="color: darkgrey;">_API: 60 RPS, Web: 6 RPS, Git (Pull): 6 RPS, Git (Push): 1 RPS_</span>
- [Up to 100 RPS or 5,000 users](5k_users.md) <span style="color: darkgrey;">_API: 100 RPS, Web: 10 RPS, Git (Pull): 10 RPS, Git (Push): 2 RPS_</span>
- [Up to 200 RPS or 10,000 users](10k_users.md) <span style="color: darkgrey;">_API: 200 RPS, Web: 20 RPS, Git (Pull): 20 RPS, Git (Push): 4 RPS_</span>
- [Up to 500 RPS or 25,000 users](25k_users.md) <span style="color: darkgrey;">_API: 500 RPS, Web: 50 RPS, Git (Pull): 50 RPS, Git (Push): 10 RPS_</span>
- [Up to 1000 RPS or 50,000 users](50k_users.md) <span style="color: darkgrey;">_API: 1000 RPS, Web: 100 RPS, Git (Pull): 100 RPS, Git (Push): 20 RPS_</span>
### Cloud native hybrid
Below is a list of Cloud Native Hybrid reference architectures, where select recommended components can be run in Kubernetes:
- [Up to 2,000 users](2k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 40 RPS, Web: 4 RPS, Git (Pull): 4 RPS, Git (Push): 1 RPS_</span>
- [Up to 3,000 users](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 60 RPS, Web: 6 RPS, Git (Pull): 6 RPS, Git (Push): 1 RPS_</span>
- [Up to 5,000 users](5k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 100 RPS, Web: 10 RPS, Git (Pull): 10 RPS, Git (Push): 2 RPS_</span>
- [Up to 10,000 users](10k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 200 RPS, Web: 20 RPS, Git (Pull): 20 RPS, Git (Push): 4 RPS_</span>
- [Up to 25,000 users](25k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 500 RPS, Web: 50 RPS, Git (Pull): 50 RPS, Git (Push): 10 RPS_</span>
- [Up to 50,000 users](50k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 1000 RPS, Web: 100 RPS, Git (Pull): 100 RPS, Git (Push): 20 RPS_</span>
- [40 RPS or Up to 2,000 users](2k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 40 RPS, Web: 4 RPS, Git (Pull): 4 RPS, Git (Push): 1 RPS_</span>
- [60 RPS or Up to 3,000 users](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 60 RPS, Web: 6 RPS, Git (Pull): 6 RPS, Git (Push): 1 RPS_</span>
- [100 RPS or Up to 5,000 users](5k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 100 RPS, Web: 10 RPS, Git (Pull): 10 RPS, Git (Push): 2 RPS_</span>
- [200 RPS or Up to 10,000 users](10k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 200 RPS, Web: 20 RPS, Git (Pull): 20 RPS, Git (Push): 4 RPS_</span>
- [500 RPS or Up to 25,000 users](25k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 500 RPS, Web: 50 RPS, Git (Pull): 50 RPS, Git (Push): 10 RPS_</span>
- [1000 RPS or Up to 50,000 users](50k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) <span style="color: darkgrey;">_API: 1000 RPS, Web: 100 RPS, Git (Pull): 100 RPS, Git (Push): 20 RPS_</span>
## Before you start
@ -67,18 +68,18 @@ As a general guide, **the more performant and/or resilient you want your environ
This section explains the designs you can choose from. It begins with the least complexity, goes to the most, and ends with a decision tree.
### Expected Load (RPS)
### Expected Load (RPS or user count)
The first thing to check is what the expected load is your environment would be expected to serve.
The first thing to check is what the expected peak load is your environment would be expected to serve.
The Reference Architectures have been designed with substantial headroom by default, but it's recommended to also check the
load of what each architecture has been tested against under the "Testing Methodology" section found on each page,
comparing those values with what load you are expecting against your existing GitLab environment to help select the right Reference Architecture
size.
Each architecture is described in terms of peak Requests per Second (RPS) or user count load. As detailed under the "Testing Methodology" section on each page, each architecture is tested
against its listed RPS for each endpoint type (API, Web, Git), which is the typical peak load of the given user count, both manual and automated, with headroom.
Load is given in terms of Requests per Second (RPS) for each endpoint type (API, Web, Git). This information on your existing infrastructure
can typically be surfaced by most reputable monitoring solutions or in some other ways such as load balancer metrics. For example, on existing GitLab environments,
[Prometheus metrics](../monitoring/prometheus/gitlab_metrics.md) such as `gitlab_transaction_duration_seconds` can be used to see this data.
It's strongly recommended finding out what peak RPS your environment will be expected to handle across endpoint types, through existing metrics (such as [Prometheus](../monitoring/prometheus/gitlab_metrics.md))
or estimates, and to select the corresponding architecture as this is the most objective.
If it's not possible for you to find out the expected peak RPS then it's recommended to select based on user count to start and then monitor the environment
closely to confirm the RPS, whether the architecture is performing and adjust accordingly is necessary.
### Standalone (non-HA)
@ -170,10 +171,10 @@ graph TD
L3A("<a href=#do-you-need-high-availability-ha>Do you need HA?</a><br>(or Zero-Downtime Upgrades)")
L3B[Do you have experience with<br/>and want additional resilience<br/>with select components in Kubernetes?]
L4A><b>Recommendation</b><br><br>3K architecture with HA<br>and supported reductions]
L4A><b>Recommendation</b><br><br>60 RPS / 3K users architecture with HA<br>and supported reductions]
L4B><b>Recommendation</b><br><br>Architecture closest to user<br>count with HA]
L4C><b>Recommendation</b><br><br>Cloud Native Hybrid architecture<br>closest to user count]
L4D>"<b>Recommendation</b><br><br>Standalone 1K or 2K<br/>architecture with Backups"]
L4D>"<b>Recommendation</b><br><br>Standalone 20 RPS / 1K users or 40 RPS / 2K users<br/>architecture with Backups"]
L0A --> L1A
L1A --> L2A
@ -412,7 +413,7 @@ If you choose to use a third party external service:
[When selecting to use an external Redis service](../redis/replication_and_failover_external.md#redis-as-a-managed-service-in-a-cloud-provider), it should run a standard, performant, and supported version. Note that this specifically must not be run in [Cluster mode](../../install/requirements.md#redis) as this is unsupported by GitLab.
Redis is primarily single threaded. For the 10,000 user and above Reference Architectures, separate out the instances as specified into Cache and Persistent data to achieve optimum performance at this scale.
Redis is primarily single threaded. For environments targeting up to 200 RPS / 10,000 users or higher, separate out the instances as specified into Cache and Persistent data to achieve optimum performance at this scale.
### Recommendation notes for Object Storage
@ -477,7 +478,7 @@ For deploying GitLab over multiple data centers or regions we offer [GitLab Geo]
## Validation and test results
The [Quality Engineering team](https://handbook.gitlab.com/handbook/engineering/quality/)
The [Test Platform team](https://handbook.gitlab.com/handbook/engineering/quality/)
does regular smoke and performance tests for the reference architectures to ensure they
remain compliant.
@ -517,7 +518,7 @@ per 1,000 users:
- Git (Pull): 2 RPS
- Git (Push): 0.4 RPS (rounded to the nearest integer)
The above targets were selected based on real customer data of total environmental loads corresponding to the user count, including CI and other workloads along with additional substantial headroom added.
The above RPS targets were selected based on real customer data of total environmental loads corresponding to the user count, including CI and other workloads along with additional substantial headroom added.
### How to interpret the results

View File

@ -371,7 +371,7 @@ Cluster-wide features are strongly discouraged because:
Services that might initially be cluster-wide are still expected to be split in the future to achieve full service isolation.
No feature should be built to depend on such a service (like Elasticsearch).
### Will Cells use the [reference architecture for 50,000 users](../../../administration/reference_architectures/50k_users.md)?
### Will Cells use the [reference architecture for up to 1000 RPS or 50,000 users](../../../administration/reference_architectures/50k_users.md)?
The infrastructure team will properly size Cells depending on the load.
The Tenant Scale team sees an opportunity to use GitLab Dedicated as a base for Cells deployment.

View File

@ -40,13 +40,13 @@ GitLab Reference Architecture sizes and [costs](../../../../administration/refer
| Reference Architecture | ClickHouse type | ClickHouse cost / (GitLab cost + ClickHouse cost) |
|-------------|-----------------|-----------------------------------|
| [1k - non HA](https://cloud.google.com/products/calculator#id=a6d6a94a-c7dc-4c22-85c4-7c5747f272ed) | [non-HA](https://cloud.google.com/products/calculator#id=9af5359e-b155-451c-b090-5f0879bb591e) | 78.01% |
| [2k - non HA](https://cloud.google.com/products/calculator#id=0d3aff1f-ea3d-43f9-aa59-df49d27c35ca) | [non-HA](https://cloud.google.com/products/calculator#id=9af5359e-b155-451c-b090-5f0879bb591e) | 44.50% |
| [3k - HA](https://cloud.google.com/products/calculator/#id=15fc2bd9-5b1c-479d-bc46-d5ce096b8107) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 37.87% |
| [5k - HA](https://cloud.google.com/products/calculator/#id=9a798136-53f2-4c35-be43-8e1e975a6663) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 30.92% |
| [10k - HA](https://cloud.google.com/products/calculator#id=cbe61840-31a1-487f-88fa-631251c2fde5) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 20.47% |
| [25k - HA](https://cloud.google.com/products/calculator#id=b4b8b587-508a-4433-adc8-dc506bbe924f) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 14.30% |
| [50k - HA](https://cloud.google.com/products/calculator/#id=48b4d817-d6cd-44b8-b069-0ba9a5d123ea) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 8.16% |
| [20 RPS / 1k users - non HA](https://cloud.google.com/products/calculator#id=a6d6a94a-c7dc-4c22-85c4-7c5747f272ed) | [non-HA](https://cloud.google.com/products/calculator#id=9af5359e-b155-451c-b090-5f0879bb591e) | 78.01% |
| [40 RPS / 2k users- non HA](https://cloud.google.com/products/calculator#id=0d3aff1f-ea3d-43f9-aa59-df49d27c35ca) | [non-HA](https://cloud.google.com/products/calculator#id=9af5359e-b155-451c-b090-5f0879bb591e) | 44.50% |
| [60 RPS / 3k users - HA](https://cloud.google.com/products/calculator/#id=15fc2bd9-5b1c-479d-bc46-d5ce096b8107) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 37.87% |
| [100 RPS / 5k users - HA](https://cloud.google.com/products/calculator/#id=9a798136-53f2-4c35-be43-8e1e975a6663) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 30.92% |
| [200 RPS / 10k users - HA](https://cloud.google.com/products/calculator#id=cbe61840-31a1-487f-88fa-631251c2fde5) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 20.47% |
| [500 RPS / 25k users - HA](https://cloud.google.com/products/calculator#id=b4b8b587-508a-4433-adc8-dc506bbe924f) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 14.30% |
| [1000 RPS / 50k users - HA](https://cloud.google.com/products/calculator/#id=48b4d817-d6cd-44b8-b069-0ba9a5d123ea) | [HA](https://cloud.google.com/products/calculator#id=9909f5af-d41a-4da2-b8cc-a0347702a823) | 8.16% |
NOTE:
The ClickHouse Self-Managed component evaluation is the minimum estimation for the costs
@ -57,7 +57,7 @@ The following components increase the cost, and were not considered in the minim
- Disk size - depends on data size, hard to estimate.
- Disk types - ClickHouse recommends [fast SSDs](https://clickhouse.com/docs/ru/operations/tips#storage-subsystem).
- Network usage - ClickHouse recommends using [10 GB network, if possible](https://clickhouse.com/docs/en/operations/tips#network).
- For HA we sum minimum cost across all reference architectures from 3k to 50k users, but HA specs tend to increase with user count.
- For HA we sum minimum cost across all reference architectures from 60 RPS / 3k users to 1000 RPS / 50k users, but HA specs tend to increase with user count.
### Resources

View File

@ -273,12 +273,33 @@ first check that the resource group is working correctly:
1. If **View job currently using resource** is not available, the resource is not assigned to a job. Instead, check the resource's upcoming jobs.
1. Get the resource's upcoming jobs with the [REST API](../../api/resource_groups.md#list-upcoming-jobs-for-a-specific-resource-group).
1. Verify that the job's [process mode](#process-modes) is **Oldest first**.
1. Verify that the resource group's [process mode](#process-modes) is **Oldest first**.
1. Find the first job in the list of upcoming jobs, and get the job details [with GraphQL](#get-job-details-through-graphql).
1. If the first job's pipeline is an older pipeline, try to cancel the pipeline or the job itself.
1. Optional. Repeat this process if the next upcoming job is still in an older pipeline that should no longer run.
1. If the problem persists, [report the issue to GitLab](#report-an-issue).
#### Race conditions in complex or busy pipelines
If you can't resolve your issue with the solutions above, you might be encountering a known race condition issue. The race condition happens in complex or busy pipelines.
For example, you might encounter the race condition if you have:
- A pipeline with multiple child pipelines.
- A single project with multiple pipelines running simultaneously.
If you think you are running into this problem, [report the issue to GitLab](#report-an-issue) and leave a comment on [issue 436988](https://gitlab.com/gitlab-org/gitlab/-/issues/436988) with a link to your new issue.
To confirm the problem, GitLab might ask for additional details such
as your full pipeline configuration.
As a temporary workaround, you can:
- Start a new pipeline.
- Re-run a finished job that has the same resource group as the stuck job.
For example, if you have a `setup_job` and a `deploy_job` with the same resource group,
the `setup_job` might finish while the `deploy_job` is stuck at "waiting for resource".
Re-run the `setup_job` to restart the whole process and allow `deploy_job` to finish.
#### Get job details through GraphQL
You can get job information from the GraphQL API. You should use the GraphQL API if you use [pipeline-level concurrency control with cross-project/parent-child pipelines](#pipeline-level-concurrency-control-with-cross-projectparent-child-pipelines) because the trigger jobs are not accessible from the UI.

View File

@ -468,27 +468,49 @@ test:
In this example, GitLab checks for the existence of `file.md` in the current project.
There is a known issue if you configure `include` with `rules:exists` to add a configuration file
There is a known issue if you configure `include` with `rules:exists` in an include file
from a different project. GitLab checks for the existence of the file in the _other_ project.
For example:
```yaml
# Pipeline configuration in my-group/my-project
include:
- project: my-group/my-project-2
ref: main
file: test-file.yml
rules:
- exists:
- file.md
- project: my-group/other-project
ref: other_branch
file: other-file.yml
test:
stage: test
script: exit 0
# other-file.yml in my-group/other-project on ref other_branch
include:
- project: my-group/my-project
ref: main
file: my-file.yml
rules:
- exists:
- file.md
```
In this example, GitLab checks for the existence of `test-file.yml` in `my-group/my-project-2`,
not the current project. Follow [issue 386040](https://gitlab.com/gitlab-org/gitlab/-/issues/386040)
for information about work to improve this behavior.
In this example, GitLab searches for the existence of `file.md` in `my-group/other-project`
on commit ref `other_branch`, not the project/ref in which the pipeline runs.
To change the search context you can use [`rules:exists:paths`](index.md#rulesexistspaths)
with [`rules:exists:project`](index.md#rulesexistsproject).
For example:
```yaml
include:
- project: my-group/my-project
ref: main
file: my-file.yml
rules:
- exists:
paths:
- file.md
project: my-group/my-project
ref: main
```
### `include` with `rules:changes`

View File

@ -4182,7 +4182,7 @@ relative to `refs/heads/branch1` and the pipeline source is a merge request even
Use `exists` to run a job when certain files exist in the repository.
**Keyword type**: Job keyword. You can use it only as part of a job.
**Keyword type**: Job keyword. You can use it as part of a job or an [`include`](#include).
**Possible inputs**:
@ -4213,6 +4213,88 @@ job:
- A maximum of 50 patterns or file paths can be defined per `rules:exists` section.
- `exists` resolves to `true` if any of the listed files are found (an `OR` operation).
- With job-level `rules:exists`, GitLab searches for the files in the project and
ref that runs the pipeline. When using [`include` with `rules:exists`](includes.md#include-with-rulesexists),
GitLab searches for the files in the project and ref of the file that contains the `include`
section. The project containing the `include` section can be different than the project
running the pipeline when using:
- [Nested includes](includes.md#use-nested-includes).
- [Compliance pipelines](../../user/group/compliance_pipelines.md).
##### `rules:exists:paths`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386040) in GitLab 16.11 [with a flag](../../administration/feature_flags.md) named `ci_support_rules_exists_paths_and_project`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available.
To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `ci_support_rules_exists_paths_and_project`.
On GitLab.com and GitLab Dedicated, this feature is not available.
`rules:exists:paths` is the same as using [`rules:exists`](#rulesexists) without
any subkeys. All additional details are the same.
**Keyword type**: Job keyword. You can use it as part of a job or an [`include`](#include).
**Possible inputs**:
- An array of file paths.
**Example of `rules:exists:paths`**:
```yaml
docker-build-1:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
exists:
- Dockerfile
docker-build-2:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
exists:
paths:
- Dockerfile
```
In this example, both jobs have the same behavior.
##### `rules:exists:project`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386040) in GitLab 16.11 [with a flag](../../administration/feature_flags.md) named `ci_support_rules_exists_paths_and_project`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available.
To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `ci_support_rules_exists_paths_and_project`.
On GitLab.com and GitLab Dedicated, this feature is not available.
Use `rules:exists:project` to specify the location in which to search for the files
listed under [`rules:exists:paths`](#rulesexistspaths). Must be used with `rules:exists:paths`.
**Keyword type**: Job keyword. You can use it as part of a job or an [`include`](#include), and it must be combined with `rules:exists:paths`.
**Possible inputs**:
- `exists:project`: A full project path, including namespace and group.
- `exists:ref`: Optional. The commit ref to use to search for the file. The ref can be a tag, branch name, or SHA. Defaults to the `HEAD` of the project when not specified.
**Example of `rules:exists:project`**:
```yaml
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- exists:
paths:
- Dockerfile
project: my-group/my-project
ref: v1.0.0
```
In this example, the `docker build` job is only included when the `Dockerfile` exists in
the project `my-group/my-project` on the commit tagged with `v1.0.0`.
#### `rules:allow_failure`
Use [`allow_failure: true`](#allow_failure) in `rules` to allow a job to fail

View File

@ -689,7 +689,7 @@ After triggering a successful [e2e:package-and-test-ee](testing_guide/end_to_end
1. The `GET:Geo` job can be found and triggered under the `trigger-qa` stage.
This pipeline uses [GET](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) to spin up a
[1k](../administration/reference_architectures/1k_users.md) Geo installation,
[20 RPS / 1k users](../administration/reference_architectures/1k_users.md) Geo installation,
and run the [`gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa) Geo scenario against the instance.
When working on Geo features, it is a good idea to ensure the `qa-geo` job passes in a triggered `GET:Geo pipeline`.

View File

@ -93,7 +93,7 @@ These users accept some downtime during the update. Unfortunately we can't ignor
## What kind of components can GitLab be broken down into?
The [50,000 reference architecture](../administration/reference_architectures/50k_users.md) runs GitLab on 48+ nodes. GitLab.com is [bigger than that](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/), plus a portion of the [infrastructure runs on Kubernetes](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#gitlab-com-architecture), plus there is a ["canary" stage which receives updates first](https://handbook.gitlab.com/handbook/engineering/infrastructure/environments/canary-stage/).
The [1000 RPS or 50,000 user reference architecture](../administration/reference_architectures/50k_users.md) runs GitLab on 48+ nodes. GitLab.com is [bigger than that](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/), plus a portion of the [infrastructure runs on Kubernetes](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#gitlab-com-architecture), plus there is a ["canary" stage which receives updates first](https://handbook.gitlab.com/handbook/engineering/infrastructure/environments/canary-stage/).
But the problem isn't just that there are many nodes. The bigger problem is that a deployment can be divided into different contexts. And GitLab.com is not the only one that does this. Some possible divisions:

View File

@ -10,7 +10,7 @@ info: Any user with at least the Maintainer role can merge updates to this conte
## Setup Instructions
In order to use SemanticVersionable you must first create a database migration to add the required columns to your table. The required columns are `semver_major`, `semver_minor`, `semver_patch`, and `semver_prerelease`. An example migration would look like this:
In order to use SemanticVersionable you must first create a database migration to add the required columns to your table. The required columns are `semver_major`, `semver_minor`, `semver_patch`, and `semver_prerelease`. A `v` prefix can be added to the version by including a column `semver_prefixed`. An example migration would look like this:
```ruby
class AddVersionPartsToModelVersions < Gitlab::Database::Migration[2.2]
@ -23,6 +23,7 @@ class AddVersionPartsToModelVersions < Gitlab::Database::Migration[2.2]
add_column :ml_model_versions, :semver_minor, :integer
add_column :ml_model_versions, :semver_patch, :integer
add_column :ml_model_versions, :semver_prerelease, :text
add_column :ml_model_versions, :semver_prefixed, :boolean, default: false
end
def down
@ -30,32 +31,23 @@ class AddVersionPartsToModelVersions < Gitlab::Database::Migration[2.2]
remove_column :ml_model_versions, :semver_minor, :integer
remove_column :ml_model_versions, :semver_patch, :integer
remove_column :ml_model_versions, :semver_prerelease, :text
remove_column :ml_model_versions, :semver_prefixed, :boolean
end
end
```
Once the columns are in the database, you can enable the module by including it in your model and configuring it by setting the name of the semver accessor method. For example:
Once the columns are in the database, you can enable the module by including it in your model. For example:
```ruby
module Ml
class ModelVersion < ApplicationRecord
include SemanticVersionable
semver_method :semver
...
end
end
```
The module has two configuation options:
- `semver_method` specifies the name of accessor method that will be added to the objecct
- `validate_semver` is `true` or `false` (defaults to `false`). If true it will throw a validation error if the provided semver string is not in a valid semver format.
Depending on the use case, you may want to disable the validation during the rollout or backfill process.
Please refer to [this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142228) as a reference.
The module is configured to validate a semantic version by default.
## Sorting

View File

@ -16,16 +16,16 @@ DETAILS:
This page offers a walkthrough of a common configuration for GitLab on AWS using the official Linux package. You should customize it to accommodate your needs.
NOTE:
For organizations with 1,000 users or less, the recommended AWS installation method is to launch an EC2 single box [Linux package installation](https://about.gitlab.com/install/) and implement a snapshot strategy for backing up the data. See the [1,000 user reference architecture](../../administration/reference_architectures/1k_users.md) for more information.
For organizations with 1,000 users or less, the recommended AWS installation method is to launch an EC2 single box [Linux package installation](https://about.gitlab.com/install/) and implement a snapshot strategy for backing up the data. See the [20 RPS or 1,000 user reference architecture](../../administration/reference_architectures/1k_users.md) for more information.
## Getting started for production-grade GitLab
NOTE:
This document is an installation guide for a proof of concept instance. It is not a reference architecture and it does not result in a highly available configuration.
Following this guide exactly results in a proof of concept instance that roughly equates to a **scaled down** version of a **two availability zone implementation** of the **Non-HA** [2000 User Reference Architecture](../../administration/reference_architectures/2k_users.md). The 2K reference architecture is not HA because it is primarily intended to provide some scaling while keeping costs and complexity low. The [3000 User Reference Architecture](../../administration/reference_architectures/3k_users.md) is the smallest size that is GitLab HA. It has additional service roles to achieve HA, most notably it uses Gitaly Cluster to achieve HA for Git repository storage and specifies triple redundancy.
Following this guide exactly results in a proof of concept instance that roughly equates to a **scaled down** version of a **two availability zone implementation** of the **Non-HA** [40 RPS or 2,000 User Reference Architecture](../../administration/reference_architectures/2k_users.md). The 2K reference architecture is not HA because it is primarily intended to provide some scaling while keeping costs and complexity low. The [60 RPS or 3,000 User Reference Architecture](../../administration/reference_architectures/3k_users.md) is the smallest size that is GitLab HA. It has additional service roles to achieve HA, most notably it uses Gitaly Cluster to achieve HA for Git repository storage and specifies triple redundancy.
GitLab maintains and tests two main types of Reference Architectures. The **Linux package architectures** are implemented on instance compute while **Cloud Native Hybrid architectures** maximize the use of a Kubernetes cluster. Cloud Native Hybrid reference architecture specifications are addendum sections to the Reference Architecture size pages that start by describing the Linux package architecture. For example, the 3000 User Cloud Native Reference Architecture is in the subsection titled [Cloud Native Hybrid reference architecture with Helm Charts (alternative)](../../administration/reference_architectures/3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) in the 3000 User Reference Architecture page.
GitLab maintains and tests two main types of Reference Architectures. The **Linux package architectures** are implemented on instance compute while **Cloud Native Hybrid architectures** maximize the use of a Kubernetes cluster. Cloud Native Hybrid reference architecture specifications are addendum sections to the Reference Architecture size pages that start by describing the Linux package architecture. For example, the 60 RPS or 3,000 User Cloud Native Reference Architecture is in the subsection titled [Cloud Native Hybrid reference architecture with Helm Charts (alternative)](../../administration/reference_architectures/3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) in the 60 RPS or 3,000 User Reference Architecture page.
### Getting started for production-grade Linux package installations

View File

@ -97,7 +97,6 @@ To configure your project settings in GitLab:
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - Ability to enable Jira issues at the group level [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325715) in GitLab 16.9.
@ -126,7 +125,6 @@ Issues are grouped into the following tabs based on their
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
Prerequisites:
@ -146,12 +144,33 @@ You can also filter the issues by:
(for example, `/-/integrations/jira/issues?author_username=John Smith`).
- **Assignee**: specify the Jira display name of the `assignee_username` parameter in the URL
(for example, `/-/integrations/jira/issues?assignee_username=John Smith`).
- **Project**: specify the [Jira project key](#multiple-jira-project-keys) in the `project` parameter in the URL
(for example, `/-/integrations/jira/issues?project=GTL`).
### Multiple Jira project keys
DETAILS:
**Tier:** Premium, Ultimate
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/440430) in GitLab 16.11 [with a flag](../../administration/feature_flags.md) named `jira_multiple_project_keys`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available.
To make it available, an administrator can enable the feature flag named `jira_multiple_project_keys`.
On GitLab.com and GitLab Dedicated, this feature is not available.
When you enable `jira_multiple_project_keys`, you can:
- [View issues](#view-jira-issues) from multiple Jira projects in a GitLab project.
- [Filter Jira issues](#filter-jira-issues) by project.
In **Jira project keys**, you can enter up to 100 project keys separated by commas.
Leave blank to include all available keys.
## Create a Jira issue for a vulnerability
DETAILS:
**Tier:** Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
Prerequisites:

View File

@ -221,12 +221,16 @@ The following operational features are not available:
The following is a list of AWS regions verified for use in GitLab Dedicated. Regions must support io2 volumes and meet other requirements. If there is a region you are interested in that is not on this list, reach out through your account representative or [GitLab Support](https://about.gitlab.com/support/) to inquire about its availability. This list will be updated from time to time as additional regions are verified.
- Asia Pacific (Mumbai)
- Asia Pacific (Seoul)
- Asia Pacific (Singapore)
- Asia Pacific (Sydney)
- Asia Pacific (Tokyo)
- Canada (Central)
- Europe (Frankfurt)
- Europe (Ireland)
- Europe (London)
- Europe (Stockholm)
- US East (Ohio)
- US East (N. Virginia)
- US West (N. California)

View File

@ -489,6 +489,54 @@ git revert <rev commit hash>
# reverted commit is back (new commit created again)
```
## Unstage changes
When you _stage_ a file in Git, you instruct Git to track changes to the file in
preparation for a commit. To disregard changes to a file, and not
include it in your next commit, _unstage_ the file.
### Unstage a file
- To remove files from staging, but keep your changes:
```shell
git reset HEAD <file>
```
- To unstage the last three commits:
```shell
git reset HEAD^3
```
- To unstage changes to a certain file from HEAD:
```shell
git reset <filename>
```
After you unstage the file, to revert the file back to the state it was in before the changes:
```shell
git checkout -- <file>
```
### Remove a file
- To remove a file from disk and repository, use `git rm`. To remove a directory, use the `-r` flag:
```shell
git rm '*.txt'
git rm -r <dirname>
```
- To keep a file on disk but remove it from the repository (such as a file you want
to add to `.gitignore`), use the `rm` command with the `--cache` flag:
```shell
git rm <filename> --cache
```
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues

View File

@ -1,54 +1,11 @@
---
stage: Create
group: Source Code
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
description: "Use the unstage command in Git to stop tracking your changes to a file."
redirect_to: 'undo.md'
remove_date: '2024-07-12'
---
# Unstage files by using Git
This document was moved to [another location](undo.md).
When you _stage_ a file in Git, you instruct Git to track changes to the file in
preparation for a commit. To disregard changes to a file, and not
include it in your next commit, _unstage_ the file.
## Unstage a file
- To remove files from staging, but keep your changes:
```shell
git reset HEAD <file>
```
- To unstage the last three commits:
```shell
git reset HEAD^3
```
- To unstage changes to a certain file from HEAD:
```shell
git reset <filename>
```
After you unstage the file, to revert the file back to the state it was in before the changes:
```shell
git checkout -- <file>
```
## Remove a file
- To remove a file from disk and repository, use `git rm`. To remove a directory, use the `-r` flag:
```shell
git rm '*.txt'
git rm -r <dirname>
```
- To keep a file on disk but remove it from the repository (such as a file you want
to add to `.gitignore`), use the `rm` command with the `--cache` flag:
```shell
git rm <filename> --cache
```
<!-- This redirect file can be deleted after <2024-07-12>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -12,7 +12,7 @@ DETAILS:
In this tutorial you will learn how to install and securely configure a single
node GitLab instance that can accommodate up to
[1,000 users](../../administration/reference_architectures/1k_users.md).
[20 RPS or 1,000 users](../../administration/reference_architectures/1k_users.md).
To install a single node GitLab instance and configure it to be secure:

View File

@ -80,7 +80,7 @@ As such, we generally recommend the following order:
In this section we'll go through the core process of upgrading a multi-node GitLab environment by
sequentially going through each as per the [upgrade order](#upgrade-order) and load balancers / HA mechanisms handle each node going down accordingly.
For the purposes of this guide we'll upgrade a [10,000 Reference Architecture](../administration/reference_architectures/10k_users.md) built with the Linux package.
For the purposes of this guide we'll upgrade a [200 RPS or 10,000 Reference Architecture](../administration/reference_architectures/10k_users.md) built with the Linux package.
### Consul, PostgreSQL, PgBouncer and Redis

View File

@ -34,17 +34,35 @@ Some features are still in development. View details about [support for each sta
| Assists you in determining the root cause for a pipeline failure and failed CI/CD build. | [Root cause analysis](#root-cause-analysis) | **Tier:** Ultimate <br>**Offering:** GitLab.com <br>**Status:** Experiment |
| Assists you with predicting productivity metrics and identifying anomalies across your software development lifecycle. | [Value stream forecasting](#forecast-deployment-frequency-with-value-stream-forecasting) | **Tier:** Ultimate <br>**Offering:** GitLab.com, Self-managed, GitLab Dedicated <br>**Status:** Experiment |
## Enable AI/ML features
## Controlling GitLab Duo features
For features listed as Experiment and Beta:
There are two different levels at which GitLab Duo features can be controlled. The user level and the content level.
- These features are disabled by default.
- To enable, a user with the Owner role for the group must [turn on this setting](group/manage.md#enable-experiment-and-beta-features).
On GitLab.com, this setting is available for Ultimate subscriptions only.
- These features are subject to the
[Testing Terms of Use](https://handbook.gitlab.com/handbook/legal/testing-agreement/).
GitLab Duo features that are generally available are always enabled for all users that have access to these features. Whether they have access depends on the tier or the add-on as stated in the previous table. [Experimental](../policy/experiment-beta-support.md#experiment) and [Beta](../policy/experiment-beta-support.md#beta) GitLab Duo features need to be enabled as follows.
For all self-managed features:
Owners of projects and groups as well as administrators of self-managed instances can control if GitLab Duo features can be used with their content such as code files.
### Giving access to users
If a feature is dependent on an add-on seat such as [Code Suggestions](project/repository/code_suggestions/index.md), access to the feature can be controlled through [GitLab Duo seat assignment](../subscriptions/subscription-add-ons.md#assign-gitlab-duo-pro-seats).
### Enabling Beta and Experimental AI-powered features
Features listed as Experiment and Beta are disabled by default. These features are subject to the [Testing Agreement](https://handbook.gitlab.com/handbook/legal/testing-agreement/).
#### GitLab.com
Prerequisites
- You must have the Owner role in the top-level group.
To enable Beta and Experimental AI-powered features, use the [Experiment and Beta features checkbox](group/manage.md#enable-experiment-and-beta-features).
#### GitLab self-managed
To enable Beta and Experimental AI-powered features for GitLab versions where GitLab Duo Chat is not yet generally available, see the [GitLab Duo Chat documentation](gitlab_duo_chat.md#for-self-managed-and-gitlab-dedicated).
### Enable outbound connections to enable GitLab Duo features on Self-managed instances
- Your firewalls and HTTP/S proxy servers must allow outbound connections
to `gitlab.com` and `cloud.gitlab.com` on port `443`.
@ -56,15 +74,7 @@ For all self-managed features:
Network policy restrictions on `wss://` traffic can cause issues with some GitLab Duo
chat services. Consider policy updates to allow these services.
For other features:
- [Code Suggestions](project/repository/code_suggestions/index.md) is enabled when you purchase the
GitLab Duo Pro add-on and assign seats to users.
- [Chat](gitlab_duo_chat.md)
- View [how to enable for self-managed](gitlab_duo_chat.md#for-self-managed-and-gitlab-dedicated).
- View [how to enable for GitLab.com](gitlab_duo_chat.md#for-gitlabcom).
### Disable GitLab Duo features
### Disable GitLab Duo features for specific groups or projects or an entire instance
DETAILS:
**Tier:** Premium, Ultimate

View File

@ -87,7 +87,7 @@ The sparkline color ranges from blue to green, where green indicates a positive
Sparklines help you identify patterns in metric trends (such as seasonal changes) over time.
NOTE:
The contributor count metric is available only on GitLab.com at the group-level. To view this metric in the comparison panel, you must [set up ClickHouse](../../integration/clickhouse.md), and enable the [feature flags](../../administration/feature_flags.md) `clickhouse_data_collection` and `event_sync_worker_for_click_house`.
The contributor count metric is available only on GitLab.com at the group-level. To view this metric in the comparison panel, you must [set up ClickHouse](../../integration/clickhouse.md).
### DORA Performers score panel

View File

@ -55,7 +55,7 @@ Prerequisites:
- You must be a member of the project.
- The vulnerability must be a SAST finding.
Learn more about [how to enable all GitLab Duo features](../../ai_features.md#enable-aiml-features).
Learn more about [how to enable all GitLab Duo features](../../ai_features.md#enabling-beta-and-experimental-ai-powered-features).
To explain the vulnerability:
@ -110,7 +110,7 @@ Prerequisites:
- You must be a member of the project.
- The vulnerability must be a SAST finding.
Learn more about [how to enable all GitLab Duo features](../../ai_features.md#enable-aiml-features).
Learn more about [how to enable all GitLab Duo features](../../ai_features.md#enabling-beta-and-experimental-ai-powered-features).
To resolve the vulnerability:

View File

@ -207,6 +207,38 @@ include: # Execute individual project's configuration (if project contains .git
- if: $CI_PIPELINE_SOURCE != 'merge_request_event'
```
#### Compliance pipelines in projects with no configuration file
The [example configuration](#example-configuration) above assumes that all projects contain
a pipeline configuration file (`.gitlab-ci.yml` by default). However, in projects
with no configuration file (and therefore no pipelines by default), the compliance pipeline
fails because the file specified in `include:project` is required.
To only include a configuration file if it exists in a target project, use
[`rules:exists:project`](../../ci/yaml/index.md#rulesexistsproject):
```yaml
include: # Execute individual project's configuration
- project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_SHA'
rules:
- exists:
paths:
- '$CI_CONFIG_PATH'
project: '$CI_PROJECT_PATH'
ref: '$CI_COMMIT_SHA'
```
In this example, a configuration file is only included if it exists for the given `ref`
in the project in `exists:project: $CI_PROJECT_PATH'`.
You cannot use [`rules:exists` with `include`](../../ci/yaml/includes.md#include-with-rulesexists)
to solve this problem because `include:rules:exists` searches for files in the project
in which the `include` is defined. In compliance pipelines, the `include` from the example above
is defined in the project hosting the compliance pipeline configuration file, not the project
running the pipeline.
## Ensure compliance jobs are always run
Compliance pipelines [use GitLab CI/CD](../../ci/index.md) to give you an incredible amount of flexibility

View File

@ -208,7 +208,8 @@ to change their user notification settings to **Watch** instead.
### Edit notification settings for issues, merge requests, and epics
To toggle notifications on an issue, merge request, or epic: on the right sidebar, turn on or off the **Notifications** toggle.
To toggle notifications on an issue, merge request, or epic: on the right sidebar,
turn on or off the **Notifications** (**{notifications}**) toggle.
When you **turn on** notifications, you start receiving notifications on each update, even if you
haven't participated in the discussion.
@ -241,9 +242,9 @@ epics:
| Issue | Reopened | Subscribers and participants. |
| Merge Request | Closed | Subscribers and participants. |
| Merge Request | Conflict | Author and any user that has set the merge request to auto-merge. |
| Merge Request | [Marked as ready](../project/merge_requests/drafts.md) | Watchers and participants. _[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15332) in GitLab 13.10._ |
| Merge Request | [Marked as ready](../project/merge_requests/drafts.md) | Watchers and participants. |
| Merge Request | Merged | Subscribers and participants. |
| Merge Request | Merged when pipeline succeeds | Author, Participants, Watchers, Subscribers, and Custom notification level with this event selected. Custom notification level is ignored for Author, Watchers and Subscribers. _[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211961) in GitLab 13.4._ |
| Merge Request | Merged when pipeline succeeds | Author, Participants, Watchers, Subscribers, and Custom notification level with this event selected. Custom notification level is ignored for Author, Watchers and Subscribers. |
| Merge Request | Milestone changed | Subscribers and participants. |
| Merge Request | Milestone removed | Subscribers and participants. |
| Merge Request | New | Anyone mentioned by username in the description, with notification level "Mention" or higher. |
@ -254,7 +255,7 @@ epics:
| Merge Request | Reopened | Subscribers and participants. |
| Merge Request | Title or description changed | Any new mentions by username. |
| Pipeline | Failed | The author of the pipeline. |
| Pipeline | Fixed | The author of the pipeline. Enabled by default. _[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24309) in GitLab 13.1._ |
| Pipeline | Fixed | The author of the pipeline. Enabled by default. |
| Pipeline | Successful | The author of the pipeline, with Custom notification level for successful pipelines. If the pipeline failed previously, a "Fixed pipeline" message is sent for the first successful pipeline after the failure, and then a "Successful pipeline" message for any further successful pipelines. |
By default, you don't receive notifications for issues, merge requests, or epics created by yourself.
@ -263,7 +264,6 @@ To always receive notifications on your own issues, merge requests, and so on, t
## Notifications for unknown sign-ins
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27211) in GitLab 13.0.
> - Listing the full name and username of the signed-in user [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225183) in GitLab 15.10.
NOTE:
@ -299,8 +299,6 @@ to brute force 2FA.
## Notifications on designs
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217095) in GitLab 13.6.
Email notifications are sent to the participants when someone comments on a design.
The participants are:
@ -342,21 +340,21 @@ a merge request or an issue.
The following table lists all GitLab-specific email headers:
| Header | Description |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `List-Id` | The path of the project in an RFC 2919 mailing list identifier. You can use it for email organization with filters. |
| `X-GitLab-(Resource)-ID` | The ID of the resource the notification is for. The resource, for example, can be `Issue`, `MergeRequest`, `Commit`, or another such resource. |
| Header | Description |
|-------------------------------|-------------|
| `List-Id` | The path of the project in an RFC 2919 mailing list identifier. You can use it for email organization with filters. |
| `X-GitLab-(Resource)-ID` | The ID of the resource the notification is for. The resource, for example, can be `Issue`, `MergeRequest`, `Commit`, or another such resource. |
| `X-GitLab-(Resource)-State` | The state of the resource the notification is for. The resource can be, for example, `Issue` or `MergeRequest`. The value can be `opened`, `closed`, `merged`, or `locked`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130967) in GitLab 16.4. |
| `X-GitLab-ConfidentialIssue` | The boolean value indicating issue confidentiality for notifications. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222908) in GitLab 16.0. |
| `X-GitLab-Discussion-ID` | The ID of the thread the comment belongs to, in notification emails for comments. |
| `X-GitLab-Group-Id` | The group's ID. Only present on notification emails for [epics](../group/epics/index.md). |
| `X-GitLab-Group-Path` | The group's path. Only present on notification emails for [epics](../group/epics/index.md) |
| `X-GitLab-NotificationReason` | The reason for the notification. [See possible values.](#x-gitlab-notificationreason). |
| `X-GitLab-Pipeline-Id` | The ID of the pipeline the notification is for, in notification emails for pipelines. |
| `X-GitLab-Project-Id` | The project's ID. |
| `X-GitLab-Project-Path` | The project's path. |
| `X-GitLab-Project` | The name of the project the notification belongs to. |
| `X-GitLab-Reply-Key` | A unique token to support reply by email. |
| `X-GitLab-ConfidentialIssue` | The boolean value indicating issue confidentiality for notifications. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222908) in GitLab 16.0. |
| `X-GitLab-Discussion-ID` | The ID of the thread the comment belongs to, in notification emails for comments. |
| `X-GitLab-Group-Id` | The group's ID. Only present on notification emails for [epics](../group/epics/index.md). |
| `X-GitLab-Group-Path` | The group's path. Only present on notification emails for [epics](../group/epics/index.md) |
| `X-GitLab-NotificationReason` | The reason for the notification. [See possible values.](#x-gitlab-notificationreason). |
| `X-GitLab-Pipeline-Id` | The ID of the pipeline the notification is for, in notification emails for pipelines. |
| `X-GitLab-Project-Id` | The project's ID. |
| `X-GitLab-Project-Path` | The project's path. |
| `X-GitLab-Project` | The name of the project the notification belongs to. |
| `X-GitLab-Reply-Key` | A unique token to support reply by email. |
### X-GitLab-NotificationReason

View File

@ -24,7 +24,8 @@ cannot merge until the **Draft** flag is removed, even if all other merge criter
You can flag a merge request as a draft in several ways:
- **Viewing a merge request**: In the upper-right corner of the merge request, select **Mark as draft**.
- **Viewing a merge request**: In the upper-right corner of the merge request,
select **Merge request actions** (**{ellipsis_v}**), then **Mark as draft**.
- **Creating or editing a merge request**: Add `[Draft]`, `Draft:` or `(Draft)` to
the beginning of the merge request's title, or select **Mark as draft**
below the **Title** field.

View File

@ -11,6 +11,10 @@ DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - Sidebar actions menu [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85584) in GitLab 14.10 [with a flag](../../../administration/feature_flags.md) named `moved_mr_sidebar`. Enabled by default.
> - Sidebar actions menu [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/373757) to also move actions on issues, incidents, and epics in GitLab 16.0.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127001) in GitLab 16.9. Feature flag `moved_mr_sidebar` removed.
A merge request (MR) is a proposal to incorporate changes from a source branch to a target branch.
When you open a merge request, you can visualize and collaborate on the changes before merge.
@ -171,8 +175,6 @@ DETAILS:
**Tier:** Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - Moved to GitLab Premium in 13.9.
GitLab enables multiple assignees for merge requests, if multiple people are
accountable for it:
@ -256,27 +258,6 @@ This feature works only when a merge request is merged. Selecting **Remove sourc
after merging does not retarget open merge requests. This improvement is
[proposed as a follow-up](https://gitlab.com/gitlab-org/gitlab/-/issues/321559).
## Move sidebar actions
<!-- When the `moved_mr_sidebar` feature flag is removed, delete this topic and update the steps for these actions
like in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87727/diffs?diff_id=522279685#5d9afba799c4af9920dab533571d7abb8b9e9163 -->
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85584) in GitLab 14.10 [with a flag](../../../administration/feature_flags.md) named `moved_mr_sidebar`. Enabled by default.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/373757) to also move actions on issues, incidents, and epics in GitLab 16.0.
When this feature flag is enabled, in the upper-right corner,
**Merge request actions** (**{ellipsis_v}**) contains the following actions:
- The [notifications](../../profile/notifications.md#edit-notification-settings-for-issues-merge-requests-and-epics) toggle
- Mark merge request as ready or [draft](../merge_requests/drafts.md)
- Close merge request
- [Lock discussion](../../discussions/index.md#prevent-comments-by-locking-the-discussion)
- Copy reference
In GitLab 16.0 and later, similar action menus are available on issues, incidents, and epics.
When this feature flag is disabled, these actions are in the right sidebar.
## Merge request workflows
For a software developer working in a team:

View File

@ -19,16 +19,16 @@ GitLab does not limit the number of private projects you can create.
- [Manage projects](working_with_projects.md)
- [Project visibility](../public_access.md)
- [Project settings](working_with_projects.md)
- [Description templates](../../user/project/description_templates.md)
- [Project access tokens](../project/settings/project_access_tokens.md)
- [Deploy keys](../../user/project/deploy_keys/index.md)
- [Deploy tokens](../../user/project/deploy_tokens/index.md)
- [Share projects](../project/members/share_project_with_groups.md)
- [Reserved project and group names](../../user/reserved_names.md)
- [Search](../../user/search/index.md)
- [Badges](../../user/project/badges.md)
- [Code intelligence](../../user/project/code_intelligence.md)
- [Compliance](../../user/compliance/index.md)
- [Description templates](../../user/project/description_templates.md)
- [Deploy keys](../../user/project/deploy_keys/index.md)
- [Deploy tokens](../../user/project/deploy_tokens/index.md)
- [File finder](../../user/project/repository/file_finder.md)
- [Migrating projects](../../user/project/import/index.md)
- [Migrate projects by using file exports](../../user/project/settings/import_export.md)
- [System notes](../../user/project/system_notes.md)
- [Transfer a project to another namespace](../../user/project/import/index.md)

View File

@ -7,7 +7,7 @@ module Gitlab
include ParallelScheduling
def execute
page = 1
page = page_counter.current
loop do
log_info(
@ -21,21 +21,6 @@ module Gitlab
break if pull_requests.empty?
commits_to_fetch = pull_requests.filter_map do |pull_request|
next if already_processed?(pull_request)
next unless pull_request.merged? || pull_request.closed?
[].tap do |commits|
source_sha = pull_request.source_branch_sha
target_sha = pull_request.target_branch_sha
existing_commits = repo.commits_by(oids: [source_sha, target_sha]).map(&:sha)
commits << source_branch_commit(source_sha, pull_request) unless existing_commits.include?(source_sha)
commits << target_branch_commit(target_sha) unless existing_commits.include?(target_sha)
end
end.flatten
# Bitbucket Server keeps tracks of references for open pull requests in
# refs/heads/pull-requests, but closed and merged requests get moved
# into hidden internal refs under stash-refs/pull-requests. As a result,
@ -43,12 +28,10 @@ module Gitlab
#
# This method call explicitly fetches head and start commits for affected pull requests.
# That allows us to correctly assign diffs and commits to merge requests.
fetch_missing_commits(commits_to_fetch)
fetch_missing_commits(pull_requests)
pull_requests.each do |pull_request|
# Needs to come before `already_processed?` as `jobs_remaining` resets to zero when the job restarts and
# jobs_remaining needs to be the total amount of enqueued jobs
job_waiter.jobs_remaining += 1
job_waiter.jobs_remaining = Gitlab::Cache::Import::Caching.increment(job_waiter_remaining_cache_key)
next if already_processed?(pull_request)
@ -60,14 +43,32 @@ module Gitlab
end
page += 1
page_counter.set(page)
end
page_counter.expire!
job_waiter
end
private
def fetch_missing_commits(commits_to_fetch)
def fetch_missing_commits(pull_requests)
commits_to_fetch = pull_requests.filter_map do |pull_request|
next if already_processed?(pull_request)
next unless pull_request.merged? || pull_request.closed?
[].tap do |commits|
source_sha = pull_request.source_branch_sha
target_sha = pull_request.target_branch_sha
existing_commits = repo.commits_by(oids: [source_sha, target_sha]).map(&:sha)
commits << source_branch_commit(source_sha, pull_request) unless existing_commits.include?(source_sha)
commits << target_branch_commit(target_sha) unless existing_commits.include?(target_sha)
end
end.flatten
return if commits_to_fetch.blank?
project.repository.fetch_remote(project.import_url, refmap: commits_to_fetch, prune: false)

View File

@ -5,7 +5,8 @@ module Gitlab
module ParallelScheduling
include Loggable
attr_reader :project, :already_processed_cache_key, :job_waiter_cache_key
attr_reader :project, :page_counter, :already_processed_cache_key,
:job_waiter_cache_key, :job_waiter_remaining_cache_key
# The base cache key to use for tracking already processed objects.
ALREADY_PROCESSED_CACHE_KEY =
@ -15,14 +16,21 @@ module Gitlab
JOB_WAITER_CACHE_KEY =
'bitbucket-server-importer/job-waiter/%{project}/%{collection}'
# The base cache key to use for storing job waiter remaining jobs
JOB_WAITER_REMAINING_CACHE_KEY =
'bitbucket-server-importer/job-waiter-remaining/%{project}/%{collection}'
# project - An instance of `Project`.
def initialize(project)
@project = project
@page_counter = Gitlab::Import::PageCounter.new(project, collection_method, 'bitbucket-server-importer')
@already_processed_cache_key =
format(ALREADY_PROCESSED_CACHE_KEY, project: project.id, collection: collection_method)
@job_waiter_cache_key =
format(JOB_WAITER_CACHE_KEY, project: project.id, collection: collection_method)
@job_waiter_remaining_cache_key = format(JOB_WAITER_REMAINING_CACHE_KEY, project: project.id,
collection: collection_method)
end
private
@ -62,8 +70,9 @@ module Gitlab
@job_waiter ||= begin
key = Gitlab::Cache::Import::Caching.read(job_waiter_cache_key)
key ||= Gitlab::Cache::Import::Caching.write(job_waiter_cache_key, JobWaiter.generate_key)
jobs_remaining = Gitlab::Cache::Import::Caching.read(job_waiter_remaining_cache_key).to_i || 0
JobWaiter.new(0, key)
JobWaiter.new(jobs_remaining, key)
end
end

View File

@ -4,18 +4,37 @@ module Gitlab
module Ci
module Build
class Rules::Rule::Clause::Exists < Rules::Rule::Clause
include Gitlab::Utils::StrongMemoize
# The maximum number of patterned glob comparisons that will be
# performed before the rule assumes that it has a match
MAX_PATTERN_COMPARISONS = 10_000
WILDCARD_NESTED_PATTERN = "**/*"
def initialize(globs)
@globs = Array(globs)
def initialize(clause)
# Remove this variable when FF `ci_support_rules_exists_paths_and_project` is removed
@clause = clause
if complex_exists_enabled?
@globs = Array(clause[:paths])
@project_path = clause[:project]
@ref = clause[:ref]
else
@globs = Array(clause)
end
@top_level_only = @globs.all?(&method(:top_level_glob?))
end
def satisfied_by?(_pipeline, context)
if complex_exists_enabled? && @project_path
# Return early to avoid redundant Gitaly calls
return false unless @globs.any?
context = change_context(context)
end
paths = worktree_paths(context)
exact_globs, extension_globs, pattern_globs = separate_globs(context)
@ -35,6 +54,7 @@ module Gitlab
def expand_globs(context)
@globs.map do |glob|
# TODO: Replace w/ `expand_value(glob, context)` when FF `ci_support_rules_exists_paths_and_project` removed
ExpandVariables.expand_existing(glob, -> { context.variables_hash })
end
end
@ -110,6 +130,79 @@ module Gitlab
def without_wildcard_nested_pattern(glob)
glob.delete_prefix(WILDCARD_NESTED_PATTERN)
end
def change_context(old_context)
user = find_context_user(old_context)
new_project = find_context_project(user, old_context)
new_sha = find_context_sha(new_project, old_context)
Gitlab::Ci::Config::External::Context.new(
project: new_project,
user: user,
sha: new_sha,
variables: old_context.variables
)
end
def find_context_user(context)
context.is_a?(Gitlab::Ci::Config::External::Context) ? context.user : context.pipeline.user
end
def find_context_project(user, context)
full_path = expand_value(@project_path, context)
project = Project.find_by_full_path(full_path)
unless project
raise Rules::Rule::Clause::ParseError,
"rules:exists:project `#{mask_context_variables_from(context, full_path)}` is not a valid project path"
end
unless Ability.allowed?(user, :read_code, project)
raise Rules::Rule::Clause::ParseError,
"rules:exists:project access denied to project " \
"`#{mask_context_variables_from(context, project.full_path)}`"
end
project
end
def find_context_sha(project, context)
return project.commit&.sha unless @ref
ref = expand_value(@ref, context)
commit = project.commit(ref)
unless commit
raise Rules::Rule::Clause::ParseError,
"rules:exists:ref `#{mask_context_variables_from(context, ref)}` is not a valid ref " \
"in project `#{mask_context_variables_from(context, project.full_path)}`"
end
commit.sha
end
def mask_context_variables_from(context, string)
context.variables.reduce(string.dup) do |str, variable|
if variable[:masked]
Gitlab::Ci::MaskSecret.mask!(str, variable[:value])
else
str
end
end
end
def expand_value(value, context)
ExpandVariables.expand_existing(value, -> { context.variables_hash })
end
def complex_exists_enabled?
# We do not need to check the FF `ci_support_rules_exists_paths_and_project` here.
# Instead, we can simply check if the value is a Hash because it can only be a Hash
# if the FF was on when `Entry::Rules::Rule::Exists` was composed. The entry is
# always composed before we reach this point. This also ensures we have the correct
# value type before processing, which is safer.
@clause.is_a?(Hash)
end
end
end
end

View File

@ -13,11 +13,15 @@ module Gitlab
ALLOWED_KEYS = %i[if exists when changes].freeze
ALLOWED_WHEN = %w[never always].freeze
# Remove `exists` when FF `ci_support_rules_exists_paths_and_project` is removed
attributes :if, :exists, :when
entry :changes, Entry::Rules::Rule::Changes,
description: 'File change condition rule.'
entry :exists, Entry::Rules::Rule::Exists,
description: 'File exists condition rule.'
validations do
validates :config, presence: true
validates :config, type: { with: Hash }
@ -25,15 +29,26 @@ module Gitlab
with_options allow_nil: true do
validates :if, expression: true
validates :exists, array_of_strings_or_string: true, allow_blank: true
validates :exists, array_of_strings_or_string: true, allow_blank: true, unless: :complex_exists_enabled?
validates :when, allowed_values: { in: ALLOWED_WHEN }
end
end
def value
config.merge(
changes: (changes_value if changes_defined?)
).compact
if complex_exists_enabled?
config.merge(
changes: (changes_value if changes_defined?),
exists: (exists_value if exists_defined?)
).compact
else
config.merge(
changes: (changes_value if changes_defined?)
).compact
end
end
def complex_exists_enabled?
::Feature.enabled?(:ci_support_rules_exists_paths_and_project, ::Feature.current_request)
end
end
end

View File

@ -14,11 +14,15 @@ module Gitlab
include ::Gitlab::Config::Entry::Configurable
include ::Gitlab::Config::Entry::Attributable
# Remove `exists` when FF `ci_support_rules_exists_paths_and_project` is removed
attributes :if, :exists, :when, :start_in, :allow_failure, :interruptible
entry :changes, Entry::Rules::Rule::Changes,
description: 'File change condition rule.'
entry :exists, Entry::Rules::Rule::Exists,
description: 'File exists condition rule.'
entry :variables, Entry::Variables,
description: 'Environment variables to define for rule conditions.'
@ -39,7 +43,7 @@ module Gitlab
with_options allow_nil: true do
validates :if, expression: true
validates :exists, array_of_strings: true, length: { maximum: 50 }
validates :exists, array_of_strings: true, length: { maximum: 50 }, unless: :complex_exists_enabled?
validates :allow_failure, boolean: true
validates :interruptible, boolean: true
end
@ -61,12 +65,22 @@ module Gitlab
end
def value
config.merge(
changes: (changes_value if changes_defined?),
variables: (variables_value if variables_defined?),
needs: (needs_value if needs_defined?),
auto_cancel: (auto_cancel_value if auto_cancel_defined?)
).compact
if complex_exists_enabled?
config.merge(
changes: (changes_value if changes_defined?),
exists: (exists_value if exists_defined?),
variables: (variables_value if variables_defined?),
needs: (needs_value if needs_defined?),
auto_cancel: (auto_cancel_value if auto_cancel_defined?)
).compact
else
config.merge(
changes: (changes_value if changes_defined?),
variables: (variables_value if variables_defined?),
needs: (needs_value if needs_defined?),
auto_cancel: (auto_cancel_value if auto_cancel_defined?)
).compact
end
end
def specifies_delay?
@ -75,6 +89,10 @@ module Gitlab
def default
end
def complex_exists_enabled?
::Feature.enabled?(:ci_support_rules_exists_paths_and_project, ::Feature.current_request)
end
end
end
end

View File

@ -0,0 +1,69 @@
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
class Rules
class Rule
class Exists < ::Gitlab::Config::Entry::Simplifiable
# TODO: We should not have the String support for `exists`.
# Issue to remove: https://gitlab.com/gitlab-org/gitlab/-/issues/455040
strategy :SimpleExists, if: ->(config) { config.is_a?(String) || config.is_a?(Array) || config.blank? }
strategy :ComplexExists, if: ->(config) { config.is_a?(Hash) }
class SimpleExists < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
validations do
validates :config, array_of_strings: true,
length: { maximum: 50, too_long: 'has too many entries (maximum %{count})' },
if: -> { config.is_a?(Array) }
end
def value
{ paths: Array(config) }
end
end
class ComplexExists < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[paths project ref].freeze
REQUIRED_KEYS = %i[paths].freeze
attributes ALLOWED_KEYS
validations do
validates :config, allowed_keys: ALLOWED_KEYS
validates :config, required_keys: REQUIRED_KEYS
validates :config, required_keys: %i[project], if: :has_ref_value?
with_options allow_nil: true do
validates :paths, array_of_strings: true,
length: { maximum: 50, too_long: 'has too many entries (maximum %{count})' }
validates :project, type: String
validates :ref, type: String
end
end
def value
config.merge(
paths: Array(paths)
).compact
end
end
class UnknownStrategy < ::Gitlab::Config::Entry::Node
def errors
["#{location} should be a string, an array of strings, or a hash"]
end
end
end
end
end
end
end
end
end

View File

@ -34,6 +34,10 @@ module Gitlab
# we can end with different config types like String
next unless config.is_a?(Hash)
if key == :exists
next unless ::Feature.enabled?(:ci_support_rules_exists_paths_and_project, ::Feature.current_request)
end
entry_create!(key, config[key])
end

View File

@ -57,6 +57,7 @@ module Gitlab
config.before_send = method(:before_send_sentry)
config.background_worker_threads = 0
config.send_default_pii = true
config.send_modules = false
config.traces_sample_rate = 0.2 if Gitlab::Utils.to_boolean(ENV['ENABLE_SENTRY_PERFORMANCE_MONITORING'])
yield config if block_given?

View File

@ -701,19 +701,9 @@ module Gitlab
end
end
def cherry_pick(user:, commit:, branch_name:, message:, start_branch_name:, start_repository:, dry_run: false)
args = {
user: user,
commit: commit,
branch_name: branch_name,
message: message,
start_branch_name: start_branch_name,
start_repository: start_repository,
dry_run: dry_run
}
def cherry_pick(...)
wrapped_gitaly_errors do
gitaly_operation_client.user_cherry_pick(**args)
gitaly_operation_client.user_cherry_pick(...)
end
end

View File

@ -235,15 +235,33 @@ module Gitlab
raise Gitlab::Git::CommitError, e
end
def user_cherry_pick(user:, commit:, branch_name:, message:, start_branch_name:, start_repository:, dry_run: false)
response = call_cherry_pick_or_revert(:cherry_pick,
user: user,
commit: commit,
branch_name: branch_name,
message: message,
start_branch_name: start_branch_name,
start_repository: start_repository,
dry_run: dry_run)
# rubocop:disable Metrics/ParameterLists
def user_cherry_pick(
user:, commit:, branch_name:, message:,
start_branch_name:, start_repository:, author_name: nil, author_email: nil, dry_run: false)
request = Gitaly::UserCherryPickRequest.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit: commit.to_gitaly_commit,
branch_name: encode_binary(branch_name),
message: encode_binary(message),
start_branch_name: encode_binary(start_branch_name.to_s),
start_repository: start_repository.gitaly_repository,
commit_author_name: encode_binary(author_name),
commit_author_email: encode_binary(author_email),
dry_run: dry_run,
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = gitaly_client_call(
@repository.storage,
:operation_service,
:user_cherry_pick,
request,
remote_storage: start_repository.storage,
timeout: GitalyClient.long_timeout
)
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update)
rescue GRPC::BadStatus => e
@ -264,16 +282,29 @@ module Gitlab
raise e
end
end
# rubocop:enable Metrics/ParameterLists
def user_revert(user:, commit:, branch_name:, message:, start_branch_name:, start_repository:, dry_run: false)
response = call_cherry_pick_or_revert(:revert,
user: user,
commit: commit,
branch_name: branch_name,
message: message,
start_branch_name: start_branch_name,
start_repository: start_repository,
dry_run: dry_run)
request = Gitaly::UserRevertRequest.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit: commit.to_gitaly_commit,
branch_name: encode_binary(branch_name),
message: encode_binary(message),
start_branch_name: encode_binary(start_branch_name.to_s),
start_repository: start_repository.gitaly_repository,
dry_run: dry_run,
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = gitaly_client_call(
@repository.storage,
:operation_service,
:user_revert,
request,
remote_storage: start_repository.storage,
timeout: GitalyClient.long_timeout
)
if response.pre_receive_error.presence
raise Gitlab::Git::PreReceiveError, response.pre_receive_error
@ -541,31 +572,6 @@ module Gitlab
private
def call_cherry_pick_or_revert(rpc, user:, commit:, branch_name:, message:, start_branch_name:, start_repository:, dry_run:)
request_class = "Gitaly::User#{rpc.to_s.camelcase}Request".constantize
request = request_class.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit: commit.to_gitaly_commit,
branch_name: encode_binary(branch_name),
message: encode_binary(message),
start_branch_name: encode_binary(start_branch_name.to_s),
start_repository: start_repository.gitaly_repository,
dry_run: dry_run,
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
gitaly_client_call(
@repository.storage,
:operation_service,
:"user_#{rpc}",
request,
remote_storage: start_repository.storage,
timeout: GitalyClient.long_timeout
)
end
# rubocop:disable Metrics/ParameterLists
def user_commit_files_request_header(
user, branch_name, commit_message, actions, author_email, author_name,

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
module Gitlab
module Regex
module SemVer
extend self
def optional_prefixed
Regexp.new("\\Av?#{::Gitlab::Regex.unbounded_semver_regex.source}\\z",
::Gitlab::Regex.unbounded_semver_regex.options)
end
end
end
end

View File

@ -44,7 +44,7 @@ module Gitlab
'suggestions_count' => ->(user, suggestion_set) { suggestion_set.suggestions.size },
'co_authored_by' => ->(user, suggestions_set) {
suggestions_set.authors.without(user).map do |author|
"Co-authored-by: #{author.name} <#{author.commit_email_or_default}>"
"#{Commit::CO_AUTHORED_TRAILER}: #{author.name} <#{author.commit_email_or_default}>"
end.join("\n")
}
}.freeze

View File

@ -40671,12 +40671,21 @@ msgstr ""
msgid "Projects with write access"
msgstr ""
msgid "ProjectsEdit|An error occurred updating this project. Please try again."
msgstr ""
msgid "ProjectsEdit|Project was successfully updated."
msgstr ""
msgid "ProjectsNewEdit|Must start with a letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses."
msgstr ""
msgid "ProjectsNewEdit|My awesome project"
msgstr ""
msgid "ProjectsNewEdit|Project description"
msgstr ""
msgid "ProjectsNewEdit|Project description (optional)"
msgstr ""
@ -61414,9 +61423,6 @@ msgstr ""
msgid "must contain only a mastodon username."
msgstr ""
msgid "must follow semantic version"
msgstr ""
msgid "must have a repository"
msgstr ""

View File

@ -77,10 +77,7 @@ module QA
end
end
describe 'OIDC', quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/429723',
type: :flaky
} do
describe 'OIDC', :orchestrated do
let(:consumer_name) { 'gitlab-oidc-consumer' }
let(:redirect_uri) { "#{consumer_host}/users/auth/openid_connect/callback" }
let(:scopes) { %w[openid profile email] }
@ -125,11 +122,7 @@ module QA
it_behaves_like 'Instance OAuth Application', :oidc, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/405137'
end
describe 'OAuth',
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/415011',
type: :flaky
} do
describe 'OAuth', :orchestrated do
let(:consumer_name) { 'gitlab-oauth-consumer' }
let(:redirect_uri) { "#{consumer_host}/users/auth/gitlab/callback" }
let(:scopes) { %w[read_user] }

View File

@ -1040,125 +1040,6 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
end
end
describe "resolving and unresolving" do
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
describe 'POST resolve' do
before do
sign_in user
end
specify { expect(post(:resolve, params: request_params)).to have_request_urgency(:low) }
context "when the user is not authorized to resolve the note" do
it "returns status 404" do
post :resolve, params: request_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context "when the user is authorized to resolve the note" do
before do
project.add_developer(user)
end
context "when the note is not resolvable" do
before do
note.update!(system: true)
end
it "returns status 404" do
post :resolve, params: request_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context "when the note is resolvable" do
it "resolves the note" do
post :resolve, params: request_params
expect(note.reload.resolved?).to be true
expect(note.reload.resolved_by).to eq(user)
end
it "sends notifications if all discussions are resolved" do
expect_next_instance_of(MergeRequests::ResolvedDiscussionNotificationService) do |instance|
expect(instance).to receive(:execute).with(merge_request)
end
post :resolve, params: request_params
end
it "returns the name of the resolving user" do
post :resolve, params: request_params.merge(html: true)
expect(json_response["resolved_by"]).to eq(user.name)
end
it "returns status 200" do
post :resolve, params: request_params
expect(response).to have_gitlab_http_status(:ok)
end
end
end
end
describe 'DELETE unresolve' do
before do
sign_in user
note.resolve!(user)
end
specify { expect(delete(:unresolve, params: request_params)).to have_request_urgency(:low) }
context "when the user is not authorized to resolve the note" do
it "returns status 404" do
delete :unresolve, params: request_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context "when the user is authorized to resolve the note" do
before do
project.add_developer(user)
end
context "when the note is not resolvable" do
before do
note.update!(system: true)
end
it "returns status 404" do
delete :unresolve, params: request_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context "when the note is resolvable" do
it "unresolves the note" do
delete :unresolve, params: request_params
expect(note.reload.resolved?).to be false
end
it "returns status 200" do
delete :unresolve, params: request_params
expect(response).to have_gitlab_http_status(:ok)
end
end
end
end
end
describe 'GET outdated_line_change' do
let(:request_params) do
{

View File

@ -2,7 +2,7 @@
FactoryBot.define do
factory :ci_catalog_resource_version, class: 'Ci::Catalog::Resources::Version' do
version { '1.0.0' }
semver { '1.0.0' }
catalog_resource factory: :ci_catalog_resource
project { catalog_resource.project }

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe 'CI/CD Catalog settings', :js, feature_category: :pipeline_composition do
RSpec.describe 'CI/CD Catalog settings', :js, feature_category: :pipeline_composition, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/455829' do
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:namespace) { create(:group) }
let_it_be_with_reload(:project_with_ci_components) do

View File

@ -1,5 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import getTransferLocationsResponse from 'test_fixtures/api/projects/transfer_locations_page_1.json';
import project from 'test_fixtures/api/projects/put.json';
import * as projectsApi from '~/api/projects_api';
import { DEFAULT_PER_PAGE } from '~/api';
import axios from '~/lib/utils/axios_utils';
@ -81,6 +82,19 @@ describe('~/api/projects_api.js', () => {
});
});
describe('updateProject', () => {
it('posts to the correct URL and returns the data', async () => {
const data = { name: 'Foo bar', description: 'Mock description' };
const expectedUrl = `/api/v7/projects/${projectId}`;
mock.onPut(expectedUrl, data).replyOnce(HTTP_STATUS_OK, project);
await expect(projectsApi.updateProject(projectId, data)).resolves.toMatchObject({
data: project,
});
});
});
describe('deleteProject', () => {
beforeEach(() => {
jest.spyOn(axios, 'delete');

View File

@ -23,4 +23,29 @@ rules:interruptible as integer:
script: exit 0
rules:
- if: $TEST
interruptible: 1
interruptible: 1
# invalid rules:exists
rules:exists as string:
rules:
- exists: abc.md
rules:exists as integer:
rules:
- exists: 1
rules:exists:paths as string:
rules:
- exists:
paths: abc.md
rules:exists:project without paths:
rules:
- exists:
project: my-group/my-project
rules:exists:ref without project:
rules:
- exists:
paths: [abc.md]
ref: main

View File

@ -38,4 +38,27 @@ rules:interruptible as boolean:
script: exit 0
rules:
- if: $TEST
interruptible: true
interruptible: true
# valid rules:exists
rules:exists as an array:
rules:
- exists: [abc.md, def.md]
rules:exists:paths:
rules:
- exists:
paths: [abc.md]
rules:exists:project:
rules:
- exists:
paths: [abc.md]
project: my-group/my-project
rules:exists:project with ref:
rules:
- exists:
paths: [abc.md]
project: my-group/my-project
ref: main

View File

@ -124,3 +124,31 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller, feature_cate
end
end
end
RSpec.describe API::Projects, '(JavaScript fixtures)', type: :request, feature_category: :groups_and_projects do
include ApiHelpers
include JavaScriptFixturesHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
before_all do
project.add_maintainer(user)
end
before do
sign_in(user)
end
it 'api/projects/put.json' do
put api("/projects/#{project.id}", user), params: { name: "#{project.name} updated" }
expect(response).to be_successful
end
it 'api/projects/put_validation_error.json' do
put api("/projects/#{project.id}", user), params: { name: ".", description: 'a' * 2001 }
expect(response).to have_gitlab_http_status(:bad_request)
end
end

View File

@ -1,7 +1,22 @@
import { nextTick } from 'vue';
import { GlSprintf } from '@gitlab/ui';
import project from 'test_fixtures/api/projects/put.json';
import projectValidationError from 'test_fixtures/api/projects/put_validation_error.json';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import App from '~/organizations/projects/edit/components/app.vue';
import NewEditForm from '~/projects/components/new_edit_form.vue';
import { updateProject } from '~/api/projects_api';
import { visitUrlWithAlerts } from '~/lib/utils/url_utility';
import { FORM_FIELD_NAME, FORM_FIELD_DESCRIPTION } from '~/projects/components/constants';
import { createAlert } from '~/alert';
import waitForPromises from 'helpers/wait_for_promises';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
jest.mock('~/api/projects_api');
jest.mock('~/lib/utils/url_utility');
jest.mock('~/alert');
useMockLocationHelper();
describe('OrganizationProjectsEditApp', () => {
let wrapper;
@ -28,6 +43,14 @@ describe('OrganizationProjectsEditApp', () => {
const findForm = () => wrapper.findComponent(NewEditForm);
const submitForm = async () => {
findForm().vm.$emit('submit', {
name: 'Foo bar updated',
description: 'Mock description updated',
});
await nextTick();
};
it('renders page title', () => {
createComponent();
@ -46,4 +69,106 @@ describe('OrganizationProjectsEditApp', () => {
cancelButtonHref: defaultProvide.projectsOrganizationPath,
});
});
describe('when form is submitted', () => {
describe('when API is loading', () => {
beforeEach(async () => {
updateProject.mockResolvedValueOnce({ data: project });
createComponent();
await submitForm();
});
it('sets `NewEditForm` `loading` prop to `true`', () => {
expect(findForm().props('loading')).toBe(true);
});
});
describe('when API request is successful', () => {
beforeEach(async () => {
updateProject.mockResolvedValueOnce({ data: project });
createComponent();
await submitForm();
await waitForPromises();
});
it('calls API with correct variables and reloads the page with success alert', () => {
expect(updateProject).toHaveBeenCalledWith(defaultProvide.project.id, {
name: 'Foo bar updated',
description: 'Mock description updated',
});
expect(visitUrlWithAlerts).toHaveBeenCalledWith(window.location.href, [
{
id: 'organization-project-successfully-updated',
message: 'Project was successfully updated.',
variant: 'info',
},
]);
});
});
describe('when API request is not successful', () => {
describe('when error is a server error', () => {
const error = new Error();
beforeEach(async () => {
updateProject.mockRejectedValueOnce(error);
createComponent();
await submitForm();
await waitForPromises();
});
it('displays error alert', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred updating this project. Please try again.',
error,
captureError: true,
});
});
it('sets `loading` prop to `false`', () => {
expect(findForm().props('loading')).toBe(false);
});
});
describe('when error is a validation error', () => {
const error = { response: { data: projectValidationError } };
beforeEach(async () => {
updateProject.mockRejectedValueOnce(error);
createComponent();
await submitForm();
await waitForPromises();
});
it('sets `loading` prop to `false`', () => {
expect(findForm().props('loading')).toBe(false);
});
it('shows validation error for `Project name` field', () => {
expect(findForm().props('serverValidations')).toMatchObject({
[FORM_FIELD_NAME]:
"Project name can contain only letters, digits, emoji, '_', '.', '+', dashes, or spaces. It must start with a letter, digit, emoji, or '_'.",
});
});
it('shows validation error for `Project description` field', () => {
expect(findForm().props('serverValidations')).toMatchObject({
[FORM_FIELD_DESCRIPTION]:
'Project description is too long (maximum is 2000 characters)',
});
});
describe('when `input-field` event is fired', () => {
beforeEach(() => {
findForm().vm.$emit('input-field', { name: FORM_FIELD_NAME, value: 'foo' });
});
it('clears server validation for that field', () => {
expect(findForm().props('serverValidations')[FORM_FIELD_NAME]).toBeUndefined();
});
});
});
});
});
});

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