BigW Consortium Gitlab

Commit 683770f3 by James Lopez

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into update-ruby-2.2.4

parents b8ed5789 a93f7099
...@@ -8,6 +8,27 @@ v 8.5.0 (unreleased) ...@@ -8,6 +8,27 @@ v 8.5.0 (unreleased)
- Fix diff comments loaded by AJAX to load comment with diff in discussion tab - Fix diff comments loaded by AJAX to load comment with diff in discussion tab
- Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel) - Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel)
- Don't vendor minified JS - Don't vendor minified JS
- Track project import failure
- Fix visibility level text in admin area (Zeger-Jan van de Weg)
- Update the ExternalIssue regex pattern (Blake Hitchcock)
v 8.4.2 (unreleased)
- Bump required gitlab-workhorse version to bring in a fix for missing
artifacts in the build artifacts browser
- Get rid of those ugly borders on the file tree view
- Bump gitlab_git version to 7.2.24 in order to bring in a performance
improvement when checking if a repository was empty
- Add instrumentation for Gitlab::Git::Repository instance methods so we can
track them in Performance Monitoring.
v 8.4.2 (unreleased)
- Fix method undefined when using external commit status in builds
v 8.4.1
- Apply security updates for Rails (4.2.5.1), rails-html-sanitizer (1.0.3),
and Nokogiri (1.6.7.2)
- Fix redirect loop during import
- Fix diff highlighting for all syntax themes
v 8.4.0 v 8.4.0
- Allow LDAP users to change their email if it was not set by the LDAP server - Allow LDAP users to change their email if it was not set by the LDAP server
......
source "https://rubygems.org" source "https://rubygems.org"
gem 'rails', '4.2.4' gem 'rails', '4.2.5.1'
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with # Responders respond_to and respond_with
...@@ -103,7 +103,8 @@ gem 'asciidoctor', '~> 1.5.2' ...@@ -103,7 +103,8 @@ gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 1.10.1' gem 'rouge', '~> 1.10.1'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
gem 'nokogiri', '1.6.7.1' # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
gem 'nokogiri', '1.6.7.2'
# Diffs # Diffs
gem 'diffy', '~> 3.0.3' gem 'diffy', '~> 3.0.3'
......
...@@ -4,41 +4,41 @@ GEM ...@@ -4,41 +4,41 @@ GEM
CFPropertyList (2.3.2) CFPropertyList (2.3.2)
RedCloth (4.2.9) RedCloth (4.2.9)
ace-rails-ap (2.0.1) ace-rails-ap (2.0.1)
actionmailer (4.2.4) actionmailer (4.2.5.1)
actionpack (= 4.2.4) actionpack (= 4.2.5.1)
actionview (= 4.2.4) actionview (= 4.2.5.1)
activejob (= 4.2.4) activejob (= 4.2.5.1)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.4) actionpack (4.2.5.1)
actionview (= 4.2.4) actionview (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
rack (~> 1.6) rack (~> 1.6)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.4) actionview (4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.4) activejob (4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
globalid (>= 0.3.0) globalid (>= 0.3.0)
activemodel (4.2.4) activemodel (4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
builder (~> 3.1) builder (~> 3.1)
activerecord (4.2.4) activerecord (4.2.5.1)
activemodel (= 4.2.4) activemodel (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
arel (~> 6.0) arel (~> 6.0)
activerecord-deprecated_finders (1.0.4) activerecord-deprecated_finders (1.0.4)
activerecord-session_store (0.1.2) activerecord-session_store (0.1.2)
actionpack (>= 4.0.0, < 5) actionpack (>= 4.0.0, < 5)
activerecord (>= 4.0.0, < 5) activerecord (>= 4.0.0, < 5)
railties (>= 4.0.0, < 5) railties (>= 4.0.0, < 5)
activesupport (4.2.4) activesupport (4.2.5.1)
i18n (~> 0.7) i18n (~> 0.7)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
minitest (~> 5.1) minitest (~> 5.1)
...@@ -356,7 +356,7 @@ GEM ...@@ -356,7 +356,7 @@ GEM
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab_emoji (0.2.0) gitlab_emoji (0.2.0)
gemojione (~> 2.1) gemojione (~> 2.1)
gitlab_git (7.2.23) gitlab_git (7.2.24)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
...@@ -482,7 +482,7 @@ GEM ...@@ -482,7 +482,7 @@ GEM
grape grape
newrelic_rpm newrelic_rpm
newrelic_rpm (3.9.4.245) newrelic_rpm (3.9.4.245)
nokogiri (1.6.7.1) nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2) mini_portile2 (~> 2.0.0.rc2)
nprogress-rails (0.1.6.7) nprogress-rails (0.1.6.7)
oauth (0.4.7) oauth (0.4.7)
...@@ -588,16 +588,16 @@ GEM ...@@ -588,16 +588,16 @@ GEM
rack rack
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (4.2.4) rails (4.2.5.1)
actionmailer (= 4.2.4) actionmailer (= 4.2.5.1)
actionpack (= 4.2.4) actionpack (= 4.2.5.1)
actionview (= 4.2.4) actionview (= 4.2.5.1)
activejob (= 4.2.4) activejob (= 4.2.5.1)
activemodel (= 4.2.4) activemodel (= 4.2.5.1)
activerecord (= 4.2.4) activerecord (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.2.4) railties (= 4.2.5.1)
sprockets-rails sprockets-rails
rails-deprecated_sanitizer (1.0.3) rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha) activesupport (>= 4.2.0.alpha)
...@@ -605,11 +605,11 @@ GEM ...@@ -605,11 +605,11 @@ GEM
activesupport (>= 4.2.0.beta, < 5.0) activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0) nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2) rails-html-sanitizer (1.0.3)
loofah (~> 2.0) loofah (~> 2.0)
railties (4.2.4) railties (4.2.5.1)
actionpack (= 4.2.4) actionpack (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.0.0) rainbow (2.0.0)
...@@ -962,7 +962,7 @@ DEPENDENCIES ...@@ -962,7 +962,7 @@ DEPENDENCIES
net-ssh (~> 3.0.1) net-ssh (~> 3.0.1)
newrelic-grape newrelic-grape
newrelic_rpm (~> 3.9.4.245) newrelic_rpm (~> 3.9.4.245)
nokogiri (= 1.6.7.1) nokogiri (= 1.6.7.2)
nprogress-rails (~> 0.1.6.7) nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0) oauth2 (~> 1.0.0)
octokit (~> 3.7.0) octokit (~> 3.7.0)
...@@ -988,7 +988,7 @@ DEPENDENCIES ...@@ -988,7 +988,7 @@ DEPENDENCIES
rack-attack (~> 4.3.1) rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1) rack-oauth2 (~> 1.2.1)
rails (= 4.2.4) rails (= 4.2.5.1)
rails-deprecated_sanitizer (~> 1.0.3) rails-deprecated_sanitizer (~> 1.0.3)
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
rblineprof rblineprof
......
...@@ -203,4 +203,13 @@ $ -> ...@@ -203,4 +203,13 @@ $ ->
form = btn.closest("form") form = btn.closest("form")
new ConfirmDangerModal(form, text) new ConfirmDangerModal(form, text)
$('input[type="search"]').each ->
$this = $(this)
$this.attr 'value', $this.val()
return
$(document).on 'keyup', 'input[type="search"]' , (e) ->
$this = $(this)
$this.attr 'value', $this.val()
new Aside() new Aside()
...@@ -32,6 +32,7 @@ class @EditBlob ...@@ -32,6 +32,7 @@ class @EditBlob
content: editor.getValue() content: editor.getValue()
, (response) -> , (response) ->
currentPane.empty().append response currentPane.empty().append response
currentPane.syntaxHighlight()
return return
else else
......
...@@ -5,11 +5,11 @@ class @ShortcutsIssuable extends ShortcutsNavigation ...@@ -5,11 +5,11 @@ class @ShortcutsIssuable extends ShortcutsNavigation
constructor: (isMergeRequest) -> constructor: (isMergeRequest) ->
super() super()
Mousetrap.bind('a', -> Mousetrap.bind('a', ->
$('.js-assignee').select2('open') $('.block.assignee .edit-link').trigger('click')
return false return false
) )
Mousetrap.bind('m', -> Mousetrap.bind('m', ->
$('.js-milestone').select2('open') $('.block.milestone .edit-link').trigger('click')
return false return false
) )
Mousetrap.bind('r', => Mousetrap.bind('r', =>
......
...@@ -311,14 +311,6 @@ table { ...@@ -311,14 +311,6 @@ table {
} }
} }
.wiki .highlight, .note-body .highlight {
margin: 12px 0 12px 0;
}
.wiki .code {
overflow-x: auto;
}
.footer-links { .footer-links {
margin-bottom: 20px; margin-bottom: 20px;
a { a {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
border: 1px solid $border-color; border: 1px solid $border-color;
&.readme-holder { &.readme-holder {
margin-top: 10px;
border-bottom: 0; border-bottom: 0;
} }
......
...@@ -2,11 +2,42 @@ textarea { ...@@ -2,11 +2,42 @@ textarea {
resize: vertical; resize: vertical;
} }
input[type='search'].search-text-input { input {
background-image: image-url("icon-search.png"); border-radius: $border-radius-base;
}
input[type='search'] {
background-color: white;
padding-left: 10px;
}
input[type='search'].search-input {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 10px; background-position: 10px;
padding-left: 25px; background-size: 16px;
background-position-x: 30%;
padding-left: 10px;
background-color: $gray-light;
&.search-input[value=""] {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAFu0lEQVRIia1WTahkVxH+quqce7vf6zdvJpHoIlkYJ2SiJiIokmQjgoGgIAaEIYuYXWICgojiwkmC4taFwhjcyIDusogEIwwiSSCKPwsdwzAg0SjJ9Izzk5n3+nXfe8+pqizOvd395scfsJqi6dPnnDr11Vc/NJ1OwUTosqJLCmYCHCAC2mSHs+ojZv6AO46Y+20AhIneJsafhPhXVZSXDk7qi+aOLhtQNuBmQtcarAKjTXpn2+l3u2yPunvZSABRucjcAV/eMZuM48/Go/g1d19kc4wq+e8MZjWkbI/P5t2P3RFFbv7SQdyBlBUx8N8OTuqjMcof+N94yMPrY2DMm/ytnb32J0QrY+6AqsHM4Q64O9SKDmerKDD3Oy/tNL9vk342CC8RuU6n0ymCMHb22scu7zQngtASOjUHE1BX4UUAv4b7Ow6qiXCXuz/UdvogAAweDY943/b4cAz0ZlYHXeMsnT07RVb7wMUr8ykI4H5HVkMd5Rcb4/jNURVOL5qErAaAUUdCCIJ5kx5q2nw8m39ImEAAsjpE6PStB0YfMcd1wqqG3Xn7A3PfZyyKnNjaqD4fmE/fCNKshirIyY1xvI+Av6g5QIAIIWX7cJPssboSiBBEeKmsZne0Sb8kzAUWNYyq8NvbDo0fZ6beqxuLmqOOMr/lwOh+YXpXtbjERGja9JyZ9+HxpXKb9Gj5oywRESbj+Cj1ENG1QViTGBl1FbC1We1tbVRfHWIoQkhqH9xbpE92XUbb6VJZ1R4crjRz1JWcDMJvLdoMcyAEhjuwHo8Bfndg3mbszhOY+adVlMtD3po51OwzIQiEaams7oeJhxRw1FFOVpFRRUYIhMBAFRnjOsC8IFHHUA4TQQhgAqpAiIFfGbxkIqj54ayGbL7UoOqHCniAEKHLNr26l+D9wQJzeUwMAnfHvEnLECzZRwRV++d60ptjW9VLZeolEJG6GwCCE0CFVNB+Ay0NEqoQYG4YYFu7B8IEVRt3uRzy/osIoLV9QZimWXGHUMFdmI6M64DUF2Je88R9VZqCSP+QlcF5k+4tCzSsXaqjINuK6UyE0+s/mk6/qFq8oAIL9pqMLhkGsNrOyoOIlszust3aJv0U9+kFdwjTGwWl1YdF+KWlQSZ0Se/psj8yGVdg5tJyfH96EBWmLtoEMwMzMFt031NzGWLLzKhC+KV7H5ZeeaMOPxemma2x68puc0LN3+/u6LJiePS6MKHvn4wu6cPzJj0hsioeMfDrEvjv5r6W9gBvjKJujuKzQ0URIZj75NylvT+mbHfXQa4rwAMaVRTMm/SFyzvNy0yF6+4AM+1ubcSnqkAIUjQKl1RKSbE5jt+vovx1MBqF0WW7/d1Z80ab9BtmuJ3Xk5cJKds9TZt/uLPXvtiTrQ+dIwqfAejUvM1os6FNikXKUHfQ+ekUsXT5u85enJ0CaBSkkGEo1syUQ+DfMdE/4GA1uzupf9zdbzhOmLsF4efHVXjaHHAzmDtGdQRd/Nc5wAEJjNki3XfhyvwVNz80xANrht3LsENY9cBBdN1L9GUyyvFRFZ42t75sBvCQRykbRlU4tT2pPxoCvzx09d4GmPs200M6wKdWSDGK8mppYSWdhAlt0qeaLv+IadXU9/Evq4FAZ8ej+LmtcTxaRX4NWI0Uag5Vg1p5MYg8BnlhXIdPHDow+vTWZvVMVttXDLqkTzZdPj6Qii6cP1cSvIdl3iQkNYyi9HH0I22y+93tY3DcQkTZgQtM+POoCr8x97eylkmtrgKuztrvXJ21x/aNKuqIkZ/fntRfCdcTfhUTAIhRzoDojJD0aSNLLwMzmpT7+JaLtyf1MwDo6qz9djFaUq3t9MlFmy/c1OCSceY9fMsVaL9mvH9ocXdkdWxv1scAePG0THAhMOaLdOw/Gvxfxb1w4eCapyIENUcV5M3/u8FitAxZ25P6GAHT3UX39Srw+QOb1ZffA98Dl2Wy1BYkAAAAAElFTkSuQmCC');
}
&.search-input::-webkit-input-placeholder {
text-align: center;
}
&.search-input:-moz-placeholder { /* Firefox 18- */
text-align: center;
}
&.search-input::-moz-placeholder { /* Firefox 19+ */
text-align: center;
}
&.search-input:-ms-input-placeholder {
text-align: center;
}
} }
input[type='text'].danger { input[type='text'].danger {
...@@ -74,6 +105,7 @@ label { ...@@ -74,6 +105,7 @@ label {
.form-control { .form-control {
@include box-shadow(none); @include box-shadow(none);
border-radius: 3px;
} }
.form-control-inline { .form-control-inline {
......
...@@ -108,16 +108,10 @@ header { ...@@ -108,16 +108,10 @@ header {
.search-input { .search-input {
width: 220px; width: 220px;
background-image: image-url("icon-search.png");
background-repeat: no-repeat;
background-position: 195px;
@include input-big;
&:focus { &:focus {
@include box-shadow(none); @include box-shadow(none);
outline: none; outline: none;
border-color: #DDD;
background-color: #FFF;
} }
} }
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
overflow-y: hidden; overflow-y: hidden;
white-space: pre; white-space: pre;
word-wrap: normal; word-wrap: normal;
border-left: 1px solid;
code { code {
font-family: $monospace_font; font-family: $monospace_font;
...@@ -25,7 +26,7 @@ ...@@ -25,7 +26,7 @@
padding: 0; padding: 0;
.line { .line {
display: inline; display: inline-block;
} }
} }
} }
...@@ -53,18 +54,3 @@ ...@@ -53,18 +54,3 @@
} }
} }
} }
.note-text .code {
border: none;
box-shadow: none;
background: $background-color;
padding: 1em;
overflow-x: auto;
code {
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 0;
}
}
...@@ -33,12 +33,12 @@ table { ...@@ -33,12 +33,12 @@ table {
background-color: $background-color; background-color: $background-color;
font-weight: normal; font-weight: normal;
font-size: 15px; font-size: 15px;
border-bottom: 1px solid $border-color !important; border-bottom: 1px solid $border-color;
} }
td { td {
border-color: $table-border-color !important; border-color: $table-border-color;
border-bottom: 1px solid; border-bottom: 1px solid $border-color;
} }
} }
} }
......
...@@ -22,9 +22,9 @@ $brand-info: $gl-info; ...@@ -22,9 +22,9 @@ $brand-info: $gl-info;
$brand-warning: $gl-warning; $brand-warning: $gl-warning;
$brand-danger: $gl-danger; $brand-danger: $gl-danger;
$border-radius-base: 2px !default; $border-radius-base: 3px !default;
$border-radius-large: 2px !default; $border-radius-large: 3px !default;
$border-radius-small: 2px !default; $border-radius-small: 3px !default;
//== Scaffolding //== Scaffolding
......
...@@ -87,8 +87,8 @@ ...@@ -87,8 +87,8 @@
} }
p { p {
color:#5c5d5e; color: #5c5d5e;
margin:6px 0 0 0; margin: 6px 0 0 0;
} }
table { table {
...@@ -102,11 +102,10 @@ ...@@ -102,11 +102,10 @@
} }
pre { pre {
margin: 12px 0 12px 0 !important; margin: 12px 0 12px 0;
background-color: #f8fafc; font-size: 13px;
font-size: 13px !important; line-height: 1.6em;
color: #5b6169; overflow-x: auto;
line-height: 1.6em !important;
@include border-radius(2px); @include border-radius(2px);
} }
...@@ -204,11 +203,6 @@ h1, h2, h3, h4, h5, h6 { ...@@ -204,11 +203,6 @@ h1, h2, h3, h4, h5, h6 {
pre { pre {
font-family: $monospace_font; font-family: $monospace_font;
&.dark {
background: #333;
color: $background-color;
}
&.plain-readme { &.plain-readme {
background: none; background: none;
border: none; border: none;
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #666; border-color: #666;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #555; border-color: #555;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #113b46; border-color: #113b46;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
// Diff line // Diff line
.line_holder { .line_holder {
.diff-line-num.new, .line_content.new { .diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #808080); @include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #113b46);
} }
.diff-line-num.old, .line_content.old { .diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.3), rgba(220, 50, 47, 0.3), #808080); @include diff_background(rgba(220, 50, 47, 0.3), rgba(220, 50, 47, 0.3), #113b46);
} }
.line_content.match { .line_content.match {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #c5d0d4; border-color: #c5d0d4;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
// Diff line // Diff line
.line_holder { .line_holder {
.diff-line-num.new, .line_content.new { .diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #FAF3DD); @include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #c5d0d4);
} }
.diff-line-num.old, .line_content.old { .diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #FAF3DD); @include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #c5d0d4);
} }
.line_content.match { .line_content.match {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid $border-color; border-color: $border-color;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
......
...@@ -79,10 +79,8 @@ ...@@ -79,10 +79,8 @@
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
border: none; border: none;
background: $background-color;
color: rgba(0, 0, 0, 0.3);
padding: 0px 5px; padding: 0px 5px;
border-right: 1px solid $border-color; border-right: 1px solid;
text-align: right; text-align: right;
min-width: 35px; min-width: 35px;
max-width: 50px; max-width: 50px;
...@@ -92,7 +90,6 @@ ...@@ -92,7 +90,6 @@
float: left; float: left;
width: 35px; width: 35px;
font-weight: normal; font-weight: normal;
color: rgba(0, 0, 0, 0.3);
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
......
.member-search-form { .member-search-form {
float: left; float: left;
input[type='search'] {
width: 225px;
vertical-align: bottom;
@media (max-width: $screen-xs-max) {
width: 100px;
vertical-align: bottom;
}
}
} }
.milestone-row { .milestone-row {
......
...@@ -49,11 +49,6 @@ ...@@ -49,11 +49,6 @@
.issue-search-form { .issue-search-form {
margin: 0; margin: 0;
height: 24px; height: 24px;
.issue_search {
border: 1px solid #DDD !important;
background-color: #f4f4f4;
}
} }
form.edit-issue { form.edit-issue {
......
...@@ -154,6 +154,7 @@ ul.notes { ...@@ -154,6 +154,7 @@ ul.notes {
text-align: center; text-align: center;
padding: 10px 0; padding: 10px 0;
background: #FFF; background: #FFF;
color: $text-color;
} }
&.notes_line2 { &.notes_line2 {
text-align: center; text-align: center;
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
&:hover { &:hover {
td { td {
background: $hover; background: $hover;
border-top: 1px solid #ADF;
border-bottom: 1px solid #ADF;
} }
cursor: pointer; cursor: pointer;
} }
......
...@@ -2,17 +2,18 @@ class GroupsController < Groups::ApplicationController ...@@ -2,17 +2,18 @@ class GroupsController < Groups::ApplicationController
include IssuesAction include IssuesAction
include MergeRequestsAction include MergeRequestsAction
skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests]
respond_to :html respond_to :html
before_action :group, except: [:new, :create]
skip_before_action :authenticate_user!, only: [:index, :show, :issues, :merge_requests]
before_action :group, except: [:index, :new, :create]
# Authorize # Authorize
before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete] before_action :authorize_read_group!, except: [:index, :show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects] before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create] before_action :authorize_create_group!, only: [:new, :create]
# Load group projects # Load group projects
before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete] before_action :load_projects, except: [:index, :new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show before_action :event_filter, only: :show
layout :determine_layout layout :determine_layout
......
class Projects::ImportsController < Projects::ApplicationController class Projects::ImportsController < Projects::ApplicationController
# Authorize # Authorize
before_action :authorize_admin_project! before_action :authorize_admin_project!
before_action :require_no_repo, except: :show before_action :require_no_repo, only: [:new, :create]
before_action :redirect_if_progress, except: :show before_action :redirect_if_progress, only: [:new, :create]
def new def new
end end
...@@ -24,11 +24,11 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -24,11 +24,11 @@ class Projects::ImportsController < Projects::ApplicationController
end end
def show def show
if @project.repository_exists? || @project.import_finished? if @project.import_finished?
if continue_params if continue_params
redirect_to continue_params[:to], notice: continue_params[:notice] redirect_to continue_params[:to], notice: continue_params[:notice]
else else
redirect_to project_path(@project), notice: "The project was successfully forked." redirect_to namespace_project_path(@project.namespace, @project), notice: finished_notice
end end
elsif @project.import_failed? elsif @project.import_failed?
redirect_to new_namespace_project_import_path(@project.namespace, @project) redirect_to new_namespace_project_import_path(@project.namespace, @project)
...@@ -36,6 +36,7 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -36,6 +36,7 @@ class Projects::ImportsController < Projects::ApplicationController
if continue_params && continue_params[:notice_now] if continue_params && continue_params[:notice_now]
flash.now[:notice] = continue_params[:notice_now] flash.now[:notice] = continue_params[:notice_now]
end end
# Render # Render
end end
end end
...@@ -44,6 +45,7 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -44,6 +45,7 @@ class Projects::ImportsController < Projects::ApplicationController
def continue_params def continue_params
continue_params = params[:continue] continue_params = params[:continue]
if continue_params if continue_params
continue_params.permit(:to, :notice, :notice_now) continue_params.permit(:to, :notice, :notice_now)
else else
...@@ -51,8 +53,16 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -51,8 +53,16 @@ class Projects::ImportsController < Projects::ApplicationController
end end
end end
def finished_notice
if @project.forked?
'The project was successfully forked.'
else
'The project was successfully imported.'
end
end
def require_no_repo def require_no_repo
if @project.repository_exists? && !@project.import_in_progress? if @project.repository_exists?
redirect_to(namespace_project_path(@project.namespace, @project)) redirect_to(namespace_project_path(@project.namespace, @project))
end end
end end
......
...@@ -171,7 +171,7 @@ module ApplicationHelper ...@@ -171,7 +171,7 @@ module ApplicationHelper
def search_placeholder def search_placeholder
if @project && @project.persisted? if @project && @project.persisted?
'Search in this project' 'Search'
elsif @snippet || @snippets || @show_snippets elsif @snippet || @snippets || @show_snippets
'Search snippets' 'Search snippets'
elsif @group && @group.persisted? elsif @group && @group.persisted?
......
...@@ -83,7 +83,11 @@ module LabelsHelper ...@@ -83,7 +83,11 @@ module LabelsHelper
end end
def text_color_for_bg(bg_color) def text_color_for_bg(bg_color)
r, g, b = bg_color.slice(1,7).scan(/.{2}/).map(&:hex) if bg_color.length == 4
r, g, b = bg_color[1, 4].scan(/./).map { |v| (v * 2).hex }
else
r, g, b = bg_color[1, 7].scan(/.{2}/).map(&:hex)
end
if (r + g + b) > 500 if (r + g + b) > 500
'#333333' '#333333'
......
...@@ -31,7 +31,7 @@ class ExternalIssue ...@@ -31,7 +31,7 @@ class ExternalIssue
# Pattern used to extract `JIRA-123` issue references from text # Pattern used to extract `JIRA-123` issue references from text
def self.reference_pattern def self.reference_pattern
%r{(?<issue>([A-Z\-]+-)\d+)} %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)}
end end
def to_reference(_from_project = nil) def to_reference(_from_project = nil)
......
...@@ -57,7 +57,7 @@ class Repository ...@@ -57,7 +57,7 @@ class Repository
# This method return true if repository contains some content visible in project page. # This method return true if repository contains some content visible in project page.
# #
def has_visible_content? def has_visible_content?
!raw_repository.branches.empty? raw_repository.branch_count > 0
end end
def commit(id = 'HEAD') def commit(id = 'HEAD')
......
...@@ -17,12 +17,20 @@ class Tree ...@@ -17,12 +17,20 @@ class Tree
def readme def readme
return @readme if defined?(@readme) return @readme if defined?(@readme)
# Take the first previewable readme, or return nil if none is available or available_readmes = blobs.select(&:readme?)
# we can't preview any of them
readme_tree = blobs.find do |blob| previewable_readmes = available_readmes.select do |blob|
blob.readme? && (previewable?(blob.name) || plain?(blob.name)) previewable?(blob.name)
end
plain_readmes = available_readmes.select do |blob|
plain?(blob.name)
end end
# Prioritize previewable over plain readmes
readme_tree = previewable_readmes.first || plain_readmes.first
# Return if we can't preview any of them
if readme_tree.nil? if readme_tree.nil?
return @readme = nil return @readme = nil
end end
......
module Projects
class ImportService < BaseService
include Gitlab::ShellAdapter
class Error < StandardError; end
ALLOWED_TYPES = [
'bitbucket',
'fogbugz',
'gitlab',
'github',
'google_code'
]
def execute
if unknown_url?
# In this case, we only want to import issues, not a repository.
create_repository
else
import_repository
end
import_data
success
rescue Error => e
error(e.message)
end
private
def create_repository
unless project.create_repository
raise Error, 'The repository could not be created.'
end
end
def import_repository
begin
gitlab_shell.import_repository(project.path_with_namespace, project.import_url)
rescue Gitlab::Shell::Error => e
raise Error, e.message
end
end
def import_data
return unless has_importer?
unless importer.execute
raise Error, 'The remote data could not be imported.'
end
end
def has_importer?
ALLOWED_TYPES.include?(project.import_type)
end
def importer
class_name = "Gitlab::#{project.import_type.camelize}Import::Importer"
class_name.constantize.new(project)
end
def unknown_url?
project.import_url == Project::UNKNOWN_IMPORT_URL
end
end
end
...@@ -14,11 +14,11 @@ ...@@ -14,11 +14,11 @@
.form-group.project-visibility-level-holder .form-group.project-visibility-level-holder
= f.label :default_project_visibility, class: 'control-label col-sm-2' = f.label :default_project_visibility, class: 'control-label col-sm-2'
.col-sm-10 .col-sm-10
= render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project) = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new)
.form-group.project-visibility-level-holder .form-group.project-visibility-level-holder
= f.label :default_snippet_visibility, class: 'control-label col-sm-2' = f.label :default_snippet_visibility, class: 'control-label col-sm-2'
.col-sm-10 .col-sm-10
= render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: PersonalSnippet) = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new)
.form-group .form-group
= f.label :restricted_visibility_levels, class: 'control-label col-sm-2' = f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
.col-sm-10 .col-sm-10
...@@ -268,4 +268,4 @@ ...@@ -268,4 +268,4 @@
= f.text_field :sentry_dsn, class: 'form-control' = f.text_field :sentry_dsn, class: 'form-control'
.form-actions .form-actions
= f.submit 'Save', class: 'btn btn-primary' = f.submit 'Save', class: 'btn btn-save'
...@@ -22,5 +22,5 @@ ...@@ -22,5 +22,5 @@
%code= Doorkeeper.configuration.native_redirect_uri %code= Doorkeeper.configuration.native_redirect_uri
for local tests for local tests
.form-actions .form-actions
= f.submit 'Submit', class: "btn btn-primary wide" = f.submit 'Submit', class: "btn btn-save wide"
= link_to "Cancel", admin_applications_path, class: "btn btn-default" = link_to "Cancel", admin_applications_path, class: "btn btn-default"
...@@ -21,6 +21,5 @@ ...@@ -21,6 +21,5 @@
- else - else
.form-actions .form-actions
= f.submit 'Save changes', class: "btn btn-primary" = f.submit 'Save changes', class: "btn btn-save"
= link_to 'Cancel', admin_group_path(@group), class: "btn btn-cancel" = link_to 'Cancel', admin_group_path(@group), class: "btn btn-cancel"
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
.file-content.wiki .file-content.wiki
= render_markup(blob.name, blob.data) = render_markup(blob.name, blob.data)
- else - else
.file-content.code - unless blob.empty?
- unless blob.empty? = render 'shared/file_highlight', blob: blob
= render 'shared/file_highlight', blob: blob - else
- else .file-content.code
.nothing-here-block Empty file .nothing-here-block Empty file
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
.file-content.wiki .file-content.wiki
= raw render_markup(@blob.name, @content) = raw render_markup(@blob.name, @content)
- else - else
.file-content.code .file-content.code.js-syntax-highlight
- unless @diff_lines.empty? - unless @diff_lines.empty?
%table.text-file %table.text-file
- @diff_lines.each do |line| - @diff_lines.each do |line|
......
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
%td %td
.pull-right .pull-right
- if current_user && can?(current_user, :read_build_artifacts, commit_status.project) && commit_status.artifacts? - if current_user && can?(current_user, :read_build_artifacts, commit_status.project) && commit_status.artifacts_download_url
= link_to commit_status.artifacts_download_url, title: 'Download artifacts' do = link_to commit_status.artifacts_download_url, title: 'Download artifacts' do
%i.fa.fa-download %i.fa.fa-download
- if current_user && can?(current_user, :manage_builds, commit_status.project) - if current_user && can?(current_user, :manage_builds, commit_status.project)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
= diff.new_path = diff.new_path
- if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
%span.file-mode= "#{diff.a_mode}#{diff.b_mode}" %span.file-mode= "#{diff.a_mode}#{diff.b_mode}"
.diff-content .diff-content.code.js-syntax-highlight
%table %table
- note.truncated_diff_lines.each do |line| - note.truncated_diff_lines.each do |line|
- type = line.type - type = line.type
......
.gitlab-promo .gitlab-promo
= link_to 'Homepage', promo_url = link_to 'Homepage', promo_url
= link_to "Blog", promo_url + '/blog/' = link_to 'Blog', promo_url + '/blog/'
= link_to "@gitlab", "https://twitter.com/gitlab" = link_to '@gitlab', 'https://twitter.com/gitlab'
= link_to "Requests", "http://feedback.gitlab.com/" = link_to 'Requests', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#feature-proposals'
= form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do = form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do
.append-right-10.hidden-xs.hidden-sm .append-right-10.hidden-xs.hidden-sm
= search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input', spellcheck: false } = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by name ...', class: 'form-control issue_search search-text-input', spellcheck: false }
= hidden_field_tag :state, params['state'] = hidden_field_tag :state, params['state']
= hidden_field_tag :scope, params['scope'] = hidden_field_tag :scope, params['scope']
= hidden_field_tag :assignee_id, params['assignee_id'] = hidden_field_tag :assignee_id, params['assignee_id']
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
.file-content.wiki .file-content.wiki
= render_markup(@snippet.file_name, @snippet.data) = render_markup(@snippet.file_name, @snippet.data)
- else - else
.file-content.code = render 'shared/file_highlight', blob: @snippet
= render 'shared/file_highlight', blob: @snippet
- else - else
.file-content.code .file-content.code
.nothing-here-block Empty file .nothing-here-block Empty file
...@@ -4,52 +4,20 @@ class RepositoryImportWorker ...@@ -4,52 +4,20 @@ class RepositoryImportWorker
sidekiq_options queue: :gitlab_shell sidekiq_options queue: :gitlab_shell
def perform(project_id) attr_accessor :project, :current_user
project = Project.find(project_id)
if project.import_url == Project::UNKNOWN_IMPORT_URL def perform(project_id)
# In this case, we only want to import issues, not a repository. @project = Project.find(project_id)
unless project.create_repository @current_user = @project.creator
project.update(import_error: "The repository could not be created.")
project.import_fail
return
end
else
begin
gitlab_shell.import_repository(project.path_with_namespace, project.import_url)
rescue Gitlab::Shell::Error => e
project.update(import_error: e.message)
project.import_fail
return
end
end
data_import_result = result = Projects::ImportService.new(project, current_user).execute
case project.import_type
when 'github'
Gitlab::GithubImport::Importer.new(project).execute
when 'gitlab'
Gitlab::GitlabImport::Importer.new(project).execute
when 'bitbucket'
Gitlab::BitbucketImport::Importer.new(project).execute
when 'google_code'
Gitlab::GoogleCodeImport::Importer.new(project).execute
when 'fogbugz'
Gitlab::FogbugzImport::Importer.new(project).execute
else
true
end
unless data_import_result if result[:status] == :error
project.update(import_error: "The remote issue data could not be imported.") project.update(import_error: result[:message])
project.import_fail project.import_fail
return return
end end
if project.import_type == 'bitbucket'
Gitlab::BitbucketImport::KeyDeleter.new(project).execute
end
project.import_finish project.import_finish
end end
end end
...@@ -176,7 +176,7 @@ Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled']. ...@@ -176,7 +176,7 @@ Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].
Settings.gitlab['twitter_sharing_enabled'] ||= true if Settings.gitlab['twitter_sharing_enabled'].nil? Settings.gitlab['twitter_sharing_enabled'] ||= true if Settings.gitlab['twitter_sharing_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z]*-\d*))+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil?
Settings.gitlab['default_projects_features'] ||= {} Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10 Settings.gitlab['webhook_timeout'] ||= 10
Settings.gitlab['max_attachment_size'] ||= 10 Settings.gitlab['max_attachment_size'] ||= 10
......
## This patch is from rails 4.2-stable. Remove it when 4.2.6 is released
## https://github.com/rails/rails/issues/21108
module ActiveRecord
module ConnectionAdapters
class AbstractMysqlAdapter < AbstractAdapter
# SHOW VARIABLES LIKE 'name'
def show_variable(name)
variables = select_all("select @@#{name} as 'Value'", 'SCHEMA')
variables.first['Value'] unless variables.empty?
rescue ActiveRecord::StatementInvalid
nil
end
# MySQL is too stupid to create a temporary table for use subquery, so we have
# to give it some prompting in the form of a subsubquery. Ugh!
def subquery_for(key, select)
subsubselect = select.clone
subsubselect.projections = [key]
subselect = Arel::SelectManager.new(select.engine)
subselect.project Arel.sql(key.name)
# Materialized subquery by adding distinct
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
subselect.from subsubselect.distinct.as('__active_record_temp')
end
end
end
end
module ActiveRecord
module ConnectionAdapters
class MysqlAdapter < AbstractMysqlAdapter
ADAPTER_NAME = 'MySQL'.freeze
# Get the client encoding for this database
def client_encoding
return @client_encoding if @client_encoding
result = exec_query(
"select @@character_set_client",
'SCHEMA')
@client_encoding = ENCODINGS[result.rows.last.last]
end
end
end
end
...@@ -13,8 +13,8 @@ ability of downloading the files separately. ...@@ -13,8 +13,8 @@ ability of downloading the files separately.
**Note:** **Note:**
The artifacts browser will be available only for new artifacts that are sent The artifacts browser will be available only for new artifacts that are sent
to GitLab using GitLab Runner version 1.0 and up. You will not be available to to GitLab using GitLab Runner version 1.0 and up. It will not be possible to
see the browser for old artifacts already uploaded to GitLab. browse old artifacts already uploaded to GitLab.
## Enabling build artifacts ## Enabling build artifacts
......
...@@ -5,7 +5,7 @@ trackers and external authentication. ...@@ -5,7 +5,7 @@ trackers and external authentication.
See the documentation below for details on how to configure these services. See the documentation below for details on how to configure these services.
- [Jira](jira.md) Integrate with the JIRA issue tracker - [Jira](../project_services/jira.md) Integrate with the JIRA issue tracker
- [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc. - [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
- [LDAP](ldap.md) Set up sign in via LDAP - [LDAP](ldap.md) Set up sign in via LDAP
- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd and Azure - [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd and Azure
......
...@@ -19,7 +19,7 @@ To enable an external issue tracker you must configure the appropriate **Service ...@@ -19,7 +19,7 @@ To enable an external issue tracker you must configure the appropriate **Service
Visit the links below for details: Visit the links below for details:
- [Redmine](../project_services/redmine.md) - [Redmine](../project_services/redmine.md)
- [Jira](jira.md) - [Jira](../project_services/jira.md)
### Service Template ### Service Template
......
# GitLab Jira integration # GitLab JIRA integration
GitLab can be configured to interact with Jira. Configuration happens via This document was moved under [project_services/jira](../project_services/jira.md).
username and password. Connecting to a Jira server via CAS is not possible.
Each project can be configured to connect to a different Jira instance, see the
[configuration](#configuration) section. If you have one Jira instance you can
pre-fill the settings page with a default template. To configure the template
see the [Services Templates][services-templates] document.
Once the project is connected to Jira, you can reference and close the issues
in Jira directly from GitLab.
## Table of Contents
* [Referencing Jira Issues from GitLab](#referencing-jira-issues)
* [Closing Jira Issues from GitLab](#closing-jira-issues)
* [Configuration](#configuration)
### Referencing Jira Issues
When GitLab project has Jira issue tracker configured and enabled, mentioning
Jira issue in GitLab will automatically add a comment in Jira issue with the
link back to GitLab. This means that in comments in merge requests and commits
referencing an issue, eg. `PROJECT-7`, will add a comment in Jira issue in the
format:
```
USER mentioned this issue in LINK_TO_THE_MENTION
```
* `USER` A user that mentioned the issue. This is the link to the user profile in GitLab.
* `LINK_TO_THE_MENTION` Link to the origin of mention with a name of the entity where Jira issue was mentioned.
Can be commit or merge request.
![example of mentioning or closing the Jira issue](img/jira_issue_reference.png)
---
### Closing Jira Issues
Jira issues can be closed directly from GitLab by using trigger words, eg.
`Resolves PROJECT-1`, `Closes PROJECT-1` or `Fixes PROJECT-1`, in commits and
merge requests. When a commit which contains the trigger word in the commit
message is pushed, GitLab will add a comment in the mentioned Jira issue.
For example, for project named `PROJECT` in Jira, we implemented a new feature
and created a merge request in GitLab.
This feature was requested in Jira issue `PROJECT-7`. Merge request in GitLab
contains the improvement and in merge request description we say that this
merge request `Closes PROJECT-7` issue.
Once this merge request is merged, the Jira issue will be automatically closed
with a link to the commit that resolved the issue.
![A Git commit that causes the Jira issue to be closed](img/jira_merge_request_close.png)
---
![The GitLab integration user leaves a comment on Jira](img/jira_service_close_issue.png)
---
## Configuration
### Configuring JIRA
We need to create a user in JIRA which will have access to all projects that
need to integrate with GitLab. Login to your JIRA instance as admin and under
Administration go to User Management and create a new user.
As an example, we'll create a user named `gitlab` and add it to `jira-developers`
group.
**It is important that the user `gitlab` has write-access to projects in JIRA**
### Configuring GitLab
JIRA configuration in GitLab is done via a project's **Services**.
#### GitLab 7.8 and up with JIRA v6.x
See next section.
#### GitLab 7.8 and up
_The currently supported JIRA versions are v6.x and v7.x._
To enable JIRA integration in a project, navigate to the project's
**Settings > Services > JIRA**.
Fill in the required details on the page as described in the table below.
| Field | Description |
| ----- | ----------- |
| `description` | A name for the issue tracker (to differentiate between instances, for instance). |
| `project url` | The URL to the JIRA project which is being linked to this GitLab project. |
| `issues url` | The URL to the JIRA project issues overview for the project that is linked to this GitLab project. |
| `new issue url` | This is the URL to create a new issue in JIRA for the project linked to this GitLab project. |
| `api url` | The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`, i.e. `https://jira.example.com/rest/api/2`. |
| `username` | The username of the user created in [configuring JIRA step](#configuring-jira). |
| `password` |The password of the user created in [configuring JIRA step](#configuring-jira). |
| `Jira issue transition` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). By default, this ID is `2` (in the example image, this is `2` as well) |
After saving the configuration, your GitLab project will be able to interact
with the linked JIRA project.
![Jira service page](img/jira_service_page.png)
---
#### GitLab 6.x-7.7 with JIRA v6.x
_**Note:** GitLab versions 7.8 and up contain various integration improvements.
We strongly recommend upgrading._
In `gitlab.yml` enable the JIRA issue tracker section by
[uncommenting these lines][jira-gitlab-yml]. This will make sure that all
issues within GitLab are pointing to the JIRA issue tracker.
After you set this, you will be able to close issues in JIRA by a commit in
GitLab.
Go to your project's **Settings** page and fill in the project name for the
JIRA project:
![Set the JIRA project name in GitLab to 'NEW'](img/jira_project_name.png)
---
You can also enable the JIRA service that will allow you to interact with JIRA
issues. Go to the **Settings > Services > JIRA** and:
1. Tick the active check box to enable the service
1. Supply the URL to JIRA server, for example http://jira.example.com
1. Supply the username of a user we created under `Configuring JIRA` section,
for example `gitlab`
1. Supply the password of the user
1. Optional: supply the JIRA API version, default is version `2`
1. Optional: supply the JIRA issue transition ID (issue transition to closed).
This is dependent on JIRA settings, default is `2`
1. Hit save
![Jira services page](img/jira_service.png)
[services-templates]: ../project_services/services_templates.md
[jira-gitlab-yml]: https://gitlab.com/subscribers/gitlab-ee/blob/6-8-stable-ee/config/gitlab.yml.example#L111-115
...@@ -6,15 +6,17 @@ To enable Slack integration you must create an Incoming WebHooks integration on ...@@ -6,15 +6,17 @@ To enable Slack integration you must create an Incoming WebHooks integration on
1. [Sign in to Slack](https://slack.com/signin) 1. [Sign in to Slack](https://slack.com/signin)
1. Select **Configure Integrations** from the dropdown next to your team name. 1. Select **Apps & Custom Integrations** from the dropdown next to your team name.
1. Select the **All Services** tab 1. Click the **Configure** link (right-upper corner).
1. Click **Add** next to Incoming Webhooks 1. Select the **Custom integrations** tab.
1. Pick Incoming WebHooks 1. Click the **Incoming WebHooks** row.
1. Choose the channel name you want to send notifications to 1. Click the **Add configuration** button.
1. Choose the channel name you want to send notifications to.
1. Click **Add Incoming WebHooks Integration** 1. Click **Add Incoming WebHooks Integration**
- Optional step; You can change bot's name and avatar by clicking modifying the bot name or avatar under **Integration Settings**. - Optional step; You can change bot's name and avatar by clicking modifying the bot name or avatar under **Integration Settings**.
......
...@@ -88,6 +88,9 @@ GFM will autolink almost any URL you copy and paste into your text. ...@@ -88,6 +88,9 @@ GFM will autolink almost any URL you copy and paste into your text.
## Code and Syntax Highlighting ## Code and Syntax Highlighting
_GitLab uses the [rouge ruby library][rouge] for syntax highlighting. For a
list of supported languages visit the rouge website._
Blocks of code are either fenced by lines with three back-ticks <code>```</code>, or are indented with four spaces. Only the fenced code blocks support syntax highlighting. Blocks of code are either fenced by lines with three back-ticks <code>```</code>, or are indented with four spaces. Only the fenced code blocks support syntax highlighting.
```no-highlight ```no-highlight
...@@ -585,3 +588,5 @@ By including colons in the header row, you can align the text within that column ...@@ -585,3 +588,5 @@ By including colons in the header row, you can align the text within that column
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). - This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
- The [Markdown Syntax Guide](https://daringfireball.net/projects/markdown/syntax) at Daring Fireball is an excellent resource for a detailed explanation of standard markdown. - The [Markdown Syntax Guide](https://daringfireball.net/projects/markdown/syntax) at Daring Fireball is an excellent resource for a detailed explanation of standard markdown.
- [Dillinger.io](http://dillinger.io) is a handy tool for testing standard markdown. - [Dillinger.io](http://dillinger.io) is a handy tool for testing standard markdown.
[rouge]: http://rouge.jneen.net/ "Rouge website"
...@@ -12,6 +12,9 @@ The default is **Charcoal**. ...@@ -12,6 +12,9 @@ The default is **Charcoal**.
## Syntax highlighting theme ## Syntax highlighting theme
_GitLab uses the [rouge ruby library][rouge] for syntax highlighting. For a
list of supported languages visit the rouge website._
Changing this setting allows the user to customize the theme used when viewing Changing this setting allows the user to customize the theme used when viewing
syntax highlighted code on the site. syntax highlighted code on the site.
...@@ -36,3 +39,5 @@ The default is **Your Projects**. ...@@ -36,3 +39,5 @@ The default is **Your Projects**.
It allows user to choose what content he or she want to see on project page. It allows user to choose what content he or she want to see on project page.
The default is **Readme**. The default is **Readme**.
[rouge]: http://rouge.jneen.net/ "Rouge website"
# GitLab JIRA integration
GitLab can be configured to interact with [JIRA Core] either using an
on-premises instance or the SaaS solution that Atlassian offers. Configuration
happens via username and password on a per-project basis. Connecting to a JIRA
server via CAS is not possible.
Each project can be configured to connect to a different JIRA instance or, in
case you have a single JIRA instance, you can pre-fill the JIRA service
settings page in GitLab with a default template. To configure the JIRA template,
see the [Services Templates documentation][services-templates].
Once the GitLab project is connected to JIRA, you can reference and close the
issues in JIRA directly from GitLab's merge requests.
## Configuration
The configuration consists of two parts:
- [JIRA configuration](#configuring-jira)
- [GitLab configuration](#configuring-gitlab)
### Configuring JIRA
First things first, we need to create a user in JIRA which will have access to
all projects that need to integrate with GitLab.
We have split this stage in steps so it is easier to follow.
---
1. Login to your JIRA instance as an administrator and under **Administration**
go to **User Management** to create a new user.
![JIRA user management link](img/jira_user_management_link.png)
---
1. The next step is to create a new user (e.g., `gitlab`) who has write access
to projects in JIRA. Enter the user's name and a _valid_ e-mail address
since JIRA sends a verification e-mail to set-up the password.
_**Note:** JIRA creates the username automatically by using the e-mail
prefix. You can change it later if you want._
![JIRA create new user](img/jira_create_new_user.png)
---
1. Now, let's create a `gitlab-developers` group which will have write access
to projects in JIRA. Go to the **Groups** tab and select **Create group**.
![JIRA create new user](img/jira_create_new_group.png)
---
Give it an optional description and hit **Create group**.
![JIRA create new group](img/jira_create_new_group_name.png)
---
1. Give the newly-created group write access by going to
**Application access > View configuration** and adding the `gitlab-developers`
group to JIRA Core.
![JIRA group access](img/jira_group_access.png)
---
1. Add the `gitlab` user to the `gitlab-developers` group by going to
**Users > GitLab user > Add group** and selecting the `gitlab-developers`
group from the dropdown menu. Notice that the group says _Access_ which is
what we aim for.
![JIRA add user to group](img/jira_add_user_to_group.png)
---
The JIRA configuration is over. Write down the new JIRA username and its
password as they will be needed when configuring GitLab in the next section.
### Configuring GitLab
_**Note:** The currently supported JIRA versions are v6.x and v7.x. and GitLab
7.8 or higher is required._
---
Assuming you [have already configured JIRA](#configuring-jira), now it's time
to configure GitLab.
JIRA configuration in GitLab is done via a project's
[**Services**](../project_services/project_services.md).
To enable JIRA integration in a project, navigate to the project's
**Settings > Services > JIRA**.
Fill in the required details on the page, as described in the table below.
| Setting | Description |
| ------- | ----------- |
| `Description` | A name for the issue tracker (to differentiate between instances, for example). |
| `Project url` | The URL to the JIRA project which is being linked to this GitLab project. It is of the form: `https://<jira_host_url>/issues/?jql=project=<jira_project>`. |
| `Issues url` | The URL to the JIRA project issues overview for the project that is linked to this GitLab project. It is of the form: `https://<jira_host_url>/browse/:id`. Leave `:id` as-is, it gets replaced by GitLab at runtime. |
| `New issue url` | This is the URL to create a new issue in JIRA for the project linked to this GitLab project, and it is of the form: `https://<jira_host_url>/secure/CreateIssue.jspa` |
| `Api url` | The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`. It is of the form: `https://<jira_host_url>/rest/api/2`. |
| `Username` | The username of the user created in [configuring JIRA step](#configuring-jira). |
| `Password` |The password of the user created in [configuring JIRA step](#configuring-jira). |
| `JIRA issue transition` | This setting is very important to set up correctly. It is the ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot](img/jira_issues_workflow.png)). By default, this ID is set to `2` |
After saving the configuration, your GitLab project will be able to interact
with the linked JIRA project.
![JIRA service page](img/jira_service_page.png)
---
## JIRA issues
By now you should have [configured JIRA](#configuring-jira) and enabled the
[JIRA service in GitLab](#configuring-gitlab). If everything is set up correctly
you should be able to reference and close JIRA issues by just mentioning their
ID in GitLab commits and merge requests.
### Referencing JIRA Issues
If you reference a JIRA issue, e.g., `GITLAB-1`, in a commit comment, a link
which points back to JIRA is created.
The same works for comments in merge requests as well.
![JIRA add GitLab commit message](img/jira_add_gitlab_commit_message.png)
---
The mentioning action is two-fold, so a comment with a JIRA issue in GitLab
will automatically add a comment in that particular JIRA issue with the link
back to GitLab.
![JIRA reference commit message](img/jira_reference_commit_message_in_jira_issue.png)
---
The comment on the JIRA issue is of the form:
> USER mentioned this issue in LINK_TO_THE_MENTION
Where:
| Format | Description |
| ------ | ----------- |
| `USER` | A user that mentioned the issue. This is the link to the user profile in GitLab. |
| `LINK_TO_THE_MENTION` | Link to the origin of mention with a name of the entity where JIRA issue was mentioned. Can be commit or merge request. |
### Closing JIRA issues
JIRA issues can be closed directly from GitLab by using trigger words in
commits and merge requests. When a commit which contains the trigger word
followed by the JIRA issue ID in the commit message is pushed, GitLab will
add a comment in the mentioned JIRA issue and immediately close it (provided
the transition ID was set up correctly).
There are currently three trigger words, and you can use either one to achieve
the same goal:
- `Resolves GITLAB-1`
- `Closes GITLAB-1`
- `Fixes GITLAB-1`
where `GITLAB-1` the issue ID of the JIRA project.
### JIRA issue closing example
Let's say for example that we submitted a bug fix and created a merge request
in GitLab. The workflow would be something like this:
1. Create a new branch
1. Fix the bug
1. Commit the changes and push branch to GitLab
1. Open a new merge request and reference the JIRA issue including one of the
trigger words, e.g.: `Fixes GITLAB-1`, in the description
1. Submit the merge request
1. Ask someone to review
1. Merge the merge request
1. The JIRA issue is automatically closed
---
In the following screenshot you can see what the link references to the JIRA
issue look like.
![JIRA - submit a GitLab merge request](img/jira_submit_gitlab_merge_request.png)
---
Once this merge request is merged, the JIRA issue will be automatically closed
with a link to the commit that resolved the issue.
![The GitLab integration user leaves a comment on JIRA](img/jira_issue_closed.png)
---
You can see from the above image that there are four references to GitLab:
- The first is from a comment in a specific commit
- The second is from the JIRA issue reference in the merge request description
- The third is from the actual commit that solved the issue
- And the fourth is from the commit that the merge request created
[services-templates]: ../project_services/services_templates.md "Services templates documentation"
[JIRA Core]: https://www.atlassian.com/software/jira/core "The JIRA Core website"
...@@ -22,7 +22,7 @@ further configuration instructions and details. Contributions are welcome. ...@@ -22,7 +22,7 @@ further configuration instructions and details. Contributions are welcome.
| Gemnasium | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities | | Gemnasium | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities |
| [HipChat](hipchat.md) | Private group chat and IM | | [HipChat](hipchat.md) | Private group chat and IM |
| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway | | [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway |
| JIRA | Jira issue tracker | | [JIRA](jira.md) | JIRA issue tracker |
| JetBrains TeamCity CI | A continuous integration and build server | | JetBrains TeamCity CI | A continuous integration and build server |
| PivotalTracker | Project Management Software (Source Commits Endpoint) | | PivotalTracker | Project Management Software (Source Commits Endpoint) |
| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | | Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop |
......
# Project forking workflow # Project forking workflow
Forking a project to your own namespace is useful if you have no write access to the project you want to contribute Forking a project to your own namespace is useful if you have no write
to. If you do have write access or can request it we recommend working together in the same repository since it is simpler. access to the project you want to contribute to. If you do have write
See our **[GitLab Flow](https://about.gitlab.com/2014/09/29/gitlab-flow/)** article for more information about using access or can request it, we recommend working together in the same
branches to work together. repository since it is simpler. See our [GitLab Flow](gitlab_flow.md)
document more information about using branches to work together.
## Creating a fork ## Creating a fork
In order to create a fork of a project, all you need to do is click on the fork button located on the top right side Forking a project is in most cases a two-step process.
of the screen, close to the project's URL and right next to the stars button.
![Fork button](forking/fork_button.png)
Once you do that you'll be presented with a screen where you can choose the namespace to fork to. Only namespaces 1. Click on the fork button located in the middle of the page or a project's
(groups and your own namespace) where you have write access to, will be shown. Click on the namespace to create your home page right next to the stars button.
fork there.
![Groups view](forking/groups.png) ![Fork button](img/forking_workflow_fork_button.png)
After the forking is done, you can start working on the newly created repository. There you will have full ---
[Owner](../permissions/permissions.md) access, so you can set it up as you please.
1. Once you do that, you'll be presented with a screen where you can choose
the namespace to fork to. Only namespaces (groups and your own
namespace) where you have write access to, will be shown. Click on the
namespace to create your fork there.
![Choose namespace](img/forking_workflow_choose_namespace.png)
---
**Note:**
If the namespace you chose to fork the project to has another project with
the same path name, you will be presented with a warning that the forking
could not be completed. Try to resolve the error and repeat the forking
process.
![Path taken error](img/forking_workflow_path_taken_error.png)
---
After the forking is done, you can start working on the newly created
repository. There, you will have full [Owner](../permissions/permissions.md)
access, so you can set it up as you please.
## Merging upstream ## Merging upstream
Once you are ready to send your code back to the main project, you need to create a merge request. Choose your forked Once you are ready to send your code back to the main project, you need
project's main branch as the source and the original project's main branch as the destination and create the merge request. to create a merge request. Choose your forked project's main branch as
the source and the original project's main branch as the destination and
create the [merge request](merge_requests.md).
![Selecting branches](forking/branch_select.png) ![Selecting branches](forking/branch_select.png)
You can then assign the merge request to someone to have them review your changes. Upon pressing the 'Accept Merge Request' You can then assign the merge request to someone to have them review
button, your changes will be added to the repository and branch you're merging into. your changes. Upon pressing the 'Accept Merge Request' button, your
changes will be added to the repository and branch you're merging into.
![New merge request](forking/merge_request.png) ![New merge request](forking/merge_request.png)
[gitlab flow]: https://about.gitlab.com/2014/09/29/gitlab-flow/ "GitLab Flow blog post"
...@@ -51,3 +51,12 @@ Feature: Project Builds Artifacts ...@@ -51,3 +51,12 @@ Feature: Project Builds Artifacts
And I click artifacts browse button And I click artifacts browse button
And I click a link to file within build artifacts And I click a link to file within build artifacts
Then download of a file extracted from build artifacts should start Then download of a file extracted from build artifacts should start
@javascript
Scenario: I click on a row in an artifacts table
Given recent build has artifacts available
And recent build has artifacts metadata available
When I visit recent build details page
And I click artifacts browse button
And I click a first row within build artifacts table
Then page with a coresponding path is loading
...@@ -73,4 +73,14 @@ class Spinach::Features::ProjectBuildsArtifacts < Spinach::FeatureSteps ...@@ -73,4 +73,14 @@ class Spinach::Features::ProjectBuildsArtifacts < Spinach::FeatureSteps
expect(response_json[:archive]).to end_with('build_artifacts.zip') expect(response_json[:archive]).to end_with('build_artifacts.zip')
expect(response_json[:entry]).to eq Base64.encode64('ci_artifacts.txt') expect(response_json[:entry]).to eq Base64.encode64('ci_artifacts.txt')
end end
step 'I click a first row within build artifacts table' do
row = first('tr[data-link]')
@row_path = row['data-link']
row.click
end
step 'page with a coresponding path is loading' do
expect(current_path).to eq @row_path
end
end end
...@@ -163,7 +163,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps ...@@ -163,7 +163,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end end
step 'I search for Wiki content' do step 'I search for Wiki content' do
fill_in "Search in this project", with: "wiki_content" fill_in "Search", with: "wiki_content"
click_button "Search" click_button "Search"
end end
......
...@@ -13,12 +13,36 @@ module Gitlab ...@@ -13,12 +13,36 @@ module Gitlab
end end
def execute def execute
project_identifier = project.import_source import_issues if has_issues?
return true unless client.project(project_identifier)["has_issues"] true
rescue ActiveRecord::RecordInvalid => e
raise Projects::ImportService::Error.new, e.message
ensure
Gitlab::BitbucketImport::KeyDeleter.new(project).execute
end
#Issues && Comments private
issues = client.issues(project_identifier)
def gl_user_id(project, bitbucket_id)
if bitbucket_id
user = User.joins(:identities).find_by("identities.extern_uid = ? AND identities.provider = 'bitbucket'", bitbucket_id.to_s)
(user && user.id) || project.creator_id
else
project.creator_id
end
end
def identifier
project.import_source
end
def has_issues?
client.project(identifier)["has_issues"]
end
def import_issues
issues = client.issues(identifier)
issues.each do |issue| issues.each do |issue|
body = '' body = ''
...@@ -33,7 +57,7 @@ module Gitlab ...@@ -33,7 +57,7 @@ module Gitlab
body = @formatter.author_line(author) body = @formatter.author_line(author)
body += issue["content"] body += issue["content"]
comments = client.issue_comments(project_identifier, issue["local_id"]) comments = client.issue_comments(identifier, issue["local_id"])
if comments.any? if comments.any?
body += @formatter.comments_header body += @formatter.comments_header
...@@ -56,20 +80,9 @@ module Gitlab ...@@ -56,20 +80,9 @@ module Gitlab
author_id: gl_user_id(project, reporter) author_id: gl_user_id(project, reporter)
) )
end end
rescue ActiveRecord::RecordInvalid => e
true raise Projects::ImportService::Error, e.message
end end
private
def gl_user_id(project, bitbucket_id)
if bitbucket_id
user = User.joins(:identities).find_by("identities.extern_uid = ? AND identities.provider = 'bitbucket'", bitbucket_id.to_s)
(user && user.id) || project.creator_id
else
project.creator_id
end
end
end end
end end
end end
...@@ -35,8 +35,8 @@ module Gitlab ...@@ -35,8 +35,8 @@ module Gitlab
end end
true true
rescue ActiveRecord::RecordInvalid rescue ActiveRecord::RecordInvalid => e
false raise Projects::ImportService::Error, e.message
end end
def import_pull_requests def import_pull_requests
...@@ -53,8 +53,8 @@ module Gitlab ...@@ -53,8 +53,8 @@ module Gitlab
end end
true true
rescue ActiveRecord::RecordInvalid rescue ActiveRecord::RecordInvalid => e
false raise Projects::ImportService::Error, e.message
end end
def import_comments(issue_number, noteable) def import_comments(issue_number, noteable)
...@@ -83,10 +83,13 @@ module Gitlab ...@@ -83,10 +83,13 @@ module Gitlab
true true
rescue Gitlab::Shell::Error => e rescue Gitlab::Shell::Error => e
if e.message =~ /repository not exported/ # GitHub error message when the wiki repo has not been created,
true # this means that repo has wiki enabled, but have no pages. So,
# we can skip the import.
if e.message !~ /repository not exported/
raise Projects::ImportService::Error, e.message
else else
false true
end end
end end
end end
......
...@@ -106,20 +106,36 @@ module Gitlab ...@@ -106,20 +106,36 @@ module Gitlab
if type == :instance if type == :instance
target = mod target = mod
label = "#{mod.name}##{name}" label = "#{mod.name}##{name}"
method = mod.instance_method(name)
else else
target = mod.singleton_class target = mod.singleton_class
label = "#{mod.name}.#{name}" label = "#{mod.name}.#{name}"
method = mod.method(name)
end
# Some code out there (e.g. the "state_machine" Gem) checks the arity of
# a method to make sure it only passes arguments when the method expects
# any. If we were to always overwrite a method to take an `*args`
# signature this would break things. As a result we'll make sure the
# generated method _only_ accepts regular arguments if the underlying
# method also accepts them.
if method.arity == 0
args_signature = '&block'
else
args_signature = '*args, &block'
end end
send_signature = "__send__(#{alias_name.inspect}, #{args_signature})"
target.class_eval <<-EOF, __FILE__, __LINE__ + 1 target.class_eval <<-EOF, __FILE__, __LINE__ + 1
alias_method #{alias_name.inspect}, #{name.inspect} alias_method #{alias_name.inspect}, #{name.inspect}
def #{name}(*args, &block) def #{name}(#{args_signature})
trans = Gitlab::Metrics::Instrumentation.transaction trans = Gitlab::Metrics::Instrumentation.transaction
if trans if trans
start = Time.now start = Time.now
retval = __send__(#{alias_name.inspect}, *args, &block) retval = #{send_signature}
duration = (Time.now - start) * 1000.0 duration = (Time.now - start) * 1000.0
if duration >= Gitlab::Metrics.method_call_threshold if duration >= Gitlab::Metrics.method_call_threshold
...@@ -132,7 +148,7 @@ module Gitlab ...@@ -132,7 +148,7 @@ module Gitlab
retval retval
else else
__send__(#{alias_name.inspect}, *args, &block) #{send_signature}
end end
end end
EOF EOF
......
...@@ -10,7 +10,7 @@ if [ -f /.dockerinit ]; then ...@@ -10,7 +10,7 @@ if [ -f /.dockerinit ]; then
apt-get update -qq apt-get update -qq
apt-get -o dir::cache::archives="/cache/apt" install -y -qq --force-yes \ apt-get -o dir::cache::archives="/cache/apt" install -y -qq --force-yes \
libicu-dev libkrb5-dev cmake nodejs postgresql-client mysql-client libicu-dev libkrb5-dev cmake nodejs postgresql-client mysql-client unzip
cp config/database.yml.mysql config/database.yml cp config/database.yml.mysql config/database.yml
sed -i 's/username:.*/username: root/g' config/database.yml sed -i 's/username:.*/username: root/g' config/database.yml
......
require 'rails_helper'
describe GroupsController do
describe 'GET index' do
context 'as a user' do
it 'redirects to Groups Dashboard' do
sign_in(create(:user))
get :index
expect(response).to redirect_to(dashboard_groups_path)
end
end
context 'as a guest' do
it 'redirects to Explore Groups' do
get :index
expect(response).to redirect_to(explore_groups_path)
end
end
end
end
require 'spec_helper'
describe Projects::ImportsController do
let(:user) { create(:user) }
describe 'GET #show' do
context 'when repository does not exists' do
let(:project) { create(:empty_project) }
before do
sign_in(user)
project.team << [user, :master]
end
it 'renders template' do
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param
expect(response).to render_template :show
end
it 'sets flash.now if params is present' do
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { notice_now: 'Started' }
expect(flash.now[:notice]).to eq 'Started'
end
end
context 'when repository exists' do
let(:project) { create(:project_empty_repo, import_url: 'https://github.com/vim/vim.git') }
before do
sign_in(user)
project.team << [user, :master]
end
context 'when import is in progress' do
before do
project.update_attribute(:import_status, :started)
end
it 'renders template' do
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param
expect(response).to render_template :show
end
it 'sets flash.now if params is present' do
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: { notice_now: 'In progress' }
expect(flash.now[:notice]).to eq 'In progress'
end
end
context 'when import failed' do
before do
project.update_attribute(:import_status, :failed)
end
it 'redirects to new_namespace_project_import_path' do
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param
expect(response).to redirect_to new_namespace_project_import_path(project.namespace, project)
end
end
context 'when import finished' do
before do
project.update_attribute(:import_status, :finished)
end
context 'when project is a fork' do
it 'redirects to namespace_project_path' do
allow_any_instance_of(Project).to receive(:forked?).and_return(true)
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param
expect(flash[:notice]).to eq 'The project was successfully forked.'
expect(response).to redirect_to namespace_project_path(project.namespace, project)
end
end
context 'when project is external' do
it 'redirects to namespace_project_path' do
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param
expect(flash[:notice]).to eq 'The project was successfully imported.'
expect(response).to redirect_to namespace_project_path(project.namespace, project)
end
end
context 'when continue params is present' do
let(:params) do
{
to: namespace_project_path(project.namespace, project),
notice: 'Finished'
}
end
it 'redirects to params[:to]' do
get :show, namespace_id: project.namespace.to_param, project_id: project.to_param, continue: params
expect(flash[:notice]).to eq params[:notice]
expect(response).to redirect_to params[:to]
end
end
end
end
end
end
FactoryGirl.define do FactoryGirl.define do
factory :commit_status, class: CommitStatus do factory :commit_status, class: CommitStatus do
started_at 'Di 29. Okt 09:51:28 CET 2013'
finished_at 'Di 29. Okt 09:53:28 CET 2013'
name 'default' name 'default'
status 'success' status 'success'
description 'commit status' description 'commit status'
commit factory: :ci_commit_with_one_job commit factory: :ci_commit_with_one_job
started_at 'Tue, 26 Jan 2016 08:21:42 +0100'
finished_at 'Tue, 26 Jan 2016 08:23:42 +0100'
after(:build) do |build, evaluator|
build.project = build.commit.project
end
factory :generic_commit_status, class: GenericCommitStatus do factory :generic_commit_status, class: GenericCommitStatus do
name 'generic' name 'generic'
......
...@@ -16,83 +16,104 @@ describe 'Commits' do ...@@ -16,83 +16,104 @@ describe 'Commits' do
FactoryGirl.create :ci_commit, project: project, sha: project.commit.sha FactoryGirl.create :ci_commit, project: project, sha: project.commit.sha
end end
let!(:build) { FactoryGirl.create :ci_build, commit: commit } context 'commit status is Generic Commit Status' do
let!(:status) { FactoryGirl.create :generic_commit_status, commit: commit }
describe 'Project commits' do describe 'Commit builds' do
before do before do
visit namespace_project_commits_path(project.namespace, project, :master) visit ci_status_path(commit)
end end
it 'should show build status' do it { expect(page).to have_content commit.sha[0..7] }
page.within("//li[@id='commit-#{commit.short_sha}']") do
expect(page).to have_css(".ci-status-link") it 'contains generic commit status build' do
page.within('.table-holder') do
expect(page).to have_content "##{status.id}" # build id
expect(page).to have_content 'generic' # build name
end
end end
end end
end end
describe 'Commit builds' do context 'commit status is Ci Build' do
before do let!(:build) { FactoryGirl.create :ci_build, commit: commit }
visit ci_status_path(commit)
end
it { expect(page).to have_content commit.sha[0..7] }
it { expect(page).to have_content commit.git_commit_message }
it { expect(page).to have_content commit.git_author_name }
end
context 'Download artifacts' do describe 'Project commits' do
let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } before do
visit namespace_project_commits_path(project.namespace, project, :master)
end
before do it 'should show build status' do
build.update_attributes(artifacts_file: artifacts_file) page.within("//li[@id='commit-#{commit.short_sha}']") do
expect(page).to have_css(".ci-status-link")
end
end
end end
it do describe 'Commit builds' do
visit ci_status_path(commit) before do
click_on 'Download artifacts' visit ci_status_path(commit)
expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type) end
end
end
describe 'Cancel all builds' do it { expect(page).to have_content commit.sha[0..7] }
it 'cancels commit' do it { expect(page).to have_content commit.git_commit_message }
visit ci_status_path(commit) it { expect(page).to have_content commit.git_author_name }
click_on 'Cancel running'
expect(page).to have_content 'canceled'
end end
end
describe 'Cancel build' do context 'Download artifacts' do
it 'cancels build' do let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
visit ci_status_path(commit)
click_on 'Cancel' before do
expect(page).to have_content 'canceled' build.update_attributes(artifacts_file: artifacts_file)
end end
end
describe '.gitlab-ci.yml not found warning' do it do
context 'ci builds enabled' do
it "does not show warning" do
visit ci_status_path(commit) visit ci_status_path(commit)
expect(page).not_to have_content '.gitlab-ci.yml not found in this commit' click_on 'Download artifacts'
expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type)
end end
end
it 'shows warning' do describe 'Cancel all builds' do
stub_ci_commit_yaml_file(nil) it 'cancels commit' do
visit ci_status_path(commit) visit ci_status_path(commit)
expect(page).to have_content '.gitlab-ci.yml not found in this commit' click_on 'Cancel running'
expect(page).to have_content 'canceled'
end end
end end
context 'ci builds disabled' do describe 'Cancel build' do
before do it 'cancels build' do
stub_ci_builds_disabled
stub_ci_commit_yaml_file(nil)
visit ci_status_path(commit) visit ci_status_path(commit)
click_on 'Cancel'
expect(page).to have_content 'canceled'
end end
end
describe '.gitlab-ci.yml not found warning' do
context 'ci builds enabled' do
it "does not show warning" do
visit ci_status_path(commit)
expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
end
it 'shows warning' do
stub_ci_commit_yaml_file(nil)
visit ci_status_path(commit)
expect(page).to have_content '.gitlab-ci.yml not found in this commit'
end
end
context 'ci builds disabled' do
before do
stub_ci_builds_disabled
stub_ci_commit_yaml_file(nil)
visit ci_status_path(commit)
end
it 'does not show warning' do it 'does not show warning' do
expect(page).not_to have_content '.gitlab-ci.yml not found in this commit' expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
end
end end
end end
end end
......
...@@ -66,5 +66,10 @@ describe LabelsHelper do ...@@ -66,5 +66,10 @@ describe LabelsHelper do
it 'uses dark text on light backgrounds' do it 'uses dark text on light backgrounds' do
expect(text_color_for_bg('#EEEEEE')).to eq('#333333') expect(text_color_for_bg('#EEEEEE')).to eq('#333333')
end end
it 'supports RGB triplets' do
expect(text_color_for_bg('#FFF')).to eq '#333333'
expect(text_color_for_bg('#000')).to eq '#FFFFFF'
end
end end
end end
...@@ -135,6 +135,17 @@ describe Gitlab::ClosingIssueExtractor, lib: true do ...@@ -135,6 +135,17 @@ describe Gitlab::ClosingIssueExtractor, lib: true do
message = "resolve #{reference}" message = "resolve #{reference}"
expect(subject.closed_by_message(message)).to eq([issue]) expect(subject.closed_by_message(message)).to eq([issue])
end end
context 'with an external issue tracker reference' do
it 'extracts the referenced issue' do
jira_project = create(:jira_project, name: 'JIRA_EXT1')
jira_issue = ExternalIssue.new("#{jira_project.name}-1", project: jira_project)
closing_issue_extractor = described_class.new jira_project
message = "Resolve #{jira_issue.to_reference}"
expect(closing_issue_extractor.closed_by_message(message)).to eq([jira_issue])
end
end
end end
context "with a cross-project reference" do context "with a cross-project reference" do
......
...@@ -66,6 +66,16 @@ describe Gitlab::Metrics::Instrumentation do ...@@ -66,6 +66,16 @@ describe Gitlab::Metrics::Instrumentation do
@dummy.foo @dummy.foo
end end
it 'generates a method with the correct arity when using methods without arguments' do
dummy = Class.new do
def self.test; end
end
described_class.instrument_method(dummy, :test)
expect(dummy.method(:test).arity).to eq(0)
end
end end
describe 'with metrics disabled' do describe 'with metrics disabled' do
......
...@@ -10,6 +10,21 @@ describe ExternalIssue, models: true do ...@@ -10,6 +10,21 @@ describe ExternalIssue, models: true do
it { is_expected.to include_module(Referable) } it { is_expected.to include_module(Referable) }
end end
describe '.reference_pattern' do
it 'allows underscores in the project name' do
expect(ExternalIssue.reference_pattern.match('EXT_EXT-1234')[0]).to eq 'EXT_EXT-1234'
end
it 'allows numbers in the project name' do
expect(ExternalIssue.reference_pattern.match('EXT3_EXT-1234')[0]).to eq 'EXT3_EXT-1234'
end
it 'requires the project name to begin with A-Z' do
expect(ExternalIssue.reference_pattern.match('3EXT_EXT-1234')).to eq nil
expect(ExternalIssue.reference_pattern.match('EXT_EXT-1234')[0]).to eq 'EXT_EXT-1234'
end
end
describe '#to_reference' do describe '#to_reference' do
it 'returns a String reference to the object' do it 'returns a String reference to the object' do
expect(issue.to_reference).to eq issue.id expect(issue.to_reference).to eq issue.id
......
...@@ -219,4 +219,24 @@ describe Repository, models: true do ...@@ -219,4 +219,24 @@ describe Repository, models: true do
end end
end end
end end
describe '#has_visible_content?' do
subject { repository.has_visible_content? }
describe 'when there are no branches' do
before do
allow(repository.raw_repository).to receive(:branch_count).and_return(0)
end
it { is_expected.to eq(false) }
end
describe 'when there are branches' do
before do
allow(repository.raw_repository).to receive(:branch_count).and_return(3)
end
it { is_expected.to eq(true) }
end
end
end end
require 'spec_helper'
describe Tree, models: true do
let(:repository) { create(:project).repository }
let(:sha) { repository.root_ref }
subject { described_class.new(repository, '54fcc214') }
describe '#readme' do
class FakeBlob
attr_reader :name
def initialize(name)
@name = name
end
def readme?
name =~ /^readme/i
end
end
it 'returns nil when repository does not contains a README file' do
files = [FakeBlob.new('file'), FakeBlob.new('license'), FakeBlob.new('copying')]
expect(subject).to receive(:blobs).and_return(files)
expect(subject.readme).to eq nil
end
it 'returns nil when repository does not contains a previewable README file' do
files = [FakeBlob.new('file'), FakeBlob.new('README.pages'), FakeBlob.new('README.png')]
expect(subject).to receive(:blobs).and_return(files)
expect(subject.readme).to eq nil
end
it 'returns README when repository contains a previewable README file' do
files = [FakeBlob.new('README.png'), FakeBlob.new('README'), FakeBlob.new('file')]
expect(subject).to receive(:blobs).and_return(files)
expect(subject.readme.name).to eq 'README'
end
it 'returns first previewable README when repository contains more than one' do
files = [FakeBlob.new('file'), FakeBlob.new('README.md'), FakeBlob.new('README.asciidoc')]
expect(subject).to receive(:blobs).and_return(files)
expect(subject.readme.name).to eq 'README.md'
end
it 'returns first plain text README when repository contains more than one' do
files = [FakeBlob.new('file'), FakeBlob.new('README'), FakeBlob.new('README.txt')]
expect(subject).to receive(:blobs).and_return(files)
expect(subject.readme.name).to eq 'README'
end
it 'prioritizes previewable README file over one in plain text' do
files = [FakeBlob.new('file'), FakeBlob.new('README'), FakeBlob.new('README.md')]
expect(subject).to receive(:blobs).and_return(files)
expect(subject.readme.name).to eq 'README.md'
end
end
end
require 'spec_helper'
describe Projects::ImportService, services: true do
let!(:project) { create(:empty_project) }
let(:user) { project.creator }
subject { described_class.new(project, user) }
describe '#execute' do
context 'with unknown url' do
before do
project.import_url = Project::UNKNOWN_IMPORT_URL
end
it 'succeeds if repository is created successfully' do
expect(project).to receive(:create_repository).and_return(true)
result = subject.execute
expect(result[:status]).to eq :success
end
it 'fails if repository creation fails' do
expect(project).to receive(:create_repository).and_return(false)
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq 'The repository could not be created.'
end
end
context 'with known url' do
before do
project.import_url = 'https://github.com/vim/vim.git'
end
it 'succeeds if repository import is successfully' do
expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true)
result = subject.execute
expect(result[:status]).to eq :success
end
it 'fails if repository import fails' do
expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_raise(Gitlab::Shell::Error.new('Failed to import the repository'))
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq 'Failed to import the repository'
end
end
context 'with valid importer' do
before do
stub_github_omniauth_provider
project.import_url = 'https://github.com/vim/vim.git'
project.import_type = 'github'
allow(project).to receive(:import_data).and_return(double.as_null_object)
end
it 'succeeds if importer succeeds' do
expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true)
expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(true)
result = subject.execute
expect(result[:status]).to eq :success
end
it 'fails if importer fails' do
expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true)
expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(false)
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq 'The remote data could not be imported.'
end
it 'fails if importer raise an error' do
expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true)
expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_raise(Projects::ImportService::Error.new('Github: failed to connect API'))
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq 'Github: failed to connect API'
end
end
def stub_github_omniauth_provider
provider = OpenStruct.new(
name: 'github',
app_id: 'asd123',
app_secret: 'asd123'
)
Gitlab.config.omniauth.providers << provider
end
end
end
...@@ -48,4 +48,10 @@ FactoryGirl::SyntaxRunner.class_eval do ...@@ -48,4 +48,10 @@ FactoryGirl::SyntaxRunner.class_eval do
include RSpec::Mocks::ExampleMethods include RSpec::Mocks::ExampleMethods
end end
# Work around a Rails 4.2.5.1 issue
# See https://github.com/rspec/rspec-rails/issues/1532
RSpec::Rails::ViewRendering::EmptyTemplatePathSetDecorator.class_eval do
alias_method :find_all_anywhere, :find_all
end
ActiveRecord::Migration.maintain_test_schema! ActiveRecord::Migration.maintain_test_schema!
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