Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-05-19 18:10:39 +00:00
parent a6508d0028
commit e4fc62c0af
56 changed files with 625 additions and 246 deletions

View File

@ -55,21 +55,25 @@ export const createNodeDict = (nodes) => {
export const makeLinksFromNodes = (nodes, nodeDict) => {
const constantLinkValue = 10; // all links are the same weight
return nodes
.map((group) => {
return group.jobs.map((job) => {
if (!job.needs) {
return [];
}
.map(({ jobs, name: groupName }) =>
jobs.map(({ needs = [] }) =>
needs.reduce((acc, needed) => {
// It's possible that we have an optional job, which
// is being needed by another job. In that scenario,
// the needed job doesn't exist, so we don't want to
// create link for it.
if (nodeDict[needed]?.name) {
acc.push({
source: nodeDict[needed].name,
target: groupName,
value: constantLinkValue,
});
}
return job.needs.map((needed) => {
return {
source: nodeDict[needed]?.name,
target: group.name,
value: constantLinkValue,
};
});
});
})
return acc;
}, []),
),
)
.flat(2);
};

View File

@ -39,7 +39,13 @@ export const generateJobNeedsDict = (jobs = {}) => {
}
return jobs[jobName].needs
.map((job) => {
.reduce((needsAcc, job) => {
// It's possible that a needs refer to an optional job
// that is not defined in which case we don't add that entry
if (!jobs[job]) {
return needsAcc;
}
// If we already have the needs of a job in the accumulator,
// then we use the memoized data instead of the recursive call
// to save some performance.
@ -50,11 +56,11 @@ export const generateJobNeedsDict = (jobs = {}) => {
// to the list of `needs` to ensure we can properly reference it.
const group = jobs[job];
if (group.size > 1) {
return [job, group.name, newNeeds];
return [...needsAcc, job, group.name, newNeeds];
}
return [job, newNeeds];
})
return [...needsAcc, job, newNeeds];
}, [])
.flat(Infinity);
};

View File

@ -363,21 +363,8 @@
// Collapsed nav
.toggle-sidebar-button,
.close-nav-button,
.toggle-right-sidebar-button {
transition: width $sidebar-transition-duration;
height: $toggle-sidebar-height;
padding: 0 $gl-padding;
background-color: $gray-light;
border: 0;
color: $gl-text-color-secondary;
display: flex;
align-items: center;
&:hover {
background-color: $border-color;
color: $gl-text-color;
}
.close-nav-button {
@include side-panel-toggle;
}
.toggle-sidebar-button,
@ -396,10 +383,6 @@
}
}
.toggle-right-sidebar-button {
border-bottom: 1px solid $border-color;
}
.collapse-text {
white-space: nowrap;
overflow: hidden;

View File

@ -446,3 +446,19 @@
}
}
}
@mixin side-panel-toggle {
transition: width $sidebar-transition-duration;
height: $toggle-sidebar-height;
padding: 0 $gl-padding;
background-color: $gray-light;
border: 0;
color: $gl-text-color-secondary;
display: flex;
align-items: center;
&:hover {
background-color: $border-color;
color: $gl-text-color;
}
}

View File

@ -232,3 +232,8 @@
}
}
}
.toggle-right-sidebar-button {
@include side-panel-toggle;
border-bottom: 1px solid $border-color;
}

View File

