summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Lopez <james@jameslopez.es>2016-01-27 15:42:35 +0100
committerJames Lopez <james@jameslopez.es>2016-01-27 15:42:35 +0100
commit683770f35d8ef691d8bcc828aa958b3619081d37 (patch)
treedb61ef12bbbe56a21a51f2eace53d45ad8389dc2
parentb8ed5789c03961444fc40baca31f870b30a73766 (diff)
parenta93f7099fa2ed98746ebfb5e55322d0afb5068f8 (diff)
downloadgitlab-ce-683770f35d8ef691d8bcc828aa958b3619081d37.tar.gz
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into update-ruby-2.2.4
-rw-r--r--CHANGELOG21
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock68
-rw-r--r--app/assets/javascripts/application.js.coffee9
-rw-r--r--app/assets/javascripts/blob/edit_blob.js.coffee1
-rw-r--r--app/assets/javascripts/shortcuts_issuable.coffee4
-rw-r--r--app/assets/stylesheets/framework/common.scss8
-rw-r--r--app/assets/stylesheets/framework/files.scss1
-rw-r--r--app/assets/stylesheets/framework/forms.scss38
-rw-r--r--app/assets/stylesheets/framework/header.scss6
-rw-r--r--app/assets/stylesheets/framework/highlight.scss18
-rw-r--r--app/assets/stylesheets/framework/tables.scss6
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap_variables.scss6
-rw-r--r--app/assets/stylesheets/framework/typography.scss18
-rw-r--r--app/assets/stylesheets/highlight/dark.scss4
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss4
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss8
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss8
-rw-r--r--app/assets/stylesheets/highlight/white.scss4
-rw-r--r--app/assets/stylesheets/pages/diff.scss5
-rw-r--r--app/assets/stylesheets/pages/groups.scss10
-rw-r--r--app/assets/stylesheets/pages/issues.scss5
-rw-r--r--app/assets/stylesheets/pages/notes.scss1
-rw-r--r--app/assets/stylesheets/pages/tree.scss2
-rw-r--r--app/controllers/groups_controller.rb9
-rw-r--r--app/controllers/projects/imports_controller.rb20
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/labels_helper.rb6
-rw-r--r--app/models/external_issue.rb2
-rw-r--r--app/models/repository.rb2
-rw-r--r--app/models/tree.rb16
-rw-r--r--app/services/projects/import_service.rb67
-rw-r--r--app/views/admin/application_settings/_form.html.haml6
-rw-r--r--app/views/admin/applications/_form.html.haml2
-rw-r--r--app/views/admin/groups/_form.html.haml3
-rw-r--r--app/views/projects/blob/_text.html.haml8
-rw-r--r--app/views/projects/blob/preview.html.haml2
-rw-r--r--app/views/projects/commit_statuses/_commit_status.html.haml2
-rw-r--r--app/views/projects/notes/discussions/_diff.html.haml2
-rw-r--r--app/views/shared/_promo.html.haml6
-rw-r--r--app/views/shared/issuable/_search_form.html.haml2
-rw-r--r--app/views/shared/snippets/_blob.html.haml3
-rw-r--r--app/workers/repository_import_worker.rb46
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/monkey_patch.rb48
-rw-r--r--doc/ci/build_artifacts/README.md4
-rw-r--r--doc/integration/README.md2
-rw-r--r--doc/integration/external-issue-tracker.md2
-rw-r--r--doc/integration/jira.md150
-rw-r--r--doc/integration/slack.md12
-rw-r--r--doc/markdown/markdown.md5
-rw-r--r--doc/profile/preferences.md5
-rw-r--r--doc/project_services/img/jira_add_gitlab_commit_message.pngbin0 -> 57136 bytes
-rw-r--r--doc/project_services/img/jira_add_user_to_group.pngbin0 -> 59251 bytes
-rw-r--r--doc/project_services/img/jira_create_new_group.pngbin0 -> 41294 bytes
-rw-r--r--doc/project_services/img/jira_create_new_group_name.pngbin0 -> 12535 bytes
-rw-r--r--doc/project_services/img/jira_create_new_user.pngbin0 -> 26532 bytes
-rw-r--r--doc/project_services/img/jira_group_access.pngbin0 -> 46028 bytes
-rw-r--r--doc/project_services/img/jira_issue_closed.pngbin0 -> 92601 bytes
-rw-r--r--doc/project_services/img/jira_issue_reference.png (renamed from doc/integration/img/jira_issue_reference.png)bin39942 -> 39942 bytes
-rw-r--r--doc/project_services/img/jira_issues_workflow.pngbin0 -> 105237 bytes
-rw-r--r--doc/project_services/img/jira_merge_request_close.png (renamed from doc/integration/img/jira_merge_request_close.png)bin111150 -> 111150 bytes
-rw-r--r--doc/project_services/img/jira_project_name.png (renamed from doc/integration/img/jira_project_name.png)bin60598 -> 60598 bytes
-rw-r--r--doc/project_services/img/jira_reference_commit_message_in_jira_issue.pngbin0 -> 42452 bytes
-rw-r--r--doc/project_services/img/jira_service.png (renamed from doc/integration/img/jira_service.png)bin59082 -> 59082 bytes
-rw-r--r--doc/project_services/img/jira_service_close_issue.png (renamed from doc/integration/img/jira_service_close_issue.png)bin88433 -> 88433 bytes
-rw-r--r--doc/project_services/img/jira_service_page.png (renamed from doc/integration/img/jira_service_page.png)bin35496 -> 35496 bytes
-rw-r--r--doc/project_services/img/jira_submit_gitlab_merge_request.pngbin0 -> 63063 bytes
-rw-r--r--doc/project_services/img/jira_user_management_link.pngbin0 -> 58211 bytes
-rw-r--r--doc/project_services/img/jira_workflow_screenshot.png (renamed from doc/integration/img/jira_workflow_screenshot.png)bin121534 -> 121534 bytes
-rw-r--r--doc/project_services/jira.md212
-rw-r--r--doc/project_services/project_services.md2
-rw-r--r--doc/workflow/forking/fork_button.pngbin68271 -> 0 bytes
-rw-r--r--doc/workflow/forking/groups.pngbin98109 -> 0 bytes
-rw-r--r--doc/workflow/forking_workflow.md59
-rw-r--r--doc/workflow/img/forking_workflow_choose_namespace.pngbin0 -> 70405 bytes
-rw-r--r--doc/workflow/img/forking_workflow_fork_button.pngbin0 -> 26438 bytes
-rw-r--r--doc/workflow/img/forking_workflow_path_taken_error.pngbin0 -> 22380 bytes
-rw-r--r--features/project/builds/artifacts.feature9
-rw-r--r--features/steps/project/builds/artifacts.rb10
-rw-r--r--features/steps/project/wiki.rb2
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb49
-rw-r--r--lib/gitlab/github_import/importer.rb17
-rw-r--r--lib/gitlab/metrics/instrumentation.rb22
-rwxr-xr-xscripts/prepare_build.sh2
-rw-r--r--spec/controllers/groups_controller_spec.rb23
-rw-r--r--spec/controllers/projects/imports_controller_spec.rb109
-rw-r--r--spec/factories/commit_statuses.rb8
-rw-r--r--spec/features/commits_spec.rb127
-rw-r--r--spec/helpers/labels_helper_spec.rb5
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb11
-rw-r--r--spec/lib/gitlab/metrics/instrumentation_spec.rb10
-rw-r--r--spec/models/external_issue_spec.rb15
-rw-r--r--spec/models/repository_spec.rb20
-rw-r--r--spec/models/tree_spec.rb64
-rw-r--r--spec/services/projects/import_service_spec.rb106
-rw-r--r--spec/spec_helper.rb6
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
diff --git a/Gemfile b/Gemfile
index 8e727d950bf..37aeb09e93c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -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
new file mode 100644
index 00000000000..85e54861b3e
--- /dev/null
+++ b/doc/project_services/img/jira_add_gitlab_commit_message.png
Binary files differ
diff --git a/doc/project_services/img/jira_add_user_to_group.png b/doc/project_services/img/jira_add_user_to_group.png
new file mode 100644
index 00000000000..e4576433889
--- /dev/null
+++ b/doc/project_services/img/jira_add_user_to_group.png
Binary files differ
diff --git a/doc/project_services/img/jira_create_new_group.png b/doc/project_services/img/jira_create_new_group.png
new file mode 100644
index 00000000000..edaa1326058
--- /dev/null
+++ b/doc/project_services/img/jira_create_new_group.png
Binary files differ
diff --git a/doc/project_services/img/jira_create_new_group_name.png b/doc/project_services/img/jira_create_new_group_name.png
new file mode 100644
index 00000000000..9e518ad7843
--- /dev/null
+++ b/doc/project_services/img/jira_create_new_group_name.png
Binary files differ
diff --git a/doc/project_services/img/jira_create_new_user.png b/doc/project_services/img/jira_create_new_user.png
new file mode 100644
index 00000000000..57e433dd818
--- /dev/null
+++ b/doc/project_services/img/jira_create_new_user.png
Binary files differ
diff --git a/doc/project_services/img/jira_group_access.png b/doc/project_services/img/jira_group_access.png
new file mode 100644
index 00000000000..47716ca6d0e
--- /dev/null
+++ b/doc/project_services/img/jira_group_access.png
Binary files differ
diff --git a/doc/project_services/img/jira_issue_closed.png b/doc/project_services/img/jira_issue_closed.png
new file mode 100644
index 00000000000..cabec1ae137
--- /dev/null
+++ b/doc/project_services/img/jira_issue_closed.png
Binary files differ
diff --git a/doc/integration/img/jira_issue_reference.png b/doc/project_services/img/jira_issue_reference.png
index 15739a22dc7..15739a22dc7 100644
--- a/doc/integration/img/jira_issue_reference.png
+++ b/doc/project_services/img/jira_issue_reference.png
Binary files differ
diff --git a/doc/project_services/img/jira_issues_workflow.png b/doc/project_services/img/jira_issues_workflow.png
new file mode 100644
index 00000000000..28e17be3a84
--- /dev/null
+++ b/doc/project_services/img/jira_issues_workflow.png
Binary files differ
diff --git a/doc/integration/img/jira_merge_request_close.png b/doc/project_services/img/jira_merge_request_close.png
index 1e78daf105f..1e78daf105f 100644
--- a/doc/integration/img/jira_merge_request_close.png
+++ b/doc/project_services/img/jira_merge_request_close.png
Binary files differ
diff --git a/doc/integration/img/jira_project_name.png b/doc/project_services/img/jira_project_name.png
index 5986fdb63fb..5986fdb63fb 100644
--- a/doc/integration/img/jira_project_name.png
+++ b/doc/project_services/img/jira_project_name.png
Binary files differ
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
new file mode 100644
index 00000000000..0149181dc86
--- /dev/null
+++ b/doc/project_services/img/jira_reference_commit_message_in_jira_issue.png
Binary files differ
diff --git a/doc/integration/img/jira_service.png b/doc/project_services/img/jira_service.png
index 1f6628c4371..1f6628c4371 100644
--- a/doc/integration/img/jira_service.png
+++ b/doc/project_services/img/jira_service.png
Binary files differ
diff --git a/doc/integration/img/jira_service_close_issue.png b/doc/project_services/img/jira_service_close_issue.png
index 67dfc6144c4..67dfc6144c4 100644
--- a/doc/integration/img/jira_service_close_issue.png
+++ b/doc/project_services/img/jira_service_close_issue.png
Binary files differ
diff --git a/doc/integration/img/jira_service_page.png b/doc/project_services/img/jira_service_page.png
index 2b37eda3520..2b37eda3520 100644
--- a/doc/integration/img/jira_service_page.png
+++ b/doc/project_services/img/jira_service_page.png
Binary files differ
diff --git a/doc/project_services/img/jira_submit_gitlab_merge_request.png b/doc/project_services/img/jira_submit_gitlab_merge_request.png
new file mode 100644
index 00000000000..e935d9362aa
--- /dev/null
+++ b/doc/project_services/img/jira_submit_gitlab_merge_request.png
Binary files differ
diff --git a/doc/project_services/img/jira_user_management_link.png b/doc/project_services/img/jira_user_management_link.png
new file mode 100644
index 00000000000..2745916972c
--- /dev/null
+++ b/doc/project_services/img/jira_user_management_link.png
Binary files differ
diff --git a/doc/integration/img/jira_workflow_screenshot.png b/doc/project_services/img/jira_workflow_screenshot.png
index 8635a32eb68..8635a32eb68 100644
--- a/doc/integration/img/jira_workflow_screenshot.png
+++ b/doc/project_services/img/jira_workflow_screenshot.png
Binary files differ
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
deleted file mode 100644
index def4266476a..00000000000
--- a/doc/workflow/forking/fork_button.png
+++ /dev/null
Binary files differ
diff --git a/doc/workflow/forking/groups.png b/doc/workflow/forking/groups.png
deleted file mode 100644
index 3ac64b3c8e7..00000000000
--- a/doc/workflow/forking/groups.png
+++ /dev/null
Binary files differ
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
new file mode 100644
index 00000000000..eefe5769554
--- /dev/null
+++ b/doc/workflow/img/forking_workflow_choose_namespace.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_fork_button.png b/doc/workflow/img/forking_workflow_fork_button.png
new file mode 100644
index 00000000000..49e68d33e89
--- /dev/null
+++ b/doc/workflow/img/forking_workflow_fork_button.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_path_taken_error.png b/doc/workflow/img/forking_workflow_path_taken_error.png
new file mode 100644
index 00000000000..7a3139506fe
--- /dev/null
+++ b/doc/workflow/img/forking_workflow_path_taken_error.png
Binary files differ
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!