Commit 54cbcea9 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 71221554
...@@ -70,9 +70,9 @@ export default ({ container }) => ...@@ -70,9 +70,9 @@ export default ({ container }) =>
let durationString = ''; let durationString = '';
if (navigationEntries.length > 0) { if (navigationEntries.length > 0) {
durationString = `BE ${this.formatMs(navigationEntries[0].responseEnd)} / `; durationString = `${Math.round(navigationEntries[0].responseEnd)} | `;
durationString += `FCP ${this.formatMs(paintEntries[1].startTime)} / `; durationString += `${Math.round(paintEntries[1].startTime)} | `;
durationString += `DOM ${this.formatMs(navigationEntries[0].domContentLoadedEventEnd)}`; durationString += ` ${Math.round(navigationEntries[0].domContentLoadedEventEnd)}`;
} }
let newEntries = resourceEntries.map(this.transformResourceEntry); let newEntries = resourceEntries.map(this.transformResourceEntry);
...@@ -105,10 +105,6 @@ export default ({ container }) => ...@@ -105,10 +105,6 @@ export default ({ container }) =>
size: entry.transferSize ? `${nf.format(entry.transferSize)} bytes` : 'cached', size: entry.transferSize ? `${nf.format(entry.transferSize)} bytes` : 'cached',
}; };
}, },
formatMs(msValue) {
const nf = new Intl.NumberFormat();
return `${nf.format(Math.round(msValue))}ms`;
},
}, },
render(createElement) { render(createElement) {
return createElement('performance-bar-app', { return createElement('performance-bar-app', {
......
...@@ -12,6 +12,7 @@ import { scrollToElement } from '~/lib/utils/common_utils'; ...@@ -12,6 +12,7 @@ import { scrollToElement } from '~/lib/utils/common_utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ReleaseBlockFooter from './release_block_footer.vue'; import ReleaseBlockFooter from './release_block_footer.vue';
import EvidenceBlock from './evidence_block.vue'; import EvidenceBlock from './evidence_block.vue';
import ReleaseBlockMilestoneInfo from './release_block_milestone_info.vue';
export default { export default {
name: 'ReleaseBlock', name: 'ReleaseBlock',
...@@ -23,6 +24,7 @@ export default { ...@@ -23,6 +24,7 @@ export default {
Icon, Icon,
UserAvatarLink, UserAvatarLink,
ReleaseBlockFooter, ReleaseBlockFooter,
ReleaseBlockMilestoneInfo,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
...@@ -90,6 +92,12 @@ export default { ...@@ -90,6 +92,12 @@ export default {
shouldShowFooter() { shouldShowFooter() {
return this.glFeatures.releaseIssueSummary; return this.glFeatures.releaseIssueSummary;
}, },
shouldRenderReleaseMetaData() {
return !this.glFeatures.releaseIssueSummary;
},
shouldRenderMilestoneInfo() {
return Boolean(this.glFeatures.releaseIssueSummary && !_.isEmpty(this.release.milestones));
},
}, },
mounted() { mounted() {
const hash = getLocationHash(); const hash = getLocationHash();
...@@ -106,26 +114,30 @@ export default { ...@@ -106,26 +114,30 @@ export default {
</script> </script>
<template> <template>
<div :id="id" :class="{ 'bg-line-target-blue': isHighlighted }" class="card release-block"> <div :id="id" :class="{ 'bg-line-target-blue': isHighlighted }" class="card release-block">
<div class="card-header d-flex align-items-center bg-white pr-0">
<h2 class="card-title my-2 mr-auto gl-font-size-20">
{{ release.name }}
<gl-badge v-if="release.upcoming_release" variant="warning" class="align-middle">{{
__('Upcoming Release')
}}</gl-badge>
</h2>
<gl-link
v-if="shouldShowEditButton"
v-gl-tooltip
class="btn btn-default append-right-10 js-edit-button ml-2"
:title="__('Edit this release')"
:href="release._links.edit_url"
>
<icon name="pencil" />
</gl-link>
</div>
<div class="card-body"> <div class="card-body">
<div class="d-flex align-items-start"> <div v-if="shouldRenderMilestoneInfo">
<h2 class="card-title mt-0 mr-auto"> <release-block-milestone-info :milestones="release.milestones" />
{{ release.name }} <hr class="mb-3 mt-0" />
<gl-badge v-if="release.upcoming_release" variant="warning" class="align-middle">{{
__('Upcoming Release')
}}</gl-badge>
</h2>
<gl-link
v-if="shouldShowEditButton"
v-gl-tooltip
class="btn btn-default js-edit-button ml-2"
:title="__('Edit this release')"
:href="release._links.edit_url"
>
<icon name="pencil" />
</gl-link>
</div> </div>
<div class="card-subtitle d-flex flex-wrap text-secondary"> <div v-if="shouldRenderReleaseMetaData" class="card-subtitle d-flex flex-wrap text-secondary">
<div class="append-right-8"> <div class="append-right-8">
<icon name="commit" class="align-middle" /> <icon name="commit" class="align-middle" />
<gl-link v-if="commitUrl" v-gl-tooltip.bottom :title="commit.title" :href="commitUrl"> <gl-link v-if="commitUrl" v-gl-tooltip.bottom :title="commit.title" :href="commitUrl">
......
<script>
import { GlProgressBar, GlLink, GlBadge, GlButton, GlTooltipDirective } from '@gitlab/ui';
import { __, n__, sprintf } from '~/locale';
import { MAX_MILESTONES_TO_DISPLAY } from '../constants';
/** Sums the values of an array. For use with Array.reduce. */
const sumReducer = (acc, curr) => acc + curr;
export default {
name: 'ReleaseBlockMilestoneInfo',
components: {
GlProgressBar,
GlLink,
GlBadge,
GlButton,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
milestones: {
type: Array,
required: true,
},
},
data() {
return {
showAllMilestones: false,
};
},
computed: {
percentCompleteText() {
return sprintf(__('%{percent}%{percentSymbol} complete'), {
percent: this.percentComplete,
percentSymbol: '%',
});
},
percentComplete() {
const percent = Math.round((this.closedIssuesCount / this.totalIssuesCount) * 100);
return Number.isNaN(percent) ? 0 : percent;
},
allIssueStats() {
return this.milestones.map(m => m.issue_stats || {});
},
openIssuesCount() {
return this.allIssueStats.map(stats => stats.opened || 0).reduce(sumReducer);
},
closedIssuesCount() {
return this.allIssueStats.map(stats => stats.closed || 0).reduce(sumReducer);
},
totalIssuesCount() {
return this.openIssuesCount + this.closedIssuesCount;
},
milestoneLabelText() {
return n__('Milestone', 'Milestones', this.milestones.length);
},
issueCountsText() {
return sprintf(__('Open: %{open} • Closed: %{closed}'), {
open: this.openIssuesCount,
closed: this.closedIssuesCount,
});
},
milestonesToDisplay() {
return this.showAllMilestones
? this.milestones
: this.milestones.slice(0, MAX_MILESTONES_TO_DISPLAY);
},
showMoreLink() {
return this.milestones.length > MAX_MILESTONES_TO_DISPLAY;
},
moreText() {
return this.showAllMilestones
? __('show fewer')
: sprintf(__('show %{count} more'), {
count: this.milestones.length - MAX_MILESTONES_TO_DISPLAY,
});
},
},
methods: {
toggleShowAll() {
this.showAllMilestones = !this.showAllMilestones;
},
shouldRenderBullet(milestoneIndex) {
return Boolean(milestoneIndex !== this.milestonesToDisplay.length - 1 || this.showMoreLink);
},
shouldRenderShowMoreLink(milestoneIndex) {
return Boolean(milestoneIndex === this.milestonesToDisplay.length - 1 && this.showMoreLink);
},
},
};
</script>
<template>
<div class="release-block-milestone-info d-flex align-items-start flex-wrap">
<div
v-gl-tooltip
class="milestone-progress-bar-container js-milestone-progress-bar-container d-flex flex-column align-items-start flex-shrink-1 mr-4 mb-3"
:title="__('Closed issues')"
>
<span class="mb-2">{{ percentCompleteText }}</span>
<span class="w-100">
<gl-progress-bar :value="closedIssuesCount" :max="totalIssuesCount" variant="success" />
</span>
</div>
<div class="d-flex flex-column align-items-start mr-4 mb-3 js-milestone-list-container">
<span class="mb-1">{{ milestoneLabelText }}</span>
<div class="d-flex flex-wrap align-items-end">
<template v-for="(milestone, index) in milestonesToDisplay">
<gl-link
:key="milestone.id"
v-gl-tooltip
:title="milestone.description"
:href="milestone.web_url"
class="append-right-4"
>
{{ milestone.title }}
</gl-link>
<template v-if="shouldRenderBullet(index)">
<span :key="'bullet-' + milestone.id" class="append-right-4">&bull;</span>
</template>
<template v-if="shouldRenderShowMoreLink(index)">
<gl-button :key="'more-button-' + milestone.id" variant="link" @click="toggleShowAll">
{{ moreText }}
</gl-button>
</template>
</template>
</div>
</div>
<div class="d-flex flex-column align-items-start flex-shrink-0 mr-4 mb-3 js-issues-container">
<span class="mb-1">
{{ __('Issues') }}
<gl-badge pill variant="light" class="font-weight-bold">{{ totalIssuesCount }}</gl-badge>
</span>
{{ issueCountsText }}
</div>
</div>
</template>
/* eslint-disable import/prefer-default-export */
// This eslint-disable ^^^ can be removed when at least
// one more constant is added to this file. Currently
// constants.js files with only a single constant
// are flagged by this rule.
export const MAX_MILESTONES_TO_DISPLAY = 5;
.release-block-milestone-info {
.milestone-progress-bar-container {
width: 300px;
min-height: 46px;
}
}
---
title: Add issue statistics to releases on the Releases page
merge_request: 19448
author:
type: added
...@@ -645,6 +645,7 @@ Settings.rack_attack.git_basic_auth['ip_whitelist'] ||= %w{127.0.0.1} ...@@ -645,6 +645,7 @@ Settings.rack_attack.git_basic_auth['ip_whitelist'] ||= %w{127.0.0.1}
Settings.rack_attack.git_basic_auth['maxretry'] ||= 10 Settings.rack_attack.git_basic_auth['maxretry'] ||= 10
Settings.rack_attack.git_basic_auth['findtime'] ||= 1.minute Settings.rack_attack.git_basic_auth['findtime'] ||= 1.minute
Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour
Settings.rack_attack['admin_area_protected_paths_enabled'] ||= false
# #
# Gitaly # Gitaly
......
# Specs for this file can be found on:
# * spec/lib/gitlab/throttle_spec.rb
# * spec/requests/rack_attack_global_spec.rb
module Gitlab::Throttle module Gitlab::Throttle
def self.settings def self.settings
Gitlab::CurrentSettings.current_application_settings Gitlab::CurrentSettings.current_application_settings
end end
# Returns true if we should use the Admin Area protected paths throttle
def self.protected_paths_enabled? def self.protected_paths_enabled?
!self.omnibus_protected_paths_present? && return false if should_use_omnibus_protected_paths?
self.settings.throttle_protected_paths_enabled?
self.settings.throttle_protected_paths_enabled?
end
# To be removed in 13.0: https://gitlab.com/gitlab-org/gitlab/issues/29952
def self.should_use_omnibus_protected_paths?
!Settings.rack_attack.admin_area_protected_paths_enabled &&
self.omnibus_protected_paths_present?
end end
def self.omnibus_protected_paths_present? def self.omnibus_protected_paths_present?
......
...@@ -16,10 +16,10 @@ It allows you to see (from left to right): ...@@ -16,10 +16,10 @@ It allows you to see (from left to right):
![Rugged profiling using the Performance Bar](img/performance_bar_rugged_calls.png) ![Rugged profiling using the Performance Bar](img/performance_bar_rugged_calls.png)
- time taken and number of Redis calls; click through for details of these calls - time taken and number of Redis calls; click through for details of these calls
![Redis profiling using the Performance Bar](img/performance_bar_redis_calls.png) ![Redis profiling using the Performance Bar](img/performance_bar_redis_calls.png)
- total load timings of the page; click through for details of these calls - total load timings of the page; click through for details of these calls. Values in the following order:
- BE = Backend - Time that the actual base page took to load - Backend - Time that the actual base page took to load
- FCP = [First Contentful Paint](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint) - Time until something was visible to the user - [First Contentful Paint](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint) - Time until something was visible to the user
- DOM = [DomContentLoaded](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/measure-crp) Event - [DomContentLoaded](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/measure-crp) Event
- Number of Requests that the page loaded - Number of Requests that the page loaded
![Frontend requests using the Performance Bar](img/performance_bar_frontend.png) ![Frontend requests using the Performance Bar](img/performance_bar_frontend.png)
- a link to add a request's details to the performance bar; the request can be - a link to add a request's details to the performance bar; the request can be
......
...@@ -130,5 +130,25 @@ remote: Calculating new repository size... (cancelled after 729ms) ...@@ -130,5 +130,25 @@ remote: Calculating new repository size... (cancelled after 729ms)
This could be used to further investigate what operation is performing poorly This could be used to further investigate what operation is performing poorly
and provide GitLab with more information on how to improve the service. and provide GitLab with more information on how to improve the service.
## `git clone` over HTTP fails with `transfer closed with outstanding read data remaining` error
If the buffer size is lower than what is allowed in the request, the action will fail with an error similar to the one below:
```text
error: RPC failed; curl 18 transfer closed with outstanding read data remaining
fatal: The remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed
```
This can be fixed by increasing the existing `http.postBuffer` value to one greater than the repository size. For example, if `git clone` fails when cloning a 500M repository, the solution will be to set `http.postBuffer` to `524288000` so that the request only starts buffering after the first 524288000 bytes.
NOTE: **Note:**
The default value of `http.postBuffer`, 1 MiB, is applied if the setting is not configured.
```sh
git config http.postBuffer 524288000
```
[SSH troubleshooting]: ../../ssh/README.md#troubleshooting "SSH Troubleshooting" [SSH troubleshooting]: ../../ssh/README.md#troubleshooting "SSH Troubleshooting"
[Broken-Pipe]: https://stackoverflow.com/questions/19120120/broken-pipe-when-pushing-to-git-repository/36971469#36971469 "StackOverflow: 'Broken pipe when pushing to Git repository'" [Broken-Pipe]: https://stackoverflow.com/questions/19120120/broken-pipe-when-pushing-to-git-repository/36971469#36971469 "StackOverflow: 'Broken pipe when pushing to Git repository'"
...@@ -60,18 +60,14 @@ NOTE: **Note:** If Omnibus settings are present, applications settings will be a ...@@ -60,18 +60,14 @@ NOTE: **Note:** If Omnibus settings are present, applications settings will be a
To migrate from Omnibus GitLab 12.3 and earlier settings: To migrate from Omnibus GitLab 12.3 and earlier settings:
1. Disable the Protected Paths throttle from Omnibus, by changing `rack_attack_enabled` value to `false` on [`rack_attack.rb.erb`](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-cookbooks/gitlab/templates/default/rack_attack.rb.erb#L18):
```ruby
rack_attack_enabled = false
```
1. Customize and enable your protected paths settings by following [Configure using GitLab UI](#configure-using-gitlab-ui) section. 1. Customize and enable your protected paths settings by following [Configure using GitLab UI](#configure-using-gitlab-ui) section.
1. Restart GitLab: 1. SSH into your frontend nodes and add to `/etc/gitlab/gitlab.rb`:
```bash ```ruby
sudo gitlab-ctl restart gitlab_rails['rack_attack_admin_area_protected_paths_enabled'] = true
``` ```
1. [Reconfigure GitLab](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
That's it. Protected paths throttle are now managed by GitLab admin settings. That's it. Protected paths throttle are now managed by GitLab admin settings.
apply: apply:
stage: deploy stage: deploy
image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.1.0" image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.2.0"
environment: environment:
name: production name: production
variables: variables:
......
...@@ -324,6 +324,9 @@ msgstr "" ...@@ -324,6 +324,9 @@ msgstr ""
msgid "%{percent}%% complete" msgid "%{percent}%% complete"
msgstr "" msgstr ""
msgid "%{percent}%{percentSymbol} complete"
msgstr ""
msgid "%{primary} (%{secondary})" msgid "%{primary} (%{secondary})"
msgstr "" msgstr ""
...@@ -12015,6 +12018,9 @@ msgstr "" ...@@ -12015,6 +12018,9 @@ msgstr ""
msgid "Open source software to collaborate on code" msgid "Open source software to collaborate on code"
msgstr "" msgstr ""
msgid "Open: %{open} • Closed: %{closed}"
msgstr ""
msgid "Opened" msgid "Opened"
msgstr "" msgstr ""
...@@ -21517,6 +21523,12 @@ msgstr "" ...@@ -21517,6 +21523,12 @@ msgstr ""
msgid "should be greater than or equal to %{access} inherited membership from group %{group_name}" msgid "should be greater than or equal to %{access} inherited membership from group %{group_name}"
msgstr "" msgstr ""
msgid "show %{count} more"
msgstr ""
msgid "show fewer"
msgstr ""
msgid "show less" msgid "show less"
msgstr "" msgstr ""
......
import { mount } from '@vue/test-utils';
import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui';
import ReleaseBlockMilestoneInfo from '~/releases/list/components/release_block_milestone_info.vue';
import { milestones } from '../../mock_data';
import { trimText } from 'helpers/text_helper';
import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/list/constants';
describe('Release block milestone info', () => {
let wrapper;
let milestonesClone;
const factory = milestonesProp => {
wrapper = mount(ReleaseBlockMilestoneInfo, {
propsData: {
milestones: milestonesProp,
},
sync: false,
});
return wrapper.vm.$nextTick();
};
beforeEach(() => {
milestonesClone = JSON.parse(JSON.stringify(milestones));
});
afterEach(() => {
wrapper.destroy();
});
const milestoneProgressBarContainer = () => wrapper.find('.js-milestone-progress-bar-container');
const milestoneListContainer = () => wrapper.find('.js-milestone-list-container');
const issuesContainer = () => wrapper.find('.js-issues-container');
describe('with default props', () => {
beforeEach(() => factory(milestonesClone));
it('renders the correct percentage', () => {
expect(milestoneProgressBarContainer().text()).toContain('41% complete');
});
it('renders a progress bar that displays the correct percentage', () => {
const progressBar = milestoneProgressBarContainer().find(GlProgressBar);
expect(progressBar.exists()).toBe(true);
expect(progressBar.attributes()).toEqual(
expect.objectContaining({
value: '22',
max: '54',
}),
);
});
it('renders a list of links to all associated milestones', () => {
expect(trimText(milestoneListContainer().text())).toContain('Milestones 13.6 • 13.5');
milestonesClone.forEach((m, i) => {
const milestoneLink = milestoneListContainer()
.findAll(GlLink)
.at(i);
expect(milestoneLink.text()).toBe(m.title);
expect(milestoneLink.attributes('href')).toBe(m.web_url);
expect(milestoneLink.attributes('data-original-title')).toBe(m.description);
});
});
it('renders the "Issues" section with a total count of issues associated to the milestone(s)', () => {
const totalIssueCount = 54;
const issuesContainerText = trimText(issuesContainer().text());
expect(issuesContainerText).toContain(`Issues ${totalIssueCount}`);
const badge = issuesContainer().find(GlBadge);
expect(badge.text()).toBe(totalIssueCount.toString());
expect(issuesContainerText).toContain('Open: 32 • Closed: 22');
});
});
describe('with lots of milestones', () => {
let lotsOfMilestones;
let fullListString;
let abbreviatedListString;
beforeEach(() => {
lotsOfMilestones = [];
const template = milestonesClone[0];
for (let i = 0; i < MAX_MILESTONES_TO_DISPLAY + 10; i += 1) {
lotsOfMilestones.push({
...template,
id: template.id + i,
iid: template.iid + i,
title: `m-${i}`,
});
}
fullListString = lotsOfMilestones.map(m => m.title).join('');
abbreviatedListString = lotsOfMilestones
.slice(0, MAX_MILESTONES_TO_DISPLAY)
.map(m => m.title)
.join('');
return factory(lotsOfMilestones);
});
const clickShowMoreFewerButton = () => {
milestoneListContainer()
.find(GlButton)
.trigger('click');
return wrapper.vm.$nextTick();
};
const milestoneListText = () => trimText(milestoneListContainer().text());
it('only renders a subset of the milestones', () => {
expect(milestoneListText()).toContain(`Milestones ${abbreviatedListString} • show 10 more`);
});
it('renders all milestones when "show more" is clicked', () =>
clickShowMoreFewerButton().then(() => {
expect(milestoneListText()).toContain(`Milestones ${fullListString} • show fewer`);
}));
it('returns to the original view when "show fewer" is clicked', () =>
clickShowMoreFewerButton()
.then(clickShowMoreFewerButton)
.then(() => {
expect(milestoneListText()).toContain(
`Milestones ${abbreviatedListString} • show 10 more`,
);
}));
});
const expectAllZeros = () => {
it('displays percentage as 0%', () => {
expect(milestoneProgressBarContainer().text()).toContain('0% complete');
});
it('shows 0 for all issue counts', () => {
const issuesContainerText = trimText(issuesContainer().text());
expect(issuesContainerText).toContain('Issues 0 Open: 0 • Closed: 0');
});
};
/** Ensures we don't have any issues with dividing by zero when computing percentages */
describe('when all issue counts are zero', () => {
beforeEach(() => {
milestonesClone = milestonesClone.map(m => ({
...m,
issue_stats: {
...m.issue_stats,
opened: 0,
closed: 0,
},
}));
return factory(milestonesClone);
});
expectAllZeros();
});
describe('if the API response is missing the "issue_stats" property', () => {
beforeEach(() => {
milestonesClone = milestonesClone.map(m => ({
...m,
issue_stats: undefined,
}));
return factory(milestonesClone);
});
expectAllZeros();
});
});
...@@ -117,35 +117,6 @@ describe('Release block', () => { ...@@ -117,35 +117,6 @@ describe('Release block', () => {
}); });
}); });
it('renders the milestone icon', () => {
expect(
milestoneListLabel()
.find(Icon)
.exists(),
).toBe(true);
});
it('renders the label as "Milestones" if more than one milestone is passed in', () => {
expect(
milestoneListLabel()
.find('.js-label-text')
.text(),
).toEqual('Milestones');
});
it('renders a link to the milestone with a tooltip', () => {
const milestone = first(release.milestones);
const milestoneLink = wrapper.find('.js-milestone-link');
expect(milestoneLink.exists()).toBe(true);
expect(milestoneLink.text()).toBe(milestone.title);
expect(milestoneLink.attributes('href')).toBe(milestone.web_url);
expect(milestoneLink.attributes('data-original-title')).toBe(milestone.description);
});
it('renders the footer', () => { it('renders the footer', () => {
expect(wrapper.find(ReleaseBlockFooter).exists()).toBe(true); expect(wrapper.find(ReleaseBlockFooter).exists()).toBe(true);
}); });
...@@ -187,18 +158,6 @@ describe('Release block', () => { ...@@ -187,18 +158,6 @@ describe('Release block', () => {
}); });
}); });
it('renders the label as "Milestone" if only a single milestone is passed in', () => {
releaseClone.milestones = releaseClone.milestones.slice(0, 1);
return factory(releaseClone).then(() => {
expect(
milestoneListLabel()
.find('.js-label-text')
.text(),
).toEqual('Milestone');
});
});
it('renders upcoming release badge', () => { it('renders upcoming release badge', () => {
releaseClone.upcoming_release = true; releaseClone.upcoming_release = true;
...@@ -281,4 +240,51 @@ describe('Release block', () => { ...@@ -281,4 +240,51 @@ describe('Release block', () => {
}); });
}); });
}); });
describe('when the releaseIssueSummary feature flag is disabled', () => {
describe('with default props', () => {
beforeEach(() => factory(release, { releaseIssueSummary: false }));
it('renders the milestone icon', () => {
expect(
milestoneListLabel()
.find(Icon)
.exists(),
).toBe(true);
});
it('renders the label as "Milestones" if more than one milestone is passed in', () => {
expect(
milestoneListLabel()
.find('.js-label-text')
.text(),
).toEqual('Milestones');
});
it('renders a link to the milestone with a tooltip', () => {
const milestone = first(release.milestones);
const milestoneLink = wrapper.find('.js-milestone-link');
expect(milestoneLink.exists()).toBe(true);
expect(milestoneLink.text()).toBe(milestone.title);
expect(milestoneLink.attributes('href')).toBe(milestone.web_url);
expect(milestoneLink.attributes('data-original-title')).toBe(milestone.description);
});
});
it('renders the label as "Milestone" if only a single milestone is passed in', () => {
releaseClone.milestones = releaseClone.milestones.slice(0, 1);
return factory(releaseClone, { releaseIssueSummary: false }).then(() => {
expect(
milestoneListLabel()
.find('.js-label-text')
.text(),
).toEqual('Milestone');
});
});
});
}); });
...@@ -11,6 +11,10 @@ export const milestones = [ ...@@ -11,6 +11,10 @@ export const milestones = [
due_date: '2019-09-19', due_date: '2019-09-19',
start_date: '2019-08-31', start_date: '2019-08-31',
web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/2', web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/2',
issue_stats: {
opened: 14,
closed: 19,
},
}, },
{ {
id: 49, id: 49,
...@@ -24,6 +28,10 @@ export const milestones = [ ...@@ -24,6 +28,10 @@ export const milestones = [
due_date: '2019-10-11', due_date: '2019-10-11',
start_date: '2019-08-19', start_date: '2019-08-19',
web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/1', web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/1',
issue_stats: {
opened: 18,
closed: 3,
},
}, },
]; ];
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Throttle do
describe '.protected_paths_enabled?' do
subject { described_class.protected_paths_enabled? }
context 'when omnibus protected paths throttle should be used' do
before do
expect(described_class).to receive(:should_use_omnibus_protected_paths?).and_return(true)
end
it { is_expected.to be_falsey }
end
context 'when omnibus protected paths throttle should not be used' do
before do
expect(described_class).to receive(:should_use_omnibus_protected_paths?).and_return(false)
end
it 'returns Application Settings throttle_protected_paths_enabled?' do
expect(Gitlab::CurrentSettings.current_application_settings).to receive(:throttle_protected_paths_enabled?)
subject
end
end
end
describe '.should_use_omnibus_protected_paths?' do
subject { described_class.should_use_omnibus_protected_paths? }
context 'when rack_attack.admin_area_protected_paths_enabled config is unspecified' do
context 'when the omnibus protected paths throttle has been recently used (it has data)' do
before do
expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(true)
end
it { is_expected.to be_truthy }
end
context 'when the omnibus protected paths throttle has not been recently used' do
before do
expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(false)
end
it { is_expected.to be_falsey }
end
end
context 'when rack_attack.admin_area_protected_paths_enabled config is false' do
before do
stub_config(rack_attack: {
admin_area_protected_paths_enabled: false
})
end
context 'when the omnibus protected paths throttle has been recently used (it has data)' do
before do
expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(true)
end
it { is_expected.to be_truthy }
end
context 'when the omnibus protected paths throttle has not been recently used' do
before do
expect(described_class).to receive(:omnibus_protected_paths_present?).and_return(false)
end
it { is_expected.to be_falsey }
end
end
context 'when rack_attack.admin_area_protected_paths_enabled config is true' do
before do
stub_config(rack_attack: {
admin_area_protected_paths_enabled: true
})
expect(described_class).not_to receive(:omnibus_protected_paths_present?)
end
it { is_expected.to be_falsey }
end
end
end
...@@ -249,10 +249,10 @@ describe 'Rack Attack global throttles' do ...@@ -249,10 +249,10 @@ describe 'Rack Attack global throttles' do
expect_rejection { post protected_path_that_does_not_require_authentication, params: post_params } expect_rejection { post protected_path_that_does_not_require_authentication, params: post_params }
end end
context 'when Omnibus throttle is present' do context 'when Omnibus throttle should be used' do
before do before do
allow(Gitlab::Throttle) allow(Gitlab::Throttle)
.to receive(:omnibus_protected_paths_present?).and_return(true) .to receive(:should_use_omnibus_protected_paths?).and_return(true)
end end
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
...@@ -298,7 +298,7 @@ describe 'Rack Attack global throttles' do ...@@ -298,7 +298,7 @@ describe 'Rack Attack global throttles' do
it_behaves_like 'rate-limited token-authenticated requests' it_behaves_like 'rate-limited token-authenticated requests'
end end
context 'when Omnibus throttle is present' do context 'when Omnibus throttle should be used' do
let(:request_args) { [api(api_partial_url, personal_access_token: token)] } let(:request_args) { [api(api_partial_url, personal_access_token: token)] }
let(:other_user_request_args) { [api(api_partial_url, personal_access_token: other_user_token)] } let(:other_user_request_args) { [api(api_partial_url, personal_access_token: other_user_token)] }
...@@ -309,7 +309,7 @@ describe 'Rack Attack global throttles' do ...@@ -309,7 +309,7 @@ describe 'Rack Attack global throttles' do
stub_application_setting(settings_to_set) stub_application_setting(settings_to_set)
allow(Gitlab::Throttle) allow(Gitlab::Throttle)
.to receive(:omnibus_protected_paths_present?).and_return(true) .to receive(:should_use_omnibus_protected_paths?).and_return(true)
end end
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
...@@ -339,7 +339,7 @@ describe 'Rack Attack global throttles' do ...@@ -339,7 +339,7 @@ describe 'Rack Attack global throttles' do
it_behaves_like 'rate-limited web authenticated requests' it_behaves_like 'rate-limited web authenticated requests'
context 'when Omnibus throttle is present' do context 'when Omnibus throttle should be used' do
before do before do
settings_to_set[:"#{throttle_setting_prefix}_requests_per_period"] = requests_per_period settings_to_set[:"#{throttle_setting_prefix}_requests_per_period"] = requests_per_period
settings_to_set[:"#{throttle_setting_prefix}_period_in_seconds"] = period_in_seconds settings_to_set[:"#{throttle_setting_prefix}_period_in_seconds"] = period_in_seconds
...@@ -347,7 +347,7 @@ describe 'Rack Attack global throttles' do ...@@ -347,7 +347,7 @@ describe 'Rack Attack global throttles' do
stub_application_setting(settings_to_set) stub_application_setting(settings_to_set)
allow(Gitlab::Throttle) allow(Gitlab::Throttle)
.to receive(:omnibus_protected_paths_present?).and_return(true) .to receive(:should_use_omnibus_protected_paths?).and_return(true)
login_as(user) login_as(user)
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment