Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
cea25900b7
commit
06d4ce7ee0
|
@ -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;
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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 [];
|
||||
})
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.'),
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix ruby alpine CI template
|
||||
merge_request: 57109
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update weight transaltion for Russian locale
|
||||
merge_request: 56986
|
||||
author: Gennady Kovalev (@belolap)
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Push confidential_notes feature flag to mr frontend
|
||||
merge_request: 56798
|
||||
author: Lee Tickett @leetickett
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Enable DISTINCT optimization for ObjectHierarchy globally
|
||||
merge_request: 57052
|
||||
author:
|
||||
type: changed
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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 |
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -32,6 +32,10 @@ module API
|
|||
end
|
||||
end.compact.to_set
|
||||
end
|
||||
|
||||
def endpoint_id
|
||||
"#{request.request_method} #{route.origin}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 && \
|
||||
|
|
Loading…
Reference in New Issue