@ -5,6 +5,12 @@
}
.avatar-image {
margin-bottom: $grid-size;
.avatar {
float: none;
}
@include media-breakpoint-up(sm) {
float: left;
margin-bottom: 0;

View File

@ -9,6 +9,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
respond_to do |format|
format.html do
@issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_loading_conflict_ui_action(user: current_user)
end
format.json do
@ -42,6 +43,8 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
def resolve_conflicts
return render_404 unless @conflicts_list.can_be_resolved_in_ui?
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_resolve_conflict_action(user: current_user)
if @merge_request.can_be_merged?
render status: :bad_request, json: { message: _('The merge conflicts for this merge request have already been resolved.') }
return

View File

@ -524,7 +524,7 @@ class Issue < ApplicationRecord
def could_not_move(exception)
# Symptom of running out of space - schedule rebalancing
IssueRebalancingWorker.perform_async(nil, project_id)
IssueRebalancingWorker.perform_async(nil, *project.self_or_root_group_ids)
end
end

View File

@ -2561,6 +2561,17 @@ class Project < ApplicationRecord
end
end
# for projects that are part of user namespace, return project.
def self_or_root_group_ids
if group
root_group = root_namespace
else
project = self
end
[project&.id, root_group&.id]
end
def package_already_taken?(package_name)
namespace.root_ancestor.all_projects
.joins(:packages)

View File

@ -15,14 +15,13 @@ class IssueRebalancingService
[5.seconds, 1.second]
].freeze
def initialize(issue)
@issue = issue
@base = Issue.relative_positioning_query_base(issue)
def initialize(projects_collection)
@root_namespace = projects_collection.take.root_namespace # rubocop:disable CodeReuse/ActiveRecord
@base = Issue.in_projects(projects_collection)
end
def execute
gates = [issue.project, issue.project.group].compact
return unless gates.any? { |gate| Feature.enabled?(:rebalance_issues, gate) }
return unless Feature.enabled?(:rebalance_issues, root_namespace)
raise TooManyIssues, "#{issue_count} issues" if issue_count > MAX_ISSUE_COUNT
@ -57,7 +56,7 @@ class IssueRebalancingService
private
attr_reader :issue, :base
attr_reader :root_namespace, :base
# rubocop: disable CodeReuse/ActiveRecord
def indexed_ids

View File

@ -29,7 +29,7 @@ module Issues
gates = [issue.project, issue.project.group].compact
return unless gates.any? { |gate| Feature.enabled?(:rebalance_issues, gate) }
IssueRebalancingWorker.perform_async(nil, issue.project_id)
IssueRebalancingWorker.perform_async(nil, *issue.project.self_or_root_group_ids)
end
private

View File

@ -69,8 +69,7 @@ class WebHookService
http_status: response.code,
message: response.to_s
}
rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH,
Net::OpenTimeout, Net::ReadTimeout, Gitlab::HTTP::BlockedUrlError, Gitlab::HTTP::RedirectionTooDeep,
rescue *Gitlab::HTTP::HTTP_ERRORS,
Gitlab::Json::LimitedEncoder::LimitExceeded, URI::InvalidURIError => e
execution_duration = Gitlab::Metrics::System.monotonic_time - start_time
log_execution(

View File

@ -11,7 +11,7 @@
.row.js-search-settings-section
.col-lg-4.profile-settings-sidebar
%h4.gl-mt-0
= s_("Profiles|Public Avatar")
= s_("Profiles|Public avatar")
%p
- if @user.avatar?
- if gravatar_enabled?
@ -27,18 +27,17 @@
.md
= brand_profile_image_guidelines
.col-lg-8
.clearfix.avatar-image.gl-mb-3
.avatar-image
= link_to avatar_icon_for_user(@user, 400), target: '_blank', rel: 'noopener noreferrer' do
= image_tag avatar_icon_for_user(@user, 160), alt: '', class: 'avatar s160'
= image_tag avatar_icon_for_user(@user, 96), alt: '', class: 'avatar s96'
%h5.gl-mt-0= s_("Profiles|Upload new avatar")
.gl-mt-2.gl-mb-3
%button.gl-button.btn.js-choose-user-avatar-button{ type: 'button' }= s_("Profiles|Choose file...")
.gl-my-3
%button.gl-button.btn.btn-default.js-choose-user-avatar-button{ type: 'button' }= s_("Profiles|Choose file...")
%span.avatar-file-name.gl-ml-3.js-avatar-filename= s_("Profiles|No file chosen.")
= f.file_field_without_bootstrap :avatar, class: 'js-user-avatar-input hidden', accept: 'image/*'
.form-text.text-muted= s_("Profiles|The maximum file size allowed is 200KB.")
.gl-text-gray-500= s_("Profiles|The maximum file size allowed is 200KB.")
- if @user.avatar?
%hr
= link_to s_("Profiles|Remove avatar"), profile_avatar_path, data: { confirm: s_("Profiles|Avatar will be removed. Are you sure?") }, method: :delete, class: 'gl-button btn btn-danger btn-inverted'
= link_to s_("Profiles|Remove avatar"), profile_avatar_path, data: { confirm: s_("Profiles|Avatar will be removed. Are you sure?") }, method: :delete, class: 'gl-button btn btn-danger-secondary btn-sm gl-mt-5'
.col-lg-12
%hr
.row.js-search-settings-section
@ -124,10 +123,10 @@
= f.check_box :include_private_contributions, label: s_('Profiles|Include private contributions on my profile'), wrapper_class: 'mb-2', inline: true
.help-block
= s_("Profiles|Choose to show contributions of private projects on your public profile without any project, repository or organization information")
.row.gl-mt-3.gl-mb-3.gl-justify-content-end
.col-lg-8
= f.submit s_("Profiles|Update profile settings"), class: 'gl-button btn btn-confirm'
= link_to _("Cancel"), user_path(current_user), class: 'gl-button btn btn-cancel'
.row.gl-justify-content-end.gl-mt-5
.col-lg-8.gl-display-flex
= f.submit s_("Profiles|Update profile settings"), class: 'gl-button btn btn-confirm gl-mr-3'
= link_to _("Cancel"), user_path(current_user), class: 'gl-button btn btn-default btn-cancel'
.modal.modal-profile-crop{ data: { cropper_css_path: ActionController::Base.helpers.stylesheet_path('lazy_bundles/cropper.css') } }
.modal-dialog

View File

@ -19,9 +19,6 @@
%li
.monospace
= File.basename(file)
- if File.dirname(file).ends_with?('plugins')
.text-warning
= _('Plugins directory is deprecated and will be removed in 14.0. Please move this file into /file_hooks directory.')
- else
.card.bg-light.text-center

View File

@ -41,7 +41,7 @@ class IssuePlacementWorker
IssuePlacementWorker.perform_async(nil, leftover.project_id) if leftover.present?
rescue RelativePositioning::NoSpaceLeft => e
Gitlab::ErrorTracking.log_exception(e, issue_id: issue_id, project_id: project_id)
IssueRebalancingWorker.perform_async(nil, project_id.presence || issue.project_id)
IssueRebalancingWorker.perform_async(nil, *root_namespace_id_to_rebalance(issue, project_id))
end
def find_issue(issue_id, project_id)
@ -53,4 +53,11 @@ class IssuePlacementWorker
project.issues.take
end
# rubocop: enable CodeReuse/ActiveRecord
private
def root_namespace_id_to_rebalance(issue, project_id)
project_id = project_id.presence || issue.project_id
Project.find(project_id)&.self_or_root_group_ids
end
end

View File

@ -9,21 +9,44 @@ class IssueRebalancingWorker
urgency :low
feature_category :issue_tracking
tags :exclude_from_kubernetes
deduplicate :until_executed, including_scheduled: true
def perform(ignore = nil, project_id = nil)
return if project_id.nil?
def perform(ignore = nil, project_id = nil, root_namespace_id = nil)
# we need to have exactly one of the project_id and root_namespace_id params be non-nil
raise ArgumentError, "Expected only one of the params project_id: #{project_id} and root_namespace_id: #{root_namespace_id}" if project_id && root_namespace_id
return if project_id.nil? && root_namespace_id.nil?
project = Project.find(project_id)
# pull the projects collection to be rebalanced either the project if namespace is not a group(i.e. user namesapce)
# or the root namespace, this also makes the worker backward compatible with previous version where a project_id was
# passed as the param
projects_to_rebalance = projects_collection(project_id, root_namespace_id)
# Temporary disable reabalancing for performance reasons
# something might have happened with the namespace between scheduling the worker and actually running it,
# maybe it was removed.
if projects_to_rebalance.blank?
Gitlab::ErrorTracking.log_exception(
ArgumentError.new("Projects to be rebalanced not found for arguments: project_id #{project_id}, root_namespace_id: #{root_namespace_id}"),
{ project_id: project_id, root_namespace_id: root_namespace_id })
return
end
# Temporary disable rebalancing for performance reasons
# For more information check https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4321
return if project.root_namespace&.issue_repositioning_disabled?
return if projects_to_rebalance.take&.root_namespace&.issue_repositioning_disabled? # rubocop:disable CodeReuse/ActiveRecord
# All issues are equivalent as far as we are concerned
issue = project.issues.take # rubocop: disable CodeReuse/ActiveRecord
IssueRebalancingService.new(projects_to_rebalance).execute
rescue IssueRebalancingService::TooManyIssues => e
Gitlab::ErrorTracking.log_exception(e, root_namespace_id: root_namespace_id, project_id: project_id)
end
IssueRebalancingService.new(issue).execute
rescue ActiveRecord::RecordNotFound, IssueRebalancingService::TooManyIssues => e
Gitlab::ErrorTracking.log_exception(e, project_id: project_id)
private
def projects_collection(project_id, root_namespace_id)
# we can have either project_id(older version) or project_id if project is part of a user namespace and not a group
# or root_namespace_id(newer version) never both.
return Project.id_in([project_id]) if project_id
Namespace.find_by_id(root_namespace_id)&.all_projects
end
end

View File

@ -1,20 +0,0 @@
#!/bin/sh
set -e
for file in config/*.yml.example; do
cp ${file} config/$(basename ${file} .example)
done
# Allow to override the GitLab URL from an environment variable, as this will avoid having to change the configuration file for simple deployments.
config=$(echo '<% gitlab_url = URI(ENV["GITLAB_URL"] || "http://localhost:80") %>' | cat - config/gitlab.yml)
echo "$config" > config/gitlab.yml
sed -i "s/host: localhost/host: <%= gitlab_url.host %>/" config/gitlab.yml
sed -i "s/port: 80/port: <%= gitlab_url.port %>/" config/gitlab.yml
sed -i "s/https: false/https: <%= gitlab_url.scheme == 'https' %>/" config/gitlab.yml
# No need for config file. Will be taken care of by REDIS_URL env variable
rm config/resque.yml
# Set default unicorn.rb file
echo "" > config/unicorn.rb

View File

@ -0,0 +1,6 @@
---
title: Update button variants and alignment to align with the Pajamas Design System
and modify the avatar layout to have better flow.
merge_request: 61504
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Track usage of the resolve conflict UI
merge_request: 61654
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Fix pipeline graph undefined needs error
merge_request: 62027
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Drop plugins directory support
merge_request: 55168
author:
type: removed

View File

@ -0,0 +1,5 @@
---
title: Enable Kroki on reStructuredText and Textile documents
merge_request: 60780
author: Guillaume Grossetie
type: added

View File

@ -0,0 +1,8 @@
---
name: create_vulnerability_jira_issue_via_graphql
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60593
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/329780
milestone: '13.12'
type: development
group: group::protect
default_enabled: false

View File

@ -63,6 +63,8 @@
- 'i_code_review_diff_hide_whitespace'
- 'i_code_review_diff_single_file'
- 'i_code_review_diff_multiple_files'
- 'i_code_review_user_load_conflict_ui'
- 'i_code_review_user_resolve_conflict'
- name: code_review_category_monthly_active_users
operator: OR
feature_flag: usage_data_code_review_aggregation
@ -118,6 +120,8 @@
- 'i_code_review_diff_hide_whitespace'
- 'i_code_review_diff_single_file'
- 'i_code_review_diff_multiple_files'
- 'i_code_review_user_load_conflict_ui'
- 'i_code_review_user_resolve_conflict'
- name: code_review_extension_category_monthly_active_users
operator: OR
feature_flag: usage_data_code_review_aggregation

View File

@ -0,0 +1,21 @@
---
key_path: redis_hll_counters.code_review.i_code_review_user_resolve_conflict_monthly
name: resolve_conflict
description: Count of unique users per week who attempt to resolve a conflict through the ui
product_section:
product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
milestone: "13.12"
time_frame: 28d
data_source: redis_hll
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61654
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,21 @@
---
key_path: redis_hll_counters.code_review.i_code_review_user_load_conflict_ui_monthly
name: load_conflict_ui
description: Count of unique users per week who load the conflict resolution page
product_section:
product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
milestone: "13.12"
time_frame: 28d
data_source: redis_hll
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61654
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,21 @@
---
key_path: redis_hll_counters.code_review.i_code_review_user_load_conflict_ui_weekly
name: load_conflict_ui
description: Count of unique users per week who load the conflict resolution page
product_section:
product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
milestone: "13.12"
time_frame: 7d
data_source: redis_hll
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61654
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -0,0 +1,21 @@
---
key_path: redis_hll_counters.code_review.i_code_review_user_resolve_conflict_weekly
name: resolve_conflict
description: Count of unique users per week who attempt to resolve a conflict through the ui
product_section:
product_stage: create
product_group: group::code review
product_category: code_review
value_type: number
status: implemented
milestone: "13.12"
time_frame: 28d
data_source: redis_hll
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61654
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate

View File

@ -11,6 +11,10 @@ Review this page for update instructions for your version. These steps
accompany the [general steps](updating_the_geo_nodes.md#general-update-steps)
for updating Geo nodes.
## Updating to GitLab 13.11
We found an [issue with Git clone/pull through HTTP(s)](https://gitlab.com/gitlab-org/gitlab/-/issues/330787) on Geo secondaries and on any GitLab instance if maintenance mode is enabled. This was caused by a regression in GitLab Workhorse. This is fixed in the [GitLab 13.11.4 patch release](https://about.gitlab.com/releases/2021/05/14/gitlab-13-11-4-released/). To avoid this issue, upgrade to GitLab 13.11.4 or later.
## Updating to GitLab 13.9
We've detected an issue [with a column rename](https://gitlab.com/gitlab-org/gitlab/-/issues/324160)

View File

@ -54,7 +54,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Environment variables](environment_variables.md): Supported environment
variables that can be used to override their default values to configure
GitLab.
- [Plugins](file_hooks.md): With custom plugins, GitLab administrators can
- [File hooks](file_hooks.md): With custom file hooks, GitLab administrators can
introduce custom integrations without modifying GitLab source code.
- [Enforcing Terms of Service](../user/admin_area/settings/terms.md)
- [Third party offers](../user/admin_area/settings/third_party_offers.md)

View File

@ -6,10 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Kroki diagrams **(FREE SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241744) in GitLab 13.7.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241744) in GitLab 13.7.
> - Support for reStructuredText and Textile documents [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/324766) in GitLab 13.12.
When [Kroki](https://kroki.io) integration is enabled and configured in
GitLab you can use it to create diagrams in AsciiDoc and Markdown documents.
GitLab you can use it to create diagrams in AsciiDoc, Markdown, reStructuredText, and Textile documents.
## Kroki Server
@ -85,13 +86,29 @@ your AsciiDoc or Markdown documentation using delimited blocks:
....
```
- **reStructuredText**
```plaintext
.. code-block:: plantuml
Bob->Alice : hello
Alice -> Bob : hi
```
- **Textile**
```plaintext
bc[plantuml]. Bob->Alice : hello
Alice -> Bob : hi
```
The above blocks are converted to an HTML image tag with source pointing to the
Kroki instance. If the Kroki server is correctly configured, this should
render a nice diagram instead of the block:
![PlantUML diagram](../img/kroki_plantuml_diagram.png)
Kroki supports more than a dozen diagram libraries. Here's a few examples:
Kroki supports more than a dozen diagram libraries. Here's a few examples for AsciiDoc:
**GraphViz**

View File

@ -9346,6 +9346,30 @@ Status: `data_available`
Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.code_review.i_code_review_user_load_conflict_ui_monthly`
Count of unique users per week who load the conflict resolution page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210514013549_i_code_review_user_load_conflict_ui_monthly.yml)
Group: `group::code review`
Status: `implemented`
Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.code_review.i_code_review_user_load_conflict_ui_weekly`
Count of unique users per week who load the conflict resolution page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_7d/20210514013544_i_code_review_user_load_conflict_ui_weekly.yml)
Group: `group::code review`
Status: `implemented`
Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.code_review.i_code_review_user_marked_as_draft_monthly`
Count of unique users per month who mark a merge request as a draft
@ -9562,6 +9586,30 @@ Status: `data_available`
Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.code_review.i_code_review_user_resolve_conflict_monthly`
Count of unique users per week who attempt to resolve a conflict through the ui
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210514013545_i_code_review_user_resolve_conflict_monthly.yml)
Group: `group::code review`
Status: `implemented`
Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.code_review.i_code_review_user_resolve_conflict_weekly`
Count of unique users per week who attempt to resolve a conflict through the ui
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_7d/20210514013545_i_code_review_user_resolve_conflict_weekly.yml)
Group: `group::code review`
Status: `implemented`
Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.code_review.i_code_review_user_resolve_thread_monthly`
Count of unique users per month who resolve a thread in a merge request

View File

@ -4,10 +4,10 @@ group: Monitor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Project operations **(FREE)**
# Monitor application performance **(FREE)**
GitLab provides a variety of tools to help operate and maintain
your applications:
your applications.
## Measure reliability and stability with metrics

View File

@ -351,16 +351,17 @@ You can customize the deployment namespace in a few ways:
When you customize the namespace, existing environments remain linked to their current
namespaces until you [clear the cluster cache](#clearing-the-cluster-cache).
WARNING:
#### Protecting credentials
By default, anyone who can create a deployment job can access any CI/CD variable in
an environment's deployment job. This includes `KUBECONFIG`, which gives access to
any secret available to the associated service account in your cluster.
To keep your production credentials safe, consider using
[protected environments](../../../ci/environments/protected_environments.md),
combined with either
combined with *one* of the following:
- a GitLab-managed cluster and namespace per environment,
- *or*, an environment-scoped cluster per protected environment. The same cluster
- A GitLab-managed cluster and namespace per environment.
- An environment-scoped cluster per protected environment. The same cluster
can be added multiple times with multiple restricted service accounts.
### Integrations

View File

@ -9,7 +9,8 @@ module Banzai
Filter::AssetProxyFilter,
Filter::ExternalLinkFilter,
Filter::PlantumlFilter,
Filter::SyntaxHighlightFilter
Filter::SyntaxHighlightFilter,
Filter::KrokiFilter
]
end

View File

@ -11,7 +11,7 @@ module Gitlab
end
def self.dir_glob
Dir.glob([Rails.root.join('file_hooks/*'), Rails.root.join('plugins/*')])
Dir.glob(Rails.root.join('file_hooks/*'))
end
private_class_method :dir_glob

View File

@ -219,3 +219,11 @@
category: code_review
aggregation: weekly
feature_flag: diff_settings_usage_data
- name: i_code_review_user_load_conflict_ui
redis_slot: code_review
category: code_review
aggregation: weekly
- name: i_code_review_user_resolve_conflict
redis_slot: code_review
category: code_review
aggregation: weekly

View File

@ -44,6 +44,8 @@ module Gitlab
MR_INCLUDING_CI_CONFIG_ACTION = 'o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile'
MR_MILESTONE_CHANGED_ACTION = 'i_code_review_user_milestone_changed'
MR_LABELS_CHANGED_ACTION = 'i_code_review_user_labels_changed'
MR_LOAD_CONFLICT_UI_ACTION = 'i_code_review_user_load_conflict_ui'
MR_RESOLVE_CONFLICT_ACTION = 'i_code_review_user_resolve_conflict'
class << self
def track_mr_diffs_action(merge_request:)
@ -201,6 +203,14 @@ module Gitlab
track_unique_action_by_user(MR_LABELS_CHANGED_ACTION, user)
end
def track_loading_conflict_ui_action(user:)
track_unique_action_by_user(MR_LOAD_CONFLICT_UI_ACTION, user)
end
def track_resolve_conflict_action(user:)
track_unique_action_by_user(MR_RESOLVE_CONFLICT_ACTION, user)
end
private
def track_unique_action_by_merge_request(action, merge_request)

View File

@ -3,14 +3,9 @@
namespace :file_hooks do
desc 'Validate existing file hooks'
task validate: :environment do
puts 'Validating file hooks from /file_hooks and /plugins directories'
puts 'Validating file hooks from /file_hooks directories'
Gitlab::FileHook.files.each do |file|
if File.dirname(file).ends_with?('plugins')
puts 'DEPRECATED: /plugins directory is deprecated and will be removed in 14.0. ' \
'Please move your files into /file_hooks directory.'
end
success, message = Gitlab::FileHook.execute(file, Gitlab::DataBuilder::Push::SAMPLE_DATA)
if success

View File

@ -24711,9 +24711,6 @@ msgstr ""
msgid "Please wait while we import the repository for you. Refresh at will."
msgstr ""
msgid "Plugins directory is deprecated and will be removed in 14.0. Please move this file into /file_hooks directory."
msgstr ""
msgid "Pod does not exist"
msgstr ""
@ -25254,7 +25251,7 @@ msgstr ""
msgid "Profiles|Profile was successfully updated"
msgstr ""
msgid "Profiles|Public Avatar"
msgid "Profiles|Public avatar"
msgstr ""
msgid "Profiles|Public email"

5
plugins/.gitignore vendored
View File

@ -1,5 +0,0 @@
*
!*/
!.gitignore
!.gitkeep
!examples/*

View File

@ -17,8 +17,31 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
end
describe 'GET show' do
context 'when the request is html' do
before do
allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to receive(:track_loading_conflict_ui_action)
get :show,
params: {
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid
},
format: 'html'
end
it 'does tracks the resolve call' do
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to have_received(:track_loading_conflict_ui_action).with(user: user)
end
end
context 'when the conflicts cannot be resolved in the UI' do
before do
allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to receive(:track_loading_conflict_ui_action)
allow(Gitlab::Git::Conflict::Parser).to receive(:parse)
.and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile)
@ -38,6 +61,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
it 'returns JSON with a message' do
expect(json_response.keys).to contain_exactly('message', 'type')
end
it 'does not track the resolve call' do
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.not_to have_received(:track_loading_conflict_ui_action).with(user: user)
end
end
context 'with valid conflicts' do
@ -145,20 +173,19 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
conflict_for_path(path)
end
it 'returns a 200 status code' do
expect(response).to have_gitlab_http_status(:ok)
end
it 'returns the file in JSON format' do
it 'returns a 200 and the file in JSON format' do
content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
.file_for_path(path, path)
.content
expect(json_response).to include('old_path' => path,
'new_path' => path,
'blob_icon' => 'doc-text',
'blob_path' => a_string_ending_with(path),
'content' => content)
aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to include('old_path' => path,
'new_path' => path,
'blob_icon' => 'doc-text',
'blob_path' => a_string_ending_with(path),
'content' => content)
end
end
end
end
@ -166,6 +193,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
context 'POST resolve_conflicts' do
let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha }
before do
allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to receive(:track_resolve_conflict_action)
end
def resolve_conflicts(files)
post :resolve_conflicts,
params: {
@ -201,13 +233,16 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
resolve_conflicts(resolved_files)
end
it 'creates a new commit on the branch' do
expect(original_head_sha).not_to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(merge_request_with_conflicts.source_branch_head.message).to include('Commit message')
end
it 'handles the success case' do
aggregate_failures do
# creates a new commit on the branch
expect(original_head_sha).not_to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(merge_request_with_conflicts.source_branch_head.message).to include('Commit message')
it 'returns an OK response' do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to have_received(:track_resolve_conflict_action).with(user: user)
end
end
end
@ -232,16 +267,17 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'handles the error case' do
aggregate_failures do
# has a message with the name of the first missing section
expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21')
# does not create a new commit
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
it 'has a message with the name of the first missing section' do
expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(response).to have_gitlab_http_status(:bad_request)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to have_received(:track_resolve_conflict_action).with(user: user)
end
end
end
@ -262,16 +298,17 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'handles the error case' do
aggregate_failures do
# has a message with the name of the missing file
expect(json_response['message']).to include('files/ruby/popen.rb')
# does not create a new commit
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
it 'has a message with the name of the missing file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(response).to have_gitlab_http_status(:bad_request)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to have_received(:track_resolve_conflict_action).with(user: user)
end
end
end
@ -300,16 +337,17 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'handles the error case' do
aggregate_failures do
# has a message with the path of the problem file
expect(json_response['message']).to include('files/ruby/popen.rb')
# does not create a new commit
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
it 'has a message with the path of the problem file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(response).to have_gitlab_http_status(:bad_request)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
.to have_received(:track_resolve_conflict_action).with(user: user)
end
end
end
end

View File

@ -37,24 +37,6 @@ RSpec.describe 'Admin::Hooks' do
expect(page).to have_content('foo.rb')
expect(page).to have_content('bar.clj')
end
context 'deprecation warning' do
it 'shows warning for plugins directory' do
allow(Gitlab::FileHook).to receive(:files).and_return(['plugins/foo.rb'])
visit admin_hooks_path
expect(page).to have_content('Plugins directory is deprecated and will be removed in 14.0')
end
it 'does not show warning for file_hooks directory' do
allow(Gitlab::FileHook).to receive(:files).and_return(['file_hooks/foo.rb'])
visit admin_hooks_path
expect(page).not_to have_content('Plugins directory is deprecated and will be removed in 14.0')
end
end
end
describe 'New Hook' do

View File

@ -14,7 +14,7 @@ RSpec.describe 'User searches their settings', :js do
visit profile_path
end
it_behaves_like 'can search settings', 'Public Avatar', 'Main settings'
it_behaves_like 'can search settings', 'Public avatar', 'Main settings'
end
context 'in preferences page' do

View File

@ -398,6 +398,8 @@ export const multiNote = {
},
};
export const missingJob = 'missing_job';
/*
It is important that the base include parallel jobs
as well as non-parallel jobs with spaces in the name to prevent
@ -657,4 +659,16 @@ export const mockParsedGraphQLNodes = [
],
__typename: 'CiGroup',
},
{
category: 'production',
name: 'production_e',
size: 1,
jobs: [
{
name: 'production_e',
needs: [missingJob],
},
],
__typename: 'CiGroup',
},
];

View File

@ -10,7 +10,7 @@ import {
getMaxNodes,
} from '~/pipelines/components/parsing_utils';
import { mockParsedGraphQLNodes } from './components/dag/mock_data';
import { mockParsedGraphQLNodes, missingJob } from './components/dag/mock_data';
import { generateResponse, mockPipelineResponse } from './graph/mock_data';
describe('DAG visualization parsing utilities', () => {
@ -24,6 +24,12 @@ describe('DAG visualization parsing utilities', () => {
expect(unfilteredLinks[0]).toHaveProperty('target', 'test_a');
expect(unfilteredLinks[0]).toHaveProperty('value', 10);
});
it('does not generate a link for non-existing jobs', () => {
const sources = unfilteredLinks.map(({ source }) => source);
expect(sources.includes(missingJob)).toBe(false);
});
});
describe('filterByAncestors', () => {
@ -88,7 +94,7 @@ describe('DAG visualization parsing utilities', () => {
These lengths are determined by the mock data.
If the data changes, the numbers may also change.
*/
expect(parsed.nodes).toHaveLength(21);
expect(parsed.nodes).toHaveLength(mockParsedGraphQLNodes.length);
expect(cleanedNodes).toHaveLength(12);
});
});

