Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-22 09:15:04 +00:00
parent 8cfb9f566d
commit 2fa173410a
26 changed files with 182 additions and 88 deletions

View File

@ -17,9 +17,9 @@ import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/toolt
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue';
import { ListType } from '../constants';
import eventHub from '../eventhub';
import BoardBlockedIcon from './board_blocked_icon.vue';
import IssueDueDate from './issue_due_date.vue';
import IssueTimeEstimate from './issue_time_estimate.vue';
@ -34,7 +34,7 @@ export default {
IssueDueDate,
IssueTimeEstimate,
IssueCardWeight: () => import('ee_component/boards/components/issue_card_weight.vue'),
BoardBlockedIcon,
IssuableBlockedIcon,
GlSprintf,
BoardCardMoveToPosition,
WorkItemTypeIcon,
@ -218,7 +218,7 @@ export default {
<div>
<div class="gl-display-flex" dir="auto">
<h4 class="board-card-title gl-mb-0 gl-mt-0 gl-mr-3 gl-font-base gl-overflow-break-word">
<board-blocked-icon
<issuable-blocked-icon
v-if="item.blocked"
:item="item"
:unique-id="`${item.id}${list.id}`"

View File

@ -2,8 +2,6 @@ import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql
import { __ } from '~/locale';
import updateEpicSubscriptionMutation from '~/sidebar/queries/update_epic_subscription.mutation.graphql';
import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql';
import boardBlockingIssuesQuery from './graphql/board_blocking_issues.query.graphql';
import boardBlockingEpicsQuery from './graphql/board_blocking_epics.query.graphql';
import destroyBoardListMutation from './graphql/board_list_destroy.mutation.graphql';
import updateBoardListMutation from './graphql/board_list_update.mutation.graphql';
@ -67,15 +65,6 @@ export const listsQuery = {
},
};
export const blockingIssuablesQueries = {
[issuableTypes.issue]: {
query: boardBlockingIssuesQuery,
},
[issuableTypes.epic]: {
query: boardBlockingEpicsQuery,
},
};
export const updateListQueries = {
[issuableTypes.issue]: {
mutation: updateBoardListMutation,

View File

@ -0,0 +1,12 @@
import { issuableTypes } from '~/boards/constants';
import blockingIssuesQuery from './graphql/blocking_issues.query.graphql';
import blockingEpicsQuery from './graphql/blocking_epics.query.graphql';
export const blockingIssuablesQueries = {
[issuableTypes.issue]: {
query: blockingIssuesQuery,
},
[issuableTypes.epic]: {
query: blockingEpicsQuery,
},
};

View File

@ -1,4 +1,4 @@
query BoardBlockingEpics($fullPath: ID!, $iid: ID) {
query BlockingEpics($fullPath: ID!, $iid: ID) {
group(fullPath: $fullPath) {
id
issuable: epic(iid: $iid) {

View File

@ -1,4 +1,4 @@
query BoardBlockingIssues($id: IssueID!) {
query BlockingIssues($id: IssueID!) {
issuable: issue(id: $id) {
id
blockingIssuables: blockedByIssues {

View File

@ -1,10 +1,11 @@
<script>
import { GlIcon, GlLink, GlPopover, GlLoadingIcon } from '@gitlab/ui';
import { blockingIssuablesQueries, issuableTypes } from '~/boards/constants';
import { issuableTypes } from '~/boards/constants';
import { TYPE_ISSUE, TYPE_EPIC } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { truncate } from '~/lib/utils/text_utility';
import { __, n__, s__, sprintf } from '~/locale';
import { blockingIssuablesQueries } from './constants';
export default {
i18n: {
@ -28,7 +29,6 @@ export default {
GlLink,
GlLoadingIcon,
},
blockingIssuablesQueries,
props: {
item: {
type: Object,
@ -169,8 +169,8 @@ export default {
:id="glIconId"
ref="icon"
:name="blockIcon"
class="issue-blocked-icon gl-mr-2 gl-cursor-pointer gl-text-red-500"
data-testid="issue-blocked-icon"
class="issuable-blocked-icon gl-mr-2 gl-cursor-pointer gl-text-red-500"
data-testid="issuable-blocked-icon"
@mouseenter="handleMouseEnter"
/>
<gl-popover :target="glIconId" placement="top">
@ -182,12 +182,19 @@ export default {
<p class="gl-mt-4 gl-mb-0 gl-font-small">{{ loadingMessage }}</p>
</template>
<template v-else>
<ul class="gl-list-style-none gl-p-0">
<li v-for="issuable in displayedIssuables" :key="issuable.id">
<ul class="gl-list-style-none gl-p-0 gl-mb-0">
<li v-for="(issuable, index) in displayedIssuables" :key="issuable.id">
<gl-link :href="issuable.webUrl" class="gl-text-blue-500! gl-font-sm">{{
issuable.reference
}}</gl-link>
<p class="gl-mb-3 gl-display-block!" data-testid="issuable-title">
<p
class="gl-display-block!"
:class="{
'gl-mb-3': index < displayedIssuables.length - 1,
'gl-mb-0': index === displayedIssuables.length - 1,
}"
data-testid="issuable-title"
>
{{ issuable.title }}
</p>
</li>

View File

@ -4,11 +4,10 @@
- blame_path = project_blame_path(@project, tree_join(@ref, blob.path))
.line-numbers{ class: "gl-px-0!", data: { blame_path: blame_path } }
- if blob.data.present?
- link = blob_link if defined?(blob_link)
- blob.data.each_line.each_with_index do |_, index|
- i = index + offset
-# We're not using `link_to` because it is too slow once we get to thousands of lines.
%a.file-line-num.diff-line-num{ class: ("js-line-links" if Feature.enabled?(:file_line_blame)), href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i }
%a.file-line-num.diff-line-num{ class: ("js-line-links" if Feature.enabled?(:file_line_blame)), href: "#L#{i}", id: "L#{i}", 'data-line-number' => i }
= i
- highlight = defined?(highlight_line) && highlight_line ? highlight_line - offset : nil
.blob-content{ data: { blob_id: blob.id, path: blob.path, highlight_line: highlight, qa_selector: 'file_content' } }

View File

@ -310,6 +310,12 @@ To check the status of specific migrations, you can use the following Rake task:
sudo gitlab-rake db:migrate:status
```
To check the [tracking database on a Geo secondary site](../geo/setup/external_database.md#configure-the-tracking-database), you can use the following Rake task:
```shell
sudo gitlab-rake db:migrate:status:geo
```
This outputs a table with a `Status` of `up` or `down` for
each Migration ID.

View File

@ -52,7 +52,10 @@ good title can help communicate what the blueprint is and should be considered
as part of any review.
-->
[[_TOC_]]
<!--
For long pages, consider creating a table of contents.
The `[_TOC_]` function is not supported on docs.gitlab.com.
-->
## Summary

View File

@ -477,7 +477,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
### 15.3.0
- [Incorrect deletion of object storage files on Geo secondary sites]((https://gitlab.com/gitlab-org/gitlab/-/issues/371397)) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests when [Geo proxying](../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later. See [Geo: LFS transfer redirect to primary from secondary site mid-session issue in GitLab 15.1.0 to 15.3.2](#geo-lfs-transfers-redirect-to-primary-from-secondary-site-mid-session-in-gitlab-1510-to-1532) for more details.
### 15.2.0
@ -498,7 +498,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
1. Add `gitaly['runtime_dir'] = '<PATH_WITH_EXEC_PERM>'` to `/etc/gitlab/gitlab.rb` and specify a location without `noexec` set.
1. Run `sudo gitlab-ctl reconfigure`.
- [Incorrect deletion of object storage files on Geo secondary sites]((https://gitlab.com/gitlab-org/gitlab/-/issues/371397)) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests when [Geo proxying](../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later. See [Geo: LFS transfer redirect to primary from secondary site mid-session issue in GitLab 15.1.0 to 15.3.2](#geo-lfs-transfers-redirect-to-primary-from-secondary-site-mid-session-in-gitlab-1510-to-1532) for more details.
### 15.1.0
@ -518,7 +518,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
- Unauthenticated requests to the [`ciConfig` GraphQL field](../api/graphql/reference/index.md#queryciconfig) are no longer supported.
Before you upgrade to GitLab 15.1, add an [access token](../api/index.md#authentication) to your requests.
The user creating the token must have [permission](../user/permissions.md) to create pipelines in the project.
- [Incorrect deletion of object storage files on Geo secondary sites]((https://gitlab.com/gitlab-org/gitlab/-/issues/371397)) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests when [Geo proxying](../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later. See [Geo: LFS transfer redirect to primary from secondary site mid-session issue in GitLab 15.1.0 to 15.3.2](#geo-lfs-transfers-redirect-to-primary-from-secondary-site-mid-session-in-gitlab-1510-to-1532) for more details.
### 15.0.0
@ -534,7 +534,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
Gitaly. The previous implementation in GitLab Shell was removed in GitLab 15.0. With this change, global server hooks are stored only inside a subdirectory named after the
hook type. Global server hooks can no longer be a single hook file in the root of the custom hooks directory. For example, you must use `<custom_hooks_dir>/<hook_name>.d/*` rather
than `<custom_hooks_dir>/<hook_name>`.
- [Incorrect deletion of object storage files on Geo secondary sites]((https://gitlab.com/gitlab-org/gitlab/-/issues/371397)) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- The `FF_GITLAB_REGISTRY_HELPER_IMAGE` [feature flag](../administration/feature_flags.md#enable-or-disable-the-feature) is removed and helper images are always pulled from GitLab Registry.
### 14.10.0
@ -1183,7 +1183,7 @@ Read more [in the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/364763).
### Geo: Incorrect object storage LFS file deletion on secondary sites in GitLab 15.0.0 to 15.3.2
[Incorrect deletion of object storage files on Geo secondary sites]((https://gitlab.com/gitlab-org/gitlab/-/issues/371397))
[Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397)
can occur in GitLab 15.0.0 to 15.3.2 in the following situations:
- GitLab-managed object storage replication is disabled, and LFS objects are created while importing a project with object storage enabled.

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -146,6 +146,16 @@ the timeline header represent the days of the week.
The timeline bar indicates the approximate position of an epic or milestone based on its start and
due dates.
## Blocked epics
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33587) in GitLab 15.5: View blocking epics when hovering over the “blocked” icon.
If an epic is [blocked by another epic](../epics/linked_epics.md#blocking-epics), an icon appears next to its title to indicate its blocked status.
When you hover over the blocked icon (**{issue-block}**), a detailed information popover is displayed.
![Blocked epics](img/roadmap_blocked_icon_v15_5.png)
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues

View File

@ -0,0 +1,44 @@
---
stage: ModelOps
group: Applied ML
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
type: index, reference
---
# Suggested Reviewers Data Usage
## How it works
Suggested Reviewers is the first user-facing GitLab machine learning (ML) powered feature. It leverages a project's contribution graph to generate suggestions. This data already exists within GitLab including merge request metadata, source code files, and GitLab user account metadata.
### Enabling the feature
When a Project Maintainer or Owner enables Suggested Reviewers in project settings GitLab kicks off a data extraction job for the project which leverages the Merge Request API to understand pattern of review including recency, domain experience, and frequency to suggest an appropriate reviewer.
This data extraction job can take a few hours to complete (possibly up to a day), which is largely dependent on the size of the project. The process is automated and no action is needed during this process. Once data extraction is complete, you will start getting suggestions in merge requests.
### Generating suggestions
Once Suggested Reviewers is enabled and the data extraction is complete, new merge requests or new commits to existing merge requests will automatically trigger a Suggested Reviewers ML model inference and generate up to 5 suggested reviewers. These suggestions are contextual to the changes in the merge request. Additional commits to merge requests may change the reviewer suggestions which will automatically update in the reviewer dropdown.
## Progressive enhancement
This feature is designed as a progressive enhancement to the existing GitLab Reviewers functionality. The GitLab Reviewer UI will only offer suggestions if the ML engine is able to provide a recommendation. In the event of an issue or model inference failure, the feature will gracefully degrade. At no point with the usage of Suggested Reviewers prevent a user from being able to manually set a reviewer.
## Model Accuracy
Organizations use many different processes for code review. Some focus on senior engineers reviewing junior engineer's code, others have hierarchical organizational structure based reviews. Suggested Reviewers is focused on contextual reviewers based on historical merge request activity by users. While we will continue evolving the underlying ML model to better serve various code review use cases and processes Suggested Reviewers does not replace the usage of other code review features like Code Owners and [Approval Rules](../approvals/rules.md). Reviewer selection is highly subjective therefore, we do not expect Suggested Reviewers to provide perfect suggestions everytime.
Through analysis of beta customer usage, we find that the Suggested Reviewers ML model provides suggestions that are adopted in 60% of cases. We will be introducing a feedback mechanism into the Suggested Reviewers feature in the future to allow users to flag bad reviewer suggestions to help improve the model. Additionally we will be offering an opt-in feature in the future which will allow the model to use your project's data for training the underlying model.
## Off by default
Suggested Reviewers is off by default and requires a Project Owner or Admin to enable the feature.
## Data privacy
Suggested Reviewers operates completely within the GitLab.com infrastructure providing the same level of [privacy](https://about.gitlab.com/privacy/) and [security](https://about.gitlab.com/security/) of any other feature of GitLab.com.
No new additional data is collected to enable this feature, simply GitLab is inferencing your merge request against a trained machine learning model. The content of your source code is not used as training data. Your data also never leaves GitLab.com, all training and inference is done within GitLab.com infrastructure.
[Read more about the security of GitLab.com](https://about.gitlab.com/security/faq/)

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -21,6 +21,26 @@ You can review merge requests from the GitLab interface. If you install the
[GitLab Workflow VS Code extension](../../repository/vscode.md), you can also
review merge requests in Visual Studio Code.
## Suggested reviewers **(ULTIMATE SAAS)**
> [Introduced](https://gitlab.com/groups/gitlab-org/modelops/applied-ml/review-recommender/-/epics/3) in GitLab 15.4.
GitLab can recommend reviewers with Suggested Reviewers. Using the changes in a merge request and a project's contribution graph, machine learning powered suggestions appear in the reviewer section of the right merge request sidebar.
![Suggested Reviewers](img/suggested_reviewers_v15_4.png)
This feature is currently in [Open Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#open-beta) behind a [feature flag](https://gitlab.com/gitlab-org/gitlab/-/issues/368356).
Learn more about [how suggested reviewers works and data privacy](data_usage.md).
### Enable suggested reviewers
Project Maintainers or Owners can enable suggested reviewers by visiting the [project settings](../../settings/index.md).
Enabling suggested reviewers will trigger GitLab to create an ML model for your project that will be used to generate reviewers. The larger your project, the longer this can take, but usually, the model will be ready to generate suggestions within a few hours.
No action is required once the feature is enabled. Once the model is ready, recommendations will populate the Reviewer dropdown in the right-hand sidebar of a merge request with new commits.
## Review a merge request
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4213) in GitLab 11.4.

View File

@ -67,13 +67,13 @@ RSpec.describe 'Incident Detail', :js do
expect(incident_tabs).to have_content('"yet.another": 73')
# does not show the linked issues and notes/comment components' do
hidden_items = find_all('.js-issue-widgets')
hidden_items = find_all('.js-issue-widgets', wait: false)
# Linked Issues/MRs and comment box are hidden on page
expect(hidden_items.count).to eq(0)
# does not show the edit title and description button
edit_button = find_all('[aria-label="Edit title and description"]')
edit_button = find_all('[aria-label="Edit title and description"]', wait: false)
expect(edit_button.count).to eq(0)
end
end
@ -83,12 +83,14 @@ RSpec.describe 'Incident Detail', :js do
before do
visit project_issue_path(project, incident)
wait_for_requests
click_link 'Timeline'
wait_for_requests
end
it 'does not show the linked issues and notes/comment components' do
page.within('.issuable-details') do
hidden_items = find_all('.js-issue-widgets')
hidden_items = find_all('.js-issue-widgets', wait: false)
# Linked Issues/MRs and comment box are hidden on page
expect(hidden_items.count).to eq(0)

View File

@ -5,7 +5,7 @@ import { nextTick } from 'vue';
import setWindowLocation from 'helpers/set_window_location_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import BoardBlockedIcon from '~/boards/components/board_blocked_icon.vue';
import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue';
import BoardCardInner from '~/boards/components/board_card_inner.vue';
import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
@ -39,7 +39,7 @@ describe('Board card component', () => {
let list;
let store;
const findBoardBlockedIcon = () => wrapper.findComponent(BoardBlockedIcon);
const findIssuableBlockedIcon = () => wrapper.findComponent(IssuableBlockedIcon);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findEpicCountablesTotalTooltip = () => wrapper.findComponent(GlTooltip);
const findEpicCountables = () => wrapper.findByTestId('epic-countables');
@ -189,7 +189,7 @@ describe('Board card component', () => {
},
});
expect(findBoardBlockedIcon().exists()).toBe(true);
expect(findIssuableBlockedIcon().exists()).toBe(true);
});
it('does not show blocked icon if issue is not blocked', () => {
@ -200,7 +200,7 @@ describe('Board card component', () => {
},
});
expect(findBoardBlockedIcon().exists()).toBe(false);
expect(findIssuableBlockedIcon().exists()).toBe(false);
});
});

View File

@ -1,23 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BoardBlockedIcon on mouseenter on blocked icon with more than three blocking issues matches the snapshot 1`] = `
"<div class=\\"gl-display-inline\\"><svg data-testid=\\"issue-blocked-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"issue-blocked-icon gl-mr-2 gl-cursor-pointer gl-text-red-500 gl-icon s16\\" id=\\"blocked-icon-uniqueId\\">
exports[`IssuableBlockedIcon on mouseenter on blocked icon with more than three blocking issues matches the snapshot 1`] = `
"<div class=\\"gl-display-inline\\"><svg data-testid=\\"issuable-blocked-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"issuable-blocked-icon gl-mr-2 gl-cursor-pointer gl-text-red-500 gl-icon s16\\" id=\\"blocked-icon-uniqueId\\">
<use href=\\"#issue-block\\"></use>
</svg>
<div class=\\"gl-popover\\">
<ul class=\\"gl-list-style-none gl-p-0\\">
<ul class=\\"gl-list-style-none gl-p-0 gl-mb-0\\">
<li><a href=\\"http://gdk.test:3000/gitlab-org/my-project-1/-/issues/6\\" class=\\"gl-link gl-text-blue-500! gl-font-sm\\">my-project-1#6</a>
<p data-testid=\\"issuable-title\\" class=\\"gl-mb-3 gl-display-block!\\">
<p data-testid=\\"issuable-title\\" class=\\"gl-display-block! gl-mb-3\\">
blocking issue title 1
</p>
</li>
<li><a href=\\"http://gdk.test:3000/gitlab-org/my-project-1/-/issues/5\\" class=\\"gl-link gl-text-blue-500! gl-font-sm\\">my-project-1#5</a>
<p data-testid=\\"issuable-title\\" class=\\"gl-mb-3 gl-display-block!\\">
<p data-testid=\\"issuable-title\\" class=\\"gl-display-block! gl-mb-3\\">
blocking issue title 2 + blocking issue title 2 + blocking issue title 2 + bloc…
</p>
</li>
<li><a href=\\"http://gdk.test:3000/gitlab-org/my-project-1/-/issues/4\\" class=\\"gl-link gl-text-blue-500! gl-font-sm\\">my-project-1#4</a>
<p data-testid=\\"issuable-title\\" class=\\"gl-mb-3 gl-display-block!\\">
<p data-testid=\\"issuable-title\\" class=\\"gl-display-block! gl-mb-0\\">
blocking issue title 3
</p>
</li>

View File

@ -5,8 +5,9 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import BoardBlockedIcon from '~/boards/components/board_blocked_icon.vue';
import { blockingIssuablesQueries, issuableTypes } from '~/boards/constants';
import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue';
import { blockingIssuablesQueries } from '~/vue_shared/components/issuable_blocked_icon/constants';
import { issuableTypes } from '~/boards/constants';
import { truncate } from '~/lib/utils/text_utility';
import {
mockIssue,
@ -21,9 +22,9 @@ import {
mockBlockedIssue2,
mockBlockedEpic1,
mockBlockingEpicIssuablesResponse1,
} from '../mock_data';
} from '../../boards/mock_data';
describe('BoardBlockedIcon', () => {
describe('IssuableBlockedIcon', () => {
let wrapper;
let mockApollo;
@ -64,7 +65,7 @@ describe('BoardBlockedIcon', () => {
Vue.use(VueApollo);
wrapper = extendedWrapper(
mount(BoardBlockedIcon, {
mount(IssuableBlockedIcon, {
apolloProvider: mockApollo,
propsData: {
item: {
@ -88,7 +89,7 @@ describe('BoardBlockedIcon', () => {
issuableType = issuableTypes.issue,
} = {}) => {
wrapper = extendedWrapper(
shallowMount(BoardBlockedIcon, {
shallowMount(IssuableBlockedIcon, {
propsData: {
item: {
...mockIssuable,

View File

@ -26,11 +26,10 @@ type queueMetrics struct {
// newQueueMetrics prepares Prometheus metrics for queueing mechanism
// name specifies name of the queue, used to label metrics with ConstLabel `queue_name`
// Don't call newQueueMetrics twice with the same name argument!
// timeout specifies the timeout of storing a request in queue - queueMetrics
// uses it to calculate histogram buckets for gitlab_workhorse_queueing_waiting_time
// metric
func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
func newQueueMetrics(name string, timeout time.Duration, reg prometheus.Registerer) *queueMetrics {
waitingTimeBuckets := []float64{
timeout.Seconds() * 0.01,
timeout.Seconds() * 0.05,
@ -44,8 +43,9 @@ func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
timeout.Seconds(),
}
promFactory := promauto.With(reg)
metrics := &queueMetrics{
queueingLimit: promauto.NewGauge(prometheus.GaugeOpts{
queueingLimit: promFactory.NewGauge(prometheus.GaugeOpts{
Name: "gitlab_workhorse_queueing_limit",
Help: "Current limit set for the queueing mechanism",
ConstLabels: prometheus.Labels{
@ -53,7 +53,7 @@ func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
},
}),
queueingQueueLimit: promauto.NewGauge(prometheus.GaugeOpts{
queueingQueueLimit: promFactory.NewGauge(prometheus.GaugeOpts{
Name: "gitlab_workhorse_queueing_queue_limit",
Help: "Current queueLimit set for the queueing mechanism",
ConstLabels: prometheus.Labels{
@ -61,7 +61,7 @@ func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
},
}),
queueingQueueTimeout: promauto.NewGauge(prometheus.GaugeOpts{
queueingQueueTimeout: promFactory.NewGauge(prometheus.GaugeOpts{
Name: "gitlab_workhorse_queueing_queue_timeout",
Help: "Current queueTimeout set for the queueing mechanism",
ConstLabels: prometheus.Labels{
@ -69,7 +69,7 @@ func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
},
}),
queueingBusy: promauto.NewGauge(prometheus.GaugeOpts{
queueingBusy: promFactory.NewGauge(prometheus.GaugeOpts{
Name: "gitlab_workhorse_queueing_busy",
Help: "How many queued requests are now processed",
ConstLabels: prometheus.Labels{
@ -77,7 +77,7 @@ func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
},
}),
queueingWaiting: promauto.NewGauge(prometheus.GaugeOpts{
queueingWaiting: promFactory.NewGauge(prometheus.GaugeOpts{
Name: "gitlab_workhorse_queueing_waiting",
Help: "How many requests are now queued",
ConstLabels: prometheus.Labels{
@ -85,7 +85,7 @@ func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
},
}),
queueingWaitingTime: promauto.NewHistogram(prometheus.HistogramOpts{
queueingWaitingTime: promFactory.NewHistogram(prometheus.HistogramOpts{
Name: "gitlab_workhorse_queueing_waiting_time",
Help: "How many time a request spent in queue",
ConstLabels: prometheus.Labels{
@ -94,7 +94,7 @@ func newQueueMetrics(name string, timeout time.Duration) *queueMetrics {
Buckets: waitingTimeBuckets,
}),
queueingErrors: promauto.NewCounterVec(
queueingErrors: promFactory.NewCounterVec(
prometheus.CounterOpts{
Name: "gitlab_workhorse_queueing_errors",
Help: "How many times the TooManyRequests or QueueintTimedout errors were returned while queueing, partitioned by error type",
@ -120,12 +120,11 @@ type Queue struct {
// newQueue creates a new queue
// name specifies name used to label queue metrics.
// Don't call newQueue twice with the same name argument!
// limit specifies number of requests run concurrently
// queueLimit specifies maximum number of requests that can be queued
// timeout specifies the time limit of storing the request in the queue
// if the number of requests is above the limit
func newQueue(name string, limit, queueLimit uint, timeout time.Duration) *Queue {
func newQueue(name string, limit, queueLimit uint, timeout time.Duration, reg prometheus.Registerer) *Queue {
queue := &Queue{
name: name,
busyCh: make(chan struct{}, limit),
@ -133,7 +132,7 @@ func newQueue(name string, limit, queueLimit uint, timeout time.Duration) *Queue
timeout: timeout,
}
queue.queueMetrics = newQueueMetrics(name, timeout)
queue.queueMetrics = newQueueMetrics(name, timeout, reg)
queue.queueingLimit.Set(float64(limit))
queue.queueingQueueLimit.Set(float64(queueLimit))
queue.queueingQueueTimeout.Set(timeout.Seconds())

View File

@ -3,10 +3,12 @@ package queueing
import (
"testing"
"time"
"github.com/prometheus/client_golang/prometheus"
)
func TestNormalQueueing(t *testing.T) {
q := newQueue("queue 1", 2, 1, time.Microsecond)
q := newQueue("queue name", 2, 1, time.Microsecond, prometheus.NewRegistry())
err1 := q.Acquire()
if err1 != nil {
t.Fatal("we should acquire a new slot")
@ -31,7 +33,7 @@ func TestNormalQueueing(t *testing.T) {
}
func TestQueueLimit(t *testing.T) {
q := newQueue("queue 2", 1, 0, time.Microsecond)
q := newQueue("queue name", 1, 0, time.Microsecond, prometheus.NewRegistry())
err1 := q.Acquire()
if err1 != nil {
t.Fatal("we should acquire a new slot")
@ -44,7 +46,7 @@ func TestQueueLimit(t *testing.T) {
}
func TestQueueProcessing(t *testing.T) {
q := newQueue("queue 3", 1, 1, time.Second)
q := newQueue("queue name", 1, 1, time.Second, prometheus.NewRegistry())
err1 := q.Acquire()
if err1 != nil {
t.Fatal("we should acquire a new slot")

View File

@ -4,6 +4,8 @@ import (
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/helper"
)
@ -19,7 +21,7 @@ const (
// limit specifies number of requests run concurrently
// queueLimit specifies maximum number of requests that can be queued
// queueTimeout specifies the time limit of storing the request in the queue
func QueueRequests(name string, h http.Handler, limit, queueLimit uint, queueTimeout time.Duration) http.Handler {
func QueueRequests(name string, h http.Handler, limit, queueLimit uint, queueTimeout time.Duration, reg prometheus.Registerer) http.Handler {
if limit == 0 {
return h
}
@ -27,7 +29,7 @@ func QueueRequests(name string, h http.Handler, limit, queueLimit uint, queueTim
queueTimeout = DefaultTimeout
}
queue := newQueue(name, limit, queueLimit, queueTimeout)
queue := newQueue(name, limit, queueLimit, queueTimeout, reg)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := queue.Acquire()

View File

@ -6,6 +6,8 @@ import (
"net/http/httptest"
"testing"
"time"
"github.com/prometheus/client_golang/prometheus"
)
var httpHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -21,7 +23,7 @@ func pausedHttpHandler(pauseCh chan struct{}) http.Handler {
func TestNormalRequestProcessing(t *testing.T) {
w := httptest.NewRecorder()
h := QueueRequests("Normal request processing", httpHandler, 1, 1, time.Second)
h := QueueRequests("Normal request processing", httpHandler, 1, 1, time.Second, prometheus.NewRegistry())
h.ServeHTTP(w, nil)
if w.Code != 200 {
t.Fatal("QueueRequests should process request")
@ -36,7 +38,7 @@ func testSlowRequestProcessing(name string, count int, limit, queueLimit uint, q
pauseCh := make(chan struct{})
defer close(pauseCh)
handler := QueueRequests("Slow request processing: "+name, pausedHttpHandler(pauseCh), limit, queueLimit, queueTimeout)
handler := QueueRequests("Slow request processing: "+name, pausedHttpHandler(pauseCh), limit, queueLimit, queueTimeout, prometheus.NewRegistry())
respCh := make(chan *httptest.ResponseRecorder, count)

View File

@ -37,17 +37,13 @@ func (s *s3Session) isExpired() bool {
return time.Now().After(s.expiry)
}
func newS3SessionCache() *s3SessionCache {
return &s3SessionCache{sessions: make(map[config.S3Config]*s3Session)}
}
var (
// By default, it looks like IAM instance profiles may last 6 hours
// (via curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<role_name>),
// but this may be configurable from anywhere for 15 minutes to 12
// hours. To be safe, refresh AWS sessions every 10 minutes.
sessionExpiration = time.Duration(10 * time.Minute)
sessionCache = newS3SessionCache()
sessionCache = &s3SessionCache{sessions: make(map[config.S3Config]*s3Session)}
)
// SetupS3Session initializes a new AWS S3 session and refreshes one if
@ -105,10 +101,3 @@ func setupS3Session(s3Credentials config.S3Credentials, s3Config config.S3Config
return sess, nil
}
func ResetS3Session(s3Config config.S3Config) {
sessionCache.Lock()
defer sessionCache.Unlock()
delete(sessionCache.sessions, s3Config)
}

View File

@ -12,6 +12,8 @@ import (
)
func TestS3SessionSetup(t *testing.T) {
resetS3Sessions()
credentials := config.S3Credentials{}
cfg := config.S3Config{Region: "us-west-1", PathStyle: true}
@ -28,11 +30,11 @@ func TestS3SessionSetup(t *testing.T) {
_, err = setupS3Session(credentials, anotherConfig)
require.NoError(t, err)
require.Equal(t, len(sessionCache.sessions), 1)
ResetS3Session(cfg)
}
func TestS3SessionEndpointSetup(t *testing.T) {
resetS3Sessions()
credentials := config.S3Credentials{}
const customS3Endpoint = "https://example.com"
const region = "us-west-2"
@ -48,11 +50,11 @@ func TestS3SessionEndpointSetup(t *testing.T) {
stsConfig := sess.ClientConfig(endpoints.StsServiceID)
require.Equal(t, "https://sts.amazonaws.com", stsConfig.Endpoint, "STS should use default endpoint")
ResetS3Session(cfg)
}
func TestS3SessionExpiry(t *testing.T) {
resetS3Sessions()
credentials := config.S3Credentials{}
cfg := config.S3Config{Region: "us-west-1", PathStyle: true}
@ -75,6 +77,10 @@ func TestS3SessionExpiry(t *testing.T) {
nextSession, ok := sessionCache.sessions[cfg]
require.True(t, ok)
require.False(t, nextSession.isExpired())
ResetS3Session(cfg)
}
func resetS3Sessions() {
sessionCache.Lock()
defer sessionCache.Unlock()
sessionCache.sessions = make(map[config.S3Config]*s3Session)
}

View File

@ -6,6 +6,7 @@ import (
"regexp"
"github.com/gorilla/websocket"
"github.com/prometheus/client_golang/prometheus"
"gitlab.com/gitlab-org/labkit/log"
"gitlab.com/gitlab-org/labkit/tracing"
@ -221,7 +222,7 @@ func configureRoutes(u *upstream) {
mimeMultipartUploader := upload.Multipart(api, signingProxy, preparer)
tempfileMultipartProxy := upload.FixedPreAuthMultipart(api, proxy, preparer)
ciAPIProxyQueue := queueing.QueueRequests("ci_api_job_requests", tempfileMultipartProxy, u.APILimit, u.APIQueueLimit, u.APIQueueTimeout)
ciAPIProxyQueue := queueing.QueueRequests("ci_api_job_requests", tempfileMultipartProxy, u.APILimit, u.APIQueueLimit, u.APIQueueTimeout, prometheus.DefaultRegisterer)
ciAPILongPolling := builds.RegisterHandler(ciAPIProxyQueue, u.watchKeyHandler, u.APICILongPollingDuration)
dependencyProxyInjector.SetUploadHandler(requestBodyUploader)