Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-03-22 15:09:31 +00:00
parent cea25900b7
commit 06d4ce7ee0
36 changed files with 299 additions and 184 deletions

View File

@ -1,4 +1,3 @@
/* eslint-disable no-new */
import { debounce } from 'lodash';
import {
init as initConfidentialMergeRequest,
@ -8,7 +7,7 @@ import {
import confidentialMergeRequestState from './confidential_merge_request/state';
import DropLab from './droplab/drop_lab';
import ISetter from './droplab/plugins/input_setter';
import { deprecatedCreateFlash as Flash } from './flash';
import createFlash from './flash';
import axios from './lib/utils/axios_utils';
import { __, sprintf } from './locale';
@ -132,7 +131,9 @@ export default class CreateMergeRequestDropdown {
.catch(() => {
this.unavailable();
this.disable();
Flash(__('Failed to check related branches.'));
createFlash({
message: __('Failed to check related branches.'),
});
});
}
@ -147,7 +148,11 @@ export default class CreateMergeRequestDropdown {
this.branchCreated = true;
window.location.href = data.url;
})
.catch(() => Flash(__('Failed to create a branch for this issue. Please try again.')));
.catch(() =>
createFlash({
message: __('Failed to create a branch for this issue. Please try again.'),
}),
);
}
createMergeRequest() {
@ -163,7 +168,11 @@ export default class CreateMergeRequestDropdown {
this.mergeRequestCreated = true;
window.location.href = data.url;
})
.catch(() => Flash(__('Failed to create Merge Request. Please try again.')));
.catch(() =>
createFlash({
message: __('Failed to create Merge Request. Please try again.'),
}),
);
}
disable() {
@ -256,7 +265,9 @@ export default class CreateMergeRequestDropdown {
.catch(() => {
this.unavailable();
this.disable();
new Flash(__('Failed to get ref.'));
createFlash({
message: __('Failed to get ref.'),
});
this.isGettingRef = false;

View File

@ -1,7 +1,7 @@
import { __ } from '~/locale';
import Ajax from '../droplab/plugins/ajax';
import Filter from '../droplab/plugins/filter';
import { deprecatedCreateFlash as Flash } from '../flash';
import createFlash from '../flash';
import DropdownUtils from './dropdown_utils';
import FilteredSearchDropdown from './filtered_search_dropdown';
@ -14,9 +14,9 @@ export default class DropdownEmoji extends FilteredSearchDropdown {
method: 'setData',
loadingTemplate: this.loadingTemplate,
onError() {
/* eslint-disable no-new */
new Flash(__('An error occurred fetching the dropdown data.'));
/* eslint-enable no-new */
createFlash({
message: __('An error occurred fetching the dropdown data.'),
});
},
},
Filter: {

View File

@ -1,7 +1,7 @@
import { __ } from '~/locale';
import Ajax from '../droplab/plugins/ajax';
import Filter from '../droplab/plugins/filter';
import { deprecatedCreateFlash as Flash } from '../flash';
import createFlash from '../flash';
import DropdownUtils from './dropdown_utils';
import FilteredSearchDropdown from './filtered_search_dropdown';
@ -17,9 +17,9 @@ export default class DropdownNonUser extends FilteredSearchDropdown {
loadingTemplate: this.loadingTemplate,
preprocessing,
onError() {
/* eslint-disable no-new */
new Flash(__('An error occurred fetching the dropdown data.'));
/* eslint-enable no-new */
createFlash({
message: __('An error occurred fetching the dropdown data.'),
});
},
},
Filter: {

View File

@ -10,7 +10,7 @@ import {
DOWN_KEY_CODE,
} from '~/lib/utils/keycodes';
import { __ } from '~/locale';
import { deprecatedCreateFlash as Flash } from '../flash';
import createFlash from '../flash';
import { addClassIfElementExists } from '../lib/utils/dom_utils';
import { visitUrl } from '../lib/utils/url_utility';
import FilteredSearchContainer from './container';
@ -92,8 +92,9 @@ export default class FilteredSearchManager {
.fetch()
.catch((error) => {
if (error.name === 'RecentSearchesServiceError') return undefined;
// eslint-disable-next-line no-new
new Flash(__('An error occurred while parsing recent searches'));
createFlash({
message: __('An error occurred while parsing recent searches'),
});
// Gracefully fail to empty array
return [];
})

View File

@ -22,7 +22,7 @@ import syntaxHighlight from '~/syntax_highlight';
import Autosave from './autosave';
import loadAwardsHandler from './awards_handler';
import CommentTypeToggle from './comment_type_toggle';
import { deprecatedCreateFlash as Flash } from './flash';
import createFlash from './flash';
import { defaultAutocompleteConfig } from './gfm_auto_complete';
import GLForm from './gl_form';
import axios from './lib/utils/axios_utils';
@ -399,7 +399,11 @@ export default class Notes {
if (noteEntity.commands_changes && Object.keys(noteEntity.commands_changes).length > 0) {
$notesList.find('.system-note.being-posted').remove();
}
this.addFlash(noteEntity.errors.commands_only, 'notice', this.parentTimeline.get(0));
this.addFlash({
message: noteEntity.errors.commands_only,
type: 'notice',
parent: this.parentTimeline.get(0),
});
this.refresh();
}
return;
@ -620,20 +624,21 @@ export default class Notes {
} else if ($form.hasClass('js-discussion-note-form')) {
formParentTimeline = $form.closest('.discussion-notes').find('.notes');
}
return this.addFlash(
__(
return this.addFlash({
message: __(
'Your comment could not be submitted! Please check your network connection and try again.',
),
'alert',
formParentTimeline.get(0),
);
type: 'alert',
parent: formParentTimeline.get(0),
});
}
updateNoteError() {
// eslint-disable-next-line no-new
new Flash(
__('Your comment could not be updated! Please check your network connection and try again.'),
);
createFlash({
message: __(
'Your comment could not be updated! Please check your network connection and try again.',
),
});
}
/**
@ -1289,7 +1294,7 @@ export default class Notes {
}
addFlash(...flashParams) {
this.flashContainer = new Flash(...flashParams);
this.flashContainer = createFlash(...flashParams);
}
clearFlash() {

View File

@ -5,7 +5,7 @@ export const EXCLUDED_NODES = ['OPTION'];
export const HIDE_CLASS = 'gl-display-none';
// used to highlight the text that matches the * search term
export const HIGHLIGHT_CLASS = 'gl-bg-orange-50';
export const HIGHLIGHT_CLASS = 'gl-bg-orange-100';
// How many seconds to wait until the user * stops typing
export const TYPING_DELAY = 400;

View File

@ -15,10 +15,10 @@ import { isEmpty } from 'lodash';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
import readyToMergeQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import createFlash from '~/flash';
import simplePoll from '~/lib/utils/simple_poll';
import { __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { deprecatedCreateFlash as Flash } from '../../../flash';
import MergeRequest from '../../../merge_request';
import { AUTO_MERGE_STRATEGIES, DANGER, INFO, WARNING } from '../../constants';
import eventHub from '../../event_hub';
@ -351,7 +351,9 @@ export default {
})
.catch(() => {
this.isMakingRequest = false;
new Flash(__('Something went wrong. Please try again.')); // eslint-disable-line
createFlash({
message: __('Something went wrong. Please try again.'),
});
});
},
handleMergeImmediatelyButtonClick() {
@ -402,7 +404,9 @@ export default {
}
})
.catch(() => {
new Flash(__('Something went wrong while merging this merge request. Please try again.')); // eslint-disable-line
createFlash({
message: __('Something went wrong while merging this merge request. Please try again.'),
});
stopPolling();
});
},
@ -432,7 +436,9 @@ export default {
}
})
.catch(() => {
new Flash(__('Something went wrong while deleting the source branch. Please try again.')); // eslint-disable-line
createFlash({
message: __('Something went wrong while deleting the source branch. Please try again.'),
});
});
},
},

View File

@ -43,6 +43,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml)
push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:new_pipelines_table, @project, default_enabled: :yaml)
push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml)
record_experiment_user(:invite_members_version_b)

View File

@ -2,20 +2,29 @@
class RemoveExpiredMembersWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
include CronjobQueue
feature_category :authentication_and_authorization
worker_resource_boundary :cpu
# rubocop: disable CodeReuse/ActiveRecord
def perform
Member.expired.preload(:user).find_each do |member|
Members::DestroyService.new.execute(member, skip_authorization: true)
Member.expired.preload(:user, :source).find_each do |member|
context = {
user: member.user,
# The ApplicationContext will reject type-mismatches. So a GroupMemeber will only populate `namespace`.
# while a `ProjectMember` will populate `project
project: member.source,
namespace: member.source
}
with_context(context) do
Members::DestroyService.new.execute(member, skip_authorization: true)
expired_user = member.user
expired_user = member.user
if expired_user.project_bot?
Users::DestroyService.new(nil).execute(expired_user, skip_authorization: true)
if expired_user.project_bot?
Users::DestroyService.new(nil).execute(expired_user, skip_authorization: true)
end
end
rescue => ex
logger.error("Expired Member ID=#{member.id} cannot be removed - #{ex}")

View File

@ -0,0 +1,5 @@
---
title: Fix ruby alpine CI template
merge_request: 57109
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Update weight transaltion for Russian locale
merge_request: 56986
author: Gennady Kovalev (@belolap)
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Push confidential_notes feature flag to mr frontend
merge_request: 56798
author: Lee Tickett @leetickett
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Enable DISTINCT optimization for ObjectHierarchy globally
merge_request: 57052
author:
type: changed

View File

@ -0,0 +1,8 @@
---
name: use_distinct_for_all_object_hierarchy
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57052
rollout_issue_url:
milestone: '13.11'
type: development
group: group::database
default_enabled: false

View File

@ -274,6 +274,9 @@ with secure tokens as you complete the setup process.
We note in the instructions below where these secrets are required.
NOTE:
Omnibus GitLab installations can use `gitlab-secrets.json`.
### PostgreSQL
NOTE:
@ -283,10 +286,11 @@ database on the same PostgreSQL server if using
of GitLab and should not be replicated.
These instructions help set up a single PostgreSQL database, which creates a single point of
failure. For greater fault tolerance, the following options are available:
failure. The following options are available:
- For non-Geo installations, use one of the fault-tolerant
[PostgreSQL setups](../postgresql/index.md).
- For non-Geo installations, either:
- Use one of the documented [PostgreSQL setups](../postgresql/index.md).
- Use your own third-party database setup, if fault tolerance is required.
- For Geo instances, either:
- Set up a separate [PostgreSQL instance](https://www.postgresql.org/docs/11/high-availability.html).
- Use a cloud-managed PostgreSQL service. AWS
@ -802,14 +806,26 @@ documentation](configure_gitaly.md#configure-gitaly-servers).
gitaly['auth_token'] = 'PRAEFECT_INTERNAL_TOKEN'
```
1. Configure the GitLab Shell `secret_token`, and `internal_api_url` which are
needed for `git push` operations.
1. Configure the GitLab Shell secret token, which is needed for `git push` operations. Either:
If you have already configured [Gitaly on its own server](index.md)
- Method 1:
1. Copy `/etc/gitlab/gitlab-secrets.json` from the Gitaly client to same path on the Gitaly
servers and any other Gitaly clients.
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) on Gitaly servers.
- Method 2:
1. Edit `/etc/gitlab/gitlab.rb`.
1. Replace `GITLAB_SHELL_SECRET_TOKEN` with the real secret.
```ruby
gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
```
1. Configure and `internal_api_url`, which is also needed for `git push` operations:
```ruby
gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
# Configure the gitlab-shell API callback URL. Without this, `git push` will
# fail. This can be your front door GitLab URL or an internal load balancer.
# Examples: 'https://gitlab.example.com', 'http://1.2.3.4'
@ -961,15 +977,23 @@ Particular attention should be shown to:
})
```
1. Configure the `gitlab_shell['secret_token']` so that callbacks from Gitaly
nodes during a `git push` are properly authenticated by editing
`/etc/gitlab/gitlab.rb`:
1. Configure the GitLab Shell secret token so that callbacks from Gitaly nodes during a `git push`
are properly authenticated. Either:
You need to replace `GITLAB_SHELL_SECRET_TOKEN` with the real secret.
- Method 1:
```ruby
gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
```
1. Copy `/etc/gitlab/gitlab-secrets.json` from the Gitaly client to same path on the Gitaly
servers and any other Gitaly clients.
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) on Gitaly servers.
- Method 2:
1. Edit `/etc/gitlab/gitlab.rb`.
1. Replace `GITLAB_SHELL_SECRET_TOKEN` with the real secret.
```ruby
gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
```
1. Add Prometheus monitoring settings by editing `/etc/gitlab/gitlab.rb`. If Prometheus
is enabled on a different node, make edits on that node instead.

View File

@ -1069,8 +1069,8 @@ job:
- when: on_success
```
- If the pipeline is for a merge request, the job is **not** be added to the pipeline.
- If the pipeline is a scheduled pipeline, the job is **not** be added to the pipeline.
- If the pipeline is for a merge request, the job is **not** added to the pipeline.
- If the pipeline is a scheduled pipeline, the job is **not** added to the pipeline.
- In **all other cases**, the job is added to the pipeline, with `when: on_success`.
WARNING:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -7,12 +7,10 @@ type: index, reference
# Merge requests **(FREE)**
Whenever you need to merge one branch into another branch with GitLab, you
must create a merge request (MR).
Merge requests (MRs) are the way you check source code changes into a branch.
Using merge requests, you can visualize and collaborate on proposed changes to
source code. Merge requests display information about the proposed code changes,
including:
When you open a merge request, you can visualize and collaborate on the code changes before merge.
Merge requests include:
- A description of the request.
- Code changes and inline code reviews.
@ -20,55 +18,50 @@ including:
- A comment section for discussion threads.
- The list of commits.
Based on your workflow, after review you can merge a merge request into its
target branch.
To get started, read the [introduction to merge requests](getting_started.md).
## Use cases
## Merge request workflows
A. Consider you're a software developer working in a team:
For a software developer working in a team:
1. You checkout a new branch, and submit your changes through a merge request
1. You gather feedback from your team
1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md)
1. You verify your changes with [Unit test reports](../../../ci/unit_test_reports.md) in GitLab CI/CD
1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](../../compliance/license_compliance/index.md) **(ULTIMATE)**
1. You request the [approval](merge_request_approvals.md) from your manager **(STARTER)**
1. You checkout a new branch, and submit your changes through a merge request.
1. You gather feedback from your team.
1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md).
1. You verify your changes with [Unit test reports](../../../ci/unit_test_reports.md) in GitLab CI/CD.
1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](../../compliance/license_compliance/index.md).
1. You request the [approval](merge_request_approvals.md) from your manager.
1. Your manager:
1. Pushes a commit with their final review
1. [Approves the merge request](merge_request_approvals.md) **(STARTER)**
1. Sets it to [merge when pipeline succeeds](merge_when_pipeline_succeeds.md)
1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#whenmanual) for GitLab CI/CD
1. Your implementations were successfully shipped to your customer
1. Pushes a commit with their final review.
1. [Approves the merge request](merge_request_approvals.md).
1. Sets it to [merge when pipeline succeeds](merge_when_pipeline_succeeds.md).
1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#whenmanual) for GitLab CI/CD.
1. Your implementations were successfully shipped to your customer.
B. Consider you're a web developer writing a webpage for your company's website:
For a web developer writing a webpage for your company's website:
1. You checkout a new branch, and submit a new page through a merge request
1. You gather feedback from your reviewers
1. Your changes are previewed with [Review Apps](../../../ci/review_apps/index.md)
1. You request your web designers for their implementation
1. You request the [approval](merge_request_approvals.md) from your manager **(STARTER)**
1. Once approved, your merge request is [squashed and merged](squash_and_merge.md), and [deployed to staging with GitLab Pages](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/)
1. Your production team [cherry picks](cherry_pick_changes.md) the merge commit into production
1. You checkout a new branch and submit a new page through a merge request.
1. You gather feedback from your reviewers.
1. You preview your changes with [Review Apps](../../../ci/review_apps/index.md).
1. You request your web designers for their implementation.
1. You request the [approval](merge_request_approvals.md) from your manager.
1. Once approved, your merge request is [squashed and merged](squash_and_merge.md), and [deployed to staging with GitLab Pages](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/).
1. Your production team [cherry picks](cherry_pick_changes.md) the merge commit into production.
## Merge request navigation tabs at the top
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33813) in GitLab 12.6. This positioning is experimental.
So far, the navigation tabs present in merge requests to display **Discussion**,
**Commits**, **Pipelines**, and **Changes** were located after the merge request
In GitLab 12.5 and earlier, navigation tabs in merge requests (**Discussion**,
**Commits**, **Pipelines**, and **Changes**) were located after the merge request
widget.
To facilitate this navigation without having to scroll up and down through the page
to find these tabs, based on user feedback, we're experimenting with a new positioning
of these tabs. They are now located at the top of the merge request, with a new
**Overview** tab, containing the description of the merge request followed by the
widget. Next to **Overview**, you can find **Pipelines**, **Commits**, and **Changes**.
To facilitate navigation without scrolling, and based on user feedback, the tabs are
now located at the top of the merge request tab. A new **Overview** tab was added,
and next to **Overview** are **Commits**, **Pipelines**, and **Changes**.
![Merge request tab positions](img/merge_request_tab_position_v12_6.png)
![Merge request tab positions](img/merge_request_tab_position_v13_11.png)
Please note this change is currently behind a feature flag which is enabled by default. For
This change is behind a feature flag that is enabled by default. For
self-managed instances, it can be disabled through the Rails console by a GitLab
administrator with the following command:
@ -76,23 +69,9 @@ administrator with the following command:
Feature.disable(:mr_tabs_position)
```
## Creating merge requests
## Related topics
Learn [how to create a merge request](creating_merge_requests.md).
## Reviewing and managing merge requests
See the features at your disposal to [review and manage merge requests](reviewing_and_managing_merge_requests.md).
## Testing and reports in merge requests
Learn about the options for [testing and reports](testing_and_reports_in_merge_requests.md) on the changes in a merge request.
## Authorization for merge requests
There are two main ways to have a merge request flow with GitLab:
1. Working with [protected branches](../protected_branches.md) in a single repository
1. Working with forks of an authoritative project
[Learn more about the authorization for merge requests.](authorization_for_merge_requests.md)
- [Create a merge request](creating_merge_requests.md)
- [Review and manage merge requests](reviewing_and_managing_merge_requests.md)
- [Authorization for merge requests](authorization_for_merge_requests.md)
- [Testing and reports](testing_and_reports_in_merge_requests.md)

View File

@ -344,7 +344,7 @@ terminal:
# This can be any image that has the necessary runtime environment for your project.
image: node:10-alpine
before_script:
- apt-get update
- apk update
script: sleep 60
variables:
RAILS_ENV: "test"

View File

@ -59,7 +59,7 @@ module API
project: -> { @project },
namespace: -> { @group },
runner: -> { @current_runner || @runner },
caller_id: route.origin,
caller_id: api_endpoint.endpoint_id,
remote_ip: request.ip,
feature_category: feature_category
)

View File

@ -32,6 +32,10 @@ module API
end
end.compact.to_set
end
def endpoint_id
"#{request.request_method} #{route.origin}"
end
end
end
end

View File

@ -15,7 +15,7 @@ module API
Gitlab::ApplicationContext.push(
user: -> { actor&.user },
project: -> { project },
caller_id: route.origin,
caller_id: api_endpoint.endpoint_id,
remote_ip: request.ip,
feature_category: feature_category
)

View File

@ -68,12 +68,14 @@ module Gitlab
expose_depth = hierarchy_order.present?
hierarchy_order ||= :asc
recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all).distinct
# if hierarchy_order is given, the calculated `depth` should be present in SELECT
if expose_depth
recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all).distinct
read_only(model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)).order(depth: hierarchy_order))
else
recursive_query = base_and_ancestors_cte(upto).apply_to(model.all)
recursive_query = recursive_query.reselect(*recursive_query.arel.projections, 'ROW_NUMBER() OVER () as depth').distinct
recursive_query = model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table))
read_only(remove_depth_and_maintain_order(recursive_query, hierarchy_order: hierarchy_order))
end
else
@ -93,11 +95,13 @@ module Gitlab
def base_and_descendants(with_depth: false)
if use_distinct?
# Always calculate `depth`, remove it later if with_depth is false
base_cte = base_and_descendants_cte(with_depth: true).apply_to(model.all).distinct
if with_depth
read_only(model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)).order(depth: :asc))
base_cte = base_and_descendants_cte(with_depth: true).apply_to(model.all).distinct
read_only(model.from(Arel::Nodes::As.new(base_cte.arel, objects_table)).order(depth: :asc))
else
base_cte = base_and_descendants_cte.apply_to(model.all)
base_cte = base_cte.reselect(*base_cte.arel.projections, 'ROW_NUMBER() OVER () as depth').distinct
base_cte = model.from(Arel::Nodes::As.new(base_cte.arel, objects_table))
read_only(remove_depth_and_maintain_order(base_cte, hierarchy_order: :asc))
end
else
@ -161,7 +165,12 @@ module Gitlab
# Use distinct on the Namespace queries to avoid bad planner behavior in PG11.
def use_distinct?
(model <= Namespace) && options[:use_distinct]
return unless model <= Namespace
# Global use_distinct_for_all_object_hierarchy takes precedence over use_distinct_in_object_hierarchy
return true if Feature.enabled?(:use_distinct_for_all_object_hierarchy)
return options[:use_distinct] if options.key?(:use_distinct)
false
end
# Remove the extra `depth` field using an INNER JOIN to avoid breaking UNION queries

View File

@ -523,7 +523,7 @@ msgid "%{completedCount} completed weight"
msgstr ""
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr "Завершено %{completedWeight} из %{totalWeight} приоритета"
msgstr "Завершено %{completedWeight} из %{totalWeight} единиц веса"
msgid "%{containerScanningLinkStart}Container Scanning%{containerScanningLinkEnd} and/or %{dependencyScanningLinkStart}Dependency Scanning%{dependencyScanningLinkEnd} must be enabled. %{securityBotLinkStart}GitLab-Security-Bot%{securityBotLinkEnd} will be the author of the auto-created merge request. %{moreInfoLinkStart}More information%{moreInfoLinkEnd}."
msgstr ""
@ -859,7 +859,7 @@ msgid "%{openedIssues} open, %{closedIssues} closed"
msgstr "%{openedIssues} открыто, %{closedIssues} закрыто"
msgid "%{percentage}%% weight completed"
msgstr "%{percentage}%% приоритета завершено"
msgstr "%{percentage}%% веса завершено"
msgid "%{percent}%% complete"
msgstr "%{percent}%% выполнено"
@ -1068,13 +1068,13 @@ msgid "%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)"
msgstr ""
msgid "%{totalWeight} total weight"
msgstr "общий приоритет %{totalWeight}"
msgstr "общий вес %{totalWeight}"
msgid "%{total_warnings} warning(s) found:"
msgstr ""
msgid "%{total} open issue weight"
msgstr "приоритет открытого обсуждения %{total}"
msgstr "вес открытого обсуждения %{total}"
msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
@ -1258,7 +1258,7 @@ msgstr[2] "- Пользователи"
msgstr[3] "- Пользователи"
msgid "- of - weight completed"
msgstr "- из - приоритета завершено"
msgstr "- из - единиц веса завершено"
msgid "- show less"
msgstr "- свернуть"
@ -3448,7 +3448,7 @@ msgid "An error occurred when updating the issue title"
msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr "Произошла ошибка при обновлении приоритета обсуждения"
msgstr "Произошла ошибка при обновлении весa обсуждения"
msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
msgstr ""
@ -5352,7 +5352,7 @@ msgid "Burndown charts are now fixed. This means that removing issues from a mil
msgstr "Диаграммы сгорания задач стали фиксированными. Это означает, что если убрать обсуждения из этапа, ставшего просроченным, диаграмма не изменится. Прежний вариант диаграммы можно увидеть, нажав на кнопку %{strongStart}Старый вид диаграммы сгорания%{strongEnd}."
msgid "BurndownChartLabel|Open issue weight"
msgstr "Открыть приоритет задачи"
msgstr "Bес открытых обсуждений"
msgid "BurndownChartLabel|Open issues"
msgstr "Открыть обсуждения"
@ -6346,13 +6346,13 @@ msgid "Clear templates search input"
msgstr "Очистить шаблоны ввода данных для поиска"
msgid "Clear weight"
msgstr "Очистить приоритет"
msgstr "Удалить вес"
msgid "Cleared weight."
msgstr "Приоритет очищен."
msgstr "Вес удалён."
msgid "Clears weight."
msgstr "Очищает приоритет."
msgstr "Удаляет вес."
msgid "Click %{link_start}here%{link_end} to view the request."
msgstr ""
@ -11728,7 +11728,7 @@ msgid "Enter the number of seconds, or other human-readable input, like \"1 hour
msgstr ""
msgid "Enter weights for storages for new repositories."
msgstr ""
msgstr "Введите веса хранилищ для новых репозиториев."
msgid "Enter your password to approve"
msgstr "Для продолжения введите свой пароль"
@ -12244,7 +12244,7 @@ msgid "Error occurred while updating the issue status"
msgstr "Произошла ошибка при обновлении статуса обсуждения"
msgid "Error occurred while updating the issue weight"
msgstr "Произошла ошибка при изменении приоритета задачи"
msgstr "Произошла ошибка при изменении весa обсуждения"
msgid "Error occurred. A blocked user cannot be deactivated"
msgstr "Произошла ошибка. Заблокированный пользователь не может быть деактивирован"
@ -17099,7 +17099,7 @@ msgid "Issue was closed by %{name} %{reason}"
msgstr "Обсуждение было закрыто %{name} %{reason}"
msgid "Issue weight"
msgstr "Приоритет обсуждения"
msgstr "Вес обсуждения"
msgid "IssueAnalytics|Age"
msgstr ""
@ -24622,10 +24622,10 @@ msgid "Promotions|Weight"
msgstr ""
msgid "Promotions|Weighting your issue"
msgstr "Обозначить приоритет обсуждения"
msgstr "Установка веса обсуждения"
msgid "Promotions|When you have a lot of issues, it can be hard to get an overview. By adding a weight to your issues, you can get a better idea of the effort, cost, required time, or value of each, and so better manage them."
msgstr "При большом количестве обсуждений сложно оценить общую картину. Добавив приоритет к вашим обсуждениям, вы можете получить лучшее представление о затрачиваемых усилиях, времени, стоимости или значимости каждого из них и, таким образом, лучше ими управлять."
msgstr "При большом количестве обсуждений сложно оценить общую картину. Добавив вес к вашим обсуждениям, вы можете получить лучшее представление о затрачиваемых усилиях, времени, стоимости или значимости каждого из них и, таким образом, лучше ими управлять."
msgid "Promotions|With Contribution Analytics you can have an overview for the activity of issues, merge requests, and push events of your organization and its members."
msgstr ""
@ -27685,10 +27685,10 @@ msgid "Set verification limit and frequency."
msgstr ""
msgid "Set weight"
msgstr "Установить приоритет"
msgstr "Установить вес"
msgid "Set weight to %{weight}."
msgstr "Установить приоритет на %{weight}."
msgstr "Установить вес в следующее количество единиц: %{weight}."
msgid "Set what should be replicated by this secondary node."
msgstr ""
@ -27748,7 +27748,7 @@ msgid "Sets time estimate to %{time_estimate}."
msgstr "Задаёт оценку времени в %{time_estimate}."
msgid "Sets weight to %{weight}."
msgstr "Устанавливает приоритет на %{weight}."
msgstr "Устанавливает вес в следующее количество единиц: %{weight}."
msgid "Setting this to 0 means using the system default timeout value."
msgstr ""
@ -27975,7 +27975,7 @@ msgid "Sidebar|Only numeral characters allowed"
msgstr ""
msgid "Sidebar|Weight"
msgstr "Приоритет"
msgstr "Вес"
msgid "Sign in"
msgstr "Вход"
@ -28458,7 +28458,7 @@ msgid "SortOptions|Least popular"
msgstr "Наименее популярный"
msgid "SortOptions|Less weight"
msgstr "Сначала с меньшим приоритетом"
msgstr "Сначала с меньшим весом"
msgid "SortOptions|Manual"
msgstr "Ручная"
@ -28473,7 +28473,7 @@ msgid "SortOptions|Milestone due soon"
msgstr "Веха, наступающая раньше"
msgid "SortOptions|More weight"
msgstr "Сначала с большим приоритетом"
msgstr "Сначала с большим весом"
msgid "SortOptions|Most popular"
msgstr "Наиболее популярный"
@ -28554,7 +28554,7 @@ msgid "SortOptions|Version"
msgstr "По версии"
msgid "SortOptions|Weight"
msgstr "Приоритет"
msgstr "Вес"
msgid "Source"
msgstr "Источник"
@ -31798,7 +31798,7 @@ msgid "Total users"
msgstr ""
msgid "Total weight"
msgstr "Итоговый приоритет"
msgstr "Общий вес"
msgid "Total: %{total}"
msgstr "Всего: %{total}"
@ -33976,10 +33976,10 @@ msgid "Weeks"
msgstr "Недели"
msgid "Weight"
msgstr "Приоритет"
msgstr "Вес"
msgid "Weight %{weight}"
msgstr "Приоритет %{weight}"
msgstr "Вес %{weight}"
msgid "Welcome back! Your account had been deactivated due to inactivity but is now reactivated."
msgstr "Добро пожаловать! Ваша учётная запись была деактивирована из-за неактивности, но сейчас восстановлена."
@ -36507,7 +36507,7 @@ msgid "remove due date"
msgstr "удалить дату завершения"
msgid "remove weight"
msgstr "удалить приоритет"
msgstr "удалить вес"
msgid "removed a Zoom call from this issue"
msgstr ""

View File

@ -1,45 +1,47 @@
import Vue from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import banner from '~/cycle_analytics/components/banner.vue';
import { shallowMount } from '@vue/test-utils';
import Banner from '~/cycle_analytics/components/banner.vue';
describe('Value Stream Analytics banner', () => {
let vm;
let wrapper;
const createComponent = () => {
wrapper = shallowMount(Banner, {
propsData: {
documentationLink: 'path',
},
});
};
beforeEach(() => {
const Component = Vue.extend(banner);
vm = mountComponent(Component, {
documentationLink: 'path',
});
createComponent();
});
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
it('should render value stream analytics information', () => {
expect(vm.$el.querySelector('h4').textContent.trim()).toEqual(
'Introducing Value Stream Analytics',
);
expect(wrapper.find('h4').text().trim()).toBe('Introducing Value Stream Analytics');
expect(
vm.$el
.querySelector('p')
.textContent.trim()
wrapper
.find('p')
.text()
.trim()
.replace(/[\r\n]+/g, ' '),
).toContain(
'Value Stream Analytics gives an overview of how much time it takes to go from idea to production in your project.',
);
expect(vm.$el.querySelector('a').textContent.trim()).toEqual('Read more');
expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('path');
expect(wrapper.find('a').text().trim()).toBe('Read more');
expect(wrapper.find('a').attributes('href')).toBe('path');
});
it('should emit an event when close button is clicked', () => {
jest.spyOn(vm, '$emit').mockImplementation(() => {});
it('should emit an event when close button is clicked', async () => {
jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
vm.$el.querySelector('.js-ca-dismiss-button').click();
await wrapper.find('.js-ca-dismiss-button').trigger('click');
expect(vm.$emit).toHaveBeenCalled();
expect(wrapper.vm.$emit).toHaveBeenCalled();
});
});

View File

@ -187,6 +187,21 @@ RSpec.describe Gitlab::ObjectHierarchy do
context 'when the use_distinct_in_object_hierarchy feature flag is enabled' do
before do
stub_feature_flags(use_distinct_in_object_hierarchy: true)
stub_feature_flags(use_distinct_for_all_object_hierarchy: false)
end
it_behaves_like 'Gitlab::ObjectHierarchy test cases'
it 'calls DISTINCT' do
expect(parent.self_and_descendants.to_sql).to include("DISTINCT")
expect(child2.self_and_ancestors.to_sql).to include("DISTINCT")
end
end
context 'when the use_distinct_for_all_object_hierarchy feature flag is enabled' do
before do
stub_feature_flags(use_distinct_in_object_hierarchy: false)
stub_feature_flags(use_distinct_for_all_object_hierarchy: true)
end
it_behaves_like 'Gitlab::ObjectHierarchy test cases'
@ -200,6 +215,7 @@ RSpec.describe Gitlab::ObjectHierarchy do
context 'when the use_distinct_in_object_hierarchy feature flag is disabled' do
before do
stub_feature_flags(use_distinct_in_object_hierarchy: false)
stub_feature_flags(use_distinct_for_all_object_hierarchy: false)
end
it_behaves_like 'Gitlab::ObjectHierarchy test cases'

View File

@ -107,7 +107,7 @@ RSpec.describe API::API do
allow_any_instance_of(Gitlab::GrapeLogging::Loggers::ContextLogger).to receive(:parameters) do
Gitlab::ApplicationContext.current.tap do |log_context|
expect(log_context).to match('correlation_id' => an_instance_of(String),
'meta.caller_id' => '/api/:version/projects/:id/issues',
'meta.caller_id' => 'GET /api/:version/projects/:id/issues',
'meta.remote_ip' => an_instance_of(String),
'meta.project' => project.full_path,
'meta.root_namespace' => project.namespace.full_path,
@ -124,7 +124,7 @@ RSpec.describe API::API do
allow_any_instance_of(Gitlab::GrapeLogging::Loggers::ContextLogger).to receive(:parameters) do
Gitlab::ApplicationContext.current.tap do |log_context|
expect(log_context).to match('correlation_id' => an_instance_of(String),
'meta.caller_id' => '/api/:version/users',
'meta.caller_id' => 'GET /api/:version/users',
'meta.remote_ip' => an_instance_of(String),
'meta.client_id' => an_instance_of(String),
'meta.feature_category' => 'users')
@ -141,7 +141,7 @@ RSpec.describe API::API do
let(:component_map) do
{
"application" => "test",
"endpoint_id" => "/api/:version/users/:id"
"endpoint_id" => "GET /api/:version/users/:id"
}
end

View File

@ -127,7 +127,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
authorize_artifacts_with_token_in_params
end
it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/artifacts/authorize' do
it_behaves_like 'API::CI::Runner application context metadata', 'POST /api/:version/jobs/:id/artifacts/authorize' do
let(:send_request) { subject }
end
@ -262,7 +262,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
describe 'POST /api/v4/jobs/:id/artifacts' do
it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/artifacts' do
it_behaves_like 'API::CI::Runner application context metadata', 'POST /api/:version/jobs/:id/artifacts' do
let(:send_request) do
upload_artifacts(file_upload, headers_with_token)
end
@ -784,7 +784,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
describe 'GET /api/v4/jobs/:id/artifacts' do
let(:token) { job.token }
it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/artifacts' do
it_behaves_like 'API::CI::Runner application context metadata', 'GET /api/:version/jobs/:id/artifacts' do
let(:send_request) { download_artifact }
end

View File

@ -36,7 +36,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
job.run!
end
it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id' do
it_behaves_like 'API::CI::Runner application context metadata', 'PUT /api/:version/jobs/:id' do
let(:send_request) { update_job(state: 'success') }
end

View File

@ -41,7 +41,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
initial_patch_the_trace
end
it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/trace' do
it_behaves_like 'API::CI::Runner application context metadata', 'PATCH /api/:version/jobs/:id/trace' do
let(:send_request) { patch_the_trace }
end

View File

@ -644,7 +644,7 @@ RSpec.describe API::Internal::Base do
context 'with Project' do
it_behaves_like 'storing arguments in the application context' do
let(:expected_params) { { user: key.user.username, project: project.full_path } }
let(:expected_params) { { user: key.user.username, project: project.full_path, caller_id: "POST /api/:version/internal/allowed" } }
subject { push(key, project) }
end
@ -652,7 +652,7 @@ RSpec.describe API::Internal::Base do
context 'with PersonalSnippet' do
it_behaves_like 'storing arguments in the application context' do
let(:expected_params) { { user: key.user.username } }
let(:expected_params) { { user: key.user.username, caller_id: "POST /api/:version/internal/allowed" } }
subject { push(key, personal_snippet) }
end
@ -660,7 +660,7 @@ RSpec.describe API::Internal::Base do
context 'with ProjectSnippet' do
it_behaves_like 'storing arguments in the application context' do
let(:expected_params) { { user: key.user.username, project: project_snippet.project.full_path } }
let(:expected_params) { { user: key.user.username, project: project_snippet.project.full_path, caller_id: "POST /api/:version/internal/allowed" } }
subject { push(key, project_snippet) }
end

View File

@ -228,6 +228,7 @@ module Ci
context 'when the use_distinct_in_register_job_object_hierarchy feature flag is enabled' do
before do
stub_feature_flags(use_distinct_in_register_job_object_hierarchy: true)
stub_feature_flags(use_distinct_for_all_object_hierarchy: true)
end
it 'calls DISTINCT' do
@ -238,6 +239,7 @@ module Ci
context 'when the use_distinct_in_register_job_object_hierarchy feature flag is disabled' do
before do
stub_feature_flags(use_distinct_in_register_job_object_hierarchy: false)
stub_feature_flags(use_distinct_for_all_object_hierarchy: false)
end
it 'does not call DISTINCT' do

View File

@ -25,7 +25,7 @@ RSpec.shared_examples 'can highlight results' do |search_term|
end
it 'highlights the search terms' do
selector = '.gl-bg-orange-50'
selector = '.gl-bg-orange-100'
fill_in SearchHelpers::INPUT_PLACEHOLDER, with: search_term
expect(page).to have_css(selector)

View File

@ -29,6 +29,15 @@ RSpec.describe RemoveExpiredMembersWorker do
worker.perform
expect(non_expiring_project_member.reload).to be_present
end
it 'adds context to resulting jobs' do
worker.perform
new_job = Sidekiq::Worker.jobs.last
expect(new_job).to include('meta.project' => expired_project_member.project.full_path,
'meta.user' => expired_project_member.user.username)
end
end
context 'project bots' do
@ -98,6 +107,15 @@ RSpec.describe RemoveExpiredMembersWorker do
worker.perform
expect(non_expiring_group_member.reload).to be_present
end
it 'adds context to resulting jobs' do
worker.perform
new_job = Sidekiq::Worker.jobs.last
expect(new_job).to include('meta.root_namespace' => expired_group_member.group.full_path,
'meta.user' => expired_group_member.user.username)
end
end
context 'when the last group owner expires' do

View File

@ -9,7 +9,7 @@ RUN bundle config --global frozen 1
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock .
COPY Gemfile Gemfile.lock /usr/src/app/
# Install build dependencies - required for gems with native dependencies
RUN apk add --no-cache --virtual build-deps build-base postgresql-dev && \
bundle install && \