View File

@ -111,6 +111,28 @@ describe('utils functions', () => {
});
});
it('removes needs which are not in the data', () => {
const inexistantJobName = 'job5';
const jobsWithNeeds = {
[jobName1]: job1,
[jobName2]: job2,
[jobName3]: job3,
[jobName4]: {
name: jobName4,
script: 'echo deploy',
stage: 'deploy',
needs: [inexistantJobName],
},
};
expect(generateJobNeedsDict(jobsWithNeeds)).toEqual({
[jobName1]: [],
[jobName2]: [],
[jobName3]: [jobName1, jobName2],
[jobName4]: [],
});
});
it('handles parallel jobs by adding the group name as a need', () => {
const size = 3;
const jobOptimize1 = 'optimize_1';

View File

@ -386,4 +386,20 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
let(:action) { described_class::MR_LABELS_CHANGED_ACTION }
end
end
describe '.track_loading_conflict_ui_action' do
subject { described_class.track_loading_conflict_ui_action(user: user) }
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_LOAD_CONFLICT_UI_ACTION }
end
end
describe '.track_resolve_conflict_action' do
subject { described_class.track_resolve_conflict_action(user: user) }
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_RESOLVE_CONFLICT_ACTION }
end
end
end

View File

@ -1287,15 +1287,33 @@ RSpec.describe Issue do
end
end
let(:project) { build_stubbed(:project_empty_repo) }
let(:issue) { build_stubbed(:issue, relative_position: 100, project: project) }
shared_examples 'schedules issues rebalancing' do
let(:issue) { build_stubbed(:issue, relative_position: 100, project: project) }
it 'schedules rebalancing if we time-out when moving' do
lhs = build_stubbed(:issue, relative_position: 99, project: project)
to_move = build(:issue, project: project)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, project.id)
it 'schedules rebalancing if we time-out when moving' do
lhs = build_stubbed(:issue, relative_position: 99, project: project)
to_move = build(:issue, project: project)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, project_id, namespace_id)
expect { to_move.move_between(lhs, issue) }.to raise_error(ActiveRecord::QueryCanceled)
expect { to_move.move_between(lhs, issue) }.to raise_error(ActiveRecord::QueryCanceled)
end
end
context 'when project in user namespace' do
let(:project) { build_stubbed(:project_empty_repo) }
let(:project_id) { project.id }
let(:namespace_id) { nil }
it_behaves_like 'schedules issues rebalancing'
end
context 'when project in a group namespace' do
let(:group) { create(:group) }
let(:project) { build_stubbed(:project_empty_repo, group: group) }
let(:project_id) { nil }
let(:namespace_id) { group.id }
it_behaves_like 'schedules issues rebalancing'
end
end

View File

@ -39,7 +39,7 @@ RSpec.describe IssueRebalancingService do
shared_examples 'IssueRebalancingService shared examples' do
it 'rebalances a set of issues with clumps at the end and start' do
all_issues = start_clump + unclumped + end_clump.reverse
service = described_class.new(project.issues.first)
service = described_class.new(Project.id_in([project.id]))
expect { service.execute }.not_to change { issues_in_position_order.map(&:id) }
@ -55,7 +55,7 @@ RSpec.describe IssueRebalancingService do
end
it 'is idempotent' do
service = described_class.new(project.issues.first)
service = described_class.new(Project.id_in(project))
expect do
service.execute
@ -70,17 +70,17 @@ RSpec.describe IssueRebalancingService do
issue.project.group
old_pos = issue.relative_position
service = described_class.new(issue)
service = described_class.new(Project.id_in(project))
expect { service.execute }.not_to exceed_query_limit(0)
expect(old_pos).to eq(issue.reload.relative_position)
end
it 'acts if the flag is enabled for the project' do
it 'acts if the flag is enabled for the root namespace' do
issue = create(:issue, project: project, author: user, relative_position: max_pos)
stub_feature_flags(rebalance_issues: issue.project)
stub_feature_flags(rebalance_issues: project.root_namespace)
service = described_class.new(issue)
service = described_class.new(Project.id_in(project))
expect { service.execute }.to change { issue.reload.relative_position }
end
@ -90,23 +90,22 @@ RSpec.describe IssueRebalancingService do
project.update!(group: create(:group))
stub_feature_flags(rebalance_issues: issue.project.group)
service = described_class.new(issue)
service = described_class.new(Project.id_in(project))
expect { service.execute }.to change { issue.reload.relative_position }
end
it 'aborts if there are too many issues' do
issue = project.issues.first
base = double(count: 10_001)
allow(Issue).to receive(:relative_positioning_query_base).with(issue).and_return(base)
allow(Issue).to receive(:in_projects).and_return(base)
expect { described_class.new(issue).execute }.to raise_error(described_class::TooManyIssues)
expect { described_class.new(Project.id_in(project)).execute }.to raise_error(described_class::TooManyIssues)
end
end
shared_examples 'rebalancing is retried on statement timeout exceptions' do
subject { described_class.new(project.issues.first) }
subject { described_class.new(Project.id_in(project)) }
it 'retries update statement' do
call_count = 0

