Commit c3241009 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent d8ccc7a0
......@@ -73,9 +73,14 @@ const handleUserPopoverMouseOver = event => {
location: userData.location,
bio: userData.bio,
organization: userData.organization,
status: userData.status,
loaded: true,
});
if (userData.status) {
return Promise.resolve();
}
return UsersCache.retrieveStatusById(userId);
})
.then(status => {
......
......@@ -51,7 +51,7 @@ export default {
</script>
<template>
<gl-popover :target="target" boundary="viewport" placement="top" show>
<gl-popover :target="target" boundary="viewport" placement="top" offset="0, 1" show>
<div class="user-popover d-flex">
<div class="p-1 flex-shrink-1">
<user-avatar-image :img-src="user.avatarUrl" :size="60" css-classes="mr-2" />
......@@ -90,7 +90,7 @@ export default {
name="location"
class="category-icon flex-shrink-0"
/>
<span class="ml-1">{{ user.location }}</span>
<span v-if="user.location" class="ml-1">{{ user.location }}</span>
<gl-skeleton-loading
v-if="locationIsLoading"
:lines="1"
......
......@@ -53,12 +53,10 @@ module MilestoneActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def milestone_redirect_path
if @project
project_milestone_path(@project, @milestone)
elsif @group
group_milestone_path(@group, @milestone.safe_title, title: @milestone.title)
if @milestone.global_milestone?
url_for(action: :show, title: @milestone.title)
else
dashboard_milestone_path(@milestone.safe_title, title: @milestone.title)
url_for(action: :show)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
......
......@@ -4,6 +4,18 @@ module MilestonesHelper
include EntityDateHelper
include Gitlab::Utils::StrongMemoize
def milestone_status_string(milestone)
if milestone.closed?
_('Closed')
elsif milestone.expired?
_('Past due')
elsif milestone.upcoming?
_('Upcoming')
else
_('Open')
end
end
def milestones_filter_path(opts = {})
if @project
project_milestones_path(@project, opts)
......@@ -213,33 +225,19 @@ module MilestonesHelper
end
end
def milestone_merge_request_tab_path(milestone)
if @project
merge_requests_project_milestone_path(@project, milestone, format: :json)
elsif @group
merge_requests_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json)
def milestone_tab_path(milestone, tab)
if milestone.global_milestone?
url_for(action: tab, title: milestone.title, format: :json)
else
merge_requests_dashboard_milestone_path(milestone, title: milestone.title, format: :json)
url_for(action: tab, format: :json)
end
end
def milestone_participants_tab_path(milestone)
if @project
participants_project_milestone_path(@project, milestone, format: :json)
elsif @group
participants_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json)
def update_milestone_path(milestone, params = {})
if milestone.project_milestone?
project_milestone_path(milestone.project, milestone, milestone: params)
else
participants_dashboard_milestone_path(milestone, title: milestone.title, format: :json)
end
end
def milestone_labels_tab_path(milestone)
if @project
labels_project_milestone_path(@project, milestone, format: :json)
elsif @group
labels_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json)
else
labels_dashboard_milestone_path(milestone, title: milestone.title, format: :json)
group_milestone_route(milestone, params)
end
end
......@@ -264,6 +262,14 @@ module MilestonesHelper
milestone_path(milestone.milestone, params)
end
def edit_milestone_path(milestone)
if milestone.group_milestone?
edit_group_milestone_path(milestone.group, milestone)
elsif milestone.project_milestone?
edit_project_milestone_path(milestone.project, milestone)
end
end
def can_admin_project_milestones?
strong_memoize(:can_admin_project_milestones) do
can?(current_user, :admin_milestone, @project)
......
......@@ -101,6 +101,10 @@ module Milestoneish
false
end
def global_milestone?
false
end
def total_issue_time_spent
@total_issue_time_spent ||= issues.joins(:timelogs).sum(:time_spent)
end
......
......@@ -18,4 +18,8 @@ class DashboardGroupMilestone < GlobalMilestone
milestones = milestones.search_title(params[:search_title]) if params[:search_title].present?
Milestone.filter_by_state(milestones, params[:state]).map { |m| new(m) }
end
def dashboard_milestone?
true
end
end
......@@ -100,4 +100,8 @@ class GlobalMilestone
def labels
@labels ||= GlobalLabel.build_collection(milestone.labels).sort_by!(&:title)
end
def global_milestone?
true
end
end
......@@ -330,6 +330,6 @@ class Milestone < ApplicationRecord
end
def issues_finder_params
{ project_id: project_id }
{ project_id: project_id, group_id: group_id }.compact
end
end
= render "header_title"
= render 'shared/milestones/top', milestone: @milestone, group: @group
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true if @milestone.legacy_group_milestone?
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true
= render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 102
......@@ -3,57 +3,8 @@
- page_title @milestone.title, _('Milestones')
- page_description @milestone.description
.detail-page-header.milestone-page-header
.status-box{ class: status_box_class(@milestone) }
- if @milestone.closed?
= _('Closed')
- elsif @milestone.expired?
= _('Past due')
- elsif @milestone.upcoming?
= _('Upcoming')
- else
= _('Open')
.header-text-content
%span.identifier
%strong
= _('Milestone')
- if @milestone.due_date || @milestone.start_date
= milestone_date_range(@milestone)
.milestone-buttons
- if can?(current_user, :admin_milestone, @project)
= link_to edit_project_milestone_path(@project, @milestone), class: 'btn btn-grouped btn-nr' do
= _('Edit')
- if @project.group
%button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
target: '#promote-milestone-modal',
milestone_title: @milestone.title,
group_name: @project.group.name,
url: promote_project_milestone_path(@milestone.project, @milestone),
container: 'body' },
disabled: true,
type: 'button' }
= _('Promote')
#promote-milestone-modal
- if @milestone.active?
= link_to _('Close milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: 'btn btn-close btn-nr btn-grouped'
- else
= link_to _('Reopen milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: 'btn btn-reopen btn-nr btn-grouped'
= render 'shared/milestones/delete_button'
%a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: '#' }
= icon('angle-double-left')
.detail-page-description.milestone-detail
%h2.title.qa-milestone-title
= markdown_field(@milestone, :title)
%div
- if @milestone.description.present?
.description.md
= markdown_field(@milestone, :description)
= render 'shared/milestones/header', milestone: @milestone
= render 'shared/milestones/description', milestone: @milestone
= render_if_exists 'shared/milestones/burndown', milestone: @milestone, project: @project
......
.detail-page-description.milestone-detail
%h2.title
= markdown_field(milestone, :title)
- if milestone.try(:description).present?
%div
.description.md
= markdown_field(milestone, :description)
.detail-page-header.milestone-page-header
.status-box{ class: status_box_class(milestone) }
= milestone_status_string(milestone)
.header-text-content
%span.identifier
%strong
= _('Milestone')
- if milestone.due_date || milestone.start_date
= milestone_date_range(milestone)
.milestone-buttons
- if can?(current_user, :admin_milestone, @group || @project)
- unless milestone.legacy_group_milestone?
= link_to _('Edit'), edit_milestone_path(milestone), class: 'btn btn-grouped'
- if milestone.project_milestone? && milestone.project.group
%button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
target: '#promote-milestone-modal',
milestone_title: milestone.title,
group_name: milestone.project.group.name,
url: promote_project_milestone_path(milestone.project, milestone),
container: 'body' },
disabled: true,
type: 'button' }
= _('Promote')
#promote-milestone-modal
- if milestone.active?
= link_to _('Close milestone'), update_milestone_path(milestone, { state_event: :close }), method: :put, class: 'btn btn-grouped btn-close'
- else
= link_to _('Reopen milestone'), update_milestone_path(milestone, { state_event: :activate }), method: :put, class: 'btn btn-grouped btn-reopen'
- unless milestone.legacy_group_milestone?
= render 'shared/milestones/delete_button'
%button.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ type: 'button' }
= icon('angle-double-left')
- issues_accessible = milestone.is_a?(GlobalMilestone) || can?(current_user, :read_issue, @project)
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
%ul.nav-links.scrolling-tabs.js-milestone-tabs.nav.nav-tabs
- if issues_accessible
%li.nav-item
= link_to '#tab-issues', class: 'nav-link active', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do
Issues
%span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
Merge Requests
%span.badge.badge-pill= milestone.merge_requests_visible_to_user(current_user).size
- else
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link active', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
Merge Requests
%span.badge.badge-pill= milestone.merge_requests.size
%li.nav-item
= link_to '#tab-participants', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do
Participants
= link_to '#tab-issues', class: 'nav-link active', data: { toggle: 'tab', show: '.tab-issues-buttons' } do
= _('Issues')
%span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'merge_requests') } do
= _('Merge Requests')
%span.badge.badge-pill= milestone.merge_requests_visible_to_user(current_user).size
%li.nav-item
= link_to '#tab-participants', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'participants') } do
= _('Participants')
%span.badge.badge-pill= milestone.issue_participants_visible_by_user(current_user).count
%li.nav-item
= link_to '#tab-labels', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do
Labels
= link_to '#tab-labels', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'labels') } do
= _('Labels')
%span.badge.badge-pill= milestone.issue_labels_visible_by_user(current_user).count
- issues = milestone.sorted_issues(current_user)
......@@ -32,16 +24,11 @@
- show_full_project_name = local_assigns.fetch(:show_full_project_name, false)
.tab-content.milestone-content
- if issues_accessible
.tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_project_milestone_path(@project, @milestone) if @project && current_user) } }
= render 'shared/milestones/issues_tab', issues: issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name
.tab-pane#tab-merge-requests
-# loaded async
= render "shared/milestones/tab_loading"
- else
.tab-pane.active#tab-merge-requests
-# loaded async
= render "shared/milestones/tab_loading"
.tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_project_milestone_path(@project, @milestone) if @project && current_user) } }
= render 'shared/milestones/issues_tab', issues: issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name
.tab-pane#tab-merge-requests
-# loaded async
= render "shared/milestones/tab_loading"
.tab-pane#tab-participants
-# loaded async
= render "shared/milestones/tab_loading"
......
......@@ -4,54 +4,15 @@
- group = local_assigns[:group]
- is_dynamic_milestone = milestone.legacy_group_milestone? || milestone.dashboard_milestone?
.detail-page-header.milestone-page-header
.status-box{ class: "status-box-#{milestone.closed? ? 'closed' : 'open'}" }
- if milestone.closed?
Closed
- elsif milestone.expired?
Expired
- else
Open
.header-text-content
%span.identifier
Milestone #{milestone.title}
- if milestone.due_date || milestone.start_date
%span.creator
&nbsp;&middot;
= milestone_date_range(milestone)
.milestone-buttons
- if group
- if can?(current_user, :admin_milestone, group)
- if milestone.group_milestone?
= link_to edit_group_milestone_path(group, milestone), class: "btn btn btn-grouped" do
Edit
- if milestone.active?
= link_to 'Close Milestone', group_milestone_route(milestone, {state_event: :close }), method: :put, class: "btn btn-grouped btn-close"
- else
= link_to 'Reopen Milestone', group_milestone_route(milestone, {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
- unless is_dynamic_milestone
= render 'shared/milestones/delete_button'
%a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: "#" }
= icon('angle-double-left')
= render 'shared/milestones/header', milestone: milestone
= render 'shared/milestones/deprecation_message' if is_dynamic_milestone
.detail-page-description.milestone-detail
%h2.title
= markdown_field(milestone, :title)
- if milestone.group_milestone? && milestone.description.present?
%div
.description.md
= markdown_field(milestone, :description)
= render 'shared/milestones/description', milestone: milestone
- if milestone.complete?(current_user) && milestone.active?
.alert.alert-success.prepend-top-default
- close_msg = group ? 'You may close the milestone now.' : 'Navigate to the project to close the milestone.'
%span All issues for this milestone are closed. #{close_msg}
%span
= _('All issues for this milestone are closed.')
= group ? _('You may close the milestone now.') : _('Navigate to the project to close the milestone.')
= render_if_exists 'shared/milestones/burndown', milestone: milestone, project: @project
......@@ -77,10 +38,3 @@
Open
%td
= milestone.expires_at
- elsif milestone.group_milestone?
%br
View
= link_to 'Issues', issues_group_path(@group, milestone_title: milestone.title)
or
= link_to 'Merge Requests', merge_requests_group_path(@group, milestone_title: milestone.title)
in this milestone
---
title: Add issues, MRs, participants, and labels tabs in group milestone page
merge_request: 18818
author:
type: added
---
title: Fix user popover not being displayed when the user has a status message
merge_request: 19519
author:
type: fixed
---
title: Add maven cli opts flag to maven security analyzer (part of dependency scanning)
merge_request: 19174
author:
type: changed
......@@ -39,16 +39,20 @@ Follow [Git for enormous repositories](https://gitlab.com/groups/gitlab-org/-/ep
## Enabling partial clone
GitLab 12.1 uses Git 2.21.0 which has an arbitrary file access security
vulnerability when `uploadpack.allowFilter` is enabled, and should not be
enabled in production environments.
> [Introduced](https://gitlab.com/gitlab-org/gitaly/issues/1553) in GitLab 12.4.
A feature flag is planned to enable `uploadpack.allowFilter` and
`uploadpack.allowAnySHA1InWant` once the version of Git used by GitLab has been
updated to Git 2.22.0.
To enable partial clone, use the [feature flags API](../../api/features.md).
For example:
Follow [this issue](https://gitlab.com/gitlab-org/gitaly/issues/1553) for
updated.
```sh
curl --data "value=true" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features/gitaly_upload_pack_filter
```
Alternatively, flip the switch and enable the feature flag:
```ruby
Feature.enable(:gitaly_upload_pack_filter)
```
## Excluding objects by size
......
......@@ -140,6 +140,33 @@ using environment variables.
| `DS_RUN_ANALYZER_TIMEOUT` | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | |
| `PIP_INDEX_URL` | Base URL of Python Package Index (default `https://pypi.org/simple`). | |
| `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. | |
| `MAVEN_CLI_OPTS` | List of command line arguments that will be passed to the maven analyzer during the project's build phase (see example for [using private repos](#using-private-maven-repos)). | |
### Using private Maven repos
If you have a private Maven repository which requires login credentials,
you can use the `MAVEN_CLI_OPTS` environment variable to pass variables
specified in your settings (e.g., username, password, etc.).
For example, if you have a settings file in your project source (e.g., `mysettings.xml`)
that looks like the following, you can specify the variables
[by adding an entry under your project's settings](../../../ci/variables/README.md#via-the-ui),
so that you don't have to expose your private data in `.gitlab-ci.yml` (e.g., adding
`MAVEN_CLI_OPTS` with value `--settings mysettings.xml -Dprivate.username=foo -Dprivate.password=bar`).
```xml
<!-- mysettings.xml -->
<settings>
...
<servers>
<server>
<id>private_server</id>
<username>${private.username}</username>
<password>${private.password}</password>
</server>
</servers>
</settings>
```
## Interacting with the vulnerabilities
......
......@@ -103,30 +103,18 @@ When filtering by milestone, in addition to choosing a specific project mileston
## Milestone view
Not all features in the project milestone view are available in the group milestone view. This table summarizes the differences:
| Feature | Project milestone view | Group milestone view |
|--------------------------------------|:----------------------:|:--------------------:|
| Title and description | ✓ | ✓ |
| Issues assigned to milestone | ✓ | |
| Merge requests assigned to milestone | ✓ | |
| Participants and labels used | ✓ | |
| Percentage complete | ✓ | ✓ |
| Start date and due date | ✓ | ✓ |
| Total issue time spent | ✓ | ✓ |
| Total issue weight | ✓ | |
| Burndown chart **[STARTER}** | ✓ | ✓ |
The milestone view shows the title and description.
### Project milestone features
These features are only available for project milestones and not group milestones.
There are also tabs below these that show the following:
- Issues assigned to the milestone are displayed in three columns: Unstarted issues, ongoing issues, and completed issues.
- Merge requests assigned to the milestone are displayed in four columns: Work in progress merge requests, waiting for merge, rejected, and closed.
- Participants and labels that are used in issues and merge requests that have the milestone assigned are displayed.
- [Burndown chart](#project-burndown-charts-starter).
- Issues
Shows all issues assigned to the milestone. These are displayed in three columns: Unstarted issues, ongoing issues, and completed issues.
- Merge requests
Shows all merge requests assigned to the milestone. These are displayed in four columns: Work in progress merge requests, waiting for merge, rejected, and closed.
- Participants
Shows all assignees of issues assigned to the milestone.
- Labels
Shows all labels that are used in issues assigned to the milestone.
### Project Burndown Charts **(STARTER)**
......@@ -144,9 +132,8 @@ The milestone sidebar on the milestone view shows the following:
- Percentage complete, which is calculated as number of closed issues divided by total number of issues.
- The start date and due date.
- The total time spent on all issues that have the milestone assigned.
For project milestones only, the milestone sidebar shows the total issue weight of all issues that have the milestone assigned.
- The total time spent on all issues assigned to the milestone.
- The total issue weight of all issues assigned to the milestone.
![Project milestone page](img/milestones_project_milestone_page.png)
......
......@@ -51,6 +51,7 @@ dependency_scanning:
DS_PIP_DEPENDENCY_PATH \
PIP_INDEX_URL \
PIP_EXTRA_INDEX_URL \
MAVEN_CLI_OPTS \
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
......
......@@ -1396,6 +1396,9 @@ msgstr ""
msgid "All groups and projects"
msgstr ""
msgid "All issues for this milestone are closed."
msgstr ""
msgid "All issues for this milestone are closed. You may close this milestone now."
msgstr ""
......@@ -10941,6 +10944,9 @@ msgstr ""
msgid "Naming, visibility"
msgstr ""
msgid "Navigate to the project to close the milestone."
msgstr ""
msgid "Nav|Help"
msgstr ""
......@@ -11782,6 +11788,9 @@ msgstr ""
msgid "Part of merge request changes"
msgstr ""
msgid "Participants"
msgstr ""
msgid "Passed"
msgstr ""
......@@ -19497,6 +19506,9 @@ msgstr ""
msgid "You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>."
msgstr ""
msgid "You may close the milestone now."
msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
......
......@@ -3,9 +3,9 @@
require 'spec_helper'
describe 'Group milestones' do
let(:group) { create(:group) }
let!(:project) { create(:project_empty_repo, group: group) }
let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project_empty_repo, group: group) }
let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
around do |example|
Timecop.freeze { example.run }
......@@ -71,9 +71,9 @@ describe 'Group milestones' do
end
context 'when milestones exists' do
let!(:other_project) { create(:project_empty_repo, group: group) }
let_it_be(:other_project) { create(:project_empty_repo, group: group) }
let!(:active_project_milestone1) do
let_it_be(:active_project_milestone1) do
create(
:milestone,
project: project,
......@@ -83,12 +83,12 @@ describe 'Group milestones' do
description: 'Lorem Ipsum is simply dummy text'
)
end
let!(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.1') }
let!(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') }
let!(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') }
let!(:active_group_milestone) { create(:milestone, group: group, state: 'active', title: 'GL-113') }
let!(:closed_group_milestone) { create(:milestone, group: group, state: 'closed') }
let!(:issue) do
let_it_be(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.1') }
let_it_be(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') }
let_it_be(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') }
let_it_be(:active_group_milestone) { create(:milestone, group: group, state: 'active', title: 'GL-113') }
let_it_be(:closed_group_milestone) { create(:milestone, group: group, state: 'closed') }
let_it_be(:issue) do
create :issue, project: project, assignees: [user], author: user, milestone: active_project_milestone1
end
......@@ -143,38 +143,111 @@ describe 'Group milestones' do
expect(page).to have_content('Issues 1 Open: 1 Closed: 0')
expect(page).to have_link(issue.title, href: project_issue_path(issue.project, issue))
end
end
end
describe 'milestone tabs', :js do
context 'for a legacy group milestone' do
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:label) { create(:label, project: project) }
let_it_be(:issue) { create(:labeled_issue, project: project, milestone: milestone, labels: [label], assignees: [create(:user)]) }
let_it_be(:mr) { create(:merge_request, source_project: project, milestone: milestone) }
before do
visit group_milestone_path(group, milestone.title, title: milestone.title)
end
it 'renders the issues tab' do
within('#tab-issues') do
expect(page).to have_content issue.title
end
end
it 'renders the merge requests tab' do
within('.js-milestone-tabs') do
click_link('Merge Requests')
end
describe 'labels' do
before do
create(:label, project: project, title: 'bug') do |label|
issue.labels << label
end
within('#tab-merge-requests') do
expect(page).to have_content mr.title
end
end
it 'renders the participants tab' do
within('.js-milestone-tabs') do
click_link('Participants')
end
create(:label, project: project, title: 'feature') do |label|
issue.labels << label
end
within('#tab-participants') do
expect(page).to have_content issue.assignees.first.name
end
end
it 'renders labels' do
click_link 'v1.0'
it 'renders the labels tab' do
within('.js-milestone-tabs') do
click_link('Labels')
end
page.within('#tab-issues') do
expect(page).to have_content 'bug'
expect(page).to have_content 'feature'
end
within('#tab-labels') do
expect(page).to have_content label.title
end
end
end
context 'for a group milestone' do
let_it_be(:other_project) { create(:project_empty_repo, group: group) }
let_it_be(:milestone) { create(:milestone, group: group) }
it 'renders labels list', :js do
click_link 'v1.0'
let_it_be(:project_label) { create(:label, project: project) }
let_it_be(:other_project_label) { create(:label, project: other_project) }
page.within('.content .nav-links') do
page.find(:xpath, "//a[@href='#tab-labels']").click
end
let_it_be(:project_issue) { create(:labeled_issue, project: project, milestone: milestone, labels: [project_label], assignees: [create(:user)]) }
let_it_be(:other_project_issue) { create(:labeled_issue, project: other_project, milestone: milestone, labels: [other_project_label], assignees: [create(:user)]) }
let_it_be(:project_mr) { create(:merge_request, source_project: project, milestone: milestone) }
let_it_be(:other_project_mr) { create(:merge_request, source_project: other_project, milestone: milestone) }
before do
visit group_milestone_path(group, milestone)
end
it 'renders the issues tab' do
within('#tab-issues') do
expect(page).to have_content project_issue.title
expect(page).to have_content other_project_issue.title
end
end
it 'renders the merge requests tab' do
within('.js-milestone-tabs') do
click_link('Merge Requests')
end
within('#tab-merge-requests') do
expect(page).to have_content project_mr.title
expect(page).to have_content other_project_mr.title
end
end
it 'renders the participants tab' do
within('.js-milestone-tabs') do
click_link('Participants')
end
within('#tab-participants') do
expect(page).to have_content project_issue.assignees.first.name
expect(page).to have_content other_project_issue.assignees.first.name
end
end
it 'renders the labels tab' do
within('.js-milestone-tabs') do
click_link('Labels')
end
page.within('#tab-labels') do
expect(page).to have_content 'bug'
expect(page).to have_content 'feature'
end
within('#tab-labels') do
expect(page).to have_content project_label.title
expect(page).to have_content other_project_label.title
end
end
end
......
......@@ -51,15 +51,16 @@ describe 'Project milestone' do
context 'when project has disabled issues' do
before do
create(:issue, project: project, milestone: milestone)
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
visit project_milestone_path(project, milestone)
end
it 'hides issues tab' do
it 'does not show any issues under the issues tab' do
within('#content-body') do
expect(page).not_to have_link 'Issues', href: '#tab-issues'
expect(page).to have_selector '.nav-links li a.active', count: 1
expect(find('.nav-links li a.active')).to have_content 'Merge Requests'
expect(find('.nav-links li a.active')).to have_content 'Issues'
expect(page).not_to have_selector '.issuable-row'
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