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
59b301b1
Commit
59b301b1
authored
Feb 25, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab-ce master
parents
c6af4aff
0b0a04fd
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
248 additions
and
42 deletions
+248
-42
app/assets/javascripts/notes/components/discussion_resolve_with_issue_button.vue
...notes/components/discussion_resolve_with_issue_button.vue
+34
-0
app/assets/javascripts/notes/components/noteable_discussion.vue
...sets/javascripts/notes/components/noteable_discussion.vue
+9
-10
app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
...cripts/vue_merge_request_widget/components/deployment.vue
+10
-4
app/controllers/projects/graphs_controller.rb
app/controllers/projects/graphs_controller.rb
+8
-1
changelogs/unreleased/55925-if-there-is-only-one-changed-page-in-review-app-go-directly-there.yml
...only-one-changed-page-in-review-app-go-directly-there.yml
+5
-0
changelogs/unreleased/refactor-56367-extract-resolve-with-issue-button-component.yml
...tor-56367-extract-resolve-with-issue-button-component.yml
+5
-0
changelogs/unreleased/zj-load-languages-from-database.yml
changelogs/unreleased/zj-load-languages-from-database.yml
+5
-0
lib/api/projects.rb
lib/api/projects.rb
+5
-1
spec/controllers/projects/graphs_controller_spec.rb
spec/controllers/projects/graphs_controller_spec.rb
+16
-0
spec/javascripts/notes/components/discussion_resolve_with_issue_button_spec.js
...s/components/discussion_resolve_with_issue_button_spec.js
+31
-0
spec/javascripts/notes/components/noteable_discussion_spec.js
.../javascripts/notes/components/noteable_discussion_spec.js
+39
-0
spec/javascripts/vue_mr_widget/components/deployment_spec.js
spec/javascripts/vue_mr_widget/components/deployment_spec.js
+55
-26
spec/requests/api/projects_spec.rb
spec/requests/api/projects_spec.rb
+26
-0
No files found.
app/assets/javascripts/notes/components/discussion_resolve_with_issue_button.vue
0 → 100644
View file @
59b301b1
<
script
>
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
{
GlTooltipDirective
,
GlButton
}
from
'
@gitlab/ui
'
;
export
default
{
name
:
'
ResolveWithIssueButton
'
,
components
:
{
Icon
,
GlButton
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
props
:
{
url
:
{
type
:
String
,
required
:
true
,
},
},
};
</
script
>
<
template
>
<div
class=
"btn-group"
role=
"group"
>
<gl-button
v-gl-tooltip
:href=
"url"
:title=
"s__('MergeRequests|Resolve this discussion in a new issue')"
class=
"new-issue-for-discussion discussion-create-issue-btn"
>
<icon
name=
"issue-new"
/>
</gl-button>
</div>
</
template
>
app/assets/javascripts/notes/components/noteable_discussion.vue
View file @
59b301b1
...
@@ -27,6 +27,7 @@ import noteable from '../mixins/noteable';
...
@@ -27,6 +27,7 @@ import noteable from '../mixins/noteable';
import
resolvable
from
'
../mixins/resolvable
'
;
import
resolvable
from
'
../mixins/resolvable
'
;
import
discussionNavigation
from
'
../mixins/discussion_navigation
'
;
import
discussionNavigation
from
'
../mixins/discussion_navigation
'
;
import
ReplyPlaceholder
from
'
./discussion_reply_placeholder.vue
'
;
import
ReplyPlaceholder
from
'
./discussion_reply_placeholder.vue
'
;
import
ResolveWithIssueButton
from
'
./discussion_resolve_with_issue_button.vue
'
;
import
jumpToNextDiscussionButton
from
'
./discussion_jump_to_next_button.vue
'
;
import
jumpToNextDiscussionButton
from
'
./discussion_jump_to_next_button.vue
'
;
import
eventHub
from
'
../event_hub
'
;
import
eventHub
from
'
../event_hub
'
;
...
@@ -46,6 +47,7 @@ export default {
...
@@ -46,6 +47,7 @@ export default {
ReplyPlaceholder
,
ReplyPlaceholder
,
placeholderNote
,
placeholderNote
,
placeholderSystemNote
,
placeholderSystemNote
,
ResolveWithIssueButton
,
systemNote
,
systemNote
,
DraftNote
,
DraftNote
,
TimelineEntryItem
,
TimelineEntryItem
,
...
@@ -244,6 +246,9 @@ export default {
...
@@ -244,6 +246,9 @@ export default {
url
:
this
.
discussion
.
discussion_path
,
url
:
this
.
discussion
.
discussion_path
,
};
};
},
},
resolveWithIssuePath
()
{
return
!
this
.
discussionResolved
&&
this
.
discussion
.
resolve_with_issue_path
;
},
},
},
watch
:
{
watch
:
{
isReplying
()
{
isReplying
()
{
...
@@ -502,16 +507,10 @@ Please check your network connection and try again.`;
...
@@ -502,16 +507,10 @@ Please check your network connection and try again.`;
class=
"btn-group discussion-actions ml-sm-2"
class=
"btn-group discussion-actions ml-sm-2"
role=
"group"
role=
"group"
>
>
<div
v-if=
"!discussionResolved"
class=
"btn-group"
role=
"group"
>
<resolve-with-issue-button
<a
v-if=
"resolveWithIssuePath"
v-gl-tooltip
:url=
"resolveWithIssuePath"
:href=
"discussion.resolve_with_issue_path"
/>
:title=
"s__('MergeRequests|Resolve this discussion in a new issue')"
class=
"new-issue-for-discussion btn btn-default discussion-create-issue-btn"
>
<icon
name=
"issue-new"
/>
</a>
</div>
<jump-to-next-discussion-button
<jump-to-next-discussion-button
v-if=
"shouldShowJumpToNextDiscussion"
v-if=
"shouldShowJumpToNextDiscussion"
@
onClick=
"jumpToNextDiscussion"
@
onClick=
"jumpToNextDiscussion"
...
...
app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
View file @
59b301b1
...
@@ -54,6 +54,12 @@ export default {
...
@@ -54,6 +54,12 @@ export default {
deployTimeago
()
{
deployTimeago
()
{
return
this
.
timeFormated
(
this
.
deployment
.
deployed_at
);
return
this
.
timeFormated
(
this
.
deployment
.
deployed_at
);
},
},
deploymentExternalUrl
()
{
if
(
this
.
deployment
.
changes
&&
this
.
deployment
.
changes
.
length
===
1
)
{
return
this
.
deployment
.
changes
[
0
].
external_url
;
}
return
this
.
deployment
.
external_url
;
},
hasExternalUrls
()
{
hasExternalUrls
()
{
return
!!
(
this
.
deployment
.
external_url
&&
this
.
deployment
.
external_url_formatted
);
return
!!
(
this
.
deployment
.
external_url
&&
this
.
deployment
.
external_url_formatted
);
},
},
...
@@ -78,7 +84,7 @@ export default {
...
@@ -78,7 +84,7 @@ export default {
:
''
;
:
''
;
},
},
shouldRenderDropdown
()
{
shouldRenderDropdown
()
{
return
this
.
deployment
.
changes
&&
this
.
deployment
.
changes
.
length
>
0
;
return
this
.
deployment
.
changes
&&
this
.
deployment
.
changes
.
length
>
1
;
},
},
showMemoryUsage
()
{
showMemoryUsage
()
{
return
this
.
hasMetrics
&&
this
.
showMetrics
;
return
this
.
hasMetrics
&&
this
.
showMetrics
;
...
@@ -154,12 +160,12 @@ export default {
...
@@ -154,12 +160,12 @@ export default {
v-if=
"shouldRenderDropdown"
v-if=
"shouldRenderDropdown"
class=
"js-mr-wigdet-deployment-dropdown inline"
class=
"js-mr-wigdet-deployment-dropdown inline"
:items=
"deployment.changes"
:items=
"deployment.changes"
:main-action-link=
"deployment
.external_u
rl"
:main-action-link=
"deployment
ExternalU
rl"
filter-key=
"path"
filter-key=
"path"
>
>
<template
slot=
"mainAction"
slot-scope=
"slotProps"
>
<template
slot=
"mainAction"
slot-scope=
"slotProps"
>
<review-app-link
<review-app-link
:link=
"deployment
.external_u
rl"
:link=
"deployment
ExternalU
rl"
:css-class=
"`deploy-link js-deploy-url inline $
{slotProps.className}`"
:css-class=
"`deploy-link js-deploy-url inline $
{slotProps.className}`"
/>
/>
</
template
>
</
template
>
...
@@ -183,7 +189,7 @@ export default {
...
@@ -183,7 +189,7 @@ export default {
</filtered-search-dropdown>
</filtered-search-dropdown>
<review-app-link
<review-app-link
v-else
v-else
:link=
"deployment
.external_u
rl"
:link=
"deployment
ExternalU
rl"
css-class=
"js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inlin"
css-class=
"js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inlin"
/>
/>
</template>
</template>
...
...
app/controllers/projects/graphs_controller.rb
View file @
59b301b1
...
@@ -45,7 +45,14 @@ class Projects::GraphsController < Projects::ApplicationController
...
@@ -45,7 +45,14 @@ class Projects::GraphsController < Projects::ApplicationController
end
end
def
get_languages
def
get_languages
@languages
=
@project
.
repository
.
languages
@languages
=
if
@project
.
repository_languages
.
present?
@project
.
repository_languages
.
map
do
|
lang
|
{
value:
lang
.
share
,
label:
lang
.
name
,
color:
lang
.
color
,
highlight:
lang
.
color
}
end
else
@project
.
repository
.
languages
end
end
end
def
fetch_graph
def
fetch_graph
...
...
changelogs/unreleased/55925-if-there-is-only-one-changed-page-in-review-app-go-directly-there.yml
0 → 100644
View file @
59b301b1
---
title
:
Review App Link to Changed Page if Only One Change Present
merge_request
:
25048
author
:
type
:
changed
changelogs/unreleased/refactor-56367-extract-resolve-with-issue-button-component.yml
0 → 100644
View file @
59b301b1
---
title
:
Extracted ResolveWithIssueButton to its own component
merge_request
:
25093
author
:
Martin Hobert
type
:
other
changelogs/unreleased/zj-load-languages-from-database.yml
0 → 100644
View file @
59b301b1
---
title
:
Load repository language from the database if detected before
merge_request
:
25518
author
:
type
:
performance
lib/api/projects.rb
View file @
59b301b1
...
@@ -391,7 +391,11 @@ module API
...
@@ -391,7 +391,11 @@ module API
desc
'Get languages in project repository'
desc
'Get languages in project repository'
get
':id/languages'
do
get
':id/languages'
do
user_project
.
repository
.
languages
.
map
{
|
language
|
language
.
values_at
(
:label
,
:value
)
}.
to_h
if
user_project
.
repository_languages
.
present?
user_project
.
repository_languages
.
map
{
|
l
|
[
l
.
name
,
l
.
share
]
}.
to_h
else
user_project
.
repository
.
languages
.
map
{
|
language
|
language
.
values_at
(
:label
,
:value
)
}.
to_h
end
end
end
desc
'Remove a project'
desc
'Remove a project'
...
...
spec/controllers/projects/graphs_controller_spec.rb
View file @
59b301b1
...
@@ -24,4 +24,20 @@ describe Projects::GraphsController do
...
@@ -24,4 +24,20 @@ describe Projects::GraphsController do
expect
(
response
).
to
redirect_to
action: :charts
expect
(
response
).
to
redirect_to
action: :charts
end
end
end
end
describe
'charts'
do
context
'when languages were previously detected'
do
let!
(
:repository_language
)
{
create
(
:repository_language
,
project:
project
)
}
it
'sets the languages properly'
do
get
(
:charts
,
params:
{
namespace_id:
project
.
namespace
.
path
,
project_id:
project
.
path
,
id:
'master'
})
expect
(
assigns
[
:languages
]).
to
eq
(
[
value:
repository_language
.
share
,
label:
repository_language
.
name
,
color:
repository_language
.
color
,
highlight:
repository_language
.
color
])
end
end
end
end
end
spec/javascripts/notes/components/discussion_resolve_with_issue_button_spec.js
0 → 100644
View file @
59b301b1
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
ResolveWithIssueButton
from
'
~/notes/components/discussion_resolve_with_issue_button.vue
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
TEST_HOST
}
from
'
spec/test_constants
'
;
const
localVue
=
createLocalVue
();
describe
(
'
ResolveWithIssueButton
'
,
()
=>
{
let
wrapper
;
const
url
=
`
${
TEST_HOST
}
/hello-world/`
;
beforeEach
(()
=>
{
wrapper
=
shallowMount
(
ResolveWithIssueButton
,
{
localVue
,
sync
:
false
,
propsData
:
{
url
,
},
});
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
it should have a link with the provided link property as href
'
,
()
=>
{
const
button
=
wrapper
.
find
(
GlButton
);
expect
(
button
.
attributes
().
href
).
toBe
(
url
);
});
});
spec/javascripts/notes/components/noteable_discussion_spec.js
View file @
59b301b1
...
@@ -2,6 +2,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
...
@@ -2,6 +2,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import
createStore
from
'
~/notes/stores
'
;
import
createStore
from
'
~/notes/stores
'
;
import
noteableDiscussion
from
'
~/notes/components/noteable_discussion.vue
'
;
import
noteableDiscussion
from
'
~/notes/components/noteable_discussion.vue
'
;
import
ReplyPlaceholder
from
'
~/notes/components/discussion_reply_placeholder.vue
'
;
import
ReplyPlaceholder
from
'
~/notes/components/discussion_reply_placeholder.vue
'
;
import
ResolveWithIssueButton
from
'
~/notes/components/discussion_resolve_with_issue_button.vue
'
;
import
'
~/behaviors/markdown/render_gfm
'
;
import
'
~/behaviors/markdown/render_gfm
'
;
import
{
noteableDataMock
,
discussionMock
,
notesDataMock
}
from
'
../mock_data
'
;
import
{
noteableDataMock
,
discussionMock
,
notesDataMock
}
from
'
../mock_data
'
;
import
mockDiffFile
from
'
../../diffs/mock_data/diff_file
'
;
import
mockDiffFile
from
'
../../diffs/mock_data/diff_file
'
;
...
@@ -238,4 +239,42 @@ describe('noteable_discussion component', () => {
...
@@ -238,4 +239,42 @@ describe('noteable_discussion component', () => {
});
});
});
});
});
});
describe
(
'
for resolved discussion
'
,
()
=>
{
beforeEach
(()
=>
{
const
discussion
=
getJSONFixture
(
discussionWithTwoUnresolvedNotes
)[
0
];
wrapper
.
setProps
({
discussion
});
});
it
(
'
does not display a button to resolve with issue
'
,
()
=>
{
const
button
=
wrapper
.
find
(
ResolveWithIssueButton
);
expect
(
button
.
exists
()).
toBe
(
false
);
});
});
describe
(
'
for unresolved discussion
'
,
()
=>
{
beforeEach
(
done
=>
{
const
discussion
=
{
...
getJSONFixture
(
discussionWithTwoUnresolvedNotes
)[
0
],
expanded
:
true
,
};
discussion
.
notes
=
discussion
.
notes
.
map
(
note
=>
({
...
note
,
resolved
:
false
,
}));
wrapper
.
setProps
({
discussion
});
wrapper
.
vm
.
$nextTick
()
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
displays a button to resolve with issue
'
,
()
=>
{
const
button
=
wrapper
.
find
(
ResolveWithIssueButton
);
expect
(
button
.
exists
()).
toBe
(
true
);
});
});
});
});
spec/javascripts/vue_mr_widget/components/deployment_spec.js
View file @
59b301b1
...
@@ -6,32 +6,36 @@ import mountComponent from '../../helpers/vue_mount_component_helper';
...
@@ -6,32 +6,36 @@ import mountComponent from '../../helpers/vue_mount_component_helper';
describe
(
'
Deployment component
'
,
()
=>
{
describe
(
'
Deployment component
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
deploymentComponent
);
const
Component
=
Vue
.
extend
(
deploymentComponent
);
const
deploymentMockData
=
{
let
deploymentMockData
;
id
:
15
,
name
:
'
review/diplo
'
,
beforeEach
(()
=>
{
url
:
'
/root/review-apps/environments/15
'
,
deploymentMockData
=
{
stop_url
:
'
/root/review-apps/environments/15/stop
'
,
id
:
15
,
metrics_url
:
'
/root/review-apps/environments/15/deployments/1/metrics
'
,
name
:
'
review/diplo
'
,
metrics_monitoring_url
:
'
/root/review-apps/environments/15/metrics
'
,
url
:
'
/root/review-apps/environments/15
'
,
external_url
:
'
http://gitlab.com.
'
,
stop_url
:
'
/root/review-apps/environments/15/stop
'
,
external_url_formatted
:
'
gitlab
'
,
metrics_url
:
'
/root/review-apps/environments/15/deployments/1/metrics
'
,
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
metrics_monitoring_url
:
'
/root/review-apps/environments/15/metrics
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
external_url
:
'
http://gitlab.com.
'
,
changes
:
[
external_url_formatted
:
'
gitlab
'
,
{
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
path
:
'
index.html
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/index.html
'
,
changes
:
[
},
{
{
path
:
'
index.html
'
,
path
:
'
imgs/gallery.html
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/index.html
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html
'
,
},
},
{
{
path
:
'
imgs/gallery.html
'
,
path
:
'
about/
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/about/
'
,
},
},
{
],
path
:
'
about/
'
,
};
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/about/
'
,
},
],
};
});
let
vm
;
let
vm
;
...
@@ -207,6 +211,31 @@ describe('Deployment component', () => {
...
@@ -207,6 +211,31 @@ describe('Deployment component', () => {
});
});
});
});
describe
(
'
with a single change
'
,
()
=>
{
beforeEach
(()
=>
{
deploymentMockData
.
changes
=
deploymentMockData
.
changes
.
slice
(
0
,
1
);
vm
=
mountComponent
(
Component
,
{
deployment
:
{
...
deploymentMockData
},
showMetrics
:
true
,
});
});
it
(
'
renders the link to the review app without dropdown
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-mr-wigdet-deployment-dropdown
'
)).
toBeNull
();
expect
(
vm
.
$el
.
querySelector
(
'
.js-deploy-url-feature-flag
'
)).
not
.
toBeNull
();
});
it
(
'
renders the link to the review app linked to to the first change
'
,
()
=>
{
const
expectedUrl
=
deploymentMockData
.
changes
[
0
].
external_url
;
const
deployUrl
=
vm
.
$el
.
querySelector
(
'
.js-deploy-url-feature-flag
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-mr-wigdet-deployment-dropdown
'
)).
toBeNull
();
expect
(
deployUrl
).
not
.
toBeNull
();
expect
(
deployUrl
.
href
).
toEqual
(
expectedUrl
);
});
});
describe
(
'
deployment status
'
,
()
=>
{
describe
(
'
deployment status
'
,
()
=>
{
describe
(
'
running
'
,
()
=>
{
describe
(
'
running
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
...
...
spec/requests/api/projects_spec.rb
View file @
59b301b1
...
@@ -4,6 +4,15 @@ require 'spec_helper'
...
@@ -4,6 +4,15 @@ require 'spec_helper'
shared_examples
'languages and percentages JSON response'
do
shared_examples
'languages and percentages JSON response'
do
let
(
:expected_languages
)
{
project
.
repository
.
languages
.
map
{
|
language
|
language
.
values_at
(
:label
,
:value
)}.
to_h
}
let
(
:expected_languages
)
{
project
.
repository
.
languages
.
map
{
|
language
|
language
.
values_at
(
:label
,
:value
)}.
to_h
}
before
do
allow
(
project
.
repository
).
to
receive
(
:languages
).
and_return
(
[{
value:
66.69
,
label:
"Ruby"
,
color:
"#701516"
,
highlight:
"#701516"
},
{
value:
22.98
,
label:
"JavaScript"
,
color:
"#f1e05a"
,
highlight:
"#f1e05a"
},
{
value:
7.91
,
label:
"HTML"
,
color:
"#e34c26"
,
highlight:
"#e34c26"
},
{
value:
2.42
,
label:
"CoffeeScript"
,
color:
"#244776"
,
highlight:
"#244776"
}]
)
end
it
'returns expected language values'
do
it
'returns expected language values'
do
get
api
(
"/projects/
#{
project
.
id
}
/languages"
,
user
)
get
api
(
"/projects/
#{
project
.
id
}
/languages"
,
user
)
...
@@ -11,6 +20,23 @@ shared_examples 'languages and percentages JSON response' do
...
@@ -11,6 +20,23 @@ shared_examples 'languages and percentages JSON response' do
expect
(
json_response
).
to
eq
(
expected_languages
)
expect
(
json_response
).
to
eq
(
expected_languages
)
expect
(
json_response
.
count
).
to
be
>
1
expect
(
json_response
.
count
).
to
be
>
1
end
end
context
'when the languages were detected before'
do
before
do
Projects
::
DetectRepositoryLanguagesService
.
new
(
project
,
project
.
owner
).
execute
end
it
'returns the detection from the database'
do
# Allow this to happen once, so the expected languages can be determined
expect
(
project
.
repository
).
to
receive
(
:languages
).
once
get
api
(
"/projects/
#{
project
.
id
}
/languages"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
).
to
eq
(
expected_languages
)
expect
(
json_response
.
count
).
to
be
>
1
end
end
end
end
describe
API
::
Projects
do
describe
API
::
Projects
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