View File

@ -225,7 +225,7 @@ RSpec.describe Issues::UpdateService, :mailer do
opts[:move_between_ids] = [issue1.id, issue2.id]
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, project.id)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, nil, project.root_namespace.id)
update_issue(opts)
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
@ -239,7 +239,7 @@ RSpec.describe Issues::UpdateService, :mailer do
opts[:move_between_ids] = [issue1.id, issue2.id]
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, project.id)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, nil, project.root_namespace.id)
update_issue(opts)
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
@ -253,7 +253,7 @@ RSpec.describe Issues::UpdateService, :mailer do
opts[:move_between_ids] = [issue1.id, issue2.id]
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, project.id)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, nil, project.root_namespace.id)
update_issue(opts)
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)

View File

@ -128,11 +128,10 @@ RSpec.describe WebHookService do
end
it 'handles exceptions' do
exceptions = [
SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED,
Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout,
Gitlab::HTTP::BlockedUrlError, Gitlab::HTTP::RedirectionTooDeep
exceptions = Gitlab::HTTP::HTTP_ERRORS + [
Gitlab::Json::LimitedEncoder::LimitExceeded, URI::InvalidURIError
]
exceptions.each do |exception_class|
exception = exception_class.new('Exception message')
project_hook.enable!

View File

@ -139,18 +139,18 @@ RSpec.describe Tooling::Danger::ProjectHelper do
'db/post_migrate/foo' | [:database, :migration]
'ee/db/geo/migrate/foo' | [:database, :migration]
'ee/db/geo/post_migrate/foo' | [:database, :migration]
'app/models/project_authorization.rb' | [:database]
'app/services/users/refresh_authorized_projects_service.rb' | [:database]
'app/services/authorized_project_update/find_records_due_for_refresh_service.rb' | [:database]
'lib/gitlab/background_migration.rb' | [:database]
'lib/gitlab/background_migration/foo' | [:database]
'ee/lib/gitlab/background_migration/foo' | [:database]
'lib/gitlab/database.rb' | [:database]
'lib/gitlab/database/foo' | [:database]
'ee/lib/gitlab/database/foo' | [:database]
'lib/gitlab/github_import.rb' | [:database]
'lib/gitlab/github_import/foo' | [:database]
'lib/gitlab/sql/foo' | [:database]
'app/models/project_authorization.rb' | [:database, :backend]
'app/services/users/refresh_authorized_projects_service.rb' | [:database, :backend]
'app/services/authorized_project_update/find_records_due_for_refresh_service.rb' | [:database, :backend]
'lib/gitlab/background_migration.rb' | [:database, :backend]
'lib/gitlab/background_migration/foo' | [:database, :backend]
'ee/lib/gitlab/background_migration/foo' | [:database, :backend]
'lib/gitlab/database.rb' | [:database, :backend]
'lib/gitlab/database/foo' | [:database, :backend]
'ee/lib/gitlab/database/foo' | [:database, :backend]
'lib/gitlab/github_import.rb' | [:database, :backend]
'lib/gitlab/github_import/foo' | [:database, :backend]
'lib/gitlab/sql/foo' | [:database, :backend]
'rubocop/cop/migration/foo' | [:database]
'db/fixtures/foo.rb' | [:backend]

View File

@ -35,7 +35,7 @@ RSpec.describe IssuePlacementWorker do
it 'schedules rebalancing if needed' do
issue_a.update!(relative_position: RelativePositioning::MAX_POSITION)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, project.id)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, nil, project.group.id)
run_worker
end
@ -101,7 +101,7 @@ RSpec.describe IssuePlacementWorker do
it 'anticipates the failure to place the issues, and schedules rebalancing' do
allow(Issue).to receive(:move_nulls_to_end) { raise RelativePositioning::NoSpaceLeft }
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, project.id)
expect(IssueRebalancingWorker).to receive(:perform_async).with(nil, nil, project.group.id)
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(RelativePositioning::NoSpaceLeft, worker_arguments)

