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
91bbdc90
Commit
91bbdc90
authored
Jul 23, 2018
by
Winnie Hellmann
Committed by
Phil Hughes
Jul 23, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Display GPG status on repository and blob pages
parent
1a959e1b
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
213 additions
and
134 deletions
+213
-134
app/assets/javascripts/gpg_badges.js
app/assets/javascripts/gpg_badges.js
+22
-9
app/assets/javascripts/pages/projects/blob/show/index.js
app/assets/javascripts/pages/projects/blob/show/index.js
+3
-0
app/assets/javascripts/pages/projects/show/index.js
app/assets/javascripts/pages/projects/show/index.js
+3
-0
app/assets/javascripts/pages/projects/tree/show/index.js
app/assets/javascripts/pages/projects/tree/show/index.js
+5
-1
app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
...ects/tree/components/commit_pipeline_status_component.vue
+82
-80
app/assets/javascripts/vue_shared/components/clipboard_button.vue
...ts/javascripts/vue_shared/components/clipboard_button.vue
+8
-5
app/assets/stylesheets/framework/buttons.scss
app/assets/stylesheets/framework/buttons.scss
+4
-0
app/assets/stylesheets/pages/commits.scss
app/assets/stylesheets/pages/commits.scss
+1
-5
app/helpers/button_helper.rb
app/helpers/button_helper.rb
+1
-1
app/helpers/ci_status_helper.rb
app/helpers/ci_status_helper.rb
+7
-6
app/views/projects/blob/show.html.haml
app/views/projects/blob/show.html.haml
+2
-0
app/views/projects/show.html.haml
app/views/projects/show.html.haml
+4
-0
app/views/projects/tree/show.html.haml
app/views/projects/tree/show.html.haml
+3
-0
app/views/sherlock/queries/_general.html.haml
app/views/sherlock/queries/_general.html.haml
+2
-2
changelogs/unreleased/winh-tree-view-gpg.yml
changelogs/unreleased/winh-tree-view-gpg.yml
+5
-0
locale/gitlab.pot
locale/gitlab.pot
+1
-1
spec/helpers/button_helper_spec.rb
spec/helpers/button_helper_spec.rb
+4
-2
spec/javascripts/gpg_badges_spec.js
spec/javascripts/gpg_badges_spec.js
+55
-21
spec/javascripts/vue_shared/components/clipboard_button_spec.js
...avascripts/vue_shared/components/clipboard_button_spec.js
+1
-1
No files found.
app/assets/javascripts/gpg_badges.js
View file @
91bbdc90
import
$
from
'
jquery
'
;
import
{
parseQueryStringIntoObject
}
from
'
~/lib/utils/common_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
f
lash
from
'
~/flash
'
;
import
createF
lash
from
'
~/flash
'
;
import
{
__
}
from
'
~/locale
'
;
export
default
class
GpgBadges
{
static
fetch
()
{
const
badges
=
$
(
'
.js-loading-gpg-badge
'
);
const
tag
=
$
(
'
.js-signature-container
'
);
if
(
tag
.
length
===
0
)
{
return
Promise
.
resolve
();
}
const
badges
=
$
(
'
.js-loading-gpg-badge
'
);
badges
.
html
(
'
<i class="fa fa-spinner fa-spin"></i>
'
);
const
displayError
=
()
=>
createFlash
(
__
(
'
An error occurred while loading commit signatures
'
));
const
endpoint
=
tag
.
data
(
'
signaturesPath
'
);
if
(
!
endpoint
)
{
displayError
();
return
Promise
.
reject
(
new
Error
(
'
Missing commit signatures endpoint!
'
));
}
const
params
=
parseQueryStringIntoObject
(
tag
.
serialize
());
return
axios
.
get
(
tag
.
data
(
'
signaturesPath
'
),
{
params
})
return
axios
.
get
(
endpoint
,
{
params
})
.
then
(({
data
})
=>
{
data
.
signatures
.
forEach
((
signature
)
=>
{
data
.
signatures
.
forEach
(
signature
=>
{
badges
.
filter
(
`[data-commit-sha="
${
signature
.
commit_sha
}
"]`
).
replaceWith
(
signature
.
html
);
});
})
.
catch
(()
=>
flash
(
__
(
'
An error occurred while loading commits
'
))
);
.
catch
(
displayError
);
}
}
app/assets/javascripts/pages/projects/blob/show/index.js
View file @
91bbdc90
...
...
@@ -2,6 +2,7 @@ import Vue from 'vue';
import
commitPipelineStatus
from
'
~/projects/tree/components/commit_pipeline_status_component.vue
'
;
import
BlobViewer
from
'
~/blob/viewer/index
'
;
import
initBlob
from
'
~/pages/projects/init_blob
'
;
import
GpgBadges
from
'
~/gpg_badges
'
;
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
{
new
BlobViewer
();
// eslint-disable-line no-new
...
...
@@ -26,4 +27,6 @@ document.addEventListener('DOMContentLoaded', () => {
},
});
}
GpgBadges
.
fetch
();
});
app/assets/javascripts/pages/projects/show/index.js
View file @
91bbdc90
...
...
@@ -7,6 +7,7 @@ import TreeView from '~/tree';
import
BlobViewer
from
'
~/blob/viewer/index
'
;
import
Activities
from
'
~/activities
'
;
import
{
ajaxGet
}
from
'
~/lib/utils/common_utils
'
;
import
GpgBadges
from
'
~/gpg_badges
'
;
import
Star
from
'
../../../star
'
;
import
notificationsDropdown
from
'
../../../notifications_dropdown
'
;
...
...
@@ -38,4 +39,6 @@ document.addEventListener('DOMContentLoaded', () => {
$
(
treeSlider
).
waitForImages
(()
=>
{
ajaxGet
(
document
.
querySelector
(
'
.js-tree-content
'
).
dataset
.
logsPath
);
});
GpgBadges
.
fetch
();
});
app/assets/javascripts/pages/projects/tree/show/index.js
View file @
91bbdc90
...
...
@@ -2,6 +2,7 @@ import $ from 'jquery';
import
Vue
from
'
vue
'
;
import
initBlob
from
'
~/blob_edit/blob_bundle
'
;
import
commitPipelineStatus
from
'
~/projects/tree/components/commit_pipeline_status_component.vue
'
;
import
GpgBadges
from
'
~/gpg_badges
'
;
import
TreeView
from
'
../../../../tree
'
;
import
ShortcutsNavigation
from
'
../../../../shortcuts_navigation
'
;
import
BlobViewer
from
'
../../../../blob/viewer
'
;
...
...
@@ -14,7 +15,8 @@ document.addEventListener('DOMContentLoaded', () => {
new
BlobViewer
();
// eslint-disable-line no-new
new
NewCommitForm
(
$
(
'
.js-create-dir-form
'
));
// eslint-disable-line no-new
$
(
'
#tree-slider
'
).
waitForImages
(()
=>
ajaxGet
(
document
.
querySelector
(
'
.js-tree-content
'
).
dataset
.
logsPath
));
ajaxGet
(
document
.
querySelector
(
'
.js-tree-content
'
).
dataset
.
logsPath
),
);
initBlob
();
const
commitPipelineStatusEl
=
document
.
querySelector
(
'
.js-commit-pipeline-status
'
);
...
...
@@ -36,4 +38,6 @@ document.addEventListener('DOMContentLoaded', () => {
},
});
}
GpgBadges
.
fetch
();
});
app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
View file @
91bbdc90
<
script
>
import
Visibility
from
'
visibilityjs
'
;
import
ciIcon
from
'
~/vue_shared/components/ci_icon.vue
'
;
import
loadingIcon
from
'
~/vue_shared/components/loading_icon.vue
'
;
import
Poll
from
'
~/lib/utils/poll
'
;
import
Flash
from
'
~/flash
'
;
import
{
s__
,
sprintf
}
from
'
~/locale
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
CommitPipelineService
from
'
../services/commit_pipeline_service
'
;
import
Visibility
from
'
visibilityjs
'
;
import
ciIcon
from
'
~/vue_shared/components/ci_icon.vue
'
;
import
loadingIcon
from
'
~/vue_shared/components/loading_icon.vue
'
;
import
Poll
from
'
~/lib/utils/poll
'
;
import
Flash
from
'
~/flash
'
;
import
{
s__
,
sprintf
}
from
'
~/locale
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
CommitPipelineService
from
'
../services/commit_pipeline_service
'
;
export
default
{
export
default
{
directives
:
{
tooltip
,
},
...
...
@@ -87,7 +87,8 @@
});
},
fetchPipelineCommitData
()
{
this
.
service
.
fetchData
()
this
.
service
.
fetchData
()
.
then
(
this
.
successCallback
)
.
catch
(
this
.
errorCallback
);
},
...
...
@@ -95,10 +96,10 @@
destroy
()
{
this
.
poll
.
stop
();
},
};
};
</
script
>
<
template
>
<div>
<div
class=
"ci-status-link"
>
<loading-icon
v-if=
"isLoading"
label=
"Loading pipeline status"
...
...
@@ -113,6 +114,7 @@
:title=
"statusTitle"
:aria-label=
"statusTitle"
:status=
"ciStatus"
:size=
"24"
data-container=
"body"
/>
</a>
...
...
app/assets/javascripts/vue_shared/components/clipboard_button.vue
View file @
91bbdc90
...
...
@@ -13,12 +13,19 @@
* />
*/
import
tooltip
from
'
../directives/tooltip
'
;
import
Icon
from
'
../components/icon.vue
'
;
export
default
{
name
:
'
ClipboardButton
'
,
directives
:
{
tooltip
,
},
components
:
{
Icon
,
},
props
:
{
text
:
{
type
:
String
,
...
...
@@ -58,10 +65,6 @@ export default {
type=
"button"
class=
"btn"
>
<i
aria-hidden=
"true"
class=
"fa fa-clipboard"
>
</i>
<icon
name=
"duplicate"
/>
</button>
</
template
>
app/assets/stylesheets/framework/buttons.scss
View file @
91bbdc90
...
...
@@ -294,6 +294,10 @@
.btn-clipboard
{
border
:
0
;
padding
:
0
5px
;
svg
{
top
:
auto
;
}
}
.input-group-prepend
,
...
...
app/assets/stylesheets/pages/commits.scss
View file @
91bbdc90
...
...
@@ -205,7 +205,7 @@
>
.ci-status-link
,
>
.btn
,
>
.commit-sha-group
{
margin-left
:
$gl-padding
-8
;
margin-left
:
$gl-padding
;
}
}
...
...
@@ -235,10 +235,6 @@
fill
:
$gl-text-color-secondary
;
}
.fa-clipboard
{
color
:
$gl-text-color-secondary
;
}
:first-child
{
border-bottom-left-radius
:
$border-radius-default
;
border-top-left-radius
:
$border-radius-default
;
...
...
app/helpers/button_helper.rb
View file @
91bbdc90
...
...
@@ -51,7 +51,7 @@ module ButtonHelper
}
content_tag
:button
,
button_attributes
do
concat
(
icon
(
'clipboard'
,
'aria-hidden'
:
'tru
e'
))
unless
hide_button_icon
concat
(
sprite_icon
(
'duplicat
e'
))
unless
hide_button_icon
concat
(
button_text
)
end
end
...
...
app/helpers/ci_status_helper.rb
View file @
91bbdc90
...
...
@@ -56,7 +56,7 @@ module CiStatusHelper
status
.
humanize
end
def
ci_icon_for_status
(
status
)
def
ci_icon_for_status
(
status
,
size:
16
)
if
detailed_status?
(
status
)
return
sprite_icon
(
status
.
icon
)
end
...
...
@@ -85,7 +85,7 @@ module CiStatusHelper
'status_canceled'
end
sprite_icon
(
icon_name
,
size:
16
)
sprite_icon
(
icon_name
,
size:
size
)
end
def
pipeline_status_cache_key
(
pipeline_status
)
...
...
@@ -111,7 +111,8 @@ module CiStatusHelper
'commit'
,
commit
.
status
(
ref
),
path
,
tooltip_placement:
tooltip_placement
)
tooltip_placement:
tooltip_placement
,
icon_size:
24
)
end
def
render_pipeline_status
(
pipeline
,
tooltip_placement:
'left'
)
...
...
@@ -125,16 +126,16 @@ module CiStatusHelper
Ci
::
Runner
.
instance_type
.
blank?
end
def
render_status_with_link
(
type
,
status
,
path
=
nil
,
tooltip_placement:
'left'
,
cssclass:
''
,
container:
'body'
)
def
render_status_with_link
(
type
,
status
,
path
=
nil
,
tooltip_placement:
'left'
,
cssclass:
''
,
container:
'body'
,
icon_size:
16
)
klass
=
"ci-status-link ci-status-icon-
#{
status
.
dasherize
}
#{
cssclass
}
"
title
=
"
#{
type
.
titleize
}
:
#{
ci_label_for_status
(
status
)
}
"
data
=
{
toggle:
'tooltip'
,
placement:
tooltip_placement
,
container:
container
}
if
path
link_to
ci_icon_for_status
(
status
),
path
,
link_to
ci_icon_for_status
(
status
,
size:
icon_size
),
path
,
class:
klass
,
title:
title
,
data:
data
else
content_tag
:span
,
ci_icon_for_status
(
status
),
content_tag
:span
,
ci_icon_for_status
(
status
,
size:
icon_size
),
class:
klass
,
title:
title
,
data:
data
end
end
...
...
app/views/projects/blob/show.html.haml
View file @
91bbdc90
...
...
@@ -3,6 +3,8 @@
-
page_title
@blob
.
path
,
@ref
.js-signature-container
{
data:
{
'signatures-path'
:
namespace_project_signatures_path
}
}
%div
{
class:
container_class
}
=
render
'projects/last_push'
...
...
app/views/projects/show.html.haml
View file @
91bbdc90
...
...
@@ -8,6 +8,10 @@
=
render
partial:
'flash_messages'
,
locals:
{
project:
@project
}
-
if
@project
.
repository_exists?
&&
!
@project
.
empty_repo?
-
signatures_path
=
namespace_project_signatures_path
(
project_id:
@project
.
path
,
id:
@project
.
default_branch
)
.js-signature-container
{
data:
{
'signatures-path'
:
signatures_path
}
}
%div
{
class:
[
container_class
,
(
"limit-container-width"
unless
fluid_layout
)]
}
=
render
"projects/last_push"
...
...
app/views/projects/tree/show.html.haml
View file @
91bbdc90
-
@no_container
=
true
-
breadcrumb_title
_
(
"Repository"
)
-
@content_class
=
"limit-container-width"
unless
fluid_layout
-
signatures_path
=
namespace_project_signatures_path
(
namespace_id:
@project
.
namespace
.
path
,
project_id:
@project
.
path
,
id:
@ref
)
-
page_title
@path
.
presence
||
_
(
"Files"
),
@ref
=
content_for
:meta_tags
do
=
auto_discovery_link_tag
(
:atom
,
project_commits_url
(
@project
,
@ref
,
rss_url_options
),
title:
"
#{
@project
.
name
}
:
#{
@ref
}
commits"
)
.js-signature-container
{
data:
{
'signatures-path'
:
signatures_path
}
}
%div
{
class:
[(
container_class
),
(
"limit-container-width"
unless
fluid_layout
)]
}
=
render
'projects/last_push'
=
render
'projects/files'
,
commit:
@last_commit
,
project:
@project
,
ref:
@ref
,
content_url:
project_tree_path
(
@project
,
@id
)
app/views/sherlock/queries/_general.html.haml
View file @
91bbdc90
...
...
@@ -27,7 +27,7 @@
.card-header
.float-right
%button
.js-clipboard-trigger.btn.btn-sm
{
title:
t
(
'sherlock.copy_to_clipboard'
),
type: :button
}
%i
.fa.fa-clipboard
=
sprite_icon
(
'duplicate'
)
%pre
.hidden
=
@query
.
formatted_query
%strong
...
...
@@ -42,7 +42,7 @@
.card-header
.float-right
%button
.js-clipboard-trigger.btn.btn-sm
{
title:
t
(
'sherlock.copy_to_clipboard'
),
type: :button
}
%i
.fa.fa-clipboard
=
sprite_icon
(
'duplicate'
)
%pre
.hidden
=
@query
.
explain
%strong
...
...
changelogs/unreleased/winh-tree-view-gpg.yml
0 → 100644
View file @
91bbdc90
---
title
:
Display GPG status on repository and blob pages
merge_request
:
20524
author
:
type
:
changed
locale/gitlab.pot
View file @
91bbdc90
...
...
@@ -465,7 +465,7 @@ msgstr ""
msgid "An error occurred while importing project: ${details}"
msgstr ""
msgid "An error occurred while loading commits"
msgid "An error occurred while loading commit
signature
s"
msgstr ""
msgid "An error occurred while loading diff"
...
...
spec/helpers/button_helper_spec.rb
View file @
91bbdc90
...
...
@@ -121,6 +121,8 @@ describe ButtonHelper do
end
describe
'clipboard_button'
do
include
IconsHelper
let
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
build_stubbed
(
:project
)
}
...
...
@@ -145,7 +147,7 @@ describe ButtonHelper do
expect
(
element
.
attr
(
'data-clipboard-text'
)).
to
eq
(
nil
)
expect
(
element
.
inner_text
).
to
eq
(
""
)
expect
(
element
).
to
have_selector
(
'.fa.fa-clipboard
'
)
expect
(
element
.
to_html
).
to
include
sprite_icon
(
'duplicate
'
)
end
end
...
...
@@ -178,7 +180,7 @@ describe ButtonHelper do
context
'with `hide_button_icon` attribute provided'
do
it
'shows copy to clipboard button without tooltip support'
do
expect
(
element
(
hide_button_icon:
true
)
).
not_to
have_selector
(
'.fa.fa-clipboard
'
)
expect
(
element
(
hide_button_icon:
true
)
.
to_html
).
not_to
include
sprite_icon
(
'duplicate
'
)
end
end
end
...
...
spec/javascripts/gpg_badges_spec.js
View file @
91bbdc90
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
GpgBadges
from
'
~/gpg_badges
'
;
import
{
TEST_HOST
}
from
'
spec/test_constants
'
;
describe
(
'
GpgBadges
'
,
()
=>
{
let
mock
;
const
dummyCommitSha
=
'
n0m0rec0ffee
'
;
const
dummyBadgeHtml
=
'
dummy html
'
;
const
dummyResponse
=
{
signatures
:
[{
signatures
:
[
{
commit_sha
:
dummyCommitSha
,
html
:
dummyBadgeHtml
,
}],
},
],
};
const
dummyUrl
=
`
${
TEST_HOST
}
/dummy/signatures`
;
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
setFixtures
(
`
<form
class="commits-search-form js-signature-container" data-signatures-path="
/hello" action="/hello
"
class="commits-search-form js-signature-container" data-signatures-path="
${
dummyUrl
}
" action="
${
dummyUrl
}
"
method="get">
<input name="utf8" type="hidden" value="✓">
<input type="search" name="search" id="commits-search"class="form-control search-text-input input-short">
...
...
@@ -32,25 +36,55 @@ describe('GpgBadges', () => {
mock
.
restore
();
});
it
(
'
displays a loading spinner
'
,
(
done
)
=>
{
mock
.
onGet
(
'
/hello
'
).
reply
(
200
);
it
(
'
does not make a request if there is no container element
'
,
done
=>
{
setFixtures
(
''
);
spyOn
(
axios
,
'
get
'
);
GpgBadges
.
fetch
().
then
(()
=>
{
GpgBadges
.
fetch
()
.
then
(()
=>
{
expect
(
axios
.
get
).
not
.
toHaveBeenCalled
();
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
throws an error if the endpoint is missing
'
,
done
=>
{
setFixtures
(
'
<div class="js-signature-container"></div>
'
);
spyOn
(
axios
,
'
get
'
);
GpgBadges
.
fetch
()
.
then
(()
=>
done
.
fail
(
'
Expected error to be thrown
'
))
.
catch
(
error
=>
{
expect
(
error
.
message
).
toBe
(
'
Missing commit signatures endpoint!
'
);
expect
(
axios
.
get
).
not
.
toHaveBeenCalled
();
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
displays a loading spinner
'
,
done
=>
{
mock
.
onGet
(
dummyUrl
).
replyOnce
(
200
);
GpgBadges
.
fetch
()
.
then
(()
=>
{
expect
(
document
.
querySelector
(
'
.js-loading-gpg-badge:empty
'
)).
toBe
(
null
);
const
spinners
=
document
.
querySelectorAll
(
'
.js-loading-gpg-badge i.fa.fa-spinner.fa-spin
'
);
expect
(
spinners
.
length
).
toBe
(
1
);
done
();
}).
catch
(
done
.
fail
);
})
.
catch
(
done
.
fail
);
});
it
(
'
replaces the loading spinner
'
,
(
done
)
=>
{
mock
.
onGet
(
'
/hello
'
).
reply
(
200
,
dummyResponse
);
it
(
'
replaces the loading spinner
'
,
done
=>
{
mock
.
onGet
(
dummyUrl
).
replyOnce
(
200
,
dummyResponse
);
GpgBadges
.
fetch
().
then
(()
=>
{
GpgBadges
.
fetch
()
.
then
(()
=>
{
expect
(
document
.
querySelector
(
'
.js-loading-gpg-badge
'
)).
toBe
(
null
);
const
parentContainer
=
document
.
querySelector
(
'
.parent-container
'
);
expect
(
parentContainer
.
innerHTML
.
trim
()).
toEqual
(
dummyBadgeHtml
);
done
();
}).
catch
(
done
.
fail
);
})
.
catch
(
done
.
fail
);
});
});
spec/javascripts/vue_shared/components/clipboard_button_spec.js
View file @
91bbdc90
...
...
@@ -21,7 +21,7 @@ describe('clipboard button', () => {
it
(
'
renders a button for clipboard
'
,
()
=>
{
expect
(
vm
.
$el
.
tagName
).
toEqual
(
'
BUTTON
'
);
expect
(
vm
.
$el
.
getAttribute
(
'
data-clipboard-text
'
)).
toEqual
(
'
copy me
'
);
expect
(
vm
.
$el
.
querySelector
(
'
i
'
).
className
).
toEqual
(
'
fa fa-clipboard
'
);
expect
(
vm
.
$el
).
toHaveSpriteIcon
(
'
duplicate
'
);
});
it
(
'
should have a tooltip with default values
'
,
()
=>
{
...
...
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