diff options
author | James Lopez <james@jameslopez.es> | 2016-01-27 15:42:35 +0100 |
---|---|---|
committer | James Lopez <james@jameslopez.es> | 2016-01-27 15:42:35 +0100 |
commit | 683770f35d8ef691d8bcc828aa958b3619081d37 (patch) | |
tree | db61ef12bbbe56a21a51f2eace53d45ad8389dc2 | |
parent | b8ed5789c03961444fc40baca31f870b30a73766 (diff) | |
parent | a93f7099fa2ed98746ebfb5e55322d0afb5068f8 (diff) | |
download | gitlab-ce-683770f35d8ef691d8bcc828aa958b3619081d37.tar.gz |
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into update-ruby-2.2.4
98 files changed, 1134 insertions, 452 deletions
diff --git a/CHANGELOG b/CHANGELOG index b3b4aa380d5..4b283f235a4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,27 @@ v 8.5.0 (unreleased) - Fix diff comments loaded by AJAX to load comment with diff in discussion tab - Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel) - 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 - Allow LDAP users to change their email if it was not set by the LDAP server diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index ee6cdce3c29..b6160487433 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.6.1 +0.6.2 @@ -1,6 +1,6 @@ source "https://rubygems.org" -gem 'rails', '4.2.4' +gem 'rails', '4.2.5.1' gem 'rails-deprecated_sanitizer', '~> 1.0.3' # Responders respond_to and respond_with @@ -103,7 +103,8 @@ gem 'asciidoctor', '~> 1.5.2' gem 'rouge', '~> 1.10.1' # 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 gem 'diffy', '~> 3.0.3' diff --git a/Gemfile.lock b/Gemfile.lock index 5e0718af70f..87895c55886 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,41 +4,41 @@ GEM CFPropertyList (2.3.2) RedCloth (4.2.9) ace-rails-ap (2.0.1) - actionmailer (4.2.4) - actionpack (= 4.2.4) - actionview (= 4.2.4) - activejob (= 4.2.4) + actionmailer (4.2.5.1) + actionpack (= 4.2.5.1) + actionview (= 4.2.5.1) + activejob (= 4.2.5.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.4) - actionview (= 4.2.4) - activesupport (= 4.2.4) + actionpack (4.2.5.1) + actionview (= 4.2.5.1) + activesupport (= 4.2.5.1) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.4) - activesupport (= 4.2.4) + actionview (4.2.5.1) + activesupport (= 4.2.5.1) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.4) - activesupport (= 4.2.4) + activejob (4.2.5.1) + activesupport (= 4.2.5.1) globalid (>= 0.3.0) - activemodel (4.2.4) - activesupport (= 4.2.4) + activemodel (4.2.5.1) + activesupport (= 4.2.5.1) builder (~> 3.1) - activerecord (4.2.4) - activemodel (= 4.2.4) - activesupport (= 4.2.4) + activerecord (4.2.5.1) + activemodel (= 4.2.5.1) + activesupport (= 4.2.5.1) arel (~> 6.0) activerecord-deprecated_finders (1.0.4) activerecord-session_store (0.1.2) actionpack (>= 4.0.0, < 5) activerecord (>= 4.0.0, < 5) railties (>= 4.0.0, < 5) - activesupport (4.2.4) + activesupport (4.2.5.1) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -356,7 +356,7 @@ GEM posix-spawn (~> 0.3) gitlab_emoji (0.2.0) gemojione (~> 2.1) - gitlab_git (7.2.23) + gitlab_git (7.2.24) activesupport (~> 4.0) charlock_holmes (~> 0.7.3) github-linguist (~> 4.7.0) @@ -482,7 +482,7 @@ GEM grape newrelic_rpm newrelic_rpm (3.9.4.245) - nokogiri (1.6.7.1) + nokogiri (1.6.7.2) mini_portile2 (~> 2.0.0.rc2) nprogress-rails (0.1.6.7) oauth (0.4.7) @@ -588,16 +588,16 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.4) - actionmailer (= 4.2.4) - actionpack (= 4.2.4) - actionview (= 4.2.4) - activejob (= 4.2.4) - activemodel (= 4.2.4) - activerecord (= 4.2.4) - activesupport (= 4.2.4) + rails (4.2.5.1) + actionmailer (= 4.2.5.1) + actionpack (= 4.2.5.1) + actionview (= 4.2.5.1) + activejob (= 4.2.5.1) + activemodel (= 4.2.5.1) + activerecord (= 4.2.5.1) + activesupport (= 4.2.5.1) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.4) + railties (= 4.2.5.1) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) @@ -605,11 +605,11 @@ GEM activesupport (>= 4.2.0.beta, < 5.0) nokogiri (~> 1.6.0) rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.2) + rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (4.2.4) - actionpack (= 4.2.4) - activesupport (= 4.2.4) + railties (4.2.5.1) + actionpack (= 4.2.5.1) + activesupport (= 4.2.5.1) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.0.0) @@ -962,7 +962,7 @@ DEPENDENCIES net-ssh (~> 3.0.1) newrelic-grape newrelic_rpm (~> 3.9.4.245) - nokogiri (= 1.6.7.1) + nokogiri (= 1.6.7.2) nprogress-rails (~> 0.1.6.7) oauth2 (~> 1.0.0) octokit (~> 3.7.0) @@ -988,7 +988,7 @@ DEPENDENCIES rack-attack (~> 4.3.1) rack-cors (~> 0.4.0) rack-oauth2 (~> 1.2.1) - rails (= 4.2.4) + rails (= 4.2.5.1) rails-deprecated_sanitizer (~> 1.0.3) raphael-rails (~> 2.1.2) rblineprof diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index eb18d32b25c..48c9890cfb5 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -203,4 +203,13 @@ $ -> form = btn.closest("form") 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() diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee index f6bf836f19f..390e41ed8d4 100644 --- a/app/assets/javascripts/blob/edit_blob.js.coffee +++ b/app/assets/javascripts/blob/edit_blob.js.coffee @@ -32,6 +32,7 @@ class @EditBlob content: editor.getValue() , (response) -> currentPane.empty().append response + currentPane.syntaxHighlight() return else diff --git a/app/assets/javascripts/shortcuts_issuable.coffee b/app/assets/javascripts/shortcuts_issuable.coffee index bb532194682..f717a753cf8 100644 --- a/app/assets/javascripts/shortcuts_issuable.coffee +++ b/app/assets/javascripts/shortcuts_issuable.coffee @@ -5,11 +5,11 @@ class @ShortcutsIssuable extends ShortcutsNavigation constructor: (isMergeRequest) -> super() Mousetrap.bind('a', -> - $('.js-assignee').select2('open') + $('.block.assignee .edit-link').trigger('click') return false ) Mousetrap.bind('m', -> - $('.js-milestone').select2('open') + $('.block.milestone .edit-link').trigger('click') return false ) Mousetrap.bind('r', => diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 9bc814cfd2d..6ea2219073c 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -311,14 +311,6 @@ table { } } -.wiki .highlight, .note-body .highlight { - margin: 12px 0 12px 0; -} - -.wiki .code { - overflow-x: auto; -} - .footer-links { margin-bottom: 20px; a { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index a4791cf6b34..00cb756b376 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -7,6 +7,7 @@ border: 1px solid $border-color; &.readme-holder { + margin-top: 10px; border-bottom: 0; } diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index 4dab806d50e..d097e4d32f7 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -2,11 +2,42 @@ textarea { resize: vertical; } -input[type='search'].search-text-input { - background-image: image-url("icon-search.png"); +input { + border-radius: $border-radius-base; +} + +input[type='search'] { + background-color: white; + padding-left: 10px; +} + +input[type='search'].search-input { background-repeat: no-repeat; 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 { @@ -74,6 +105,7 @@ label { .form-control { @include box-shadow(none); + border-radius: 3px; } .form-control-inline { diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index ba5e72c8c5a..f875b1460e7 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -108,16 +108,10 @@ header { .search-input { width: 220px; - background-image: image-url("icon-search.png"); - background-repeat: no-repeat; - background-position: 195px; - @include input-big; &:focus { @include box-shadow(none); outline: none; - border-color: #DDD; - background-color: #FFF; } } } diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss index 2e13ee842e0..9854df4c45c 100644 --- a/app/assets/stylesheets/framework/highlight.scss +++ b/app/assets/stylesheets/framework/highlight.scss @@ -17,6 +17,7 @@ overflow-y: hidden; white-space: pre; word-wrap: normal; + border-left: 1px solid; code { font-family: $monospace_font; @@ -25,7 +26,7 @@ padding: 0; .line { - display: inline; + display: inline-block; } } } @@ -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; - } -} diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss index c4e9f467ce4..75b770ae5a2 100644 --- a/app/assets/stylesheets/framework/tables.scss +++ b/app/assets/stylesheets/framework/tables.scss @@ -33,12 +33,12 @@ table { background-color: $background-color; font-weight: normal; font-size: 15px; - border-bottom: 1px solid $border-color !important; + border-bottom: 1px solid $border-color; } td { - border-color: $table-border-color !important; - border-bottom: 1px solid; + border-color: $table-border-color; + border-bottom: 1px solid $border-color; } } } diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index 798cd224ad0..33270388e64 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -22,9 +22,9 @@ $brand-info: $gl-info; $brand-warning: $gl-warning; $brand-danger: $gl-danger; -$border-radius-base: 2px !default; -$border-radius-large: 2px !default; -$border-radius-small: 2px !default; +$border-radius-base: 3px !default; +$border-radius-large: 3px !default; +$border-radius-small: 3px !default; //== Scaffolding diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index ab4f71af039..4866a17005d 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -87,8 +87,8 @@ } p { - color:#5c5d5e; - margin:6px 0 0 0; + color: #5c5d5e; + margin: 6px 0 0 0; } table { @@ -102,11 +102,10 @@ } pre { - margin: 12px 0 12px 0 !important; - background-color: #f8fafc; - font-size: 13px !important; - color: #5b6169; - line-height: 1.6em !important; + margin: 12px 0 12px 0; + font-size: 13px; + line-height: 1.6em; + overflow-x: auto; @include border-radius(2px); } @@ -204,11 +203,6 @@ h1, h2, h3, h4, h5, h6 { pre { font-family: $monospace_font; - &.dark { - background: #333; - color: $background-color; - } - &.plain-readme { background: none; border: none; diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index c7f7a5aaf07..41a4579e1bc 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -10,8 +10,8 @@ } // Code itself - pre.code { - border-left: 1px solid #666; + pre.code, .diff-line-num { + border-color: #666; } &, pre.code, .line_holder .line_content { diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index 516d8aef960..22cee1af39f 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -10,8 +10,8 @@ } // Code itself - pre.code { - border-left: 1px solid #555; + pre.code, .diff-line-num { + border-color: #555; } &, pre.code, .line_holder .line_content { diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index b0aaadd0f7f..0e8f30b4b0b 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -10,8 +10,8 @@ } // Code itself - pre.code { - border-left: 1px solid #113b46; + pre.code, .diff-line-num { + border-color: #113b46; } &, pre.code, .line_holder .line_content { @@ -22,11 +22,11 @@ // Diff line .line_holder { .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 { - @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 { diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index 1c138572145..08b6c835907 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -10,8 +10,8 @@ } // Code itself - pre.code { - border-left: 1px solid #c5d0d4; + pre.code, .diff-line-num { + border-color: #c5d0d4; } &, pre.code, .line_holder .line_content { @@ -22,11 +22,11 @@ // Diff line .line_holder { .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 { - @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 { diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index 8a932e6540e..8a091028a6c 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -10,8 +10,8 @@ } // Code itself - pre.code { - border-left: 1px solid $border-color; + pre.code, .diff-line-num { + border-color: $border-color; } &, pre.code, .line_holder .line_content { diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 5215df04a6e..a7925e79549 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -79,10 +79,8 @@ margin: 0px; padding: 0px; border: none; - background: $background-color; - color: rgba(0, 0, 0, 0.3); padding: 0px 5px; - border-right: 1px solid $border-color; + border-right: 1px solid; text-align: right; min-width: 35px; max-width: 50px; @@ -92,7 +90,6 @@ float: left; width: 35px; font-weight: normal; - color: rgba(0, 0, 0, 0.3); &:hover { text-decoration: underline; } diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 263993f59a5..fdd86979a36 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -1,5 +1,15 @@ .member-search-form { float: left; + + input[type='search'] { + width: 225px; + vertical-align: bottom; + + @media (max-width: $screen-xs-max) { + width: 100px; + vertical-align: bottom; + } + } } .milestone-row { diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index ad92cc22815..dd6a251f811 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -49,11 +49,6 @@ .issue-search-form { margin: 0; height: 24px; - - .issue_search { - border: 1px solid #DDD !important; - background-color: #f4f4f4; - } } form.edit-issue { diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index f6343e6bb1e..19ead07c06a 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -154,6 +154,7 @@ ul.notes { text-align: center; padding: 10px 0; background: #FFF; + color: $text-color; } &.notes_line2 { text-align: center; diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 6a6dd7dfc85..c7411617cb3 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -22,8 +22,6 @@ &:hover { td { background: $hover; - border-top: 1px solid #ADF; - border-bottom: 1px solid #ADF; } cursor: pointer; } diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index fb26a4e6fc3..f7c9e619755 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -2,17 +2,18 @@ class GroupsController < Groups::ApplicationController include IssuesAction include MergeRequestsAction - skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests] 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 - 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_create_group!, only: [:new, :create] # 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 layout :determine_layout diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb index 8d8035ef5ff..07f355c35b1 100644 --- a/app/controllers/projects/imports_controller.rb +++ b/app/controllers/projects/imports_controller.rb @@ -1,8 +1,8 @@ class Projects::ImportsController < Projects::ApplicationController # Authorize before_action :authorize_admin_project! - before_action :require_no_repo, except: :show - before_action :redirect_if_progress, except: :show + before_action :require_no_repo, only: [:new, :create] + before_action :redirect_if_progress, only: [:new, :create] def new end @@ -24,11 +24,11 @@ class Projects::ImportsController < Projects::ApplicationController end def show - if @project.repository_exists? || @project.import_finished? + if @project.import_finished? if continue_params redirect_to continue_params[:to], notice: continue_params[:notice] else - redirect_to project_path(@project), notice: "The project was successfully forked." + redirect_to namespace_project_path(@project.namespace, @project), notice: finished_notice end elsif @project.import_failed? redirect_to new_namespace_project_import_path(@project.namespace, @project) @@ -36,6 +36,7 @@ class Projects::ImportsController < Projects::ApplicationController if continue_params && continue_params[:notice_now] flash.now[:notice] = continue_params[:notice_now] end + # Render end end @@ -44,6 +45,7 @@ class Projects::ImportsController < Projects::ApplicationController def continue_params continue_params = params[:continue] + if continue_params continue_params.permit(:to, :notice, :notice_now) else @@ -51,8 +53,16 @@ class Projects::ImportsController < Projects::ApplicationController 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 - if @project.repository_exists? && !@project.import_in_progress? + if @project.repository_exists? redirect_to(namespace_project_path(@project.namespace, @project)) end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f3a2723ee0d..a2458ad3be0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -171,7 +171,7 @@ module ApplicationHelper def search_placeholder if @project && @project.persisted? - 'Search in this project' + 'Search' elsif @snippet || @snippets || @show_snippets 'Search snippets' elsif @group && @group.persisted? diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index a2c3d4d2f32..92eac0560bd 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -83,7 +83,11 @@ module LabelsHelper end 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 '#333333' diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb index 49f6c95e045..2ca79df0a29 100644 --- a/app/models/external_issue.rb +++ b/app/models/external_issue.rb @@ -31,7 +31,7 @@ class ExternalIssue # Pattern used to extract `JIRA-123` issue references from text def self.reference_pattern - %r{(?<issue>([A-Z\-]+-)\d+)} + %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)} end def to_reference(_from_project = nil) diff --git a/app/models/repository.rb b/app/models/repository.rb index 9e8bd91fde9..6c1ee4b29cd 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -57,7 +57,7 @@ class Repository # This method return true if repository contains some content visible in project page. # def has_visible_content? - !raw_repository.branches.empty? + raw_repository.branch_count > 0 end def commit(id = 'HEAD') diff --git a/app/models/tree.rb b/app/models/tree.rb index e0e04d8859f..b28f31cdd6e 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -17,12 +17,20 @@ class Tree def readme return @readme if defined?(@readme) - # Take the first previewable readme, or return nil if none is available or - # we can't preview any of them - readme_tree = blobs.find do |blob| - blob.readme? && (previewable?(blob.name) || plain?(blob.name)) + available_readmes = blobs.select(&:readme?) + + previewable_readmes = available_readmes.select do |blob| + previewable?(blob.name) + end + + plain_readmes = available_readmes.select do |blob| + plain?(blob.name) 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? return @readme = nil end diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb new file mode 100644 index 00000000000..2015897dd19 --- /dev/null +++ b/app/services/projects/import_service.rb @@ -0,0 +1,67 @@ +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 diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index c4020c8273b..baadca09518 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -14,11 +14,11 @@ .form-group.project-visibility-level-holder = f.label :default_project_visibility, class: 'control-label col-sm-2' .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 = f.label :default_snippet_visibility, class: 'control-label col-sm-2' .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 = f.label :restricted_visibility_levels, class: 'control-label col-sm-2' .col-sm-10 @@ -268,4 +268,4 @@ = f.text_field :sentry_dsn, class: 'form-control' .form-actions - = f.submit 'Save', class: 'btn btn-primary' + = f.submit 'Save', class: 'btn btn-save' diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml index fa4e6335c73..e18f7b499dd 100644 --- a/app/views/admin/applications/_form.html.haml +++ b/app/views/admin/applications/_form.html.haml @@ -22,5 +22,5 @@ %code= Doorkeeper.configuration.native_redirect_uri for local tests .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" diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml index 8de2ba74a79..198026a1f75 100644 --- a/app/views/admin/groups/_form.html.haml +++ b/app/views/admin/groups/_form.html.haml @@ -21,6 +21,5 @@ - else .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" - diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml index 4429c395aee..906e5ccb360 100644 --- a/app/views/projects/blob/_text.html.haml +++ b/app/views/projects/blob/_text.html.haml @@ -2,8 +2,8 @@ .file-content.wiki = render_markup(blob.name, blob.data) - else - .file-content.code - - unless blob.empty? - = render 'shared/file_highlight', blob: blob - - else + - unless blob.empty? + = render 'shared/file_highlight', blob: blob + - else + .file-content.code .nothing-here-block Empty file diff --git a/app/views/projects/blob/preview.html.haml b/app/views/projects/blob/preview.html.haml index c5a269f334c..541dc96c45f 100644 --- a/app/views/projects/blob/preview.html.haml +++ b/app/views/projects/blob/preview.html.haml @@ -8,7 +8,7 @@ .file-content.wiki = raw render_markup(@blob.name, @content) - else - .file-content.code + .file-content.code.js-syntax-highlight - unless @diff_lines.empty? %table.text-file - @diff_lines.each do |line| diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml index 1736dccaf3c..2e3c956ddc4 100644 --- a/app/views/projects/commit_statuses/_commit_status.html.haml +++ b/app/views/projects/commit_statuses/_commit_status.html.haml @@ -66,7 +66,7 @@ %td .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 %i.fa.fa-download - if current_user && can?(current_user, :manage_builds, commit_status.project) diff --git a/app/views/projects/notes/discussions/_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml index 92bbaf0961a..820e31ccd61 100644 --- a/app/views/projects/notes/discussions/_diff.html.haml +++ b/app/views/projects/notes/discussions/_diff.html.haml @@ -9,7 +9,7 @@ = diff.new_path - if diff.a_mode && diff.b_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 - note.truncated_diff_lines.each do |line| - type = line.type diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml index 3596aabe309..09edf4000d5 100644 --- a/app/views/shared/_promo.html.haml +++ b/app/views/shared/_promo.html.haml @@ -1,5 +1,5 @@ .gitlab-promo = link_to 'Homepage', promo_url - = link_to "Blog", promo_url + '/blog/' - = link_to "@gitlab", "https://twitter.com/gitlab" - = link_to "Requests", "http://feedback.gitlab.com/" + = link_to 'Blog', promo_url + '/blog/' + = link_to '@gitlab', 'https://twitter.com/gitlab' + = link_to 'Requests', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#feature-proposals' diff --git a/app/views/shared/issuable/_search_form.html.haml b/app/views/shared/issuable/_search_form.html.haml index 3a5ad00aa91..6672ea79629 100644 --- a/app/views/shared/issuable/_search_form.html.haml +++ b/app/views/shared/issuable/_search_form.html.haml @@ -1,6 +1,6 @@ = form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do .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 :scope, params['scope'] = hidden_field_tag :assignee_id, params['assignee_id'] diff --git a/app/views/shared/snippets/_blob.html.haml b/app/views/shared/snippets/_blob.html.haml index d26a99bb14c..e0e41fc4bea 100644 --- a/app/views/shared/snippets/_blob.html.haml +++ b/app/views/shared/snippets/_blob.html.haml @@ -3,8 +3,7 @@ .file-content.wiki = render_markup(@snippet.file_name, @snippet.data) - else - .file-content.code - = render 'shared/file_highlight', blob: @snippet + = render 'shared/file_highlight', blob: @snippet - else .file-content.code .nothing-here-block Empty file diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index d18c0706b30..e295a9ddd14 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -4,52 +4,20 @@ class RepositoryImportWorker sidekiq_options queue: :gitlab_shell - def perform(project_id) - project = Project.find(project_id) + attr_accessor :project, :current_user - if project.import_url == Project::UNKNOWN_IMPORT_URL - # In this case, we only want to import issues, not a repository. - unless project.create_repository - 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 + def perform(project_id) + @project = Project.find(project_id) + @current_user = @project.creator - data_import_result = - 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 + result = Projects::ImportService.new(project, current_user).execute - unless data_import_result - project.update(import_error: "The remote issue data could not be imported.") + if result[:status] == :error + project.update(import_error: result[:message]) project.import_fail return end - if project.import_type == 'bitbucket' - Gitlab::BitbucketImport::KeyDeleter.new(project).execute - end - project.import_finish end end diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 04a7c16ebde..d8170557f7e 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -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['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['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['webhook_timeout'] ||= 10 Settings.gitlab['max_attachment_size'] ||= 10 diff --git a/config/initializers/monkey_patch.rb b/config/initializers/monkey_patch.rb new file mode 100644 index 00000000000..62b05a55285 --- /dev/null +++ b/config/initializers/monkey_patch.rb @@ -0,0 +1,48 @@ +## 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 diff --git a/doc/ci/build_artifacts/README.md b/doc/ci/build_artifacts/README.md index 58cbe653c34..71db5aa5dc8 100644 --- a/doc/ci/build_artifacts/README.md +++ b/doc/ci/build_artifacts/README.md @@ -13,8 +13,8 @@ ability of downloading the files separately. **Note:** 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 -see the browser for old artifacts already uploaded to GitLab. +to GitLab using GitLab Runner version 1.0 and up. It will not be possible to +browse old artifacts already uploaded to GitLab. ## Enabling build artifacts diff --git a/doc/integration/README.md b/doc/integration/README.md index 846526f4e80..83116bc8370 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -5,7 +5,7 @@ trackers and external authentication. 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. - [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 diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index 3543a67dd49..a2d7e922aad 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -19,7 +19,7 @@ To enable an external issue tracker you must configure the appropriate **Service Visit the links below for details: - [Redmine](../project_services/redmine.md) -- [Jira](jira.md) +- [Jira](../project_services/jira.md) ### Service Template diff --git a/doc/integration/jira.md b/doc/integration/jira.md index de574d53410..78aa6634116 100644 --- a/doc/integration/jira.md +++ b/doc/integration/jira.md @@ -1,149 +1,3 @@ -# GitLab Jira integration +# GitLab JIRA integration -GitLab can be configured to interact with Jira. Configuration happens via -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 +This document was moved under [project_services/jira](../project_services/jira.md). diff --git a/doc/integration/slack.md b/doc/integration/slack.md index 84f1d74c058..ecbe0d3e887 100644 --- a/doc/integration/slack.md +++ b/doc/integration/slack.md @@ -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. 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** - Optional step; You can change bot's name and avatar by clicking modifying the bot name or avatar under **Integration Settings**. diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md index bc8e7d155e7..83c77742b19 100644 --- a/doc/markdown/markdown.md +++ b/doc/markdown/markdown.md @@ -88,6 +88,9 @@ GFM will autolink almost any URL you copy and paste into your text. ## 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. ```no-highlight @@ -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). - 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. + +[rouge]: http://rouge.jneen.net/ "Rouge website" diff --git a/doc/profile/preferences.md b/doc/profile/preferences.md index f17bbe8f2aa..073b8797508 100644 --- a/doc/profile/preferences.md +++ b/doc/profile/preferences.md @@ -12,6 +12,9 @@ The default is **Charcoal**. ## 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 syntax highlighted code on the site. @@ -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. The default is **Readme**. + +[rouge]: http://rouge.jneen.net/ "Rouge website" diff --git a/doc/project_services/img/jira_add_gitlab_commit_message.png b/doc/project_services/img/jira_add_gitlab_commit_message.png Binary files differnew file mode 100644 index 00000000000..85e54861b3e --- /dev/null +++ b/doc/project_services/img/jira_add_gitlab_commit_message.png diff --git a/doc/project_services/img/jira_add_user_to_group.png b/doc/project_services/img/jira_add_user_to_group.png Binary files differnew file mode 100644 index 00000000000..e4576433889 --- /dev/null +++ b/doc/project_services/img/jira_add_user_to_group.png diff --git a/doc/project_services/img/jira_create_new_group.png b/doc/project_services/img/jira_create_new_group.png Binary files differnew file mode 100644 index 00000000000..edaa1326058 --- /dev/null +++ b/doc/project_services/img/jira_create_new_group.png diff --git a/doc/project_services/img/jira_create_new_group_name.png b/doc/project_services/img/jira_create_new_group_name.png Binary files differnew file mode 100644 index 00000000000..9e518ad7843 --- /dev/null +++ b/doc/project_services/img/jira_create_new_group_name.png diff --git a/doc/project_services/img/jira_create_new_user.png b/doc/project_services/img/jira_create_new_user.png Binary files differnew file mode 100644 index 00000000000..57e433dd818 --- /dev/null +++ b/doc/project_services/img/jira_create_new_user.png diff --git a/doc/project_services/img/jira_group_access.png b/doc/project_services/img/jira_group_access.png Binary files differnew file mode 100644 index 00000000000..47716ca6d0e --- /dev/null +++ b/doc/project_services/img/jira_group_access.png diff --git a/doc/project_services/img/jira_issue_closed.png b/doc/project_services/img/jira_issue_closed.png Binary files differnew file mode 100644 index 00000000000..cabec1ae137 --- /dev/null +++ b/doc/project_services/img/jira_issue_closed.png diff --git a/doc/integration/img/jira_issue_reference.png b/doc/project_services/img/jira_issue_reference.png Binary files differindex 15739a22dc7..15739a22dc7 100644 --- a/doc/integration/img/jira_issue_reference.png +++ b/doc/project_services/img/jira_issue_reference.png diff --git a/doc/project_services/img/jira_issues_workflow.png b/doc/project_services/img/jira_issues_workflow.png Binary files differnew file mode 100644 index 00000000000..28e17be3a84 --- /dev/null +++ b/doc/project_services/img/jira_issues_workflow.png diff --git a/doc/integration/img/jira_merge_request_close.png b/doc/project_services/img/jira_merge_request_close.png Binary files differindex 1e78daf105f..1e78daf105f 100644 --- a/doc/integration/img/jira_merge_request_close.png +++ b/doc/project_services/img/jira_merge_request_close.png diff --git a/doc/integration/img/jira_project_name.png b/doc/project_services/img/jira_project_name.png Binary files differindex 5986fdb63fb..5986fdb63fb 100644 --- a/doc/integration/img/jira_project_name.png +++ b/doc/project_services/img/jira_project_name.png diff --git a/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png b/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png Binary files differnew file mode 100644 index 00000000000..0149181dc86 --- /dev/null +++ b/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png diff --git a/doc/integration/img/jira_service.png b/doc/project_services/img/jira_service.png Binary files differindex 1f6628c4371..1f6628c4371 100644 --- a/doc/integration/img/jira_service.png +++ b/doc/project_services/img/jira_service.png diff --git a/doc/integration/img/jira_service_close_issue.png b/doc/project_services/img/jira_service_close_issue.png Binary files differindex 67dfc6144c4..67dfc6144c4 100644 --- a/doc/integration/img/jira_service_close_issue.png +++ b/doc/project_services/img/jira_service_close_issue.png diff --git a/doc/integration/img/jira_service_page.png b/doc/project_services/img/jira_service_page.png Binary files differindex 2b37eda3520..2b37eda3520 100644 --- a/doc/integration/img/jira_service_page.png +++ b/doc/project_services/img/jira_service_page.png diff --git a/doc/project_services/img/jira_submit_gitlab_merge_request.png b/doc/project_services/img/jira_submit_gitlab_merge_request.png Binary files differnew file mode 100644 index 00000000000..e935d9362aa --- /dev/null +++ b/doc/project_services/img/jira_submit_gitlab_merge_request.png diff --git a/doc/project_services/img/jira_user_management_link.png b/doc/project_services/img/jira_user_management_link.png Binary files differnew file mode 100644 index 00000000000..2745916972c --- /dev/null +++ b/doc/project_services/img/jira_user_management_link.png diff --git a/doc/integration/img/jira_workflow_screenshot.png b/doc/project_services/img/jira_workflow_screenshot.png Binary files differindex 8635a32eb68..8635a32eb68 100644 --- a/doc/integration/img/jira_workflow_screenshot.png +++ b/doc/project_services/img/jira_workflow_screenshot.png diff --git a/doc/project_services/jira.md b/doc/project_services/jira.md new file mode 100644 index 00000000000..d6b2e7f521b --- /dev/null +++ b/doc/project_services/jira.md @@ -0,0 +1,212 @@ +# 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" diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md index e3403127723..55db3e4f2f3 100644 --- a/doc/project_services/project_services.md +++ b/doc/project_services/project_services.md @@ -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 | | [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 | -| JIRA | Jira issue tracker | +| [JIRA](jira.md) | JIRA issue tracker | | JetBrains TeamCity CI | A continuous integration and build server | | 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 | diff --git a/doc/workflow/forking/fork_button.png b/doc/workflow/forking/fork_button.png Binary files differdeleted file mode 100644 index def4266476a..00000000000 --- a/doc/workflow/forking/fork_button.png +++ /dev/null diff --git a/doc/workflow/forking/groups.png b/doc/workflow/forking/groups.png Binary files differdeleted file mode 100644 index 3ac64b3c8e7..00000000000 --- a/doc/workflow/forking/groups.png +++ /dev/null diff --git a/doc/workflow/forking_workflow.md b/doc/workflow/forking_workflow.md index 8edf7c6ab3d..217a4a4012f 100644 --- a/doc/workflow/forking_workflow.md +++ b/doc/workflow/forking_workflow.md @@ -1,36 +1,59 @@ # 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 -to. If you do have write access or can request it we recommend working together in the same repository since it is simpler. -See our **[GitLab Flow](https://about.gitlab.com/2014/09/29/gitlab-flow/)** article for more information about using -branches to work together. +Forking a project to your own namespace is useful if you have no write +access to the project you want to contribute to. If you do have write +access or can request it, we recommend working together in the same +repository since it is simpler. See our [GitLab Flow](gitlab_flow.md) +document more information about using branches to work together. ## 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 -of the screen, close to the project's URL and right next to the stars button. +Forking a project is in most cases a two-step process. -![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 -(groups and your own namespace) where you have write access to, will be shown. Click on the namespace to create your -fork there. +1. Click on the fork button located in the middle of the page or a project's + home page right next to the stars button. -![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 -Once you are ready to send your code back to the main project, you need 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. +Once you are ready to send your code back to the main project, you need +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) -You can then assign the merge request to someone to have them review your changes. Upon pressing the 'Accept Merge Request' -button, your changes will be added to the repository and branch you're merging into. +You can then assign the merge request to someone to have them review +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) - +[gitlab flow]: https://about.gitlab.com/2014/09/29/gitlab-flow/ "GitLab Flow blog post" diff --git a/doc/workflow/img/forking_workflow_choose_namespace.png b/doc/workflow/img/forking_workflow_choose_namespace.png Binary files differnew file mode 100644 index 00000000000..eefe5769554 --- /dev/null +++ b/doc/workflow/img/forking_workflow_choose_namespace.png diff --git a/doc/workflow/img/forking_workflow_fork_button.png b/doc/workflow/img/forking_workflow_fork_button.png Binary files differnew file mode 100644 index 00000000000..49e68d33e89 --- /dev/null +++ b/doc/workflow/img/forking_workflow_fork_button.png diff --git a/doc/workflow/img/forking_workflow_path_taken_error.png b/doc/workflow/img/forking_workflow_path_taken_error.png Binary files differnew file mode 100644 index 00000000000..7a3139506fe --- /dev/null +++ b/doc/workflow/img/forking_workflow_path_taken_error.png diff --git a/features/project/builds/artifacts.feature b/features/project/builds/artifacts.feature index 1185854453a..52dc15f2eb6 100644 --- a/features/project/builds/artifacts.feature +++ b/features/project/builds/artifacts.feature @@ -51,3 +51,12 @@ Feature: Project Builds Artifacts And I click artifacts browse button And I click a link to file within build artifacts 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 diff --git a/features/steps/project/builds/artifacts.rb b/features/steps/project/builds/artifacts.rb index 25f2f4e837c..1bdb57af9d1 100644 --- a/features/steps/project/builds/artifacts.rb +++ b/features/steps/project/builds/artifacts.rb @@ -73,4 +73,14 @@ class Spinach::Features::ProjectBuildsArtifacts < Spinach::FeatureSteps expect(response_json[:archive]).to end_with('build_artifacts.zip') expect(response_json[:entry]).to eq Base64.encode64('ci_artifacts.txt') 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 diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb index d753ae14590..2a735afbe7b 100644 --- a/features/steps/project/wiki.rb +++ b/features/steps/project/wiki.rb @@ -163,7 +163,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps end 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" end diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb index 2355b3c6ddc..3f483847efa 100644 --- a/lib/gitlab/bitbucket_import/importer.rb +++ b/lib/gitlab/bitbucket_import/importer.rb @@ -13,12 +13,36 @@ module Gitlab end 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 - issues = client.issues(project_identifier) + 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 + + 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| body = '' @@ -33,7 +57,7 @@ module Gitlab body = @formatter.author_line(author) body += issue["content"] - comments = client.issue_comments(project_identifier, issue["local_id"]) + comments = client.issue_comments(identifier, issue["local_id"]) if comments.any? body += @formatter.comments_header @@ -56,20 +80,9 @@ module Gitlab author_id: gl_user_id(project, reporter) ) end - - true + rescue ActiveRecord::RecordInvalid => e + raise Projects::ImportService::Error, e.message 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 diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 663402e8197..e2a85f29825 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -35,8 +35,8 @@ module Gitlab end true - rescue ActiveRecord::RecordInvalid - false + rescue ActiveRecord::RecordInvalid => e + raise Projects::ImportService::Error, e.message end def import_pull_requests @@ -53,8 +53,8 @@ module Gitlab end true - rescue ActiveRecord::RecordInvalid - false + rescue ActiveRecord::RecordInvalid => e + raise Projects::ImportService::Error, e.message end def import_comments(issue_number, noteable) @@ -83,10 +83,13 @@ module Gitlab true rescue Gitlab::Shell::Error => e - if e.message =~ /repository not exported/ - true + # GitHub error message when the wiki repo has not been created, + # 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 - false + true end end end diff --git a/lib/gitlab/metrics/instrumentation.rb b/lib/gitlab/metrics/instrumentation.rb index d9fce2e6758..face1921d2e 100644 --- a/lib/gitlab/metrics/instrumentation.rb +++ b/lib/gitlab/metrics/instrumentation.rb @@ -106,20 +106,36 @@ module Gitlab if type == :instance target = mod label = "#{mod.name}##{name}" + method = mod.instance_method(name) else target = mod.singleton_class 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 + send_signature = "__send__(#{alias_name.inspect}, #{args_signature})" + target.class_eval <<-EOF, __FILE__, __LINE__ + 1 alias_method #{alias_name.inspect}, #{name.inspect} - def #{name}(*args, &block) + def #{name}(#{args_signature}) trans = Gitlab::Metrics::Instrumentation.transaction if trans start = Time.now - retval = __send__(#{alias_name.inspect}, *args, &block) + retval = #{send_signature} duration = (Time.now - start) * 1000.0 if duration >= Gitlab::Metrics.method_call_threshold @@ -132,7 +148,7 @@ module Gitlab retval else - __send__(#{alias_name.inspect}, *args, &block) + #{send_signature} end end EOF diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh index b5d15847bca..5987988dc8e 100755 --- a/scripts/prepare_build.sh +++ b/scripts/prepare_build.sh @@ -10,7 +10,7 @@ if [ -f /.dockerinit ]; then apt-get update -qq 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 sed -i 's/username:.*/username: root/g' config/database.yml diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb new file mode 100644 index 00000000000..938e97298b6 --- /dev/null +++ b/spec/controllers/groups_controller_spec.rb @@ -0,0 +1,23 @@ +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 diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb new file mode 100644 index 00000000000..85d1d1e0524 --- /dev/null +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -0,0 +1,109 @@ +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 diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb index 8898b71e2a3..b7c2b32cb13 100644 --- a/spec/factories/commit_statuses.rb +++ b/spec/factories/commit_statuses.rb @@ -1,11 +1,15 @@ FactoryGirl.define 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' status 'success' description 'commit status' 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 name 'generic' diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index fe7f07f5b75..5a62da10619 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -16,83 +16,104 @@ describe 'Commits' do FactoryGirl.create :ci_commit, project: project, sha: project.commit.sha 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 - before do - visit namespace_project_commits_path(project.namespace, project, :master) - end + describe 'Commit builds' do + before do + visit ci_status_path(commit) + end - it 'should show build status' do - page.within("//li[@id='commit-#{commit.short_sha}']") do - expect(page).to have_css(".ci-status-link") + it { expect(page).to have_content commit.sha[0..7] } + + 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 - describe 'Commit builds' do - before do - 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 'commit status is Ci Build' do + let!(:build) { FactoryGirl.create :ci_build, commit: commit } - context 'Download artifacts' do - let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + describe 'Project commits' do + before do + visit namespace_project_commits_path(project.namespace, project, :master) + end - before do - build.update_attributes(artifacts_file: artifacts_file) + it 'should show build status' do + page.within("//li[@id='commit-#{commit.short_sha}']") do + expect(page).to have_css(".ci-status-link") + end + end end - it do - visit ci_status_path(commit) - click_on 'Download artifacts' - expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type) - end - end + describe 'Commit builds' do + before do + visit ci_status_path(commit) + end - describe 'Cancel all builds' do - it 'cancels commit' do - visit ci_status_path(commit) - click_on 'Cancel running' - expect(page).to have_content 'canceled' + 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 - end - describe 'Cancel build' do - it 'cancels build' do - visit ci_status_path(commit) - click_on 'Cancel' - expect(page).to have_content 'canceled' - end - end + context 'Download artifacts' do + let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + + before do + build.update_attributes(artifacts_file: artifacts_file) + end - describe '.gitlab-ci.yml not found warning' do - context 'ci builds enabled' do - it "does not show warning" do + it do 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 - it 'shows warning' do - stub_ci_commit_yaml_file(nil) + describe 'Cancel all builds' do + it 'cancels commit' do 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 - context 'ci builds disabled' do - before do - stub_ci_builds_disabled - stub_ci_commit_yaml_file(nil) + describe 'Cancel build' do + it 'cancels build' do visit ci_status_path(commit) + click_on 'Cancel' + expect(page).to have_content 'canceled' 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 - expect(page).not_to have_content '.gitlab-ci.yml not found in this commit' + it 'does not show warning' do + expect(page).not_to have_content '.gitlab-ci.yml not found in this commit' + end end end end diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index 0c8d06b7059..0b9176357bc 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -66,5 +66,10 @@ describe LabelsHelper do it 'uses dark text on light backgrounds' do expect(text_color_for_bg('#EEEEEE')).to eq('#333333') 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 diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index 99288da1e43..04cf11fc6f1 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -135,6 +135,17 @@ describe Gitlab::ClosingIssueExtractor, lib: true do message = "resolve #{reference}" expect(subject.closed_by_message(message)).to eq([issue]) 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 context "with a cross-project reference" do diff --git a/spec/lib/gitlab/metrics/instrumentation_spec.rb b/spec/lib/gitlab/metrics/instrumentation_spec.rb index 2a37cd40dde..ad4290c43bb 100644 --- a/spec/lib/gitlab/metrics/instrumentation_spec.rb +++ b/spec/lib/gitlab/metrics/instrumentation_spec.rb @@ -66,6 +66,16 @@ describe Gitlab::Metrics::Instrumentation do @dummy.foo 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 describe 'with metrics disabled' do diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb index 6ec6b9037a4..9b144dd1ecc 100644 --- a/spec/models/external_issue_spec.rb +++ b/spec/models/external_issue_spec.rb @@ -10,6 +10,21 @@ describe ExternalIssue, models: true do it { is_expected.to include_module(Referable) } 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 it 'returns a String reference to the object' do expect(issue.to_reference).to eq issue.id diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index afbf62035ac..c484ae8fc8c 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -219,4 +219,24 @@ describe Repository, models: true do 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 diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb new file mode 100644 index 00000000000..0737999e125 --- /dev/null +++ b/spec/models/tree_spec.rb @@ -0,0 +1,64 @@ +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 diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb new file mode 100644 index 00000000000..04f474c736c --- /dev/null +++ b/spec/services/projects/import_service_spec.rb @@ -0,0 +1,106 @@ +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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0225a0ee53f..8f381f46e57 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -48,4 +48,10 @@ FactoryGirl::SyntaxRunner.class_eval do include RSpec::Mocks::ExampleMethods 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! |