View File

@ -20,34 +20,83 @@ RSpec.describe IssueRebalancingWorker do
end
end
it 'runs an instance of IssueRebalancingService' do
service = double(execute: nil)
expect(IssueRebalancingService).to receive(:new).with(issue).and_return(service)
shared_examples 'running the worker' do
it 'runs an instance of IssueRebalancingService' do
service = double(execute: nil)
service_param = arguments.second.present? ? kind_of(Project.id_in([project]).class) : kind_of(group&.all_projects.class)
described_class.new.perform(nil, issue.project_id)
expect(IssueRebalancingService).to receive(:new).with(service_param).and_return(service)
described_class.new.perform(*arguments)
end
it 'anticipates there being too many issues' do
service = double
service_param = arguments.second.present? ? kind_of(Project.id_in([project]).class) : kind_of(group&.all_projects.class)
allow(service).to receive(:execute).and_raise(IssueRebalancingService::TooManyIssues)
expect(IssueRebalancingService).to receive(:new).with(service_param).and_return(service)
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(IssueRebalancingService::TooManyIssues, include(project_id: arguments.second, root_namespace_id: arguments.third))
described_class.new.perform(*arguments)
end
it 'takes no action if the value is nil' do
expect(IssueRebalancingService).not_to receive(:new)
expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
described_class.new.perform # all arguments are nil
end
end
it 'anticipates the inability to find the issue' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(ActiveRecord::RecordNotFound, include(project_id: -1))
expect(IssueRebalancingService).not_to receive(:new)
shared_examples 'safely handles non-existent ids' do
it 'anticipates the inability to find the issue' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(ArgumentError, include(project_id: arguments.second, root_namespace_id: arguments.third))
expect(IssueRebalancingService).not_to receive(:new)
described_class.new.perform(nil, -1)
described_class.new.perform(*arguments)
end
end
it 'anticipates there being too many issues' do
service = double
allow(service).to receive(:execute) { raise IssueRebalancingService::TooManyIssues }
expect(IssueRebalancingService).to receive(:new).with(issue).and_return(service)
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(IssueRebalancingService::TooManyIssues, include(project_id: issue.project_id))
context 'without root_namespace param' do
it_behaves_like 'running the worker' do
let(:arguments) { [-1, project.id] }
end
described_class.new.perform(nil, issue.project_id)
it_behaves_like 'safely handles non-existent ids' do
let(:arguments) { [nil, -1] }
end
include_examples 'an idempotent worker' do
let(:job_args) { [-1, project.id] }
end
include_examples 'an idempotent worker' do
let(:job_args) { [nil, -1] }
end
end
it 'takes no action if the value is nil' do
expect(IssueRebalancingService).not_to receive(:new)
expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
context 'with root_namespace param' do
it_behaves_like 'running the worker' do
let(:arguments) { [nil, nil, group.id] }
end
described_class.new.perform(nil, nil)
it_behaves_like 'safely handles non-existent ids' do
let(:arguments) { [nil, nil, -1] }
end
include_examples 'an idempotent worker' do
let(:job_args) { [nil, nil, group.id] }
end
include_examples 'an idempotent worker' do
let(:job_args) { [nil, nil, -1] }
end
end
end
it 'has the `until_executed` deduplicate strategy' do
expect(described_class.get_deduplicate_strategy).to eq(:until_executed)
expect(described_class.get_deduplication_options).to include({ including_scheduled: true })
end
end

View File

@ -76,11 +76,11 @@ module Tooling
)\z}x => %i[frontend engineering_productivity],
%r{\A(ee/)?db/(geo/)?(migrate|post_migrate)/} => [:database, :migration],
%r{\A(ee/)?db/(?!fixtures)[^/]+} => :database,
%r{\A(ee/)?lib/gitlab/(database|background_migration|sql|github_import)(/|\.rb)} => :database,
%r{\A(app/services/authorized_project_update/find_records_due_for_refresh_service)(/|\.rb)} => :database,
%r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => :database,
%r{\A(ee/)?app/finders/} => :database,
%r{\A(ee/)?db/(?!fixtures)[^/]+} => [:database],
%r{\A(ee/)?lib/gitlab/(database|background_migration|sql|github_import)(/|\.rb)} => [:database, :backend],
%r{\A(app/services/authorized_project_update/find_records_due_for_refresh_service)(/|\.rb)} => [:database, :backend],
%r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => [:database, :backend],
%r{\A(ee/)?app/finders/} => [:database, :backend],
%r{\Arubocop/cop/migration(/|\.rb)} => :database,
%r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :engineering_productivity,