Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-06 21:10:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-06 21:10:06 +0300
commit52dbfea964ea55b3393dc4146e541bc651f7e9e3 (patch)
treee28de820d59431bf4ead2a12cebb13092030a811
parent0a5ea888dca19dec6ce473a88c35a4ef95f61a9c (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_manual_todo.yml5
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js2
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue17
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue12
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/index/index.js5
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue15
-rw-r--r--app/graphql/types/container_expiration_policy_cadence_enum.rb2
-rw-r--r--app/graphql/types/container_expiration_policy_keep_enum.rb2
-rw-r--r--app/graphql/types/container_expiration_policy_older_than_enum.rb2
-rw-r--r--app/graphql/types/packages/package_type_enum.rb2
-rw-r--r--app/helpers/learn_gitlab_helper.rb14
-rw-r--r--app/models/ci/pipeline.rb8
-rw-r--r--app/serializers/pipeline_details_entity.rb1
-rw-r--r--app/services/issue_rebalancing_service.rb50
-rw-r--r--app/views/layouts/nav/sidebar/_project_menus.html.haml25
-rw-r--r--app/views/projects/learn_gitlab/index.html.haml2
-rw-r--r--changelogs/unreleased/fix-smtp-pool-errors.yml6
-rw-r--r--changelogs/unreleased/mo-display-artifacts-dropdown.yml5
-rw-r--r--changelogs/unreleased/ph-273179-fixSuggestionsDollarSignReplacement.yml5
-rw-r--r--changelogs/unreleased/ph-groupCreateMergeRequestPerformanceImprovement.yml2
-rw-r--r--config/feature_flags/development/issue_rebalancing_with_retry.yml8
-rw-r--r--doc/administration/geo/disaster_recovery/planned_failover.md5
-rw-r--r--doc/administration/geo/index.md38
-rw-r--r--doc/administration/geo/replication/troubleshooting.md6
-rw-r--r--doc/administration/pages/index.md11
-rw-r--r--doc/api/graphql/reference/index.md4
-rw-r--r--doc/development/usage_ping/dictionary.md6
-rw-r--r--doc/user/project/pages/introduction.md3
-rw-r--r--lib/gitlab/email/handler/service_desk_handler.rb6
-rw-r--r--lib/gitlab/graphql/docs/templates/default.md.haml4
-rw-r--r--lib/gitlab/usage/docs/helper.rb2
-rw-r--r--lib/gitlab/usage/docs/templates/default.md.haml4
-rw-r--r--lib/sidebars/projects/menus/members_menu.rb41
-rw-r--r--lib/sidebars/projects/menus/snippets_menu.rb41
-rw-r--r--lib/sidebars/projects/panel.rb2
-rw-r--r--qa/qa/page/project/menu.rb9
-rw-r--r--spec/benchmarks/banzai_benchmark.rb17
-rw-r--r--spec/frontend/lib/utils/text_markdown_spec.js19
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap6
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap2
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js4
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js3
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/mock_data.js12
-rw-r--r--spec/helpers/learn_gitlab_helper_spec.rb11
-rw-r--r--spec/lib/gitlab/email/handler/service_desk_handler_spec.rb5
-rw-r--r--spec/lib/sidebars/projects/menus/members_menu_spec.rb27
-rw-r--r--spec/lib/sidebars/projects/menus/snippets_menu_spec.rb27
-rw-r--r--spec/models/ci/pipeline_spec.rb14
-rw-r--r--spec/serializers/pipeline_details_entity_spec.rb32
-rw-r--r--spec/services/issue_rebalancing_service_spec.rb71
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb40
-rw-r--r--vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb6
-rw-r--r--vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb22
53 files changed, 511 insertions, 179 deletions
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index eba11804513..7559717ae60 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -13,15 +13,10 @@
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/322903
Graphql/Descriptions:
Exclude:
- - 'app/graphql/types/container_expiration_policy_cadence_enum.rb'
- - 'app/graphql/types/container_expiration_policy_keep_enum.rb'
- - 'app/graphql/types/container_expiration_policy_older_than_enum.rb'
- - 'app/graphql/types/packages/package_type_enum.rb'
- 'app/graphql/types/snippets/blob_action_enum.rb'
- 'app/graphql/types/snippets/type_enum.rb'
- 'app/graphql/types/snippets/visibility_scopes_enum.rb'
- 'ee/app/graphql/ee/types/list_limit_metric_enum.rb'
- - 'ee/app/graphql/types/alert_management/payload_alert_field_name_enum.rb'
- 'ee/app/graphql/types/epic_state_enum.rb'
- 'ee/app/graphql/types/health_status_enum.rb'
- 'ee/app/graphql/types/iteration_state_enum.rb'
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index 1593a363dd1..6ff2af47dd8 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -232,7 +232,7 @@ export function insertMarkdownText({
.join('\n');
}
} else if (tag.indexOf(textPlaceholder) > -1) {
- textToInsert = tag.replace(textPlaceholder, selected.replace(/\\n/g, '\n'));
+ textToInsert = tag.replace(textPlaceholder, () => selected.replace(/\\n/g, '\n'));
} else {
textToInsert = String(startChar) + tag + selected + (wrap ? tag : '');
}
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue
index ef9e13f7ccf..51980b2d971 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue
@@ -18,9 +18,13 @@ export default {
required: true,
type: Object,
},
+ sections: {
+ required: true,
+ type: Object,
+ },
},
maxValue: Object.keys(ACTION_LABELS).length,
- sections: Object.keys(ACTION_SECTIONS),
+ actionSections: Object.keys(ACTION_SECTIONS),
computed: {
progressValue() {
return Object.values(this.actions).filter((a) => a.completed).length;
@@ -38,6 +42,9 @@ export default {
);
return actions;
},
+ svgFor(section) {
+ return this.sections[section].svg;
+ },
},
};
</script>
@@ -59,8 +66,12 @@ export default {
<gl-progress-bar :value="progressValue" :max="$options.maxValue" />
</div>
<div class="row row-cols-1 row-cols-md-3 gl-mt-5">
- <div v-for="section in $options.sections" :key="section" class="col gl-mb-6">
- <learn-gitlab-section-card :section="section" :actions="actionsFor(section)" />
+ <div v-for="section in $options.actionSections" :key="section" class="col gl-mb-6">
+ <learn-gitlab-section-card
+ :section="section"
+ :svg="svgFor(section)"
+ :actions="actionsFor(section)"
+ />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue
index db694a66afd..6a196687a76 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue
@@ -1,6 +1,5 @@
<script>
import { GlCard } from '@gitlab/ui';
-import { imagePath } from '~/lib/utils/common_utils';
import { ACTION_LABELS, ACTION_SECTIONS } from '../constants';
import LearnGitlabSectionLink from './learn_gitlab_section_link.vue';
@@ -16,6 +15,10 @@ export default {
required: true,
type: String,
},
+ svg: {
+ required: true,
+ type: String,
+ },
actions: {
required: true,
type: Object,
@@ -28,17 +31,12 @@ export default {
);
},
},
- methods: {
- svg(section) {
- return imagePath(`learn_gitlab/section_${section}.svg`);
- },
- },
};
</script>
<template>
<gl-card class="gl-pt-0 learn-gitlab-section-card">
<div class="learn-gitlab-section-card-header">
- <img :src="svg(section)" />
+ <img :src="svg" />
<h2 class="gl-font-lg gl-mb-3">{{ $options.i18n[section].title }}</h2>
<p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n[section].description }}</p>
</div>
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js
index d9ad29fad99..ac7c94bdd9e 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js
@@ -12,6 +12,7 @@ function initLearnGitlab() {
}
const actions = convertObjectPropsToCamelCase(JSON.parse(el.dataset.actions));
+ const sections = convertObjectPropsToCamelCase(JSON.parse(el.dataset.sections));
const { learnGitlabA } = gon.experiments;
@@ -20,7 +21,9 @@ function initLearnGitlab() {
return new Vue({
el,
render(createElement) {
- return createElement(learnGitlabA ? LearnGitlabA : LearnGitlabB, { props: { actions } });
+ return createElement(learnGitlabA ? LearnGitlabA : LearnGitlabB, {
+ props: { actions, sections },
+ });
},
});
}
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
index 871a02755d5..85ee44f427d 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
@@ -36,14 +36,6 @@ export default {
};
},
computed: {
- displayPipelineActions() {
- return (
- this.pipeline.flags.retryable ||
- this.pipeline.flags.cancelable ||
- this.pipeline.details.manual_actions.length ||
- this.pipeline.details.has_downloadable_artifacts
- );
- },
actions() {
if (!this.pipeline || !this.pipeline.details) {
return [];
@@ -54,9 +46,6 @@ export default {
isCancelling() {
return this.cancelingPipeline === this.pipeline.id;
},
- showArtifacts() {
- return this.pipeline.details.has_downloadable_artifacts;
- },
},
watch: {
pipeline() {
@@ -79,7 +68,7 @@ export default {
</script>
<template>
- <div v-if="displayPipelineActions" class="gl-text-right">
+ <div class="gl-text-right">
<div class="btn-group">
<pipelines-manual-actions v-if="actions.length > 0" :actions="actions" />
@@ -113,7 +102,7 @@ export default {
@click="handleCancelClick"
/>
- <pipeline-multi-actions v-if="showArtifacts" :pipeline-id="pipeline.id" />
+ <pipeline-multi-actions :pipeline-id="pipeline.id" />
</div>
</div>
</template>
diff --git a/app/graphql/types/container_expiration_policy_cadence_enum.rb b/app/graphql/types/container_expiration_policy_cadence_enum.rb
index bb8bdf2197b..ac923f64b52 100644
--- a/app/graphql/types/container_expiration_policy_cadence_enum.rb
+++ b/app/graphql/types/container_expiration_policy_cadence_enum.rb
@@ -11,7 +11,7 @@ module Types
}.freeze
::ContainerExpirationPolicy.cadence_options.each do |option, description|
- value OPTIONS_MAPPING[option], description, value: option.to_s
+ value OPTIONS_MAPPING[option], description: description, value: option.to_s
end
end
end
diff --git a/app/graphql/types/container_expiration_policy_keep_enum.rb b/app/graphql/types/container_expiration_policy_keep_enum.rb
index 7632df61092..ca6fbbcf5ae 100644
--- a/app/graphql/types/container_expiration_policy_keep_enum.rb
+++ b/app/graphql/types/container_expiration_policy_keep_enum.rb
@@ -12,7 +12,7 @@ module Types
}.freeze
::ContainerExpirationPolicy.keep_n_options.each do |option, description|
- value OPTIONS_MAPPING[option], description, value: option
+ value OPTIONS_MAPPING[option], description: description, value: option
end
end
end
diff --git a/app/graphql/types/container_expiration_policy_older_than_enum.rb b/app/graphql/types/container_expiration_policy_older_than_enum.rb
index da70534b0d7..7364910f8cd 100644
--- a/app/graphql/types/container_expiration_policy_older_than_enum.rb
+++ b/app/graphql/types/container_expiration_policy_older_than_enum.rb
@@ -10,7 +10,7 @@ module Types
}.freeze
::ContainerExpirationPolicy.older_than_options.each do |option, description|
- value OPTIONS_MAPPING[option], description, value: option.to_s
+ value OPTIONS_MAPPING[option], description: description, value: option.to_s
end
end
end
diff --git a/app/graphql/types/packages/package_type_enum.rb b/app/graphql/types/packages/package_type_enum.rb
index e2b5cf3163e..48a13a581a4 100644
--- a/app/graphql/types/packages/package_type_enum.rb
+++ b/app/graphql/types/packages/package_type_enum.rb
@@ -10,7 +10,7 @@ module Types
::Packages::Package.package_types.keys.each do |package_type|
type_name = PACKAGE_TYPE_NAMES.fetch(package_type.to_sym, package_type.capitalize)
- value package_type.to_s.upcase, "Packages from the #{type_name} package manager", value: package_type.to_s
+ value package_type.to_s.upcase, description: "Packages from the #{type_name} package manager", value: package_type.to_s
end
end
end
diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb
index 51dce76c749..16a63f02271 100644
--- a/app/helpers/learn_gitlab_helper.rb
+++ b/app/helpers/learn_gitlab_helper.rb
@@ -36,6 +36,20 @@ module LearnGitlabHelper
Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_b, subject: current_user)
end
+ def onboarding_sections_data
+ {
+ workspace: {
+ svg: image_path("learn_gitlab/section_workspace.svg")
+ },
+ plan: {
+ svg: image_path("learn_gitlab/section_plan.svg")
+ },
+ deploy: {
+ svg: image_path("learn_gitlab/section_deploy.svg")
+ }
+ }
+ end
+
private
def action_urls
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index a03bd1f1818..8b38551a12e 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -1076,14 +1076,6 @@ module Ci
complete? && builds.latest.with_exposed_artifacts.exists?
end
- def has_downloadable_artifacts?
- if downloadable_artifacts.loaded?
- downloadable_artifacts.any?
- else
- downloadable_artifacts.exists?
- end
- end
-
def branch_updated?
strong_memoize(:branch_updated) do
push_details.branch_updated?
diff --git a/app/serializers/pipeline_details_entity.rb b/app/serializers/pipeline_details_entity.rb
index 0ccdd0247b7..db021463c8e 100644
--- a/app/serializers/pipeline_details_entity.rb
+++ b/app/serializers/pipeline_details_entity.rb
@@ -8,7 +8,6 @@ class PipelineDetailsEntity < Ci::PipelineEntity
end
expose :details do
- expose :has_downloadable_artifacts?, as: :has_downloadable_artifacts
expose :artifacts, unless: proc { options[:disable_artifacts] } do |pipeline, options|
rel = pipeline.downloadable_artifacts
diff --git a/app/services/issue_rebalancing_service.rb b/app/services/issue_rebalancing_service.rb
index f9c3388204f..6a8d45b92b2 100644
--- a/app/services/issue_rebalancing_service.rb
+++ b/app/services/issue_rebalancing_service.rb
@@ -3,8 +3,18 @@
class IssueRebalancingService
MAX_ISSUE_COUNT = 10_000
BATCH_SIZE = 100
+ SMALLEST_BATCH_SIZE = 5
+ RETRIES_LIMIT = 3
TooManyIssues = Class.new(StandardError)
+ TIMING_CONFIGURATION = [
+ [0.1.seconds, 0.05.seconds], # short timings, lock_timeout: 100ms, sleep after LockWaitTimeout: 50ms
+ [0.5.seconds, 0.05.seconds],
+ [1.second, 0.5.seconds],
+ [1.second, 0.5.seconds],
+ [5.seconds, 1.second]
+ ].freeze
+
def initialize(issue)
@issue = issue
@base = Issue.relative_positioning_query_base(issue)
@@ -23,14 +33,23 @@ class IssueRebalancingService
assign_positions(start, indexed_ids)
.sort_by(&:first)
.each_slice(BATCH_SIZE) do |pairs_with_position|
- update_positions(pairs_with_position, 'rebalance issue positions in batches ordered by id')
+ if Feature.enabled?(:issue_rebalancing_with_retry)
+ update_positions_with_retry(pairs_with_position, 'rebalance issue positions in batches ordered by id')
+ else
+ update_positions(pairs_with_position, 'rebalance issue positions in batches ordered by id')
+ end
end
end
else
Issue.transaction do
indexed_ids.each_slice(BATCH_SIZE) do |pairs|
pairs_with_position = assign_positions(start, pairs)
- update_positions(pairs_with_position, 'rebalance issue positions')
+
+ if Feature.enabled?(:issue_rebalancing_with_retry)
+ update_positions_with_retry(pairs_with_position, 'rebalance issue positions')
+ else
+ update_positions(pairs_with_position, 'rebalance issue positions')
+ end
end
end
end
@@ -52,12 +71,37 @@ class IssueRebalancingService
end
end
+ def update_positions_with_retry(pairs_with_position, query_name)
+ retries = 0
+ batch_size = pairs_with_position.size
+
+ until pairs_with_position.empty?
+ begin
+ update_positions(pairs_with_position.first(batch_size), query_name)
+ pairs_with_position = pairs_with_position.drop(batch_size)
+ retries = 0
+ rescue ActiveRecord::StatementTimeout, ActiveRecord::QueryCanceled => ex
+ raise ex if batch_size < SMALLEST_BATCH_SIZE
+
+ if (retries += 1) == RETRIES_LIMIT
+ # shrink the batch size in half when RETRIES limit is reached and update still fails perhaps because batch size is still too big
+ batch_size = (batch_size / 2).to_i
+ retries = 0
+ end
+
+ retry
+ end
+ end
+ end
+
def update_positions(pairs_with_position, query_name)
values = pairs_with_position.map do |id, index|
"(#{id}, #{index})"
end.join(', ')
- run_update_query(values, query_name)
+ Gitlab::Database::WithLockRetries.new(timing_configuration: TIMING_CONFIGURATION, klass: self.class).run do
+ run_update_query(values, query_name)
+ end
end
def run_update_query(values, query_name)
diff --git a/app/views/layouts/nav/sidebar/_project_menus.html.haml b/app/views/layouts/nav/sidebar/_project_menus.html.haml
index 951a8bf437d..683d9b401cc 100644
--- a/app/views/layouts/nav/sidebar/_project_menus.html.haml
+++ b/app/views/layouts/nav/sidebar/_project_menus.html.haml
@@ -1,28 +1,3 @@
-- if project_nav_tab? :snippets
- = nav_link(controller: :snippets) do
- = link_to project_snippets_path(@project), class: 'shortcuts-snippets', data: { qa_selector: 'snippets_link' } do
- .nav-icon-container
- = sprite_icon('snippet')
- %span.nav-item-name
- = _('Snippets')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :snippets, html_options: { class: "fly-out-top-item" } ) do
- = link_to project_snippets_path(@project) do
- %strong.fly-out-top-item-name
- = _('Snippets')
-
-= nav_link(controller: :project_members) do
- = link_to project_project_members_path(@project), title: _('Members'), class: 'qa-members-link', id: 'js-onboarding-members-link' do
- .nav-icon-container
- = sprite_icon('users')
- %span.nav-item-name
- = _('Members')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(path: %w[members#show], html_options: { class: "fly-out-top-item" } ) do
- = link_to project_project_members_path(@project) do
- %strong.fly-out-top-item-name
- = _('Members')
-
- if project_nav_tab? :settings
= nav_link(path: sidebar_settings_paths) do
= link_to edit_project_path(@project) do
diff --git a/app/views/projects/learn_gitlab/index.html.haml b/app/views/projects/learn_gitlab/index.html.haml
index 94023b21aab..4935b72d3fa 100644
--- a/app/views/projects/learn_gitlab/index.html.haml
+++ b/app/views/projects/learn_gitlab/index.html.haml
@@ -2,4 +2,4 @@
- page_title _("Learn GitLab")
- add_page_specific_style 'page_bundles/learn_gitlab'
-#js-learn-gitlab-app{ data: { actions: onboarding_actions_data(@project).to_json } }
+#js-learn-gitlab-app{ data: { actions: onboarding_actions_data(@project).to_json, sections: onboarding_sections_data.to_json } }
diff --git a/changelogs/unreleased/fix-smtp-pool-errors.yml b/changelogs/unreleased/fix-smtp-pool-errors.yml
new file mode 100644
index 00000000000..dea75dd797f
--- /dev/null
+++ b/changelogs/unreleased/fix-smtp-pool-errors.yml
@@ -0,0 +1,6 @@
+---
+title: Fix SMTP errors when delivering service desk thank you emails with SMTP pool
+ enabled
+merge_request: 60843
+author:
+type: fixed
diff --git a/changelogs/unreleased/mo-display-artifacts-dropdown.yml b/changelogs/unreleased/mo-display-artifacts-dropdown.yml
new file mode 100644
index 00000000000..1a091b144c5
--- /dev/null
+++ b/changelogs/unreleased/mo-display-artifacts-dropdown.yml
@@ -0,0 +1,5 @@
+---
+title: Stop exposing has_downloadable_artifacts in pipelines.json
+merge_request: 60950
+author:
+type: performance
diff --git a/changelogs/unreleased/ph-273179-fixSuggestionsDollarSignReplacement.yml b/changelogs/unreleased/ph-273179-fixSuggestionsDollarSignReplacement.yml
new file mode 100644
index 00000000000..a5662ea1c2f
--- /dev/null
+++ b/changelogs/unreleased/ph-273179-fixSuggestionsDollarSignReplacement.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed dollar signs in suggestions getting replaced incorrectly
+merge_request: 61041
+author:
+type: fixed
diff --git a/changelogs/unreleased/ph-groupCreateMergeRequestPerformanceImprovement.yml b/changelogs/unreleased/ph-groupCreateMergeRequestPerformanceImprovement.yml
index 0b651e4a4c4..c5acd396d4c 100644
--- a/changelogs/unreleased/ph-groupCreateMergeRequestPerformanceImprovement.yml
+++ b/changelogs/unreleased/ph-groupCreateMergeRequestPerformanceImprovement.yml
@@ -1,5 +1,5 @@
---
-title: Increase load time of project select dropdowns
+title: Decrease load time of project select dropdowns
merge_request: 61117
author:
type: performance
diff --git a/config/feature_flags/development/issue_rebalancing_with_retry.yml b/config/feature_flags/development/issue_rebalancing_with_retry.yml
new file mode 100644
index 00000000000..cba1b77f26e
--- /dev/null
+++ b/config/feature_flags/development/issue_rebalancing_with_retry.yml
@@ -0,0 +1,8 @@
+---
+name: issue_rebalancing_with_retry
+introduced_by_url:
+rollout_issue_url:
+milestone: '13.11'
+type: development
+group: group::project management
+default_enabled: false
diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md
index 96c6482e3db..bd8467f5437 100644
--- a/doc/administration/geo/disaster_recovery/planned_failover.md
+++ b/doc/administration/geo/disaster_recovery/planned_failover.md
@@ -27,7 +27,7 @@ have a high degree of confidence in being able to perform them accurately.
## Not all data is automatically replicated
-If you are using any GitLab features that Geo [doesn't support](../index.md#limitations),
+If you are using any GitLab features that Geo [doesn't support](../replication/datatypes.md#limitations-on-replicationverification),
you must make separate provisions to ensure that the **secondary** node has an
up-to-date copy of any data associated with that feature. This may extend the
required scheduled maintenance period significantly.
@@ -40,8 +40,7 @@ final transfer inside the maintenance window) will then transfer only the
Repository-centric strategies for using `rsync` effectively can be found in the
[moving repositories](../../operations/moving_repositories.md) documentation; these strategies can
-be adapted for use with any other file-based data, such as GitLab Pages (to
-be found in `/var/opt/gitlab/gitlab-rails/shared/pages` if using Omnibus).
+be adapted for use with any other file-based data, such as [GitLab Pages](../../pages/index.md#change-storage-path).
## Preflight checks
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index 8866d1dc9ad..876e3ca2a49 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -181,6 +181,25 @@ When something is marked to be updated in the tracking database instance, asynch
This new architecture allows GitLab to be resilient to connectivity issues between the nodes. It doesn't matter how long the **secondary** node is disconnected from the **primary** node as it will be able to replay all the events in the correct order and become synchronized with the **primary** node again.
+## Limitations
+
+WARNING:
+This list of limitations only reflects the latest version of GitLab. If you are using an older version, extra limitations may be in place.
+
+- Pushing directly to a **secondary** node redirects (for HTTP) or proxies (for SSH) the request to the **primary** node instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/-/issues/1381), except when using Git over HTTP with credentials embedded within the URI. For example, `https://user:password@secondary.tld`.
+- The **primary** node has to be online for OAuth login to happen. Existing sessions and Git are not affected. Support for the **secondary** node to use an OAuth provider independent from the primary is [being planned](https://gitlab.com/gitlab-org/gitlab/-/issues/208465).
+- The installation takes multiple manual steps that together can take about an hour depending on circumstances. We are working on improving this experience. See [Omnibus GitLab issue #2978](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/2978) for details.
+- Real-time updates of issues/merge requests (for example, via long polling) doesn't work on the **secondary** node.
+- [Selective synchronization](replication/configuration.md#selective-synchronization) applies only to files and repositories. Other datasets are replicated to the **secondary** node in full, making it inappropriate for use as an access control mechanism.
+- Object pools for forked project deduplication work only on the **primary** node, and are duplicated on the **secondary** node.
+- GitLab Runners cannot register with a **secondary** node. Support for this is [planned for the future](https://gitlab.com/gitlab-org/gitlab/-/issues/3294).
+- Geo **secondary** nodes can not be configured to [use high-availability configurations of PostgreSQL](https://gitlab.com/groups/gitlab-org/-/epics/2536).
+- [Selective synchronization](replication/configuration.md#selective-synchronization) only limits what repositories are replicated. The entire PostgreSQL data is still replicated. Selective synchronization is not built to accomodate compliance / export control use cases.
+
+### Limitations on replication/verification
+
+There is a complete list of all GitLab [data types](replication/datatypes.md) and [existing support for replication and verification](replication/datatypes.md#limitations-on-replicationverification).
+
## Setup instructions
For setup instructions, see [Setting up Geo](setup/index.md).
@@ -275,25 +294,6 @@ For more information on removing a Geo node, see [Removing **secondary** Geo nod
To find out how to disable Geo, see [Disabling Geo](replication/disable_geo.md).
-## Limitations
-
-WARNING:
-This list of limitations only reflects the latest version of GitLab. If you are using an older version, extra limitations may be in place.
-
-- Pushing directly to a **secondary** node redirects (for HTTP) or proxies (for SSH) the request to the **primary** node instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/-/issues/1381), except when using Git over HTTP with credentials embedded within the URI. For example, `https://user:password@secondary.tld`.
-- The **primary** node has to be online for OAuth login to happen. Existing sessions and Git are not affected. Support for the **secondary** node to use an OAuth provider independent from the primary is [being planned](https://gitlab.com/gitlab-org/gitlab/-/issues/208465).
-- The installation takes multiple manual steps that together can take about an hour depending on circumstances. We are working on improving this experience. See [Omnibus GitLab issue #2978](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/2978) for details.
-- Real-time updates of issues/merge requests (for example, via long polling) doesn't work on the **secondary** node.
-- [Selective synchronization](replication/configuration.md#selective-synchronization) applies only to files and repositories. Other datasets are replicated to the **secondary** node in full, making it inappropriate for use as an access control mechanism.
-- Object pools for forked project deduplication work only on the **primary** node, and are duplicated on the **secondary** node.
-- GitLab Runners cannot register with a **secondary** node. Support for this is [planned for the future](https://gitlab.com/gitlab-org/gitlab/-/issues/3294).
-- Geo **secondary** nodes can not be configured to [use high-availability configurations of PostgreSQL](https://gitlab.com/groups/gitlab-org/-/epics/2536).
-- [Selective synchronization](replication/configuration.md#selective-synchronization) only limits what repositories are replicated. The entire PostgreSQL data is still replicated. Selective synchronization is not built to accomodate compliance / export control use cases.
-
-### Limitations on replication/verification
-
-There is a complete list of all GitLab [data types](replication/datatypes.md) and [existing support for replication and verification](replication/datatypes.md#limitations-on-replicationverification).
-
## Frequently Asked Questions
For answers to common questions, see the [Geo FAQ](replication/faq.md).
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 079a3713c73..d0b00536e23 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -853,6 +853,12 @@ To resolve this issue:
the **primary** node using IPv4 in the `/etc/hosts` file. Alternatively, you should
[enable IPv6 on the **primary** node](https://docs.gitlab.com/omnibus/settings/nginx.html#setting-the-nginx-listen-address-or-addresses).
+### GitLab Pages return 404 errors after promoting
+
+This is due to [Pages data not being managed by Geo](datatypes.md#limitations-on-replicationverification).
+Find advice to resolve those errors in the
+[Pages administration documentation](../../../administration/pages/index.md#404-error-after-promoting-a-geo-secondary-to-a-primary-node).
+
## Fixing client errors
### Authorization errors from LFS HTTP(s) client requests
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index fd5642b2c4b..a422efc0fcf 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -1167,6 +1167,17 @@ date > /var/opt/gitlab/gitlab-rails/shared/pages/.update
If you've customized the Pages storage path, adjust the command above to use your custom path.
+### 404 error after promoting a Geo secondary to a primary node
+
+These are due to the Pages files not being among the
+[supported data types](../geo/replication/datatypes.md#limitations-on-replicationverification).
+
+It is possible to copy the subfolders and files in the [Pages path](#change-storage-path)
+to the new primary node to resolve this.
+For example, you can adapt the `rsync` strategy from the
+[moving repositories documenation](../operations/moving_repositories.md).
+Alternatively, run the CI pipelines of those projects that contain a `pages` job again.
+
### Failed to connect to the internal GitLab API
If you have enabled [API-based configuration](#gitlab-api-based-configuration) and see the following error:
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 7f9bd217224..f88ed6dfcd6 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -24,7 +24,9 @@ Fields that are deprecated are marked with **{warning-solid}**.
Items (fields, enums, etc) that have been removed according to our [deprecation process](../index.md#deprecation-and-removal-process) can be found
in [Removed Items](../removed_items.md).
-<!-- vale gitlab.Spelling = NO -->
+<!-- vale off -->
+<!-- Docs linting disabled after this line. -->
+<!-- See https://docs.gitlab.com/ee/development/documentation/testing.html#disable-vale-tests -->
## `Query` type
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index 234e3d7b5f1..0f49f559c15 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -10,8 +10,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Please do not edit this file directly, check generate_metrics_dictionary task on lib/tasks/gitlab/usage_data.rake.
--->
-<!-- vale gitlab.Spelling = NO -->
-
# Metrics Dictionary
This file is autogenerated, please do not edit directly.
@@ -30,6 +28,10 @@ The Metrics Dictionary is based on the following metrics definition YAML files:
Each table includes a `milestone`, which corresponds to the GitLab version when the metric
was released.
+<!-- vale off -->
+<!-- Docs linting disabled after this line. -->
+<!-- See https://docs.gitlab.com/ee/development/documentation/testing.html#disable-vale-tests -->
+
## Metrics Definitions
### `active_user_count`
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index da2e2e8dcc2..50aa2c4309c 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -302,6 +302,9 @@ A 404 can also be related to incorrect permissions. If [Pages Access Control](pa
navigates to the Pages URL and receives a 404 response, it is possible that the user does not have permission to view the site.
To fix this, verify that the user is a member of the project.
+For Geo instances, 404 errors on Pages occur after promoting a secondary to a primary.
+Find more details in the [Pages administration documentation](../../../administration/pages/index.md#404-error-after-promoting-a-geo-secondary-to-a-primary-node)
+
### Cannot play media content on Safari
Safari requires the web server to support the [Range request header](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/TP40006514-SW6)
diff --git a/lib/gitlab/email/handler/service_desk_handler.rb b/lib/gitlab/email/handler/service_desk_handler.rb
index 80e8b726099..14930e90c9e 100644
--- a/lib/gitlab/email/handler/service_desk_handler.rb
+++ b/lib/gitlab/email/handler/service_desk_handler.rb
@@ -38,7 +38,7 @@ module Gitlab
if from_address
add_email_participant
- send_thank_you_email!
+ send_thank_you_email
end
end
@@ -92,8 +92,8 @@ module Gitlab
end
end
- def send_thank_you_email!
- Notify.service_desk_thank_you_email(@issue.id).deliver_later!
+ def send_thank_you_email
+ Notify.service_desk_thank_you_email(@issue.id).deliver_later
end
def message_including_template
diff --git a/lib/gitlab/graphql/docs/templates/default.md.haml b/lib/gitlab/graphql/docs/templates/default.md.haml
index ef1de1a3e5c..7d42fb3a9f8 100644
--- a/lib/gitlab/graphql/docs/templates/default.md.haml
+++ b/lib/gitlab/graphql/docs/templates/default.md.haml
@@ -17,7 +17,9 @@
Items (fields, enums, etc) that have been removed according to our [deprecation process](../index.md#deprecation-and-removal-process) can be found
in [Removed Items](../removed_items.md).
- <!-- vale gitlab.Spelling = NO -->
+ <!-- vale off -->
+ <!-- Docs linting disabled after this line. -->
+ <!-- See https://docs.gitlab.com/ee/development/documentation/testing.html#disable-vale-tests -->
\
:plain
diff --git a/lib/gitlab/usage/docs/helper.rb b/lib/gitlab/usage/docs/helper.rb
index 6b185a5a1e9..c2e5d467dbb 100644
--- a/lib/gitlab/usage/docs/helper.rb
+++ b/lib/gitlab/usage/docs/helper.rb
@@ -18,8 +18,6 @@ module Gitlab
Please do not edit this file directly, check generate_metrics_dictionary task on lib/tasks/gitlab/usage_data.rake.
--->
-
- <!-- vale gitlab.Spelling = NO -->
MARKDOWN
end
diff --git a/lib/gitlab/usage/docs/templates/default.md.haml b/lib/gitlab/usage/docs/templates/default.md.haml
index 26f1aa4396d..8911ac2ed1a 100644
--- a/lib/gitlab/usage/docs/templates/default.md.haml
+++ b/lib/gitlab/usage/docs/templates/default.md.haml
@@ -19,6 +19,10 @@
Each table includes a `milestone`, which corresponds to the GitLab version when the metric
was released.
+ <!-- vale off -->
+ <!-- Docs linting disabled after this line. -->
+ <!-- See https://docs.gitlab.com/ee/development/documentation/testing.html#disable-vale-tests -->
+
## Metrics Definitions
\
diff --git a/lib/sidebars/projects/menus/members_menu.rb b/lib/sidebars/projects/menus/members_menu.rb
new file mode 100644
index 00000000000..9b7fe5f44ee
--- /dev/null
+++ b/lib/sidebars/projects/menus/members_menu.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class MembersMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_project_members_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ id: 'js-onboarding-members-link'
+ }
+ end
+
+ override :title
+ def title
+ _('Members')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'users'
+ end
+
+ override :render?
+ def render?
+ can?(context.current_user, :read_project_member, context.project)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :project_members }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/snippets_menu.rb b/lib/sidebars/projects/menus/snippets_menu.rb
new file mode 100644
index 00000000000..060341b3c51
--- /dev/null
+++ b/lib/sidebars/projects/menus/snippets_menu.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class SnippetsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_snippets_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-snippets'
+ }
+ end
+
+ override :title
+ def title
+ _('Snippets')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'snippet'
+ end
+
+ override :render?
+ def render?
+ can?(context.current_user, :read_snippet, context.project)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :snippets }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb
index e489bcae7a8..bc37eb262b8 100644
--- a/lib/sidebars/projects/panel.rb
+++ b/lib/sidebars/projects/panel.rb
@@ -22,6 +22,8 @@ module Sidebars
add_menu(Sidebars::Projects::Menus::AnalyticsMenu.new(context))
add_menu(confluence_or_wiki_menu)
add_menu(Sidebars::Projects::Menus::ExternalWikiMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::SnippetsMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::MembersMenu.new(context))
end
override :render_raw_menus_partial
diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb
index 0534157193d..c1a0f02d4ed 100644
--- a/qa/qa/page/project/menu.rb
+++ b/qa/qa/page/project/menu.rb
@@ -13,11 +13,6 @@ module QA
include SubMenus::Settings
include SubMenus::Packages
- view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
- element :snippets_link
- element :members_link
- end
-
def click_merge_requests
within_sidebar do
click_element(:sidebar_menu_link, menu_item: 'Merge requests')
@@ -38,13 +33,13 @@ module QA
def click_snippets
within_sidebar do
- click_element(:snippets_link)
+ click_element(:sidebar_menu_link, menu_item: 'Snippets')
end
end
def click_members
within_sidebar do
- click_element(:members_link)
+ click_element(:sidebar_menu_link, menu_item: 'Members')
end
end
end
diff --git a/spec/benchmarks/banzai_benchmark.rb b/spec/benchmarks/banzai_benchmark.rb
index 05c41eed889..86f7ee7e90b 100644
--- a/spec/benchmarks/banzai_benchmark.rb
+++ b/spec/benchmarks/banzai_benchmark.rb
@@ -88,12 +88,18 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do
def build_filter_text(pipeline, initial_text)
filter_source = {}
input_text = initial_text
+ result = nil
pipeline.filters.each do |filter_klass|
- filter_source[filter_klass] = input_text
+ # store inputs for current filter_klass
+ filter_source[filter_klass] = { input_text: input_text, input_result: result }
- output = filter_klass.call(input_text, context)
+ filter = filter_klass.new(input_text, context, result)
+ output = filter.call
+
+ # save these for the next filter_klass
input_text = output
+ result = filter.result
end
filter_source
@@ -111,7 +117,12 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do
pipeline.filters.each do |filter_klass|
label = filter_klass.name.demodulize.delete_suffix('Filter').truncate(20)
- x.report(label) { filter_klass.call(filter_source[filter_klass], context) }
+ x.report(label) do
+ filter = filter_klass.new(filter_source[filter_klass][:input_text],
+ context,
+ filter_source[filter_klass][:input_result])
+ filter.call
+ end
end
x.compare!
diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js
index b538257fac0..cad500039c0 100644
--- a/spec/frontend/lib/utils/text_markdown_spec.js
+++ b/spec/frontend/lib/utils/text_markdown_spec.js
@@ -51,6 +51,25 @@ describe('init markdown', () => {
expect(textArea.value).toEqual(`${initialValue}- `);
});
+ it('inserts dollar signs correctly', () => {
+ const initialValue = '';
+
+ textArea.value = initialValue;
+ textArea.selectionStart = 0;
+ textArea.selectionEnd = 0;
+
+ insertMarkdownText({
+ textArea,
+ text: textArea.value,
+ tag: '```suggestion:-0+0\n{text}\n```',
+ blockTag: true,
+ selected: '# Does not parse the `$` currently.',
+ wrap: false,
+ });
+
+ expect(textArea.value).toContain('# Does not parse the `$` currently.');
+ });
+
it('inserts the tag on a new line if the current one is not empty', () => {
const initialValue = 'some text';
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
index 981e4c84323..b9566741cfa 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
@@ -68,7 +68,7 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
class="learn-gitlab-section-card-header"
>
<img
- src="/assets/learn_gitlab/section_workspace.svg"
+ src="workspace.svg"
/>
<h2
@@ -246,7 +246,7 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
class="learn-gitlab-section-card-header"
>
<img
- src="/assets/learn_gitlab/section_plan.svg"
+ src="plan.svg"
/>
<h2
@@ -324,7 +324,7 @@ exports[`Learn GitLab Design A renders correctly 1`] = `
class="learn-gitlab-section-card-header"
>
<img
- src="/assets/learn_gitlab/section_deploy.svg"
+ src="deploy.svg"
/>
<h2
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap
index ad8db0822cc..9e00ace761c 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap
@@ -11,7 +11,7 @@ exports[`Learn GitLab Section Card renders correctly 1`] = `
class="learn-gitlab-section-card-header"
>
<img
- src="/assets/learn_gitlab/section_workspace.svg"
+ src="workspace.svg"
/>
<h2
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js
index 64ace341038..ac997c1f237 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js
+++ b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js
@@ -1,13 +1,13 @@
import { GlProgressBar } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import LearnGitlabA from '~/pages/projects/learn_gitlab/components/learn_gitlab_a.vue';
-import { testActions } from './mock_data';
+import { testActions, testSections } from './mock_data';
describe('Learn GitLab Design A', () => {
let wrapper;
const createWrapper = () => {
- wrapper = mount(LearnGitlabA, { propsData: { actions: testActions } });
+ wrapper = mount(LearnGitlabA, { propsData: { actions: testActions, sections: testSections } });
};
beforeEach(() => {
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js
index de6aca08235..3a511a009a9 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js
+++ b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js
@@ -3,6 +3,7 @@ import LearnGitlabSectionCard from '~/pages/projects/learn_gitlab/components/lea
import { testActions } from './mock_data';
const defaultSection = 'workspace';
+const testImage = 'workspace.svg';
describe('Learn GitLab Section Card', () => {
let wrapper;
@@ -14,7 +15,7 @@ describe('Learn GitLab Section Card', () => {
const createWrapper = () => {
wrapper = shallowMount(LearnGitlabSectionCard, {
- propsData: { section: defaultSection, actions: testActions },
+ propsData: { section: defaultSection, actions: testActions, svg: testImage },
});
};
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/mock_data.js b/spec/frontend/pages/projects/learn_gitlab/components/mock_data.js
index d6ee2b00c8e..8d6ac737db8 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/mock_data.js
+++ b/spec/frontend/pages/projects/learn_gitlab/components/mock_data.js
@@ -45,3 +45,15 @@ export const testActions = {
svg: 'http://example.com/images/illustration.svg',
},
};
+
+export const testSections = {
+ workspace: {
+ svg: 'workspace.svg',
+ },
+ deploy: {
+ svg: 'deploy.svg',
+ },
+ plan: {
+ svg: 'plan.svg',
+ },
+};
diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb
index 780bb0a1408..cf0d329c36f 100644
--- a/spec/helpers/learn_gitlab_helper_spec.rb
+++ b/spec/helpers/learn_gitlab_helper_spec.rb
@@ -96,6 +96,17 @@ RSpec.describe LearnGitlabHelper do
end
end
+ describe '.onboarding_sections_data' do
+ subject(:sections) { helper.onboarding_sections_data }
+
+ it 'has the right keys' do
+ expect(sections.keys).to contain_exactly(:deploy, :plan, :workspace)
+ end
+ it 'has the svg' do
+ expect(sections.values.map { |section| section.keys }).to eq([[:svg]] * 3)
+ end
+ end
+
describe '.learn_gitlab_experiment_tracking_category' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index 7436765e8ee..6d26b3e1064 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -90,11 +90,6 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
context 'when quick actions are present' do
let(:label) { create(:label, project: project, title: 'label1') }
let(:milestone) { create(:milestone, project: project) }
- let!(:user) { create(:user, username: 'user1') }
-
- before do
- project.add_developer(user)
- end
it 'applies quick action commands present on templates' do
file_content = %(Text from template \n/label ~#{label.title} \n/milestone %"#{milestone.name}"")
diff --git a/spec/lib/sidebars/projects/menus/members_menu_spec.rb b/spec/lib/sidebars/projects/menus/members_menu_spec.rb
new file mode 100644
index 00000000000..ecb02b657b0
--- /dev/null
+++ b/spec/lib/sidebars/projects/menus/members_menu_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Projects::Menus::MembersMenu do
+ let(:project) { build(:project) }
+ let(:user) { project.owner }
+ let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
+
+ subject { described_class.new(context) }
+
+ describe '#render?' do
+ context 'when user cannot access members' do
+ let(:user) { nil }
+
+ it 'returns false' do
+ expect(subject.render?).to eq false
+ end
+ end
+
+ context 'when user can access members' do
+ it 'returns true' do
+ expect(subject.render?).to eq true
+ end
+ end
+ end
+end
diff --git a/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb b/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb
new file mode 100644
index 00000000000..af219e4a742
--- /dev/null
+++ b/spec/lib/sidebars/projects/menus/snippets_menu_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Projects::Menus::SnippetsMenu do
+ let(:project) { build(:project) }
+ let(:user) { project.owner }
+ let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
+
+ subject { described_class.new(context) }
+
+ describe '#render?' do
+ context 'when user cannot access snippets' do
+ let(:user) { nil }
+
+ it 'returns false' do
+ expect(subject.render?).to eq false
+ end
+ end
+
+ context 'when user can access snippets' do
+ it 'returns true' do
+ expect(subject.render?).to eq true
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index dabb0f8ee8d..134fb1143cc 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -4491,18 +4491,4 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
.not_to exceed_query_limit(control_count)
end
end
-
- describe '#has_downloadable_artifacts?' do
- it 'returns false when when pipeline does not have downloadable artifacts' do
- pipeline = create(:ci_pipeline, :success)
-
- expect(pipeline.has_downloadable_artifacts?). to eq(false)
- end
-
- it 'returns false when when pipeline does not have downloadable artifacts' do
- pipeline = create(:ci_pipeline, :with_codequality_reports)
-
- expect(pipeline.has_downloadable_artifacts?). to eq(true)
- end
- end
end
diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb
index 41357212632..5756656d146 100644
--- a/spec/serializers/pipeline_details_entity_spec.rb
+++ b/spec/serializers/pipeline_details_entity_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe PipelineDetailsEntity do
expect(subject[:details])
.to include :duration, :finished_at
expect(subject[:details])
- .to include :stages, :artifacts, :has_downloadable_artifacts, :manual_actions, :scheduled_actions
+ .to include :stages, :artifacts, :manual_actions, :scheduled_actions
expect(subject[:details][:status]).to include :icon, :favicon, :text, :label
end
@@ -186,35 +186,5 @@ RSpec.describe PipelineDetailsEntity do
end
it_behaves_like 'public artifacts'
-
- context 'when pipeline has downloadable artifacts' do
- subject(:entity) { described_class.represent(pipeline, request: request, disable_artifacts: disable_artifacts).as_json }
-
- let_it_be(:pipeline) { create(:ci_pipeline, :with_codequality_reports) }
-
- context 'when disable_artifacts is true' do
- subject(:entity) { described_class.represent(pipeline, request: request, disable_artifacts: true).as_json }
-
- it 'excludes artifacts data' do
- expect(entity[:details]).not_to include(:artifacts)
- end
-
- it 'returns true for has_downloadable_artifacts' do
- expect(entity[:details][:has_downloadable_artifacts]).to eq(true)
- end
- end
-
- context 'when disable_artifacts is false' do
- subject(:entity) { described_class.represent(pipeline, request: request, disable_artifacts: false).as_json }
-
- it 'includes artifacts data' do
- expect(entity[:details]).to include(:artifacts)
- end
-
- it 'returns true for has_downloadable_artifacts' do
- expect(entity[:details][:has_downloadable_artifacts]).to eq(true)
- end
- end
- end
end
end
diff --git a/spec/services/issue_rebalancing_service_spec.rb b/spec/services/issue_rebalancing_service_spec.rb
index 7b3d4213b24..1c7f74264b7 100644
--- a/spec/services/issue_rebalancing_service_spec.rb
+++ b/spec/services/issue_rebalancing_service_spec.rb
@@ -3,31 +3,35 @@
require 'spec_helper'
RSpec.describe IssueRebalancingService do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project, reload: true) { create(:project) }
let_it_be(:user) { project.creator }
let_it_be(:start) { RelativePositioning::START_POSITION }
let_it_be(:max_pos) { RelativePositioning::MAX_POSITION }
let_it_be(:min_pos) { RelativePositioning::MIN_POSITION }
let_it_be(:clump_size) { 300 }
- let_it_be(:unclumped) do
- (0..clump_size).to_a.map do |i|
+ let_it_be(:unclumped, reload: true) do
+ (1..clump_size).to_a.map do |i|
create(:issue, project: project, author: user, relative_position: start + (1024 * i))
end
end
- let_it_be(:end_clump) do
- (0..clump_size).to_a.map do |i|
+ let_it_be(:end_clump, reload: true) do
+ (1..clump_size).to_a.map do |i|
create(:issue, project: project, author: user, relative_position: max_pos - i)
end
end
- let_it_be(:start_clump) do
- (0..clump_size).to_a.map do |i|
+ let_it_be(:start_clump, reload: true) do
+ (1..clump_size).to_a.map do |i|
create(:issue, project: project, author: user, relative_position: min_pos + i)
end
end
+ before do
+ stub_feature_flags(issue_rebalancing_with_retry: false)
+ end
+
def issues_in_position_order
project.reload.issues.reorder(relative_position: :asc).to_a
end
@@ -101,19 +105,70 @@ RSpec.describe IssueRebalancingService do
end
end
+ shared_examples 'rebalancing is retried on statement timeout exceptions' do
+ subject { described_class.new(project.issues.first) }
+
+ it 'retries update statement' do
+ call_count = 0
+ allow(subject).to receive(:run_update_query) do
+ call_count += 1
+ if call_count < 13
+ raise(ActiveRecord::QueryCanceled)
+ else
+ call_count = 0 if call_count == 13 + 16 # 16 = 17 sub-batches - 1 call that succeeded as part of 5th batch
+ true
+ end
+ end
+
+ # call math:
+ # batches start at 100 and are split in half after every 3 retries if ActiveRecord::StatementTimeout exception is raised.
+ # We raise ActiveRecord::StatementTimeout exception for 13 calls:
+ # 1. 100 => 3 calls
+ # 2. 100/2=50 => 3 calls + 3 above = 6 calls, raise ActiveRecord::StatementTimeout
+ # 3. 50/2=25 => 3 calls + 6 above = 9 calls, raise ActiveRecord::StatementTimeout
+ # 4. 25/2=12 => 3 calls + 9 above = 12 calls, raise ActiveRecord::StatementTimeout
+ # 5. 12/2=6 => 1 call + 12 above = 13 calls, run successfully
+ #
+ # so out of 100 elements we created batches of 6 items => 100/6 = 17 sub-batches of 6 or less elements
+ #
+ # project.issues.count: 900 issues, so 9 batches of 100 => 9 * (13+16) = 261
+ expect(subject).to receive(:update_positions).exactly(261).times.and_call_original
+
+ subject.execute
+ end
+ end
+
context 'when issue_rebalancing_optimization feature flag is on' do
before do
stub_feature_flags(issue_rebalancing_optimization: true)
end
it_behaves_like 'IssueRebalancingService shared examples'
+
+ context 'when issue_rebalancing_with_retry feature flag is on' do
+ before do
+ stub_feature_flags(issue_rebalancing_with_retry: true)
+ end
+
+ it_behaves_like 'IssueRebalancingService shared examples'
+ it_behaves_like 'rebalancing is retried on statement timeout exceptions'
+ end
end
- context 'when issue_rebalancing_optimization feature flag is on' do
+ context 'when issue_rebalancing_optimization feature flag is off' do
before do
stub_feature_flags(issue_rebalancing_optimization: false)
end
it_behaves_like 'IssueRebalancingService shared examples'
+
+ context 'when issue_rebalancing_with_retry feature flag is on' do
+ before do
+ stub_feature_flags(issue_rebalancing_with_retry: true)
+ end
+
+ it_behaves_like 'IssueRebalancingService shared examples'
+ it_behaves_like 'rebalancing is retried on statement timeout exceptions'
+ end
end
end
diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index 8654f10f72c..6433aea6cd8 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -863,6 +863,46 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
+ describe 'Snippets' do
+ before do
+ render
+ end
+
+ context 'when user can access snippets' do
+ it 'shows Snippets link' do
+ expect(rendered).to have_link('Snippets', href: project_snippets_path(project))
+ end
+ end
+
+ context 'when user cannot access snippets' do
+ let(:user) { nil }
+
+ it 'does not show Snippets link' do
+ expect(rendered).not_to have_link('Snippets')
+ end
+ end
+ end
+
+ describe 'Members' do
+ before do
+ render
+ end
+
+ context 'when user can access members' do
+ it 'show Members link' do
+ expect(rendered).to have_link('Members', href: project_project_members_path(project))
+ end
+ end
+
+ context 'when user cannot access members' do
+ let(:user) { nil }
+
+ it 'show Members link' do
+ expect(rendered).not_to have_link('Members')
+ end
+ end
+ end
+
describe 'operations settings tab' do
describe 'archive projects' do
before do
diff --git a/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb b/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb
index ab8a7652058..b0c82a3db71 100644
--- a/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb
+++ b/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb
@@ -30,5 +30,11 @@ module Mail
def deliver!(mail)
@pool.with { |conn| conn.deliver!(mail) }
end
+
+ # This makes it compatible with Mail's `#deliver!` method
+ # https://github.com/mikel/mail/blob/22a7afc23f253319965bf9228a0a430eec94e06d/lib/mail/message.rb#L271
+ def settings
+ {}
+ end
end
end
diff --git a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
index aa2a0e19ac8..bbe5ef8b068 100644
--- a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
+++ b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
@@ -64,5 +64,27 @@ describe Mail::SMTPPool do
expect(MockSMTP.deliveries.size).to eq(1)
end
+
+ context 'when called from Mail:Message' do
+ before do
+ mail.delivery_method(described_class, { pool: described_class.create_pool })
+ end
+
+ describe '#deliver' do
+ it 'delivers mail' do
+ mail.deliver
+
+ expect(MockSMTP.deliveries.size).to eq(1)
+ end
+ end
+
+ describe '#deliver!' do
+ it 'delivers mail' do
+ mail.deliver!
+
+ expect(MockSMTP.deliveries.size).to eq(1)
+ end
+ end
+ end
end
end