Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
30800334
Commit
30800334
authored
Nov 14, 2017
by
Simon Knox
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ee into 3551-epic-issues
parents
347fec08
f0c5977a
Changes
45
Show whitespace changes
Inline
Side-by-side
Showing
45 changed files
with
751 additions
and
348 deletions
+751
-348
app/assets/javascripts/dispatcher.js
app/assets/javascripts/dispatcher.js
+6
-6
app/assets/javascripts/main.js
app/assets/javascripts/main.js
+0
-2
app/assets/javascripts/project.js
app/assets/javascripts/project.js
+127
-135
app/assets/javascripts/project_avatar.js
app/assets/javascripts/project_avatar.js
+12
-19
app/assets/javascripts/project_import.js
app/assets/javascripts/project_import.js
+6
-11
app/assets/stylesheets/framework/blank.scss
app/assets/stylesheets/framework/blank.scss
+79
-27
app/controllers/concerns/issuable_actions.rb
app/controllers/concerns/issuable_actions.rb
+1
-8
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+1
-0
app/helpers/issuables_helper.rb
app/helpers/issuables_helper.rb
+1
-1
app/models/merge_request.rb
app/models/merge_request.rb
+1
-0
app/models/project_services/jenkins_deprecated_service.rb
app/models/project_services/jenkins_deprecated_service.rb
+8
-2
app/views/dashboard/projects/_blank_state_admin_welcome.html.haml
...s/dashboard/projects/_blank_state_admin_welcome.html.haml
+39
-31
app/views/dashboard/projects/_blank_state_welcome.html.haml
app/views/dashboard/projects/_blank_state_welcome.html.haml
+54
-44
app/views/dashboard/projects/_zero_authorized_projects.html.haml
...ws/dashboard/projects/_zero_authorized_projects.html.haml
+16
-14
app/views/layouts/nav/sidebar/_group.html.haml
app/views/layouts/nav/sidebar/_group.html.haml
+17
-0
app/views/shared/icons/_add_new_project.svg
app/views/shared/icons/_add_new_project.svg
+1
-1
app/views/shared/icons/_lightbulb.svg
app/views/shared/icons/_lightbulb.svg
+1
-0
app/views/shared/issuable/_nav.html.haml
app/views/shared/issuable/_nav.html.haml
+16
-15
changelogs/unreleased-ee/3553-epics-list.yml
changelogs/unreleased-ee/3553-epics-list.yml
+5
-0
changelogs/unreleased/3615-improve-welcome-screen.yml
changelogs/unreleased/3615-improve-welcome-screen.yml
+5
-0
doc/gitlab-geo/updating_the_geo_nodes.md
doc/gitlab-geo/updating_the_geo_nodes.md
+14
-0
ee/app/controllers/ee/projects/issues_controller.rb
ee/app/controllers/ee/projects/issues_controller.rb
+0
-1
ee/app/controllers/groups/epics_controller.rb
ee/app/controllers/groups/epics_controller.rb
+34
-3
ee/app/finders/epics_finder.rb
ee/app/finders/epics_finder.rb
+42
-0
ee/app/policies/ee/group_policy.rb
ee/app/policies/ee/group_policy.rb
+6
-1
ee/app/views/groups/epics/_epic.html.haml
ee/app/views/groups/epics/_epic.html.haml
+15
-0
ee/app/views/groups/epics/index.html.haml
ee/app/views/groups/epics/index.html.haml
+6
-0
ee/app/views/groups/epics/show.html.haml
ee/app/views/groups/epics/show.html.haml
+0
-0
ee/app/views/shared/_epics.html.haml
ee/app/views/shared/_epics.html.haml
+7
-0
ee/app/views/shared/empty_states/_epics.html.haml
ee/app/views/shared/empty_states/_epics.html.haml
+12
-0
qa/qa.rb
qa/qa.rb
+1
-0
qa/qa/ee/scenario/license/add.rb
qa/qa/ee/scenario/license/add.rb
+2
-1
qa/qa/git/repository.rb
qa/qa/git/repository.rb
+1
-1
qa/qa/page/main/entry.rb
qa/qa/page/main/entry.rb
+7
-14
qa/qa/page/main/login.rb
qa/qa/page/main/login.rb
+19
-0
qa/qa/specs/features/login/standard_spec.rb
qa/qa/specs/features/login/standard_spec.rb
+2
-1
qa/qa/specs/features/mattermost/group_create_spec.rb
qa/qa/specs/features/mattermost/group_create_spec.rb
+2
-1
qa/qa/specs/features/mattermost/login_spec.rb
qa/qa/specs/features/mattermost/login_spec.rb
+2
-1
qa/qa/specs/features/project/create_spec.rb
qa/qa/specs/features/project/create_spec.rb
+2
-1
qa/qa/specs/features/repository/clone_spec.rb
qa/qa/specs/features/repository/clone_spec.rb
+2
-1
qa/qa/specs/features/repository/push_spec.rb
qa/qa/specs/features/repository/push_spec.rb
+2
-1
spec/ee/spec/controllers/groups/epics_controller_spec.rb
spec/ee/spec/controllers/groups/epics_controller_spec.rb
+37
-1
spec/ee/spec/features/epics/epics_list_spec.rb
spec/ee/spec/features/epics/epics_list_spec.rb
+54
-0
spec/ee/spec/finders/epics_finder_spec.rb
spec/ee/spec/finders/epics_finder_spec.rb
+74
-0
spec/models/project_services/jenkins_deprecated_service_spec.rb
...odels/project_services/jenkins_deprecated_service_spec.rb
+12
-4
No files found.
app/assets/javascripts/dispatcher.js
View file @
30800334
...
...
@@ -20,8 +20,8 @@ import groupsSelect from './groups_select';
import
NamespaceSelect
from
'
./namespace_select
'
;
/* global NewCommitForm */
/* global NewBranchForm */
/* global Project */
/* global ProjectAvatar */
import
Project
from
'
./project
'
;
import
projectAvatar
from
'
./project_avatar
'
;
/* global MergeRequest */
/* global Compare */
/* global CompareAutocomplete */
...
...
@@ -29,7 +29,7 @@ import NamespaceSelect from './namespace_select';
/* global ProjectFindFile */
/* global ProjectNew */
/* global ProjectShow */
/* global ProjectImport */
import
projectImport
from
'
./project_import
'
;
import
Labels
from
'
./labels
'
;
import
LabelManager
from
'
./label_manager
'
;
/* global Sidebar */
...
...
@@ -386,7 +386,7 @@ import initGroupAnalytics from './init_group_analytics';
GpgBadges
.
fetch
();
break
;
case
'
projects:imports:show
'
:
new
P
rojectImport
();
p
rojectImport
();
break
;
case
'
projects:show
'
:
shortcut_handler
=
new
ShortcutsNavigation
();
...
...
@@ -416,7 +416,7 @@ import initGroupAnalytics from './init_group_analytics';
new
UserCallout
({
className
:
'
js-mr-approval-callout
'
});
break
;
case
'
projects:imports:show
'
:
new
P
rojectImport
();
p
rojectImport
();
break
;
case
'
projects:pipelines:new
'
:
new
NewBranchForm
(
$
(
'
.js-new-pipeline-form
'
));
...
...
@@ -686,7 +686,7 @@ import initGroupAnalytics from './init_group_analytics';
break
;
case
'
projects
'
:
new
Project
();
new
P
rojectAvatar
();
p
rojectAvatar
();
switch
(
path
[
1
])
{
case
'
compare
'
:
new
CompareAutocomplete
();
...
...
app/assets/javascripts/main.js
View file @
30800334
...
...
@@ -72,8 +72,6 @@ import './notifications_dropdown';
import
'
./notifications_form
'
;
import
'
./pager
'
;
import
'
./preview_markdown
'
;
import
'
./project
'
;
import
'
./project_avatar
'
;
import
'
./project_find_file
'
;
import
'
./project_import
'
;
import
'
./project_label_subscription
'
;
...
...
app/assets/javascripts/project.js
View file @
30800334
/* eslint-disable func-names, space-before-function-paren,
wrap-iife, no-var, quotes, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle
, no-else-return, newline-per-chained-call, no-shadow, vars-on-top, prefer-template, max-len */
/* eslint-disable func-names, space-before-function-paren,
no-var, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand
, no-else-return, newline-per-chained-call, no-shadow, vars-on-top, prefer-template, max-len */
/* global ProjectSelect */
import
Cookies
from
'
js-cookie
'
;
(
function
()
{
this
.
Project
=
(
function
()
{
function
Project
()
{
export
default
class
Project
{
constructor
()
{
const
$cloneOptions
=
$
(
'
ul.clone-options-dropdown
'
);
const
$projectCloneField
=
$
(
'
#project_clone
'
);
const
$cloneBtnText
=
$
(
'
a.clone-dropdown-btn span
'
);
...
...
@@ -28,13 +27,13 @@ import Cookies from 'js-cookie';
$
(
'
#modal-geo-info
'
).
data
({
cloneUrlSecondary
:
$this
.
attr
(
'
href
'
),
cloneUrlPrimary
:
$this
.
data
(
'
primaryUrl
'
)
||
''
cloneUrlPrimary
:
$this
.
data
(
'
primaryUrl
'
)
||
''
,
});
return
$
(
'
.clone
'
).
text
(
url
);
});
// Ref switcher
this
.
initRefSwitcher
();
Project
.
initRefSwitcher
();
$
(
'
.project-refs-select
'
).
on
(
'
change
'
,
function
()
{
return
$
(
this
).
parents
(
'
form
'
).
submit
();
});
...
...
@@ -55,23 +54,19 @@ import Cookies from 'js-cookie';
$alert
.
remove
();
e
.
preventDefault
();
});
this
.
projectSelectDropdown
();
Project
.
projectSelectDropdown
();
}
Project
.
prototype
.
projectSelectDropdown
=
functio
n
()
{
static
projectSelectDropdow
n
()
{
new
ProjectSelect
();
$
(
'
.project-item-select
'
).
on
(
'
click
'
,
(
function
(
_this
)
{
return
function
(
e
)
{
return
_this
.
changeProject
(
$
(
e
.
currentTarget
).
val
());
};
})(
this
));
};
Project
.
prototype
.
changeProject
=
function
(
url
)
{
$
(
'
.project-item-select
'
).
on
(
'
click
'
,
e
=>
Project
.
changeProject
(
$
(
e
.
currentTarget
).
val
()));
}
static
changeProject
(
url
)
{
return
window
.
location
=
url
;
};
}
Project
.
prototype
.
initRefSwitcher
=
function
()
{
static
initRefSwitcher
()
{
var
refListItem
=
document
.
createElement
(
'
li
'
);
var
refLink
=
document
.
createElement
(
'
a
'
);
...
...
@@ -87,9 +82,9 @@ import Cookies from 'js-cookie';
url
:
$dropdown
.
data
(
'
refs-url
'
),
data
:
{
ref
:
$dropdown
.
data
(
'
ref
'
),
search
:
term
search
:
term
,
},
dataType
:
"
json
"
dataType
:
'
json
'
,
}).
done
(
function
(
refs
)
{
return
callback
(
refs
);
});
...
...
@@ -141,11 +136,8 @@ import Cookies from 'js-cookie';
gl
.
utils
.
visitUrl
(
`
${
action
}${
divider
}${
$form
.
serialize
()}
`
);
}
}
}
},
});
});
};
return
Project
;
})();
}).
call
(
window
);
}
}
app/assets/javascripts/project_avatar.js
View file @
30800334
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, no-useless-escape, max-len */
(
function
()
{
this
.
ProjectAvatar
=
(
function
()
{
function
ProjectAvatar
()
{
$
(
'
.js-choose-project-avatar-button
'
).
bind
(
'
click
'
,
function
()
{
var
form
;
form
=
$
(
this
).
closest
(
'
form
'
);
export
default
function
projectAvatar
()
{
$
(
'
.js-choose-project-avatar-button
'
).
bind
(
'
click
'
,
function
onClickAvatar
()
{
const
form
=
$
(
this
).
closest
(
'
form
'
);
return
form
.
find
(
'
.js-project-avatar-input
'
).
click
();
});
$
(
'
.js-project-avatar-input
'
).
bind
(
'
change
'
,
function
()
{
var
filename
,
form
;
form
=
$
(
this
).
closest
(
'
form
'
);
filename
=
$
(
this
).
val
().
replace
(
/^.*
[\\\/]
/
,
''
);
$
(
'
.js-project-avatar-input
'
).
bind
(
'
change
'
,
function
onClickAvatarInput
()
{
const
form
=
$
(
this
).
closest
(
'
form
'
);
// eslint-disable-next-line no-useless-escape
const
filename
=
$
(
this
).
val
().
replace
(
/^.*
[\\\/]
/
,
''
);
return
form
.
find
(
'
.js-avatar-filename
'
).
text
(
filename
);
});
}
return
ProjectAvatar
;
})();
}).
call
(
window
);
}
app/assets/javascripts/project_import.js
View file @
30800334
/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */
import
{
visitUrl
}
from
'
./lib/utils/url_utility
'
;
(
function
()
{
this
.
ProjectImport
=
(
function
()
{
function
ProjectImport
()
{
setTimeout
(
function
()
{
return
gl
.
utils
.
visitUrl
(
location
.
href
);
export
default
function
projectImport
()
{
setTimeout
(()
=>
{
visitUrl
(
location
.
href
);
},
5000
);
}
}
return
ProjectImport
;
})();
}).
call
(
window
);
app/assets/stylesheets/framework/blank.scss
View file @
30800334
...
...
@@ -7,17 +7,21 @@
width
:
100%
;
height
:
100%
;
padding-bottom
:
25px
;
border
:
1px
solid
$border-color
;
border-radius
:
$border-radius-default
;
}
}
.blank-state
{
padding-top
:
20px
;
padding-bottom
:
20px
;
.blank-state-row
{
display
:
flex
;
flex-wrap
:
wrap
;
justify-content
:
space-around
;
height
:
100%
;
}
.blank-state-welcome
{
text-align
:
center
;
padding
:
20px
0
40px
;
&
.blank-state-welcome
{
.blank-state-welcome-title
{
font-size
:
24px
;
}
...
...
@@ -25,11 +29,46 @@
.blank-state-text
{
margin-bottom
:
0
;
}
}
.blank-state-link
{
display
:
block
;
color
:
$gl-text-color
;
flex
:
0
0
100%
;
margin-bottom
:
15px
;
@media
(
min-width
:
$screen-sm-min
)
{
flex
:
0
0
49%
;
&
:nth-child
(
odd
)
{
margin-right
:
5px
;
}
.blank-state-icon
{
padding-bottom
:
20px
;
&
:nth-child
(
even
)
{
margin-left
:
5px
;
}
}
&
:hover
{
background-color
:
$gray-light
;
text-decoration
:
none
;
color
:
$gl-text-color
;
}
}
.blank-state
{
padding
:
20px
;
border
:
1px
solid
$border-color
;
border-radius
:
$border-radius-default
;
@media
(
min-width
:
$screen-sm-min
)
{
display
:
flex
;
height
:
100%
;
align-items
:
center
;
padding
:
50px
30px
;
}
.blank-state-icon
{
svg
{
display
:
block
;
margin
:
auto
;
...
...
@@ -38,33 +77,46 @@
.blank-state-title
{
margin-top
:
0
;
margin-bottom
:
10px
;
font-size
:
18px
;
}
.blank-state-text
{
max-width
:
$container-text-max-width
;
margin
:
0
auto
$gl-padding
;
font-size
:
14px
;
.blank-state-body
{
@media
(
max-width
:
$screen-xs-max
)
{
text-align
:
center
;
margin-top
:
20px
;
}
@media
(
min-width
:
$screen-sm-min
)
{
padding-left
:
20px
;
}
}
}
/* EE-specific Styles */
@media
(
min-width
:
$screen-md-min
)
{
.blank-state-parent-container.has-start-trial-container
{
display
:
flex
;
@media
(
min-width
:
$screen-lg-min
)
{
.column-large
{
flex
:
2
;
}
}
.section-ee-trial
{
.section-body
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
.column-small
{
flex
:
1
;
margin-bottom
:
15px
;
.blank-state
{
padding
:
20px
;
text-align
:
center
;
max-width
:
400px
;
flex-wrap
:
wrap
;
margin-left
:
15px
;
}
.blank-state-icon
{
margin-bottom
:
30px
;
}
}
}
@media
(
max-width
:
$screen-xs-max
)
{
.blank-state-icon
svg
{
width
:
315px
;
}
}
app/controllers/concerns/issuable_actions.rb
View file @
30800334
...
...
@@ -9,10 +9,7 @@ module IssuableActions
def
show
respond_to
do
|
format
|
format
.
html
do
render
show_view
end
format
.
html
format
.
json
do
render
json:
serializer
.
represent
(
issuable
,
serializer:
params
[
:serializer
])
end
...
...
@@ -154,10 +151,6 @@ module IssuableActions
end
end
def
show_view
'show'
end
def
serializer
raise
NotImplementedError
end
...
...
app/controllers/projects/issues_controller.rb
View file @
30800334
...
...
@@ -10,6 +10,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action
:check_issues_available!
before_action
:issue
,
except:
[
:index
,
:new
,
:create
,
:bulk_update
,
:export_csv
]
before_action
:set_issuables_index
,
only:
[
:index
]
# Allow write(create) issue
...
...
app/helpers/issuables_helper.rb
View file @
30800334
...
...
@@ -159,7 +159,7 @@ module IssuablesHelper
label_names
.
join
(
', '
)
end
def
issuables_state_counter_text
(
issuable_type
,
state
)
def
issuables_state_counter_text
(
issuable_type
,
state
=
:all
)
titles
=
{
opened:
"Open"
}
...
...
app/models/merge_request.rb
View file @
30800334
...
...
@@ -3,6 +3,7 @@ class MergeRequest < ActiveRecord::Base
include
Issuable
include
Noteable
include
Referable
include
Elastic
::
MergeRequestsSearch
include
IgnorableColumn
include
TimeTrackable
...
...
app/models/project_services/jenkins_deprecated_service.rb
View file @
30800334
...
...
@@ -14,7 +14,7 @@ class JenkinsDeprecatedService < CiService
def
compose_service_hook
hook
=
service_hook
||
build_service_hook
jenkins_url
=
project_url
.
sub
(
/job\/.*/
,
''
)
hook
.
url
=
jenkins_url
+
"
/
gitlab/build_now"
hook
.
url
=
jenkins_url
+
"gitlab/build_now"
hook
.
save
end
...
...
@@ -101,7 +101,13 @@ class JenkinsDeprecatedService < CiService
if
response
.
code
==
200
# img.build-caption-status-icon for old jenkins version
begin
src
=
Nokogiri
.
parse
(
response
).
css
(
'img.build-caption-status-icon,.build-caption>img'
).
first
.
attributes
[
'src'
].
value
rescue
NoMethodError
=>
ex
Raven
.
capture_exception
(
ex
,
extra:
{
'response'
=>
response
})
return
:error
end
if
src
=~
/blue\.png$/
||
(
src
=~
/yellow\.png/
&&
pass_unstable?
)
'success'
elsif
src
=~
/(red|aborted|yellow)\.png$/
...
...
app/views/dashboard/projects/_blank_state_admin_welcome.html.haml
View file @
30800334
.blank-state
.blank-state-row
=
link_to
new_project_path
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"add_new_user
"
,
size:
50
)
=
custom_icon
(
"add_new_project
"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Add user
Create a project
%p
.blank-state-text
Add your team members and others to GitLab.
=
link_to
new_admin_user_path
,
class:
"btn btn-new"
do
New user
Projects are where you store your code, access issues, wiki and other features of GitLab.
.blank-state
-
if
current_user
.
can_create_group?
=
link_to
admin_root_path
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"configure_server
"
,
size:
50
)
=
custom_icon
(
"add_new_group
"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Configure GitLab
Create a group
%p
.blank-state-text
Make adjustments to how your GitLab instance is set up.
=
link_to
admin_root_path
,
class:
"btn btn-new"
do
Configure
Groups are a great way to organize projects and people.
-
if
current_user
.
can_create_group?
=
link_to
new_admin_user_path
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"add_new_group
"
,
size:
50
)
=
custom_icon
(
"add_new_user
"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Create a group
Add people
%p
.blank-state-text
Groups are a great way to organize projects and people.
=
link_to
new_group_path
,
class:
"btn btn-new"
do
New group
Add your team members and others to GitLab.
=
link_to
admin_root_path
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"configure_server"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Configure GitLab
%p
.blank-state-text
Make adjustments to how your GitLab instance is set up.
app/views/dashboard/projects/_blank_state_welcome.html.haml
View file @
30800334
-
public_project_count
=
ProjectsFinder
.
new
(
current_user:
current_user
).
execute
.
count
-
if
current_user
.
can_create_group?
.blank-state-row
-
if
current_user
.
can_create_project?
=
link_to
new_project_path
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"add_new_group
"
,
size:
50
)
=
custom_icon
(
"add_new_project
"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Create a group for several dependent projects.
Create a project
%p
.blank-state-text
Groups are the best way to manage projects and members.
=
link_to
new_group_path
,
class:
"btn btn-new"
do
New group
.blank-state
Projects are where you store your code, access issues, wiki and other features of GitLab.
-
else
.blank-state
.blank-state-icon
=
custom_icon
(
"add_new_project"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Create a project
%p
.blank-state-text
-
if
current_user
.
can_create_project?
You don't have access to any projects right now.
You can create up to
%strong
=
number_with_delimiter
(
current_user
.
projects_limit
)
=
succeed
"."
do
=
"project"
.
pluralize
(
current_user
.
projects_limit
)
-
else
If you are added to a project, it will be displayed here.
-
if
current_user
.
can_create_project?
=
link_to
new_project_path
,
class:
"btn btn-new"
do
New project
-
if
public_project_count
>
0
-
if
current_user
.
can_create_group?
=
link_to
new_group_path
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"add_new_group"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Create a group
%p
.blank-state-text
Groups are the best way to manage projects and members.
-
if
public_project_count
>
0
=
link_to
trending_explore_projects_path
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"globe"
,
size:
50
)
...
...
@@ -44,5 +46,13 @@
public projects on this server.
Public projects are an easy way to allow
everyone to have read-only access.
=
link_to
trending_explore_projects_path
,
class:
"btn btn-new"
do
Browse projects
=
link_to
"https://docs.gitlab.com/"
,
class:
"blank-state-link"
do
.blank-state
.blank-state-icon
=
custom_icon
(
"lightbulb"
,
size:
50
)
.blank-state-body
%h3
.blank-state-title
Learn more about GitLab
%p
.blank-state-text
Take a look at the documentation to discover all of GitLab's capabilities.
app/views/dashboard/projects/_zero_authorized_projects.html.haml
View file @
30800334
-
admin_without_ee_license
=
!
current_license
&&
current_user
.
admin?
.
row.
blank-state-parent-container
{
class:
(
'has-start-trial-container'
if
admin_without_ee_license
)
}
.blank-state-parent-container
{
class:
(
'has-start-trial-container'
if
admin_without_ee_license
)
}
.section-container.section-welcome
{
class:
(
'col-md-6'
if
admin_without_ee_license
)
}
.container.section-body
.blank-state.blank-state-welcome
.row
.blank-state-welcome
%h2
.blank-state-welcome-title
Welcome to GitLab
%p
.blank-state-text
Code, test, and deploy together
.blank-state-row
%div
{
class:
(
'column-large'
if
admin_without_ee_license
)
}
-
if
current_user
.
admin?
=
render
"blank_state_admin_welcome"
-
else
=
render
"blank_state_welcome"
-
if
admin_without_ee_license
.col-md-6.section-container.section-ee-trial
.container.section-body
.column-small
=
render
"blank_state_ee_trial"
app/views/layouts/nav/sidebar/_group.html.haml
View file @
30800334
-
issues
=
IssuesFinder
.
new
(
current_user
,
group_id:
@group
.
id
,
state:
'opened'
).
execute
-
merge_requests
=
MergeRequestsFinder
.
new
(
current_user
,
group_id:
@group
.
id
,
state:
'opened'
,
non_archived:
true
).
execute
-
epics
=
EpicsFinder
.
new
(
current_user
,
group_id:
@group
.
id
).
execute
-
epics_items
=
[
'epics#show'
,
'epics#index'
]
-
issues_sub_menu_items
=
[
'groups#issues'
,
'labels#index'
,
'milestones#index'
]
-
if
@group
.
feature_available?
(
:group_issue_boards
)
-
issues_sub_menu_items
.
push
(
'boards#index'
,
'boards#show'
)
...
...
@@ -43,6 +45,21 @@
%span
Contribution Analytics
-# TODO: Add the flag check to only show epics if available
=
nav_link
(
path:
epics_items
)
do
=
link_to
group_epics_path
(
@group
)
do
.nav-icon-container
=
sprite_icon
(
'epic'
)
%span
.nav-item-name
Epics
%span
.badge.count
=
number_with_delimiter
(
epics
.
count
)
%ul
.sidebar-sub-level-items.is-fly-out-only
=
nav_link
(
path:
epics_items
,
html_options:
{
class:
"fly-out-top-item"
}
)
do
=
link_to
group_epics_path
(
@group
)
do
%strong
.fly-out-top-item-name
#{
_
(
'Epics'
)
}
%span
.badge.count.epic_counter.fly-out-badge
=
number_with_delimiter
(
epics
.
count
)
=
nav_link
(
path:
issues_sub_menu_items
)
do
=
link_to
issues_group_path
(
@group
)
do
.nav-icon-container
...
...
app/views/shared/icons/_add_new_project.svg
View file @
30800334
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"78"
height=
"82"
viewBox=
"0 0 78 82"
><g
fill=
"none"
fill-rule=
"evenodd"
><path
fill=
"#F9F9F9"
d=
"M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76 19.575 76 3.647 61.032 2.12 42z"
/><path
fill=
"#EEE"
fill-rule=
"nonzero"
d=
"M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"
/><path
fill=
"#FEE1D3"
fill-rule=
"nonzero"
d=
"M30 24a4 4 0 0 0-4 4v22a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4V28a4 4 0 0 0-4-4H30zm0-4h18a8 8 0 0 1 8 8v22a8 8 0 0 1-8 8H30a8 8 0 0 1-8-8V28a8 8 0 0 1 8-8z"
/><path
fill=
"#FC6D26"
d=
"M33 30h8a2 2 0 1 1 0 4h-8a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4z"
/></g></svg>
\ No newline at end of file
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"78"
height=
"82"
viewBox=
"0 0 78 82"
><g
fill=
"none"
fill-rule=
"evenodd"
><path
fill=
"#F9F9F9"
d=
"M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76S3.647 61.032 2.12 42z"
/><path
fill=
"#EEE"
fill-rule=
"nonzero"
d=
"M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"
/><path
fill=
"#E1DBF2"
fill-rule=
"nonzero"
d=
"M30 24c-2.21 0-4 1.79-4 4v22c0 2.21 1.79 4 4 4h18c2.21 0 4-1.79 4-4V28c0-2.21-1.79-4-4-4H30zm0-4h18c4.418 0 8 3.582 8 8v22c0 4.418-3.582 8-8 8H30c-4.418 0-8-3.582-8-8V28c0-4.418 3.582-8 8-8z"
/><path
fill=
"#6B4FBB"
d=
"M33 30h8c1.105 0 2 .895 2 2s-.895 2-2 2h-8c-1.105 0-2-.895-2-2s.895-2 2-2zm0 7h12c1.105 0 2 .895 2 2s-.895 2-2 2H33c-1.105 0-2-.895-2-2s.895-2 2-2zm0 7h12c1.105 0 2 .895 2 2s-.895 2-2 2H33c-1.105 0-2-.895-2-2s.895-2 2-2z"
/></g></svg>
app/views/shared/icons/_lightbulb.svg
0 → 100644
View file @
30800334
<svg
xmlns=
"http://www.w3.org/2000/svg"
width=
"78"
height=
"82"
viewBox=
"0 0 78 82"
><g
fill=
"none"
fill-rule=
"evenodd"
><path
fill=
"#F9F9F9"
d=
"M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76S3.647 61.032 2.12 42z"
/><path
fill=
"#EEE"
fill-rule=
"nonzero"
d=
"M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"
/><path
fill=
"#6B4FBB"
d=
"M33 52h12c1.105 0 2 .895 2 2s-.895 2-2 2H33c-1.105 0-2-.895-2-2s.895-2 2-2zm1 5h10c1.105 0 2 .895 2 2s-.895 2-2 2H34c-1.105 0-2-.895-2-2s.895-2 2-2z"
/><path
fill=
"#E1DBF2"
fill-rule=
"nonzero"
d=
"M45.542 46.932l.346-2.36c.198-1.348.737-2.623 1.566-3.705 3.025-3.946 4.485-7.29 4.547-9.96C52.153 24.41 46.843 20 39 20c-7.777 0-13 4.374-13 11 0 2.4 1.462 5.73 4.573 9.846.815 1.08 1.343 2.345 1.536 3.683l.353 2.456 13.08-.054zm-17.038.624L28.15 45.1c-.097-.67-.36-1.303-.768-1.842C23.794 38.51 22 34.424 22 31c0-9.39 7.61-15 17-15s17.218 5.614 17 15c-.085 3.64-1.875 7.74-5.37 12.3-.416.54-.685 1.18-.784 1.853l-.346 2.36c-.288 1.958-1.963 3.41-3.942 3.42l-13.08.053c-1.994.008-3.69-1.455-3.974-3.43z"
/><path
fill=
"#6B4FBB"
d=
"M41 38.732c-.598-.345-1-.992-1-1.732 0-1.105.895-2 2-2s2 .895 2 2c0 .74-.402 1.387-1 1.732V42c0 .552-.448 1-1 1s-1-.448-1-1v-3.268zm-6 0c-.598-.345-1-.992-1-1.732 0-1.105.895-2 2-2s2 .895 2 2c0 .74-.402 1.387-1 1.732V42c0 .552-.448 1-1 1s-1-.448-1-1v-3.268z"
/></g></svg>
app/views/shared/issuable/_nav.html.haml
View file @
30800334
-
type
=
local_assigns
.
fetch
(
:type
,
:issues
)
-
page_context_word
=
type
.
to_s
.
humanize
(
capitalize:
false
)
-
issuables
=
@issues
||
@merge_requests
-
issuables
=
@issues
||
@merge_requests
||
@epics
%ul
.nav-links.issues-state-filters
-
if
type
!=
:epics
%li
{
class:
active_when
(
params
[
:state
]
==
'opened'
)
}
>
=
link_to
page_filter_path
(
state:
'opened'
,
label:
true
),
id:
'state-opened'
,
title:
"Filter by
#{
page_context_word
}
that are currently opened."
,
data:
{
state:
'opened'
}
do
#{
issuables_state_counter_text
(
type
,
:opened
)
}
...
...
changelogs/unreleased-ee/3553-epics-list.yml
0 → 100644
View file @
30800334
---
title
:
Add epics list and add epics to nav sidebar
merge_request
:
author
:
type
:
added
changelogs/unreleased/3615-improve-welcome-screen.yml
0 → 100644
View file @
30800334
---
title
:
Reorganize welcome page for new users
merge_request
:
author
:
type
:
other
doc/gitlab-geo/updating_the_geo_nodes.md
View file @
30800334
...
...
@@ -16,6 +16,20 @@ all you need to do is update GitLab itself:
## Upgrading to GitLab 10.2
### Secure PostgreSQL replication
Support for TLS-secured PostgreSQL replication has been added. If you are
currently using PostgreSQL replication across the open internet without an
external means of securing the connection (e.g., a site-to-site VPN), then you
should immediately reconfigure your primary and secondary PostgreSQL instances
according to the
[
updated instructions
](
#database.md
)
.
If you
*are*
securing the connections externally and wish to continue doing so,
ensure you include the new option
`--sslmode=prefer`
in future invocations of
`gitlab-ctl replicate-geo-database`
.
### HTTPS repository sync
Support for replicating repositories and wikis over HTTP/HTTPS has been added.
Replicating over SSH has been deprecated, and support for this option will be
removed in a future release.
...
...
ee/app/controllers/ee/projects/issues_controller.rb
View file @
30800334
...
...
@@ -12,7 +12,6 @@ module EE
def
service_desk
@issues
=
@issuables
@users
.
push
(
::
User
.
support_bot
)
end
...
...
ee/app/controllers/groups/epics_controller.rb
View file @
30800334
class
Groups::EpicsController
<
Groups
::
ApplicationController
include
IssuableActions
include
IssuableCollections
before_action
:epic
before_action
:epic
,
except: :index
before_action
:set_issuables_index
,
only: :index
before_action
:authorize_update_issuable!
,
only: :update
skip_before_action
:labels
def
index
set_default_state
@epics
=
@issuables
respond_to
do
|
format
|
format
.
html
format
.
json
do
render
json:
{
html:
view_to_html_string
(
"groups/epics/_epics"
)
}
end
end
end
private
def
epic
...
...
@@ -38,7 +54,22 @@ class Groups::EpicsController < Groups::ApplicationController
Epics
::
UpdateService
.
new
(
nil
,
current_user
,
epic_params
)
end
def
show_view
'groups/ee/epics/show'
def
set_issuables_index
@finder_type
=
EpicsFinder
super
end
def
collection_type
@collection_type
||=
'Epic'
end
def
preload_for_collection
@preload_for_collection
||=
[
:group
,
:author
]
end
# we need to override the default state which is opened for now because we don't have
# states for epics and need all as default for navigation to work correctly (#4017)
def
set_default_state
params
[
:state
]
=
'all'
end
end
ee/app/finders/epics_finder.rb
0 → 100644
View file @
30800334
class
EpicsFinder
<
IssuableFinder
def
klass
Epic
end
def
execute
raise
ArgumentError
,
'group_id argument is missing'
unless
group
items
=
init_collection
items
=
by_created_at
(
items
)
items
=
by_search
(
items
)
items
=
by_author
(
items
)
items
=
by_iids
(
items
)
sort
(
items
)
end
def
row_count
execute
.
count
end
# we don't have states for epics for now this method (#4017)
def
count_by_state
{
all:
row_count
}
end
def
group
return
nil
unless
params
[
:group_id
]
return
@group
if
defined?
(
@group
)
group
=
Group
.
find
(
params
[
:group_id
])
group
=
nil
unless
Ability
.
allowed?
(
current_user
,
:read_epic
,
group
)
@group
=
group
end
def
init_collection
group
.
epics
end
end
ee/app/policies/ee/group_policy.rb
View file @
30800334
...
...
@@ -30,7 +30,12 @@ module EE
enable
:destroy_epic
end
rule
{
auditor
}.
enable
:read_group
rule
{
auditor
}.
policy
do
enable
:read_group
enable
:read_epic
end
rule
{
admin
}.
enable
:read_epic
rule
{
has_projects
}.
enable
:read_epic
rule
{
admin
|
(
can_owners_manage_ldap
&
owner
)
}.
enable
:admin_ldap_group_links
...
...
ee/app/views/groups/epics/_epic.html.haml
0 → 100644
View file @
30800334
%li
.issue-box
.issue-info-container
.issue-main-info
.issue-title.title
%span
.issue-title-text
=
link_to
epic
.
title
,
epic_path
(
epic
)
.issuable-info
%span
.issuable-reference
-# TODO: Use to_reference
=
"&
#{
epic
.
iid
}
"
%span
.issuable-authored.hidden-xs
·
opened
#{
time_ago_with_tooltip
(
epic
.
created_at
,
placement:
'bottom'
)
}
by
#{
link_to_member
(
@group
,
epic
.
author
,
avatar:
false
)
}
ee/app/views/groups/epics/index.html.haml
0 → 100644
View file @
30800334
-
page_title
"Epics"
-
if
@epics
.
to_a
.
any?
=
render
'shared/epics'
-
else
=
render
'shared/empty_states/epics'
ee/app/views/groups/e
e/e
pics/show.html.haml
→
ee/app/views/groups/epics/show.html.haml
View file @
30800334
File moved
ee/app/views/shared/_epics.html.haml
0 → 100644
View file @
30800334
.top-area
=
render
'shared/issuable/nav'
,
type: :epics
%ul
.content-list.issuable-list
=
render
partial:
'groups/epics/epic'
,
collection:
@epics
=
paginate
@epics
,
theme:
"gitlab"
ee/app/views/shared/empty_states/_epics.html.haml
0 → 100644
View file @
30800334
.row.empty-state
.col-xs-12
.svg-content
=
image_tag
(
'illustrations/epics.svg'
)
.col-xs-12.text-center
.text-content
%h4
=
_
(
'Epics let you manage your portfolio of projects more efficiently and with less effort'
)
%p
=
_
(
'Track groups of issues that share a theme, across projects and milestones'
)
%button
.btn.btn-new
{
type:
'button'
}
New epic
qa/qa.rb
View file @
30800334
...
...
@@ -62,6 +62,7 @@ module QA
module
Main
autoload
:Entry
,
'qa/page/main/entry'
autoload
:Login
,
'qa/page/main/login'
autoload
:Menu
,
'qa/page/main/menu'
end
...
...
qa/qa/ee/scenario/license/add.rb
View file @
30800334
...
...
@@ -4,7 +4,8 @@ module QA
module
License
class
Add
<
QA
::
Scenario
::
Template
def
perform
(
license
)
QA
::
Page
::
Main
::
Entry
.
act
{
sign_in_using_credentials
}
QA
::
Page
::
Main
::
Entry
.
act
{
visit_login_page
}
QA
::
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
QA
::
Page
::
Main
::
Menu
.
act
{
go_to_admin_area
}
QA
::
Page
::
Admin
::
Menu
.
act
{
go_to_license
}
...
...
qa/qa/git/repository.rb
View file @
30800334
...
...
@@ -23,7 +23,7 @@ module QA
def
password
=
(
pass
)
@password
=
pass
@uri
.
password
=
pass
@uri
.
password
=
CGI
.
escape
(
pass
)
end
def
use_default_credentials
...
...
qa/qa/page/main/entry.rb
View file @
30800334
...
...
@@ -2,9 +2,14 @@ module QA
module
Page
module
Main
class
Entry
<
Page
::
Base
def
initialize
visit
(
Runtime
::
Scenario
.
gitlab_address
)
def
visit_login_page
visit
(
"
#{
Runtime
::
Scenario
.
gitlab_address
}
/users/sign_in"
)
wait_for_instance_to_be_ready
end
private
def
wait_for_instance_to_be_ready
# This resolves cold boot / background tasks problems
#
start
=
Time
.
now
...
...
@@ -14,18 +19,6 @@ module QA
refresh
end
end
def
sign_in_using_credentials
if
page
.
has_content?
(
'Change your password'
)
fill_in
:user_password
,
with:
Runtime
::
User
.
password
fill_in
:user_password_confirmation
,
with:
Runtime
::
User
.
password
click_button
'Change your password'
end
fill_in
:user_login
,
with:
Runtime
::
User
.
name
fill_in
:user_password
,
with:
Runtime
::
User
.
password
click_button
'Sign in'
end
end
end
end
...
...
qa/qa/page/main/login.rb
0 → 100644
View file @
30800334
module
QA
module
Page
module
Main
class
Login
<
Page
::
Base
def
sign_in_using_credentials
if
page
.
has_content?
(
'Change your password'
)
fill_in
:user_password
,
with:
Runtime
::
User
.
password
fill_in
:user_password_confirmation
,
with:
Runtime
::
User
.
password
click_button
'Change your password'
end
fill_in
:user_login
,
with:
Runtime
::
User
.
name
fill_in
:user_password
,
with:
Runtime
::
User
.
password
click_button
'Sign in'
end
end
end
end
end
qa/qa/specs/features/login/standard_spec.rb
View file @
30800334
module
QA
feature
'standard root login'
,
:core
do
scenario
'user logs in using credentials'
do
Page
::
Main
::
Entry
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Entry
.
act
{
visit_login_page
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
# TODO, since `Signed in successfully` message was removed
# this is the only way to tell if user is signed in correctly.
...
...
qa/qa/specs/features/mattermost/group_create_spec.rb
View file @
30800334
module
QA
feature
'create a new group'
,
:mattermost
do
scenario
'creating a group with a mattermost team'
do
Page
::
Main
::
Entry
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Entry
.
act
{
visit_login_page
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Menu
.
act
{
go_to_groups
}
Page
::
Dashboard
::
Groups
.
perform
do
|
page
|
...
...
qa/qa/specs/features/mattermost/login_spec.rb
View file @
30800334
module
QA
feature
'logging in to Mattermost'
,
:mattermost
do
scenario
'can use gitlab oauth'
do
Page
::
Main
::
Entry
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Entry
.
act
{
visit_login_page
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Mattermost
::
Login
.
act
{
sign_in_using_oauth
}
Page
::
Mattermost
::
Main
.
perform
do
|
page
|
...
...
qa/qa/specs/features/project/create_spec.rb
View file @
30800334
module
QA
feature
'create a new project'
,
:core
do
scenario
'user creates a new project'
do
Page
::
Main
::
Entry
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Entry
.
act
{
visit_login_page
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Scenario
::
Gitlab
::
Project
::
Create
.
perform
do
|
project
|
project
.
name
=
'awesome-project'
...
...
qa/qa/specs/features/repository/clone_spec.rb
View file @
30800334
...
...
@@ -9,7 +9,8 @@ module QA
end
before
do
Page
::
Main
::
Entry
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Entry
.
act
{
visit_login_page
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Scenario
::
Gitlab
::
Project
::
Create
.
perform
do
|
scenario
|
scenario
.
name
=
'project-with-code'
...
...
qa/qa/specs/features/repository/push_spec.rb
View file @
30800334
...
...
@@ -2,7 +2,8 @@ module QA
feature
'push code to repository'
,
:core
do
context
'with regular account over http'
do
scenario
'user pushes code to the repository'
do
Page
::
Main
::
Entry
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Entry
.
act
{
visit_login_page
}
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Scenario
::
Gitlab
::
Project
::
Create
.
perform
do
|
scenario
|
scenario
.
name
=
'project_with_code'
...
...
spec/ee/spec/controllers/groups/epics_controller_spec.rb
View file @
30800334
...
...
@@ -9,6 +9,42 @@ describe Groups::EpicsController do
sign_in
(
user
)
end
describe
"GET #index"
do
let!
(
:epic_list
)
{
create_list
(
:epic
,
2
,
group:
group
)
}
before
do
sign_in
(
user
)
group
.
add_developer
(
user
)
end
it
"returns index"
do
get
:index
,
group_id:
group
expect
(
response
).
to
have_gitlab_http_status
(
200
)
end
context
'with page param'
do
let
(
:last_page
)
{
group
.
epics
.
page
.
total_pages
}
before
do
allow
(
Kaminari
.
config
).
to
receive
(
:default_per_page
).
and_return
(
1
)
end
it
'redirects to last_page if page number is larger than number of pages'
do
get
:index
,
group_id:
group
,
page:
(
last_page
+
1
).
to_param
expect
(
response
).
to
redirect_to
(
group_epics_path
(
page:
last_page
,
state:
controller
.
params
[
:state
],
scope:
controller
.
params
[
:scope
]))
end
it
'renders the specified page'
do
get
:index
,
group_id:
group
,
page:
last_page
.
to_param
expect
(
assigns
(
:epics
).
current_page
).
to
eq
(
last_page
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
end
end
end
describe
'GET #show'
do
def
show_epic
(
format
=
:html
)
get
:show
,
group_id:
group
,
id:
epic
.
to_param
,
format:
format
...
...
@@ -20,7 +56,7 @@ describe Groups::EpicsController do
show_epic
expect
(
response
.
content_type
).
to
eq
'text/html'
expect
(
response
).
to
render_template
'groups/e
e/e
pics/show'
expect
(
response
).
to
render_template
'groups/epics/show'
end
context
'with unauthorized user'
do
...
...
spec/ee/spec/features/epics/epics_list_spec.rb
0 → 100644
View file @
30800334
require
'spec_helper'
describe
'epics list'
,
:js
do
let
(
:group
)
{
create
(
:group
,
:public
)
}
let
(
:user
)
{
create
(
:user
)
}
before
do
sign_in
(
user
)
end
context
'when epics exist for the group'
do
let!
(
:epics
)
{
create_list
(
:epic
,
2
,
group:
group
)
}
before
do
visit
group_epics_path
(
group
)
end
it
'shows the epics in the navigation sidebar'
do
expect
(
first
(
'.nav-sidebar .active a .nav-item-name'
)).
to
have_content
(
'Epics'
)
expect
(
first
(
'.nav-sidebar .active a .count'
)).
to
have_content
(
'2'
)
end
it
'renders the list correctly'
do
page
.
within
(
'.page-with-new-nav .content'
)
do
expect
(
find
(
'.top-area'
)).
to
have_content
(
'All 2'
)
within
(
'.issuable-list'
)
do
expect
(
page
).
to
have_content
(
epics
.
first
.
title
)
expect
(
page
).
to
have_content
(
epics
.
second
.
title
)
end
end
end
it
'renders the epic detail correctly after clicking the link'
do
page
.
within
(
'.page-with-new-nav .content .issuable-list'
)
do
click_link
(
epics
.
first
.
title
)
end
wait_for_requests
expect
(
page
.
find
(
'.issuable-details h2.title'
)).
to
have_content
(
epics
.
first
.
title
)
end
end
context
'when no epics exist for the group'
do
it
'renders the empty list page'
do
visit
group_epics_path
(
group
)
within
(
'#content-body'
)
do
expect
(
find
(
'.empty-state h4'
))
.
to
have_content
(
'Epics let you manage your portfolio of projects more efficiently and with less effort'
)
end
end
end
end
spec/ee/spec/finders/epics_finder_spec.rb
0 → 100644
View file @
30800334
require
'spec_helper'
describe
EpicsFinder
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:search_user
)
{
create
(
:user
)
}
let
(
:group
)
{
create
(
:group
,
:private
)
}
let
(
:another_group
)
{
create
(
:group
)
}
let!
(
:epic1
)
{
create
(
:epic
,
group:
group
,
title:
'This is awesome epic'
,
created_at:
1
.
week
.
ago
)
}
let!
(
:epic2
)
{
create
(
:epic
,
group:
group
,
created_at:
4
.
days
.
ago
,
author:
user
)
}
let!
(
:epic3
)
{
create
(
:epic
,
group:
group
,
description:
'not so awesome'
)
}
let!
(
:epic4
)
{
create
(
:epic
,
group:
another_group
)
}
describe
'#execute'
do
def
epics
(
params
=
{})
params
[
:group_id
]
=
group
.
id
described_class
.
new
(
search_user
,
params
).
execute
end
context
'without param'
do
it
'raises an error when group_id param is missing'
do
expect
{
described_class
.
new
(
search_user
).
execute
}.
to
raise_error
{
ArgumentError
}
end
end
context
'when user can not read epics of a group'
do
it
'raises an error when group_id param is missing'
do
expect
{
epics
}.
to
raise_error
{
ArgumentError
}
end
end
context
'wtih correct params'
do
before
do
group
.
add_developer
(
search_user
)
end
it
'returns all epics that belong to the given group'
do
expect
(
epics
).
to
contain_exactly
(
epic1
,
epic2
,
epic3
)
end
context
'by created_at'
do
it
'returns all epics created before the given date'
do
expect
(
epics
(
created_before:
2
.
days
.
ago
)).
to
contain_exactly
(
epic1
,
epic2
)
end
it
'returns all epics created after the given date'
do
expect
(
epics
(
created_after:
2
.
days
.
ago
)).
to
contain_exactly
(
epic3
)
end
it
'returns all epics created within the given interval'
do
expect
(
epics
(
created_after:
5
.
days
.
ago
,
created_before:
1
.
day
.
ago
)).
to
contain_exactly
(
epic2
)
end
end
context
'by search'
do
it
'returns all epics that match the search'
do
expect
(
epics
(
search:
'awesome'
)).
to
contain_exactly
(
epic1
,
epic3
)
end
end
context
'by author'
do
it
'returns all epics authored by the given user'
do
expect
(
epics
(
author_id:
user
.
id
)).
to
contain_exactly
(
epic2
)
end
end
context
'by iids'
do
it
'returns all epics by the given iids'
do
expect
(
epics
(
iids:
[
epic1
.
iid
,
epic3
.
iid
])).
to
contain_exactly
(
epic1
,
epic3
)
end
end
end
end
end
spec/models/project_services/jenkins_deprecated_service_spec.rb
View file @
30800334
...
...
@@ -11,7 +11,8 @@ describe JenkinsDeprecatedService, use_clean_rails_memory_store_caching: true do
describe
'commits methods'
do
def
status_body_for_icon
(
state
)
<<
eos
<h1 class="build-caption page-headline"><img style="width: 48px; height: 48px; " alt="Success" class="icon-
#{
state
}
icon-xlg" src="/static/855d7c3c/images/48x48/
#{
state
}
" tooltip="Success" title="Success">
<h1 class="build-caption page-headline">
<img src="/static/8b0a9b52/images/48x48/
#{
state
}
" alt="Success" tooltip="Success" style="width: 48px; height: 48px; " class="icon-
#{
state
}
icon-xlg" />
Build #188
(Oct 15, 2014 9:45:21 PM)
</h1>
...
...
@@ -49,6 +50,13 @@ eos
expect
(
@service
.
calculate_reactive_cache
(
'2ab7834c'
,
'master'
)).
to
eq
(
commit_status:
'success'
)
end
end
context
'with bad response'
do
it
'has a commit_status of error'
do
stub_request
(
:get
,
"http://jenkins.gitlab.org/job/2/scm/bySHA1/2ab7834c"
).
to_return
(
status:
200
,
body:
'<h1>404</h1>'
,
headers:
{})
expect
(
@service
.
calculate_reactive_cache
(
'2ab7834c'
,
'master'
)).
to
eq
(
commit_status: :error
)
end
end
end
describe
'#commit_status'
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment