summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG5
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock11
-rw-r--r--app/assets/javascripts/notes.js.coffee1
-rw-r--r--app/assets/javascripts/syntax_highlight.coffee5
-rw-r--r--app/assets/javascripts/zen_mode.js.coffee2
-rw-r--r--app/assets/stylesheets/base/gl_bootstrap.scss6
-rw-r--r--app/assets/stylesheets/base/gl_variables.scss11
-rw-r--r--app/assets/stylesheets/base/mixins.scss40
-rw-r--r--app/assets/stylesheets/generic/blocks.scss10
-rw-r--r--app/assets/stylesheets/generic/common.scss33
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss9
-rw-r--r--app/assets/stylesheets/generic/lists.scss2
-rw-r--r--app/assets/stylesheets/generic/markdown_area.scss11
-rw-r--r--app/assets/stylesheets/generic/timeline.scss140
-rw-r--r--app/assets/stylesheets/generic/zen.scss4
-rw-r--r--app/assets/stylesheets/pages/commit.scss13
-rw-r--r--app/assets/stylesheets/pages/diff.scss14
-rw-r--r--app/assets/stylesheets/pages/issuable.scss41
-rw-r--r--app/assets/stylesheets/pages/issues.scss12
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss37
-rw-r--r--app/assets/stylesheets/pages/milestone.scss4
-rw-r--r--app/assets/stylesheets/pages/note_form.scss16
-rw-r--r--app/assets/stylesheets/pages/notes.scss29
-rw-r--r--app/assets/stylesheets/pages/projects.scss9
-rw-r--r--app/controllers/admin/labels_controller.rb58
-rw-r--r--app/controllers/application_controller.rb7
-rw-r--r--app/controllers/import/fogbugz_controller.rb106
-rw-r--r--app/controllers/projects/wikis_controller.rb1
-rw-r--r--app/controllers/sessions_controller.rb2
-rw-r--r--app/helpers/auth_helper.rb6
-rw-r--r--app/helpers/groups_helper.rb9
-rw-r--r--app/helpers/wiki_helper.rb24
-rw-r--r--app/models/abuse_report.rb12
-rw-r--r--app/models/application_setting.rb2
-rw-r--r--app/models/issue.rb27
-rw-r--r--app/models/label.rb8
-rw-r--r--app/models/merge_request.rb1
-rw-r--r--app/models/note.rb1
-rw-r--r--app/models/project.rb11
-rw-r--r--app/models/project_services/drone_ci_service.rb20
-rw-r--r--app/models/sent_notification.rb13
-rw-r--r--app/models/user.rb108
-rw-r--r--app/services/projects/create_service.rb2
-rw-r--r--app/services/projects/download_service.rb43
-rw-r--r--app/views/admin/labels/_form.html.haml35
-rw-r--r--app/views/admin/labels/_label.html.haml5
-rw-r--r--app/views/admin/labels/destroy.js.haml2
-rw-r--r--app/views/admin/labels/edit.html.haml9
-rw-r--r--app/views/admin/labels/index.html.haml16
-rw-r--r--app/views/admin/labels/new.html.haml7
-rw-r--r--app/views/dashboard/milestones/_milestone.html.haml24
-rw-r--r--app/views/devise/sessions/_new_crowd.html.haml9
-rw-r--r--app/views/devise/shared/_signin_box.html.haml10
-rw-r--r--app/views/groups/group_members/index.html.haml4
-rw-r--r--app/views/groups/issues.html.haml25
-rw-r--r--app/views/groups/merge_requests.html.haml23
-rw-r--r--app/views/groups/milestones/_milestone.html.haml36
-rw-r--r--app/views/groups/milestones/index.html.haml26
-rw-r--r--app/views/import/fogbugz/new.html.haml25
-rw-r--r--app/views/import/fogbugz/new_user_map.html.haml49
-rw-r--r--app/views/import/fogbugz/status.html.haml51
-rw-r--r--app/views/layouts/_head.html.haml1
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/layouts/group.html.haml3
-rw-r--r--app/views/layouts/nav/_admin.html.haml6
-rw-r--r--app/views/projects/_activity.html.haml2
-rw-r--r--app/views/projects/_md_preview.html.haml4
-rw-r--r--app/views/projects/branches/_branch.html.haml13
-rw-r--r--app/views/projects/branches/_commit.html.haml7
-rw-r--r--app/views/projects/branches/index.html.haml8
-rw-r--r--app/views/projects/commit/_commit_box.html.haml2
-rw-r--r--app/views/projects/commits/_head.html.haml6
-rw-r--r--app/views/projects/commits/show.html.haml25
-rw-r--r--app/views/projects/compare/_form.html.haml2
-rw-r--r--app/views/projects/compare/index.html.haml7
-rw-r--r--app/views/projects/compare/show.html.haml12
-rw-r--r--app/views/projects/diffs/_diffs.html.haml4
-rw-r--r--app/views/projects/diffs/_stats.html.haml2
-rw-r--r--app/views/projects/empty.html.haml6
-rw-r--r--app/views/projects/issues/_discussion.html.haml23
-rw-r--r--app/views/projects/issues/_issue.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml32
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml17
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml2
-rw-r--r--app/views/projects/merge_requests/_new_compare.html.haml2
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml4
-rw-r--r--app/views/projects/merge_requests/_show.html.haml9
-rw-r--r--app/views/projects/merge_requests/show/_how_to_merge.html.haml16
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml21
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml9
-rw-r--r--app/views/projects/merge_requests/widget/open/_accept.html.haml2
-rw-r--r--app/views/projects/milestones/_milestone.html.haml42
-rw-r--r--app/views/projects/milestones/index.html.haml25
-rw-r--r--app/views/projects/new.html.haml5
-rw-r--r--app/views/projects/notes/_note.html.haml11
-rw-r--r--app/views/projects/show.html.haml6
-rw-r--r--app/views/projects/tags/_tag.html.haml12
-rw-r--r--app/views/projects/tags/index.html.haml11
-rw-r--r--app/views/projects/tree/_tree.html.haml2
-rw-r--r--app/views/projects/wikis/_main_links.html.haml11
-rw-r--r--app/views/projects/wikis/_nav.html.haml15
-rw-r--r--app/views/projects/wikis/git_access.html.haml19
-rw-r--r--app/views/projects/wikis/history.html.haml7
-rw-r--r--app/views/projects/wikis/pages.html.haml7
-rw-r--r--app/views/projects/wikis/show.html.haml21
-rw-r--r--app/workers/repository_import_worker.rb35
-rw-r--r--config/gitlab.yml.example5
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/devise.rb2
-rw-r--r--config/routes.rb33
-rw-r--r--db/migrate/20150902001023_add_template_to_label.rb5
-rw-r--r--db/schema.rb3
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/integration/crowd.md58
-rw-r--r--doc/integration/omniauth.md1
-rw-r--r--doc/update/6.x-or-7.x-to-7.14.md4
-rw-r--r--doc/update/7.13-to-7.14.md2
-rw-r--r--doc/workflow/importing/README.md1
-rw-r--r--doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.pngbin0 -> 53276 bytes
-rw-r--r--doc/workflow/importing/fogbugz_importer/fogbugz_import_login.pngbin0 -> 44444 bytes
-rw-r--r--doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.pngbin0 -> 35415 bytes
-rw-r--r--doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.pngbin0 -> 62552 bytes
-rw-r--r--doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.pngbin0 -> 157856 bytes
-rw-r--r--doc/workflow/importing/import_projects_from_fogbugz.md29
-rw-r--r--features/admin/labels.feature38
-rw-r--r--features/login_form.feature5
-rw-r--r--features/project/wiki.feature12
-rw-r--r--features/steps/admin/labels.rb117
-rw-r--r--features/steps/login_form.rb25
-rw-r--r--features/steps/project/commits/commits.rb1
-rw-r--r--features/steps/project/wiki.rb9
-rw-r--r--features/steps/shared/active_tab.rb4
-rw-r--r--lib/gitlab/fogbugz_import/client.rb56
-rw-r--r--lib/gitlab/fogbugz_import/importer.rb298
-rw-r--r--lib/gitlab/fogbugz_import/project_creator.rb38
-rw-r--r--lib/gitlab/fogbugz_import/repository.rb31
-rw-r--r--lib/gitlab/import_sources.rb1
-rw-r--r--lib/gitlab/url_builder.rb8
-rw-r--r--lib/support/nginx/gitlab9
-rw-r--r--lib/support/nginx/gitlab-ssl9
-rw-r--r--lib/tasks/gitlab/check.rake13
-rw-r--r--spec/controllers/import/fogbugz_controller_spec.rb39
-rw-r--r--spec/factories/abuse_reports.rb12
-rw-r--r--spec/factories/merge_requests.rb1
-rw-r--r--spec/factories/notes.rb1
-rw-r--r--spec/javascripts/zen_mode_spec.js.coffee5
-rw-r--r--spec/models/abuse_report_spec.rb12
-rw-r--r--spec/models/application_setting_spec.rb1
-rw-r--r--spec/models/issue_spec.rb27
-rw-r--r--spec/models/merge_request_spec.rb1
-rw-r--r--spec/models/note_spec.rb1
-rw-r--r--spec/models/user_spec.rb108
-rw-r--r--spec/services/projects/create_service_spec.rb8
-rw-r--r--spec/services/projects/download_service_spec.rb65
156 files changed, 2152 insertions, 719 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 329ce74a5d5..32f063fa751 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,10 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.0.0 (unreleased)
+ - Fix URL construction for merge requests, issues, notes, and commits for relative URL config (Stan Hu)
- Fix emoji URLs in Markdown when relative_url_root is used (Stan Hu)
- Omit filename in Content-Disposition header in raw file download to avoid RFC 6266 encoding issues (Stan HU)
+ - Fix broken Wiki Page History (Stan Hu)
- Prevent anchors from being hidden by header (Stan Hu)
- Fix bug where only the first 15 Bitbucket issues would be imported (Stan Hu)
- Sort issues by creation date in Bitbucket importer (Stan Hu)
@@ -38,6 +40,8 @@ v 8.0.0 (unreleased)
- Added web_url key project hook_attrs (Kirill Zaitsev)
- Add ability to get user information by ID of an SSH key via the API
- Fix bug which IE cannot show image at markdown when the image is raw file of gitlab
+ - Add support for Crowd
+ - Global Labels that are available to all projects
v 7.14.1
- Improve abuse reports management from admin area
@@ -45,6 +49,7 @@ v 7.14.1
- Only include base URL in OmniAuth full_host parameter (Stan Hu)
- Fix Error 500 in API when accessing a group that has an avatar (Stan Hu)
- Ability to enable SSL verification for Webhooks
+ - Add FogBugz project import (Jared Szechy)
v 7.14.0
- Fix bug where non-project members of the target project could set labels on new merge requests.
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 2714f5313ae..57cf282ebbc 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.6.4
+2.6.5
diff --git a/Gemfile b/Gemfile
index 36b71959743..d609ff6610f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -25,6 +25,7 @@ gem 'omniauth-kerberos', group: :kerberos
gem 'omniauth-gitlab'
gem 'omniauth-bitbucket'
gem 'omniauth-saml', '~> 1.4.0'
+gem 'omniauth_crowd'
gem 'doorkeeper', '2.1.3'
gem "rack-oauth2", "~> 1.0.5"
@@ -156,6 +157,9 @@ gem "slack-notifier", "~> 1.0.0"
# Asana integration
gem 'asana', '~> 0.0.6'
+# FogBugz integration
+gem 'ruby-fogbugz'
+
# d3
gem 'd3_rails', '~> 3.5.5'
@@ -258,6 +262,7 @@ group :test do
gem 'email_spec', '~> 1.6.0'
gem 'webmock', '~> 1.21.0'
gem 'test_after_commit'
+ gem 'sham_rack'
end
group :production do
diff --git a/Gemfile.lock b/Gemfile.lock
index 181b72e07e2..dce7e4964a6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -434,6 +434,10 @@ GEM
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
+ omniauth_crowd (2.2.3)
+ activesupport
+ nokogiri (>= 1.4.4)
+ omniauth (~> 1.0)
opennebula (4.12.1)
json
nokogiri
@@ -571,6 +575,8 @@ GEM
powerpack (~> 0.0.6)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
+ ruby-fogbugz (0.1.1)
+ crack
ruby-progressbar (1.7.1)
ruby-saml (1.0.0)
nokogiri (>= 1.5.10)
@@ -605,6 +611,8 @@ GEM
thor (~> 0.14)
settingslogic (2.0.9)
sexp_processor (4.4.5)
+ sham_rack (1.3.6)
+ rack
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
sidekiq (3.3.0)
@@ -821,6 +829,7 @@ DEPENDENCIES
omniauth-saml (~> 1.4.0)
omniauth-shibboleth
omniauth-twitter
+ omniauth_crowd
org-ruby (= 0.9.12)
pg
poltergeist (~> 1.6.0)
@@ -840,12 +849,14 @@ DEPENDENCIES
rqrcode-rails3
rspec-rails (~> 3.3.0)
rubocop (= 0.28.0)
+ ruby-fogbugz
sanitize (~> 2.0)
sass-rails (~> 4.0.5)
sdoc
seed-fu
select2-rails (~> 3.5.9)
settingslogic
+ sham_rack
shoulda-matchers (~> 2.8.0)
sidekiq (~> 3.3)
sidetiq (= 0.6.3)
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 0021d17d85e..b7f2c63c5a7 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -123,6 +123,7 @@ class @Notes
if @isNewNote(note)
@note_ids.push(note.id)
$('ul.main-notes-list').append(note.html)
+ $('.js-syntax-highlight').syntaxHighlight()
@initTaskList()
###
diff --git a/app/assets/javascripts/syntax_highlight.coffee b/app/assets/javascripts/syntax_highlight.coffee
index 510f15d1b49..71295cd4b08 100644
--- a/app/assets/javascripts/syntax_highlight.coffee
+++ b/app/assets/javascripts/syntax_highlight.coffee
@@ -5,5 +5,8 @@
#
# <div class="js-syntax-highlight"></div>
#
+$.fn.syntaxHighlight = ->
+ $(this).addClass(gon.user_color_scheme)
+
$(document).on 'ready page:load', ->
- $('.js-syntax-highlight').addClass(gon.user_color_scheme)
+ $('.js-syntax-highlight').syntaxHighlight()
diff --git a/app/assets/javascripts/zen_mode.js.coffee b/app/assets/javascripts/zen_mode.js.coffee
index 8a0564a9098..a1462cf3cae 100644
--- a/app/assets/javascripts/zen_mode.js.coffee
+++ b/app/assets/javascripts/zen_mode.js.coffee
@@ -38,6 +38,8 @@ class @ZenMode
@active_checkbox = $(checkbox)
@active_checkbox.prop('checked', true)
@active_zen_area = @active_checkbox.parent().find('textarea')
+ # Prevent a user-resized textarea from persisting to fullscreen
+ @active_zen_area.removeAttr('style')
@active_zen_area.focus()
exitZenMode: =>
diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss
index 21acbfa5e5a..ae72c5b8d97 100644
--- a/app/assets/stylesheets/base/gl_bootstrap.scss
+++ b/app/assets/stylesheets/base/gl_bootstrap.scss
@@ -85,14 +85,14 @@
// Labels
.label {
padding: 2px 4px;
- font-size: 12px;
+ font-size: 13px;
font-style: normal;
font-weight: normal;
display: inline-block;
&.label-gray {
- background-color: #eee;
- color: #999;
+ background-color: #f8fafc;
+ color: $gl-gray;
text-shadow: none;
}
diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
index 6d3b4b1e73a..d18b48eaca9 100644
--- a/app/assets/stylesheets/base/gl_variables.scss
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -22,6 +22,10 @@ $brand-info: $gl-info;
$brand-warning: $gl-warning;
$brand-danger: $gl-danger;
+$border-radius-base: 3px !default;
+$border-radius-large: 5px !default;
+$border-radius-small: 2px !default;
+
//== Scaffolding
//
@@ -144,3 +148,10 @@ $btn-default-border: #e7e9ed;
//
//##
$nav-link-padding: 13px $gl-padding;
+
+//== Code
+//
+//##
+$pre-bg: #f8fafc !default;
+$pre-color: $gl-gray !default;
+$pre-border-color: #e7e9ed;
diff --git a/app/assets/stylesheets/base/mixins.scss b/app/assets/stylesheets/base/mixins.scss
index 2d2e8b3dedd..0f661d6b1b6 100644
--- a/app/assets/stylesheets/base/mixins.scss
+++ b/app/assets/stylesheets/base/mixins.scss
@@ -169,7 +169,7 @@
padding: 0px;
list-style: none;
- li {
+ > li {
padding: 10px 0;
border-bottom: 1px solid #EEE;
overflow: hidden;
@@ -177,7 +177,7 @@
margin: 0px;
&:last-child {
- border:none
+ border-bottom: none;
}
&.active {
@@ -215,3 +215,39 @@
font-size: 16px;
line-height: 24px;
}
+
+@mixin nav-menu {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ margin-top: 5px;
+ height: 56px;
+
+ li {
+ display: inline-block;
+
+ a {
+ padding: 14px;
+ font-size: 17px;
+ line-height: 28px;
+ color: #7f8fa4;
+ border-bottom: 2px solid transparent;
+
+ &:hover, &:active, &:focus {
+ text-decoration: none;
+ }
+ }
+
+ &.active a {
+ color: #4c4e54;
+ border-bottom: 2px solid #1cacfc;
+ }
+
+ .badge {
+ font-weight: normal;
+ background-color: #fff;
+ background-color: #eee;
+ color: #78a;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/generic/blocks.scss b/app/assets/stylesheets/generic/blocks.scss
index 61209f73a2e..27a4c4db8c8 100644
--- a/app/assets/stylesheets/generic/blocks.scss
+++ b/app/assets/stylesheets/generic/blocks.scss
@@ -27,6 +27,16 @@
border-bottom: 1px solid #e7e9ed;
color: $gl-gray;
+ &.middle-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ &.second-block {
+ margin-top: -1px;
+ margin-bottom: 0;
+ }
+
&.footer-block {
margin-top: 0;
margin-bottom: -$gl-padding;
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 096698e8466..5e191d5dd4a 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -7,6 +7,7 @@
/** COMMON CLASSES **/
.prepend-top-10 { margin-top:10px }
+.prepend-top-default { margin-top: $gl-padding; }
.prepend-top-20 { margin-top:20px }
.prepend-left-10 { margin-left:10px }
.prepend-left-20 { margin-left:20px }
@@ -369,41 +370,11 @@ table {
}
.center-top-menu {
- padding: 0;
- margin: 0;
- list-style: none;
+ @include nav-menu;
text-align: center;
margin-top: 5px;
margin-bottom: $gl-padding;
height: 56px;
margin-top: -$gl-padding;
padding-top: $gl-padding;
-
- li {
- display: inline-block;
-
- a {
- padding: 14px;
- font-size: 17px;
- line-height: 28px;
- color: #7f8fa4;
- border-bottom: 2px solid transparent;
-
- &:hover, &:active, &:focus {
- text-decoration: none;
- }
- }
-
- &.active a {
- color: #4c4e54;
- border-bottom: 2px solid #1cacfc;
- }
-
- .badge {
- font-weight: normal;
- background-color: #fff;
- background-color: #eee;
- color: #78a;
- }
- }
}
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 869e586839b..b1fb87a6830 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -5,10 +5,13 @@
*/
.issue-box {
+ @include border-radius(3px);
+
display: inline-block;
- padding: 4px 13px;
+ padding: 10px $gl-padding;
font-weight: normal;
- margin-right: 5px;
+ margin-right: 10px;
+ font-size: $gl-font-size;
&.issue-box-closed {
background-color: $gl-danger;
@@ -21,7 +24,7 @@
}
&.issue-box-open {
- background-color: $gl-success;
+ background-color: #019875;
color: #FFF;
}
diff --git a/app/assets/stylesheets/generic/lists.scss b/app/assets/stylesheets/generic/lists.scss
index 601fdd1e329..3bfed8de772 100644
--- a/app/assets/stylesheets/generic/lists.scss
+++ b/app/assets/stylesheets/generic/lists.scss
@@ -105,7 +105,7 @@ ul.content-list {
margin: 0;
padding: 0;
- li {
+ > li {
padding: $gl-padding;
border-color: #f1f2f4;
margin-left: -$gl-padding;
diff --git a/app/assets/stylesheets/generic/markdown_area.scss b/app/assets/stylesheets/generic/markdown_area.scss
index a4fc82e90bf..ed0333d2336 100644
--- a/app/assets/stylesheets/generic/markdown_area.scss
+++ b/app/assets/stylesheets/generic/markdown_area.scss
@@ -65,8 +65,11 @@
position: relative;
}
-.md-header ul {
- float: left;
+.md-header {
+ ul {
+ float: left;
+ margin-bottom: 1px;
+ }
}
.referenced-users {
@@ -80,7 +83,7 @@
.md-preview-holder {
background: #FFF;
border: 1px solid #ddd;
- min-height: 100px;
+ min-height: 169px;
padding: 5px;
box-shadow: none;
}
@@ -105,7 +108,7 @@
.markdown-area {
background: #FFF;
border: 1px solid #ddd;
- min-height: 100px;
+ min-height: 140px;
padding: 5px;
box-shadow: none;
width: 100%;
diff --git a/app/assets/stylesheets/generic/timeline.scss b/app/assets/stylesheets/generic/timeline.scss
index 97831eb7c27..74bbaabad39 100644
--- a/app/assets/stylesheets/generic/timeline.scss
+++ b/app/assets/stylesheets/generic/timeline.scss
@@ -1,119 +1,50 @@
.timeline {
- list-style: none;
- padding: 20px 0 20px;
- position: relative;
+ @include basic-list;
- &:before {
- top: 0;
- bottom: 0;
- position: absolute;
- content: " ";
- width: 3px;
- background-color: #eeeeee;
- margin-left: 29px;
- }
+ margin: 0;
+ padding: 0;
.timeline-entry {
- position: relative;
- margin-top: 5px;
- margin-left: 30px;
- margin-bottom: 10px;
- clear: both;
-
-
- &:target {
- .timeline-entry-inner .timeline-content {
- -webkit-animation:target-note 2s linear;
- background: $hover;
- }
+ padding: $gl-padding;
+ border-color: #f1f2f4;
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ color: $gl-gray;
+ border-bottom: 1px solid #f1f2f4;
+ border-right: 1px solid #f1f2f4;
+
+ &:last-child {
+ border-bottom: none;
}
- .timeline-entry-inner {
- position: relative;
- margin-left: -20px;
-
- &:before, &:after {
- content: " ";
- display: table;
- }
-
- .timeline-icon {
- margin-top: 2px;
- background: #fff;
- color: #737881;
- float: left;
- @include border-radius($avatar_radius);
- @include box-shadow(0 0 0 3px #EEE);
- overflow: hidden;
-
- .avatar {
- margin: 0;
- padding: 0;
- }
- }
-
- .timeline-content {
- position: relative;
- background: $background-color;
- padding: 10px 15px;
- margin-left: 60px;
-
- img {
- max-width: 100%;
- }
+ .avatar {
+ margin-right: 15px;
+ }
- &:after {
- content: '';
- display: block;
- position: absolute;
- width: 0;
- height: 0;
- border-style: solid;
- border-width: 9px 9px 9px 0;
- border-color: transparent $background-color transparent transparent;
- left: 0;
- top: 10px;
- margin-left: -9px;
- }
- }
+ .controls {
+ padding-top: 10px;
+ float: right;
}
}
- .system-note .timeline-entry-inner {
- .timeline-icon {
- background: none;
- margin-left: 12px;
- margin-top: 0;
- @include box-shadow(none);
-
- span {
- margin: 0 2px;
- font-size: 16px;
- color: #eeeeee;
- }
+ .note-text {
+ p:last-child {
+ margin-bottom: 0;
}
+ }
- .timeline-content {
- background: none;
- margin-left: 45px;
- padding: 0px 15px;
-
- &:after { border: 0; }
-
- .note-header {
- span { font-size: 12px; }
-
- .avatar {
- margin-right: 5px;
- }
- }
-
- .note-text {
- font-size: 12px;
- margin-left: 20px;
- }
+ .system-note {
+ .note-text {
+ color: $gl-gray !important;
}
}
+
+ .diff-file {
+ border: 1px solid $border-color;
+ border-bottom: none;
+ margin-left: 0;
+ margin-right: 0;
+ }
}
@media (max-width: $screen-xs-max) {
@@ -132,3 +63,8 @@
}
}
}
+
+.discussion .timeline-entry {
+ margin: 0;
+ border-right: none;
+}
diff --git a/app/assets/stylesheets/generic/zen.scss b/app/assets/stylesheets/generic/zen.scss
index 7e86a0fe4b9..32e2c020e06 100644
--- a/app/assets/stylesheets/generic/zen.scss
+++ b/app/assets/stylesheets/generic/zen.scss
@@ -4,7 +4,7 @@
}
.zen-enter-link {
- color: #888;
+ color: $gl-gray;
position: absolute;
top: 0px;
right: 4px;
@@ -13,7 +13,7 @@
.zen-leave-link {
display: none;
- color: #888;
+ color: $gl-text-color;
position: absolute;
top: 10px;
right: 10px;
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index 5436c6dad97..051ca3792c3 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -26,14 +26,6 @@
margin-top: 10px;
}
-.commit-stat-summary {
- color: #666;
- font-size: 14px;
- font-weight: normal;
- padding: 3px 0;
- margin-bottom: 10px;
-}
-
.commit-info-row {
margin-bottom: 10px;
.avatar {
@@ -47,11 +39,6 @@
}
.commit-box {
- margin: 10px 0;
- border-top: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
- padding: 20px 0;
-
.commit-title {
margin: 0;
}
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 1557c243db5..487b600e31d 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -1,6 +1,8 @@
.diff-file {
- border: 1px solid $border-color;
- margin-bottom: 1em;
+ margin-left: -16px;
+ margin-right: -16px;
+ border: none;
+ border-bottom: 1px solid #E7E9EE;
.diff-header {
position: relative;
@@ -45,7 +47,7 @@
overflow-y: hidden;
background: #FFF;
color: #333;
- font-size: $code_font_size;
+
.old {
span.idiff {
background-color: #f8cbcb;
@@ -82,7 +84,7 @@
border: none;
margin: 0px;
padding: 0px;
- td {
+ .line_holder td {
line-height: $code_line_height;
font-size: $code_font_size;
}
@@ -367,3 +369,7 @@
white-space: pre-wrap;
}
+.inline-parallel-buttons {
+ float: right;
+ margin-top: -5px;
+}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 2d32d82e107..b5c61f7f91d 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -25,8 +25,6 @@
}
.issuable-context-title {
- font-size: 14px;
- line-height: 1.4;
margin-bottom: 5px;
.avatar {
@@ -34,18 +32,12 @@
}
label {
- color: #666;
+ color: $gl-gray;
font-weight: normal;
margin-right: 4px;
}
}
-.issuable-affix .context {
- font-size: 13px;
-
- .btn { font-size: 13px; }
-}
-
.project-issuable-filter {
.controls {
float: right;
@@ -56,3 +48,34 @@
text-align: left;
}
}
+
+.issuable-details {
+ .page-title {
+ margin-top: -15px;
+ padding: 10px 0;
+ margin-bottom: 0;
+ color: $gl-gray;
+ font-size: 16px;
+
+ .author {
+ color: $gl-gray;
+ }
+
+ .issue-id {
+ font-size: 19px;
+ color: $gl-text-color;
+ }
+ }
+
+ .issue-title {
+ margin: 0;
+ }
+
+ .description {
+ margin-top: 6px;
+
+ p:last-child {
+ margin-bottom: 0;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 7928b6220fc..4bf58cb4a59 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -1,6 +1,6 @@
.issues-list {
.issue {
- padding: 10px 15px;
+ padding: 10px $gl-padding;
position: relative;
.issue-title {
@@ -11,7 +11,6 @@
.issue-info {
color: $gl-gray;
- font-size: 13px;
}
.issue-check {
@@ -47,10 +46,6 @@
}
}
-.participants {
- margin-bottom: 20px;
-}
-
.issue-search-form {
margin: 0;
height: 24px;
@@ -137,11 +132,6 @@ form.edit-issue {
}
}
-h2.issue-title {
- margin-top: 0;
- font-weight: bold;
-}
-
.issue-form .select2-container {
width: 250px !important;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index f0fb68d3422..d8c8e5ad0a4 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -3,10 +3,10 @@
*
*/
.mr-state-widget {
- background: #FAFAFA;
+ background: #f8fafc;
margin-bottom: 20px;
- color: #666;
- border: 1px solid #e5e5e5;
+ color: $gl-gray;
+ border: 1px solid #eef0f2;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
@include border-radius(3px);
@@ -29,6 +29,14 @@
padding: 5px;
line-height: 20px;
+ &.right {
+ float: right;
+ padding-top: 12px;
+ a {
+ color: $gl-gray;
+ }
+ }
+
.remove_source_checkbox {
margin: 0;
}
@@ -36,7 +44,7 @@
}
.ci_widget {
- border-bottom: 1px solid #EEE;
+ border-bottom: 1px solid #eef0f2;
i {
margin-right: 4px;
@@ -89,20 +97,14 @@
}
}
-@media(min-width: $screen-sm-max) {
- .merge-request .merge-request-tabs{
- li {
- a {
- padding: 15px 40px;
- font-size: 14px;
- }
- }
- }
-}
-
.merge-request .merge-request-tabs{
- margin-top: 30px;
- margin-bottom: 20px;
+ @include nav-menu;
+ margin: -$gl-padding;
+ padding: $gl-padding;
+ text-align: center;
+ border-top: 1px solid #e7e9ed;
+ margin-top: 18px;
+ margin-bottom: 3px;
}
.mr_source_commit,
@@ -137,7 +139,6 @@
.merge-request-info {
color: $gl-gray;
- font-size: 13px;
}
}
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index 15e3948e402..e80dc9e84a1 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -6,4 +6,8 @@ li.milestone {
h4 {
font-weight: bold;
}
+
+ .progress {
+ height: 6px;
+ }
}
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 203f9374cee..b311d26d675 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -72,9 +72,13 @@
.common-note-form {
margin: 0;
- background: #F9F9F9;
- padding: 5px;
- border: 1px solid #DDD;
+ background: #f8fafc;
+ padding: $gl-padding;
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ border-right: 1px solid #f1f2f4;
+ border-top: 1px solid #f1f2f4;
+ margin-bottom: -$gl-padding;
}
.note-form-actions {
@@ -142,9 +146,9 @@
}
.discussion-reply-holder {
- background: #f9f9f9;
+ background: $background-color;
padding: 10px 15px;
- border-top: 1px solid #DDD;
+ border-top: 1px solid $border-color;
}
}
@@ -166,6 +170,6 @@
background: #FFF;
padding: 5px;
margin-top: -11px;
- border: 1px solid #DDD;
+ border: 1px solid $border-color;
font-size: 13px;
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 85c828ec1ad..2544356a5f6 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -14,6 +14,19 @@ ul.notes {
margin: 0px;
padding: 0px;
+ .system-note {
+ font-size: 14px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ background: #f8fafc;
+
+ .timeline-icon {
+ .avatar {
+ visibility: hidden;
+ }
+ }
+ }
+
.discussion-header,
.note-header {
@extend .cgray;
@@ -34,10 +47,8 @@ ul.notes {
content: "\00b7";
}
- font-size: 13px;
-
a {
- @extend .cgray;
+ color: $gl-gray;
&:hover {
text-decoration: underline;
@@ -45,8 +56,9 @@ ul.notes {
}
}
.author {
- color: #333;
- font-weight: bold;
+ color: #4c4e54;
+ margin-right: 3px;
+
&:hover {
color: $gl-link-color;
}
@@ -59,7 +71,7 @@ ul.notes {
margin-top: 1px;
border: 1px solid #bbb;
background-color: transparent;
- color: #999;
+ color: $gl-gray;
}
}
@@ -133,8 +145,6 @@ ul.notes {
}
.diff-file .notes_holder {
- font-size: 13px;
- line-height: 18px;
font-family: $regular_font;
td {
@@ -176,8 +186,7 @@ ul.notes {
a {
margin-left: 5px;
-
- color: #999;
+ color: $gl-gray;
i.fa {
font-size: 16px;
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 64db6a85ded..361fd63bc79 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -193,8 +193,9 @@ ul.nav.nav-projects-tabs {
.breadcrumb.repo-breadcrumb {
padding: 0;
line-height: 42px;
- background: white;
+ background: transparent;
border: none;
+ margin: 0;
> li + li:before {
padding: 0 3px;
@@ -331,3 +332,9 @@ pre.light-well {
padding: 10px 15px;
margin: 0;
}
+
+.project-show-activity {
+ .activity-filter-block {
+ margin-top: -1px;
+ }
+}
diff --git a/app/controllers/admin/labels_controller.rb b/app/controllers/admin/labels_controller.rb
new file mode 100644
index 00000000000..3b070e65d0d
--- /dev/null
+++ b/app/controllers/admin/labels_controller.rb
@@ -0,0 +1,58 @@
+class Admin::LabelsController < Admin::ApplicationController
+ before_action :set_label, only: [:show, :edit, :update, :destroy]
+
+ def index
+ @labels = Label.templates.page(params[:page]).per(PER_PAGE)
+ end
+
+ def show
+ end
+
+ def new
+ @label = Label.new
+ end
+
+ def edit
+ end
+
+ def create
+ @label = Label.new(label_params)
+ @label.template = true
+
+ if @label.save
+ redirect_to admin_labels_url, notice: "Label was created"
+ else
+ render :new
+ end
+ end
+
+ def update
+ if @label.update(label_params)
+ redirect_to admin_labels_path, notice: 'label was successfully updated.'
+ else
+ render :edit
+ end
+ end
+
+ def destroy
+ @label.destroy
+ @labels = Label.templates
+
+ respond_to do |format|
+ format.html do
+ redirect_to(admin_labels_path, notice: 'Label was removed')
+ end
+ format.js
+ end
+ end
+
+ private
+
+ def set_label
+ @label = Label.find(params[:id])
+ end
+
+ def label_params
+ params[:label].permit(:title, :color)
+ end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index cb1cf13d34d..4c112534ae6 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,4 +1,5 @@
require 'gon'
+require 'fogbugz'
class ApplicationController < ActionController::Base
include Gitlab::CurrentSettings
@@ -20,7 +21,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :abilities, :can?, :current_application_settings
- helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :git_import_enabled?
+ helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
@@ -337,6 +338,10 @@ class ApplicationController < ActionController::Base
current_application_settings.import_sources.include?('google_code')
end
+ def fogbugz_import_enabled?
+ current_application_settings.import_sources.include?('fogbugz')
+ end
+
def git_import_enabled?
current_application_settings.import_sources.include?('git')
end
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
new file mode 100644
index 00000000000..bda534fb4de
--- /dev/null
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -0,0 +1,106 @@
+class Import::FogbugzController < Import::BaseController
+ before_action :verify_fogbugz_import_enabled
+ before_action :user_map, only: [:new_user_map, :create_user_map]
+
+ # Doesn't work yet due to bug in ruby-fogbugz, see below
+ rescue_from Fogbugz::AuthenticationException, with: :fogbugz_unauthorized
+
+ def new
+
+ end
+
+ def callback
+ begin
+ res = Gitlab::FogbugzImport::Client.new(import_params.symbolize_keys)
+ rescue
+ # Needed until https://github.com/firmafon/ruby-fogbugz/pull/9 is merged
+ return redirect_to :back, alert: 'Could not authenticate with FogBugz, check your URL, email, and password'
+ end
+ session[:fogbugz_token] = res.get_token
+ session[:fogbugz_uri] = params[:uri]
+
+ redirect_to new_user_map_import_fogbugz_path
+ end
+
+ def new_user_map
+
+ end
+
+ def create_user_map
+ user_map = params[:users]
+
+ unless user_map.is_a?(Hash) && user_map.all? { |k, v| !v[:name].blank? }
+ flash.now[:alert] = 'All users must have a name.'
+
+ render 'new_user_map' and return
+ end
+
+ session[:fogbugz_user_map] = user_map
+
+ flash[:notice] = 'The user map has been saved. Continue by selecting the projects you want to import.'
+
+ redirect_to status_import_fogbugz_path
+ end
+
+ def status
+ unless client.valid?
+ return redirect_to new_import_fogbugz_path
+ end
+
+ @repos = client.repos
+
+ @already_added_projects = current_user.created_projects.where(import_type: 'fogbugz')
+ already_added_projects_names = @already_added_projects.pluck(:import_source)
+
+ @repos.reject! { |repo| already_added_projects_names.include? repo.name }
+ end
+
+ def jobs
+ jobs = current_user.created_projects.where(import_type: 'fogbugz').to_json(only: [:id, :import_status])
+ render json: jobs
+ end
+
+ def create
+ @repo_id = params[:repo_id]
+ repo = client.repo(@repo_id)
+ fb_session = { uri: session[:fogbugz_uri], token: session[:fogbugz_token] }
+ @target_namespace = current_user.namespace
+ @project_name = repo.name
+
+ namespace = @target_namespace
+
+ umap = session[:fogbugz_user_map] || client.user_map
+
+ @project = Gitlab::FogbugzImport::ProjectCreator.new(repo, fb_session, namespace, current_user, umap).execute
+ end
+
+ private
+
+ def client
+ @client ||= Gitlab::FogbugzImport::Client.new(token: session[:fogbugz_token], uri: session[:fogbugz_uri])
+ end
+
+ def user_map
+ @user_map ||= begin
+ user_map = client.user_map
+
+ stored_user_map = session[:fogbugz_user_map]
+ user_map.update(stored_user_map) if stored_user_map
+
+ user_map
+ end
+ end
+
+ def fogbugz_unauthorized(exception)
+ flash[:alert] = exception.message
+ redirect_to new_import_fogbugz_path
+ end
+
+ def import_params
+ params.permit(:uri, :email, :password)
+ end
+
+ def verify_fogbugz_import_enabled
+ not_found! unless fogbugz_import_enabled?
+ end
+end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 50512cb6dc3..51c26a6a465 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -5,7 +5,6 @@ class Projects::WikisController < Projects::ApplicationController
before_action :authorize_create_wiki!, only: [:edit, :create, :history]
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_project_wiki
- include WikiHelper
def pages
@wiki_pages = Kaminari.paginate_array(@project_wiki.pages).page(params[:page]).per(PER_PAGE)
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 8389f07a3bd..cfa565cd03e 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -8,6 +8,8 @@ class SessionsController < Devise::SessionsController
def new
if Gitlab.config.ldap.enabled
@ldap_servers = Gitlab::LDAP::Config.servers
+ else
+ @ldap_servers = []
end
super
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index 0e7a37b4cc6..d9502181c4f 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -1,6 +1,6 @@
module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
- FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos'].freeze
+ FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos', 'crowd'].freeze
def ldap_enabled?
Gitlab.config.ldap.enabled
@@ -26,6 +26,10 @@ module AuthHelper
auth_providers.select { |provider| form_based_provider?(provider) }
end
+ def crowd_enabled?
+ auth_providers.include? :crowd
+ end
+
def button_based_providers
auth_providers.reject { |provider| form_based_provider?(provider) }
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index b067cb54a43..82eebf4245b 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -30,4 +30,13 @@ module GroupsHelper
image_path('no_group_avatar.png')
end
end
+
+ def group_title(group, name, url)
+ content_tag :span do
+ link_to(
+ simple_sanitize(group.name), group_path(group)
+ ) + ' &middot; '.html_safe +
+ link_to(simple_sanitize(name), url)
+ end
+ end
end
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
deleted file mode 100644
index f8a96516e61..00000000000
--- a/app/helpers/wiki_helper.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-module WikiHelper
- # Rails v4.1.9+ escapes all model IDs, converting slashes into %2F. The
- # only way around this is to implement our own path generators.
- def namespace_project_wiki_path(namespace, project, wiki_page, *args)
- slug =
- case wiki_page
- when Symbol
- wiki_page
- when String
- wiki_page
- else
- wiki_page.slug
- end
- namespace_project_path(namespace, project) + "/wikis/#{slug}"
- end
-
- def edit_namespace_project_wiki_path(namespace, project, wiki_page, *args)
- namespace_project_wiki_path(namespace, project, wiki_page) + '/edit'
- end
-
- def history_namespace_project_wiki_path(namespace, project, wiki_page, *args)
- namespace_project_wiki_path(namespace, project, wiki_page) + '/history'
- end
-end
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index c8c39db11bc..07c87a7fe87 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: abuse_reports
+#
+# id :integer not null, primary key
+# reporter_id :integer
+# user_id :integer
+# message :text
+# created_at :datetime
+# updated_at :datetime
+#
+
class AbuseReport < ActiveRecord::Base
belongs_to :reporter, class_name: "User"
belongs_to :user
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 8f27e35d723..c8841178e93 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -83,7 +83,7 @@ class ApplicationSetting < ActiveRecord::Base
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
restricted_signup_domains: Settings.gitlab['restricted_signup_domains'],
- import_sources: ['github','bitbucket','gitlab','gitorious','google_code','git']
+ import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git']
)
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 2456b7d0dc1..fc7e9abe29e 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -2,19 +2,20 @@
#
# Table name: issues
#
-# id :integer not null, primary key
-# title :string(255)
-# assignee_id :integer
-# author_id :integer
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# position :integer default(0)
-# branch_name :string(255)
-# description :text
-# milestone_id :integer
-# state :string(255)
-# iid :integer
+# id :integer not null, primary key
+# title :string(255)
+# assignee_id :integer
+# author_id :integer
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# position :integer default(0)
+# branch_name :string(255)
+# description :text
+# milestone_id :integer
+# state :string(255)
+# iid :integer
+# updated_by_id :integer
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/label.rb b/app/models/label.rb
index 230631b5180..4a22bd53400 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -24,7 +24,7 @@ class Label < ActiveRecord::Base
validates :color,
format: { with: /\A#[0-9A-Fa-f]{6}\Z/ },
allow_blank: false
- validates :project, presence: true
+ validates :project, presence: true, unless: Proc.new { |service| service.template? }
# Don't allow '?', '&', and ',' for label titles
validates :title,
@@ -34,6 +34,8 @@ class Label < ActiveRecord::Base
default_scope { order(title: :asc) }
+ scope :templates, -> { where(template: true) }
+
alias_attribute :name, :title
def self.reference_prefix
@@ -78,4 +80,8 @@ class Label < ActiveRecord::Base
def open_issues_count
issues.opened.count
end
+
+ def template?
+ template
+ end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 467b90861f9..93faa133875 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -19,6 +19,7 @@
# description :text
# position :integer default(0)
# locked_at :datetime
+# updated_by_id :integer
#
require Rails.root.join("app/models/commit")
diff --git a/app/models/note.rb b/app/models/note.rb
index 36cad8f583d..89d81ab1de2 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -15,6 +15,7 @@
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
+# updated_by_id :integer
#
require 'carrierwave/orm/activerecord'
diff --git a/app/models/project.rb b/app/models/project.rb
index 8e33a4b2f0f..072d7d73f41 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -43,6 +43,8 @@ class Project < ActiveRecord::Base
extend Gitlab::ConfigHelper
extend Enumerize
+ UNKNOWN_IMPORT_URL = 'http://unknown.git'
+
default_value_for :archived, false
default_value_for :visibility_level, gitlab_config_features.visibility_level
default_value_for :issues_enabled, gitlab_config_features.issues
@@ -401,6 +403,15 @@ class Project < ActiveRecord::Base
end
end
+ def create_labels
+ Label.templates.each do |label|
+ label = label.dup
+ label.template = nil
+ label.project_id = self.id
+ label.save
+ end
+ end
+
def find_service(list, name)
list.find { |service| service.to_param == name }
end
diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb
index 39f732c8113..3e2b7faecdb 100644
--- a/app/models/project_services/drone_ci_service.rb
+++ b/app/models/project_services/drone_ci_service.rb
@@ -1,3 +1,23 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
+#
+
class DroneCiService < CiService
prop_accessor :drone_url, :token, :enable_ssl_verification
diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb
index 460ca40be3f..33b113a2a27 100644
--- a/app/models/sent_notification.rb
+++ b/app/models/sent_notification.rb
@@ -1,3 +1,16 @@
+# == Schema Information
+#
+# Table name: sent_notifications
+#
+# id :integer not null, primary key
+# project_id :integer
+# noteable_id :integer
+# noteable_type :string(255)
+# recipient_id :integer
+# commit_id :string(255)
+# reply_key :string(255) not null
+#
+
class SentNotification < ActiveRecord::Base
belongs_to :project
belongs_to :noteable, polymorphic: true
diff --git a/app/models/user.rb b/app/models/user.rb
index 48e0e6ed48b..bff8eeed96d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -2,62 +2,58 @@
#
# Table name: users
#
-# id :integer not null, primary key
-# email :string(255) default(""), not null
-# encrypted_password :string(255) default(""), not null
-# reset_password_token :string(255)
-# reset_password_sent_at :datetime
-# remember_created_at :datetime
-# sign_in_count :integer default(0)
-# current_sign_in_at :datetime
-# last_sign_in_at :datetime
-# current_sign_in_ip :string(255)
-# last_sign_in_ip :string(255)
-# created_at :datetime
-# updated_at :datetime
-# name :string(255)
-# admin :boolean default(FALSE), not null
-# projects_limit :integer default(10)
-# skype :string(255) default(""), not null
-# linkedin :string(255) default(""), not null
-# twitter :string(255) default(""), not null
-# authentication_token :string(255)
-# theme_id :integer default(1), not null
-# bio :string(255)
-# failed_attempts :integer default(0)
-# locked_at :datetime
-# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# color_scheme_id :integer default(1), not null
-# notification_level :integer default(1), not null
-# password_expires_at :datetime
-# created_by_id :integer
-# last_credential_check_at :datetime
-# avatar :string(255)
-# confirmation_token :string(255)
-# confirmed_at :datetime
-# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# github_access_token :string(255)
-# gitlab_access_token :string(255)
-# notification_email :string(255)
-# hide_no_password :boolean default(FALSE)
-# password_automatically_set :boolean default(FALSE)
-# bitbucket_access_token :string(255)
-# bitbucket_access_token_secret :string(255)
-# location :string(255)
-# encrypted_otp_secret :string(255)
-# encrypted_otp_secret_iv :string(255)
-# encrypted_otp_secret_salt :string(255)
-# otp_required_for_login :boolean default(FALSE), not null
-# otp_backup_codes :text
-# public_email :string(255) default(""), not null
-# dashboard :integer default(0)
-# project_view :integer default(0)
+# id :integer not null, primary key
+# email :string(255) default(""), not null
+# encrypted_password :string(255) default(""), not null
+# reset_password_token :string(255)
+# reset_password_sent_at :datetime
+# remember_created_at :datetime
+# sign_in_count :integer default(0)
+# current_sign_in_at :datetime
+# last_sign_in_at :datetime
+# current_sign_in_ip :string(255)
+# last_sign_in_ip :string(255)
+# created_at :datetime
+# updated_at :datetime
+# name :string(255)
+# admin :boolean default(FALSE), not null
+# projects_limit :integer default(10)
+# skype :string(255) default(""), not null
+# linkedin :string(255) default(""), not null
+# twitter :string(255) default(""), not null
+# authentication_token :string(255)
+# theme_id :integer default(1), not null
+# bio :string(255)
+# failed_attempts :integer default(0)
+# locked_at :datetime
+# username :string(255)
+# can_create_group :boolean default(TRUE), not null
+# can_create_team :boolean default(TRUE), not null
+# state :string(255)
+# color_scheme_id :integer default(1), not null
+# notification_level :integer default(1), not null
+# password_expires_at :datetime
+# created_by_id :integer
+# last_credential_check_at :datetime
+# avatar :string(255)
+# confirmation_token :string(255)
+# confirmed_at :datetime
+# confirmation_sent_at :datetime
+# unconfirmed_email :string(255)
+# hide_no_ssh_key :boolean default(FALSE)
+# website_url :string(255) default(""), not null
+# notification_email :string(255)
+# hide_no_password :boolean default(FALSE)
+# password_automatically_set :boolean default(FALSE)
+# location :string(255)
+# encrypted_otp_secret :string(255)
+# encrypted_otp_secret_iv :string(255)
+# encrypted_otp_secret_salt :string(255)
+# otp_required_for_login :boolean default(FALSE), not null
+# otp_backup_codes :text
+# public_email :string(255) default(""), not null
+# dashboard :integer default(0)
+# project_view :integer default(0)
#
require 'carrierwave/orm/activerecord'
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index b35aed005da..1bb2462565a 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -87,6 +87,8 @@ module Projects
@project.build_missing_services
+ @project.create_labels
+
event_service.create_project(@project, current_user)
system_hook_service.execute_hooks_for(@project, :create)
diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb
new file mode 100644
index 00000000000..99f22293d0d
--- /dev/null
+++ b/app/services/projects/download_service.rb
@@ -0,0 +1,43 @@
+module Projects
+ class DownloadService < BaseService
+
+ WHITELIST = [
+ /^[^.]+\.fogbugz.com$/
+ ]
+
+ def initialize(project, url)
+ @project, @url = project, url
+ end
+
+ def execute
+ return nil unless valid_url?(@url)
+
+ uploader = FileUploader.new(@project)
+ uploader.download!(@url)
+ uploader.store!
+
+ filename = uploader.image? ? uploader.file.basename : uploader.file.filename
+
+ {
+ 'alt' => filename,
+ 'url' => uploader.secure_url,
+ 'is_image' => uploader.image?
+ }
+ end
+
+ private
+
+ def valid_url?(url)
+ url && http?(url) && valid_domain?(url)
+ end
+
+ def http?(url)
+ url =~ /\A#{URI::regexp(['http', 'https'])}\z/
+ end
+
+ def valid_domain?(url)
+ host = URI.parse(url).host
+ WHITELIST.any? { |entry| entry === host }
+ end
+ end
+end
diff --git a/app/views/admin/labels/_form.html.haml b/app/views/admin/labels/_form.html.haml
new file mode 100644
index 00000000000..ad58a3837f6
--- /dev/null
+++ b/app/views/admin/labels/_form.html.haml
@@ -0,0 +1,35 @@
+= form_for [:admin, @label], html: { class: 'form-horizontal label-form js-requires-input' } do |f|
+ -if @label.errors.any?
+ .row
+ .col-sm-offset-2.col-sm-10
+ .alert.alert-danger
+ - @label.errors.full_messages.each do |msg|
+ %span= msg
+ %br
+
+ .form-group
+ = f.label :title, class: 'control-label'
+ .col-sm-10
+ = f.text_field :title, class: "form-control", required: true
+ .form-group
+ = f.label :color, "Background Color", class: 'control-label'
+ .col-sm-10
+ .input-group
+ .input-group-addon.label-color-preview &nbsp;
+ = f.color_field :color, class: "form-control"
+ .help-block
+ Choose any color.
+ %br
+ Or you can choose one of suggested colors below
+
+ .suggest-colors
+ - suggested_colors.each do |color|
+ = link_to '#', style: "background-color: #{color}", data: { color: color } do
+ &nbsp;
+
+ .form-actions
+ = f.submit 'Save', class: 'btn btn-save js-save-button'
+ = link_to "Cancel", admin_labels_path, class: 'btn btn-cancel'
+
+:coffeescript
+ new Labels
diff --git a/app/views/admin/labels/_label.html.haml b/app/views/admin/labels/_label.html.haml
new file mode 100644
index 00000000000..596e06243dd
--- /dev/null
+++ b/app/views/admin/labels/_label.html.haml
@@ -0,0 +1,5 @@
+%li{id: dom_id(label)}
+ = render_colored_label(label)
+ .pull-right
+ = link_to 'Edit', edit_admin_label_path(label), class: 'btn btn-sm'
+ = link_to 'Remove', admin_label_path(label), class: 'btn btn-sm btn-remove remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?"}
diff --git a/app/views/admin/labels/destroy.js.haml b/app/views/admin/labels/destroy.js.haml
new file mode 100644
index 00000000000..9d51762890f
--- /dev/null
+++ b/app/views/admin/labels/destroy.js.haml
@@ -0,0 +1,2 @@
+- if @labels.size == 0
+ $('.labels').load(document.URL + ' .light-well').hide().fadeIn(1000)
diff --git a/app/views/admin/labels/edit.html.haml b/app/views/admin/labels/edit.html.haml
new file mode 100644
index 00000000000..45c62a76259
--- /dev/null
+++ b/app/views/admin/labels/edit.html.haml
@@ -0,0 +1,9 @@
+- page_title "Edit", @label.name, "Labels"
+%h3
+ Edit label
+ %span.light #{@label.name}
+.back-link
+ = link_to admin_labels_path do
+ &larr; To labels list
+%hr
+= render 'form'
diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml
new file mode 100644
index 00000000000..8b11c28c56e
--- /dev/null
+++ b/app/views/admin/labels/index.html.haml
@@ -0,0 +1,16 @@
+- page_title "Labels"
+= link_to new_admin_label_path, class: "pull-right btn btn-new" do
+ New label
+%h3.page-title
+ Labels
+%hr
+
+.labels
+ - if @labels.present?
+ %ul.bordered-list.manage-labels-list
+ = render @labels
+ = paginate @labels, theme: 'gitlab'
+ - else
+ .light-well
+ .nothing-here-block There are no any labels yet
+ \ No newline at end of file
diff --git a/app/views/admin/labels/new.html.haml b/app/views/admin/labels/new.html.haml
new file mode 100644
index 00000000000..8d298ad20f7
--- /dev/null
+++ b/app/views/admin/labels/new.html.haml
@@ -0,0 +1,7 @@
+- page_title "New Label"
+%h3 New label
+.back-link
+ = link_to admin_labels_path do
+ &larr; To labels list
+%hr
+= render 'form'
diff --git a/app/views/dashboard/milestones/_milestone.html.haml b/app/views/dashboard/milestones/_milestone.html.haml
index d6f3e029a38..55080d6b3fe 100644
--- a/app/views/dashboard/milestones/_milestone.html.haml
+++ b/app/views/dashboard/milestones/_milestone.html.haml
@@ -1,20 +1,22 @@
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
- %h4
- = link_to_gfm truncate(milestone.title, length: 100), dashboard_milestone_path(milestone.safe_title, title: milestone.title)
+ .row
+ .col-sm-6
+ %strong
+ = link_to_gfm truncate(milestone.title, length: 100), dashboard_milestone_path(milestone.safe_title, title: milestone.title)
+ .col-sm-6
+ .pull-right.light #{milestone.percent_complete}% complete
.row
.col-sm-6
= link_to issues_dashboard_path(milestone_title: milestone.title) do
= pluralize milestone.issue_count, 'Issue'
- &nbsp;
+ &middot;
= link_to merge_requests_dashboard_path(milestone_title: milestone.title) do
= pluralize milestone.merge_requests_count, 'Merge Request'
- &nbsp;
- %span.light #{milestone.percent_complete}% complete
-
.col-sm-6
= milestone_progress_bar(milestone)
- %div
- - milestone.milestones.each do |milestone|
- = link_to milestone_path(milestone) do
- %span.label.label-gray
- = milestone.project.name_with_namespace
+ .row
+ .col-sm-6
+ - milestone.milestones.each do |milestone|
+ = link_to milestone_path(milestone) do
+ %span.label.label-gray
+ = milestone.project.name_with_namespace
diff --git a/app/views/devise/sessions/_new_crowd.html.haml b/app/views/devise/sessions/_new_crowd.html.haml
new file mode 100644
index 00000000000..4974bb7f7fb
--- /dev/null
+++ b/app/views/devise/sessions/_new_crowd.html.haml
@@ -0,0 +1,9 @@
+= form_tag(user_omniauth_authorize_path("crowd"), id: 'new_crowd_user' ) do
+ = text_field_tag :username, nil, {class: "form-control top", placeholder: "Username", autofocus: "autofocus"}
+ = password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
+ - if devise_mapping.rememberable?
+ .remember-me.checkbox
+ %label{for: "remember_me"}
+ = check_box_tag :remember_me, '1', false, id: 'remember_me'
+ %span Remember me
+ = button_tag "Sign in", class: "btn-save btn" \ No newline at end of file
diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml
index bb5e479697d..41ad2c231d4 100644
--- a/app/views/devise/shared/_signin_box.html.haml
+++ b/app/views/devise/shared/_signin_box.html.haml
@@ -8,15 +8,21 @@
.login-body
- if form_based_providers.any?
%ul.nav.nav-tabs
+ - if crowd_enabled?
+ %li.active
+ = link_to "Crowd", "#tab-crowd", 'data-toggle' => 'tab'
- @ldap_servers.each_with_index do |server, i|
- %li{class: (:active if i.zero?)}
+ %li{class: (:active if i.zero? && !crowd_enabled?)}
= link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab'
- if signin_enabled?
%li
= link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
.tab-content
+ - if crowd_enabled?
+ %div.tab-pane.active{id: "tab-crowd"}
+ = render 'devise/sessions/new_crowd'
- @ldap_servers.each_with_index do |server, i|
- %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero?)}
+ %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero? && !crowd_enabled?)}
= render 'devise/sessions/new_ldap', server: server
- if signin_enabled?
%div#tab-signin.tab-pane
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index dba395cc8fa..3a6d07ebddf 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -1,15 +1,13 @@
- page_title "Members"
+- header_title group_title(@group, "Members", group_group_members_path(@group))
- show_roles = should_user_see_group_roles?(current_user, @group)
-%h3.page-title
- Group members
- if show_roles
%p.light
Members of group have access to all group projects.
Read more about permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
-%hr
.clearfix.js-toggle-container
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index f0d90782556..08d97e418a3 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -1,25 +1,24 @@
- page_title "Issues"
+- header_title group_title(@group, "Issues", issues_group_path(@group))
= content_for :meta_tags do
- if current_user
= auto_discovery_link_tag(:atom, issues_group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} issues")
-%h3.page-title
- Issues
-%p.light
- Only issues from
- %strong #{@group.name}
- group are listed here.
- - if current_user
- To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
-%hr
-.append-bottom-20
+= render 'shared/issuable/filter', type: :issues
+.gray-content-block.second-block
.pull-right
- if current_user
.hidden-xs.pull-left
- = link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token), class: 'btn' do
+ = link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token) do
%i.fa.fa-rss
+ %div
+ Only issues from
+ %strong #{@group.name}
+ group are listed here.
+ - if current_user
+ To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
- = render 'shared/issuable/filter', type: :issues
-= render 'shared/issues'
+.prepend-top-default
+ = render 'shared/issues'
diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml
index ca85a158707..425ad8331bf 100644
--- a/app/views/groups/merge_requests.html.haml
+++ b/app/views/groups/merge_requests.html.haml
@@ -1,14 +1,13 @@
- page_title "Merge Requests"
-%h3.page-title
- Merge Requests
+- header_title group_title(@group, "Merge Requests", merge_requests_group_path(@group))
-%p.light
- Only merge requests from
- %strong #{@group.name}
- group are listed here.
- - if current_user
- To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
-%hr
-.append-bottom-20
- = render 'shared/issuable/filter', type: :merge_requests
-= render 'shared/merge_requests'
+= render 'shared/issuable/filter', type: :merge_requests
+.gray-content-block.second-block
+ %div
+ Only merge requests from
+ %strong #{@group.name}
+ group are listed here.
+ - if current_user
+ To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
+.prepend-top-default
+ = render 'shared/merge_requests'
diff --git a/app/views/groups/milestones/_milestone.html.haml b/app/views/groups/milestones/_milestone.html.haml
index ba30e6e07c6..41dffdd2fb8 100644
--- a/app/views/groups/milestones/_milestone.html.haml
+++ b/app/views/groups/milestones/_milestone.html.haml
@@ -1,25 +1,29 @@
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
- .pull-right
- - if can?(current_user, :admin_group, @group)
- - if milestone.closed?
- = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
- - else
- = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-sm btn-close"
- %h4
- = link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
+ .row
+ .col-sm-6
+ %strong
+ = link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
+ .col-sm-6
+ .pull-right.light #{milestone.percent_complete}% complete
.row
.col-sm-6
= link_to issues_group_path(@group, milestone_title: milestone.title) do
= pluralize milestone.issue_count, 'Issue'
- &nbsp;
+ &middot;
= link_to merge_requests_group_path(@group, milestone_title: milestone.title) do
= pluralize milestone.merge_requests_count, 'Merge Request'
- &nbsp;
- %span.light #{milestone.percent_complete}% complete
.col-sm-6
= milestone_progress_bar(milestone)
- %div
- - milestone.milestones.each do |milestone|
- = link_to milestone_path(milestone) do
- %span.label.label-gray
- = milestone.project.name
+ .row
+ .col-sm-6
+ %div
+ - milestone.milestones.each do |milestone|
+ = link_to milestone_path(milestone) do
+ %span.label.label-gray
+ = milestone.project.name
+ .col-sm-6
+ - if can?(current_user, :admin_group, @group)
+ - if milestone.closed?
+ = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-xs btn-grouped btn-reopen"
+ - else
+ = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-xs btn-close"
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index 385222fa5b7..2bbcad5fdfb 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -1,23 +1,17 @@
- page_title "Milestones"
-%h3.page-title
- Milestones
- %span.pull-right #{@group_milestones.count} milestones
+- header_title group_title(@group, "Milestones", group_milestones_path(@group))
-%p.light
+= render 'shared/milestones_filter'
+.gray-content-block
Only milestones from
%strong #{@group.name}
group are listed here.
-
-%hr
-
-= render 'shared/milestones_filter'
.milestones
- .panel.panel-default
- %ul.well-list
- - if @group_milestones.blank?
- %li
- .nothing-here-block No milestones to show
- - else
- - @group_milestones.each do |milestone|
- = render 'milestone', milestone: milestone
+ %ul.content-list
+ - if @group_milestones.blank?
+ %li
+ .nothing-here-block No milestones to show
+ - else
+ - @group_milestones.each do |milestone|
+ = render 'milestone', milestone: milestone
= paginate @group_milestones, theme: "gitlab"
diff --git a/app/views/import/fogbugz/new.html.haml b/app/views/import/fogbugz/new.html.haml
new file mode 100644
index 00000000000..e1bb88ca4ed
--- /dev/null
+++ b/app/views/import/fogbugz/new.html.haml
@@ -0,0 +1,25 @@
+- page_title "FogBugz Import"
+%h3.page-title
+ %i.fa.fa-bug
+ Import projects from FogBugz
+%hr
+
+= form_tag callback_import_fogbugz_path, class: 'form-horizontal' do
+ %p
+ To get started you enter your FogBugz URL and login information below.
+ In the next steps, you'll be able to map users and select the projects
+ you want to import.
+ .form-group
+ = label_tag :uri, 'FogBugz URL', class: 'control-label'
+ .col-sm-4
+ = text_field_tag :uri, nil, placeholder: 'https://mycompany.fogbugz.com', class: 'form-control'
+ .form-group
+ = label_tag :email, 'FogBugz Email', class: 'control-label'
+ .col-sm-4
+ = text_field_tag :email, nil, class: 'form-control'
+ .form-group
+ = label_tag :password, 'FogBugz Password', class: 'control-label'
+ .col-sm-4
+ = password_field_tag :password, nil, class: 'form-control'
+ .form-actions
+ = submit_tag 'Continue to the next step', class: 'btn btn-create'
diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml
new file mode 100644
index 00000000000..25cebfb3665
--- /dev/null
+++ b/app/views/import/fogbugz/new_user_map.html.haml
@@ -0,0 +1,49 @@
+- page_title 'User map', 'FogBugz import'
+%h3.page-title
+ %i.fa.fa-bug
+ Import projects from FogBugz
+%hr
+
+= form_tag create_user_map_import_fogbugz_path, class: 'form-horizontal' do
+ %p
+ Customize how FogBugz email addresses and usernames are imported into GitLab.
+ In the next step, you'll be able to select the projects you want to import.
+ %p
+ The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames wil be imported into GitLab. You can change this by populating the table below.
+ %ul
+ %li
+ %strong Default: Map a FogBugz account ID to a full name
+ %p
+ An empty GitLab User field will add the FogBugz user's full name
+ (e.g. "By John Smith") in the description of all issues and comments.
+ It will also associate and/or assign these issues and comments with
+ the project creator.
+ %li
+ %strong Map a FogBugz account ID to a GitLab user
+ %p
+ Selecting a GitLab user will add a link to the GitLab user in the descriptions
+ of issues and comments (e.g. "By <a href="#">@johnsmith</a>"). It will also
+ associate and/or assign these issues and comments with the selected user.
+
+ %table.table
+ %thead
+ %tr
+ %th ID
+ %th Name
+ %th Email
+ %th GitLab User
+ %tbody
+ - @user_map.each do |id, user|
+ %tr
+ %td= id
+ %td= text_field_tag "users[#{id}][name]", user[:name], class: 'form-control'
+ %td= text_field_tag "users[#{id}][email]", user[:email], class: 'form-control'
+ %td
+ = users_select_tag("users[#{id}][gitlab_user]", class: 'custom-form-control',
+ scope: :all, email_user: true, selected: user[:gitlab_user])
+
+ .form-actions
+ = submit_tag 'Continue to the next step', class: 'btn btn-create'
+
+:coffeescript
+ new UsersSelect()
diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml
new file mode 100644
index 00000000000..f179ece402d
--- /dev/null
+++ b/app/views/import/fogbugz/status.html.haml
@@ -0,0 +1,51 @@
+- page_title "FogBugz import"
+%h3.page-title
+ %i.fa.fa-bug
+ Import projects from FogBugz
+
+- if @repos.any?
+ %p.light
+ Select projects you want to import.
+ %p.light
+ Optionally, you can
+ = link_to 'customize', new_user_map_import_fogbugz_path
+ how FogBugz email addresses and usernames are imported into GitLab.
+ %hr
+ %p
+ = button_tag 'Import all projects', class: 'btn btn-success js-import-all'
+
+%table.table.import-jobs
+ %thead
+ %tr
+ %th From FogBugz
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = project.import_source
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
+
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo.id}"}
+ %td
+ = repo.name
+ %td.import-target
+ = "#{current_user.username}/#{repo.name}"
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
+
+:coffeescript
+ new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}")
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 397649dacf8..c3b137e3ddf 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -3,6 +3,7 @@
%meta{charset: "utf-8"}
%meta{'http-equiv' => 'X-UA-Compatible', content: 'IE=edge'}
%meta{content: "GitLab Community Edition", name: "description"}
+ %meta{name: 'referrer', content: 'origin'}
%title= page_title
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 1275c42000b..c1746676ae2 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -18,8 +18,8 @@
.username
= current_user.username
.content-wrapper
+ = render "layouts/flash"
%div{ class: fluid_layout ? "container-fluid" : "container-fluid container-limited" }
.content
- = render "layouts/flash"
.clearfix
= yield
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index db7dbf9bfe3..4f00d01d4cd 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,5 +1,6 @@
- page_title @group.name
-- header_title @group.name, group_path(@group)
+- unless @header_title
+ - header_title @group.name, group_path(@group)
- sidebar "group" unless sidebar
= render template: "layouts/application"
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index 2065be3828a..3fe0127041e 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -57,6 +57,12 @@
%span
Service Templates
+ = nav_link(controller: :labels) do
+ = link_to admin_labels_path, title: 'Labels', data: {placement: 'right'} do
+ = icon('tags fw')
+ %span
+ Labels
+
= nav_link(controller: :abuse_reports) do
= link_to admin_abuse_reports_path, title: "Abuse reports" do
= icon('exclamation-circle fw')
diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml
index 86133768d77..1261f6254d7 100644
--- a/app/views/projects/_activity.html.haml
+++ b/app/views/projects/_activity.html.haml
@@ -1,5 +1,5 @@
= render 'projects/last_push'
-.gray-content-block
+.gray-content-block.activity-filter-block
- if current_user
%ul.nav.nav-pills.event_filter.pull-right
%li
diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml
index b7bca6dae09..507757f6a2b 100644
--- a/app/views/projects/_md_preview.html.haml
+++ b/app/views/projects/_md_preview.html.haml
@@ -1,6 +1,6 @@
.md-area
.md-header.clearfix
- %ul.nav.nav-tabs
+ %ul.center-top-menu
%li.active
= link_to '#md-write-holder', class: 'js-md-write-button', tabindex: '-1' do
Write
@@ -14,7 +14,7 @@
You are about to add
%strong
%span.js-referenced-users-count 0
- people
+ people
to the discussion. Proceed with caution.
%div
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index a693c4b282f..cc0ec9483d2 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,20 +1,20 @@
- commit = @repository.commit(branch.target)
%li(class="js-branch-#{branch.name}")
- %h4
+ %div
= link_to namespace_project_tree_path(@project.namespace, @project, branch.name) do
%strong.str-truncated= branch.name
+ &nbsp;
- if branch.name == @repository.root_ref
- %span.label.label-info default
+ %span.label.label-primary default
- elsif @repository.merged_to_root_ref? branch.name
- %span.label.label-primary.has_tooltip(title="Merged into #{@repository.root_ref}")
- %i.fa.fa-check
+ %span.label.label-info.has_tooltip(title="Merged into #{@repository.root_ref}")
merged
- if @project.protected_branch? branch.name
%span.label.label-success
%i.fa.fa-lock
protected
- .pull-right
+ .controls.hidden-xs
- if create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-grouped btn-xs' do
= icon('plus')
@@ -30,8 +30,7 @@
= icon("trash-o")
- if commit
- %ul.list-unstyled
- = render 'projects/commits/inline_commit', commit: commit, project: @project
+ = render 'projects/branches/commit', commit: commit, project: @project
- else
%p
Cant find HEAD commit for this branch
diff --git a/app/views/projects/branches/_commit.html.haml b/app/views/projects/branches/_commit.html.haml
new file mode 100644
index 00000000000..68326e65d85
--- /dev/null
+++ b/app/views/projects/branches/_commit.html.haml
@@ -0,0 +1,7 @@
+.branch-commit.light
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
+ &middot;
+ %span.str-truncated
+ = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
+ &middot;
+ #{time_ago_with_tooltip(commit.committed_date)}
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 80acc937908..6e2dc2d2710 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,7 +1,6 @@
- page_title "Branches"
= render "projects/commits/head"
-%h3.page-title
- Branches
+.gray-content-block
.pull-right
- if can? current_user, :push_code, @project
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
@@ -24,9 +23,10 @@
= sort_title_recently_updated
= link_to namespace_project_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated
-%hr
+ .oneline
+ Protected branches can be managed in project settings
- unless @branches.empty?
- %ul.bordered-list.top-list.all-branches
+ %ul.content-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab'
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 3f645b81397..2ac79e87b4a 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -41,7 +41,7 @@
.commit-info-row.branches
%i.fa.fa-spinner.fa-spin
-.commit-box
+.commit-box.gray-content-block.middle-block
%h3.commit-title
= gfm escape_once(@commit.title)
- if @commit.description.present?
diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml
index e3d8cd0fdd5..50c0fd6803d 100644
--- a/app/views/projects/commits/_head.html.haml
+++ b/app/views/projects/commits/_head.html.haml
@@ -1,22 +1,18 @@
-%ul.nav.nav-tabs
+%ul.center-top-menu
= nav_link(controller: [:commit, :commits]) do
= link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref) do
- = icon("history")
Commits
%span.badge= number_with_delimiter(@repository.commit_count)
= nav_link(controller: :compare) do
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: @ref || @repository.root_ref) do
- = icon("exchange")
Compare
= nav_link(html_options: {class: branches_tab_class}) do
= link_to namespace_project_branches_path(@project.namespace, @project) do
- = icon("code-fork")
Branches
%span.badge.js-totalbranch-count= @repository.branches.size
= nav_link(controller: :tags) do
= link_to namespace_project_tags_path(@project.namespace, @project) do
- = icon("tags")
Tags
%span.badge.js-totaltags-count= @repository.tags.length
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 55054a31977..a01a99458a0 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -5,22 +5,23 @@
= render "head"
-.tree-ref-holder
- = render 'shared/ref_switcher', destination: 'commits'
+.gray-content-block
+ .tree-ref-holder
+ = render 'shared/ref_switcher', destination: 'commits'
-.commits-feed-holder.hidden-xs.hidden-sm
- - if create_mr_button?(@repository.root_ref, @ref)
- = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
- = icon('plus')
- Create Merge Request
+ .commits-feed-holder.hidden-xs.hidden-sm
+ - if create_mr_button?(@repository.root_ref, @ref)
+ = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
+ = icon('plus')
+ Create Merge Request
- - if current_user && current_user.private_token
- = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'prepend-left-10 btn' do
- = icon("rss")
+ - if current_user && current_user.private_token
+ = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'prepend-left-10 btn' do
+ = icon("rss")
-%ul.breadcrumb.repo-breadcrumb
- = commits_breadcrumbs
+ %ul.breadcrumb.repo-breadcrumb
+ = commits_breadcrumbs
%div{id: dom_id(@project)}
#commits-list= render "commits", project: @project
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index 3019893d12c..efc25eda26b 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -1,5 +1,5 @@
= form_tag namespace_project_compare_index_path(@project.namespace, @project), method: :post, class: 'form-inline js-requires-input' do
- .clearfix.append-bottom-20
+ .clearfix
- if params[:to] && params[:from]
= link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has_tooltip', title: 'Switch base of comparison'}
.form-group
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index d1e579a2ede..43d00726c48 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,9 +1,7 @@
- page_title "Compare"
= render "projects/commits/head"
-%h3.page-title
- Compare View
-%p.slead
+.gray-content-block
Compare branches, tags or commit ranges.
%br
Fill input field with commit id like
@@ -14,4 +12,5 @@
%br
Changes are shown <b>from</b> the version in the first field <b>to</b> the version in the second field.
-= render "form"
+.prepend-top-20
+ = render "form"
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 3670dd5c13b..8800ffdf482 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,16 +1,16 @@
- page_title "#{params[:from]}...#{params[:to]}"
= render "projects/commits/head"
-%h3.page-title
- Compare View
-= render "form"
+.gray-content-block
+ = render "form"
- if @commits.present?
- = render "projects/commits/commit_list"
- = render "projects/diffs/diffs", diffs: @diffs, project: @project
+ .prepend-top-20
+ = render "projects/commits/commit_list"
+ = render "projects/diffs/diffs", diffs: @diffs, project: @project
- else
- .light-well
+ .light-well.prepend-top-20
.center
%h4
There isn't anything to compare.
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 30943f49bba..2f24dc7c909 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -1,8 +1,8 @@
- if params[:view] == 'parallel'
- fluid_layout true
-.prepend-top-20.append-bottom-20
- .pull-right
+.gray-content-block.second-block
+ .inline-parallel-buttons
.btn-group
= inline_diff_btn
= parallel_diff_btn
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index 1625930615a..c4d7f26430b 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -10,7 +10,7 @@
and
%strong.cred #{@commit.stats.deletions} deletions
.file-stats.js-toggle-content.hide
- %ul.bordered-list
+ %ul
- diffs.each_with_index do |diff, i|
%li
- if diff.deleted_file
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index e577d35d560..798f1c47da5 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -22,15 +22,15 @@
%h5 Git global setup
%pre.light-well
:preserve
- git config --global user.name "#{git_user_name}"
- git config --global user.email "#{git_user_email}"
+ git config --global user.name "#{h git_user_name}"
+ git config --global user.email "#{h git_user_email}"
%fieldset
%h5 Create a new repository
%pre.light-well
:preserve
git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')}
- cd #{@project.path}
+ cd #{h @project.path}
touch README.md
git add README.md
git commit -m "add README"
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index f61ae957208..d4a98eca473 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -7,21 +7,24 @@
= render 'shared/show_aside'
+.gray-content-block.second-block
+ .row
+ .col-md-9
+ .votes-holder.pull-right
+ #votes= render 'votes/votes_block', votable: @issue
+ .participants
+ %span= pluralize(@participants.count, 'participant')
+ - @participants.each do |participant|
+ = link_to_member(@project, participant, name: false, size: 24)
+ .col-md-3
+ %span.slead.has_tooltip{title: 'Cross-project reference'}
+ = cross_project_reference(@project, @issue)
+
.row
%section.col-md-9
- .votes-holder.pull-right
- #votes= render 'votes/votes_block', votable: @issue
- .participants
- %span= pluralize(@participants.count, 'participant')
- - @participants.each do |participant|
- = link_to_member(@project, participant, name: false, size: 24)
.voting_notes#notes= render 'projects/notes/notes_with_form'
%aside.col-md-3
.issuable-affix
- .clearfix
- %span.slead.has_tooltip{title: 'Cross-project reference'}
- = cross_project_reference(@project, @issue)
- %hr
.context
= render 'shared/issuable/context', issuable: @issue
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index b6910c8f796..55ce912829d 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -41,4 +41,4 @@
= issue.task_status
.pull-right.issue-updated-at
- %small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
+ %span updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index e7b14e7582c..09080642293 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,15 +1,16 @@
- page_title "#{@issue.title} (##{@issue.iid})", "Issues"
.issue
.issue-details.issuable-details
- %h4.page-title
+ .page-title
.issue-box{ class: issue_box_class(@issue) }
- if @issue.closed?
Closed
- else
Open
- Issue ##{@issue.iid}
- %small.creator
- &middot; created by #{link_to_member(@project, @issue.author)}
+ %span.issue-id Issue ##{@issue.iid}
+ %span.creator
+ &middot; created by #{link_to_member(@project, @issue.author, size: 24)}
+ &middot;
= time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago')
- if @issue.updated_at != @issue.created_at
%span
@@ -32,18 +33,17 @@
= icon('pencil-square-o')
Edit
- %hr
- %h2.issue-title
- = gfm escape_once(@issue.title)
- %div
- - if @issue.description.present?
- .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
- .wiki
- = preserve do
- = markdown(@issue.description)
- %textarea.hidden.js-task-list-field
- = @issue.description
+ .gray-content-block.middle-block
+ %h2.issue-title
+ = gfm escape_once(@issue.title)
+ %div
+ - if @issue.description.present?
+ .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
+ .wiki
+ = preserve do
+ = markdown(@issue.description)
+ %textarea.hidden.js-task-list-field
+ = @issue.description
- %hr
.issue-discussion
= render 'projects/issues/discussion'
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index f855dfec321..38e66c3828b 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -7,18 +7,21 @@
= render 'shared/show_aside'
+.gray-content-block.second-block
+ .row
+ .col-md-9
+ .votes-holder.pull-right
+ #votes= render 'votes/votes_block', votable: @merge_request
+ = render "projects/merge_requests/show/participants"
+ .col-md-3
+ %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
+ = cross_project_reference(@project, @merge_request)
+
.row
%section.col-md-9
- .votes-holder.pull-right
- #votes= render 'votes/votes_block', votable: @merge_request
- = render "projects/merge_requests/show/participants"
= render "projects/notes/notes_with_form"
%aside.col-md-3
.issuable-affix
- .clearfix
- %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
- = cross_project_reference(@project, @merge_request)
- %hr
.context
= render 'shared/issuable/context', issuable: @merge_request
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 4295c828dad..25e4e8ba80d 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -43,4 +43,4 @@
= merge_request.task_status
.pull-right.hidden-xs
- %small updated #{time_ago_with_tooltip(merge_request.updated_at, placement: 'bottom', html_class: 'merge_request_updated_ago')}
+ %span updated #{time_ago_with_tooltip(merge_request.updated_at, placement: 'bottom', html_class: 'merge_request_updated_ago')}
diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml
index 7709330611a..452006162db 100644
--- a/app/views/projects/merge_requests/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/_new_compare.html.haml
@@ -37,7 +37,7 @@
%h4 Compare failed
%p We can't compare selected branches. It may be because of huge diff. Please try again or select different branches.
- else
- .light-well
+ .light-well.append-bottom-10
.center
%h4
There isn't anything to merge.
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index 76f44211dac..46aeecd8733 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -18,15 +18,13 @@
= f.hidden_field :target_branch
.mr-compare.merge-request
- %ul.nav.nav-tabs.merge-request-tabs
+ %ul.merge-request-tabs
%li.commits-tab
= link_to url_for(params), data: {target: '#commits', action: 'commits', toggle: 'tab'} do
- = icon('history')
Commits
%span.badge= @commits.size
%li.diffs-tab.active
= link_to url_for(params), data: {target: '#diffs', action: 'diffs', toggle: 'tab'} do
- = icon('list-alt')
Changes
%span.badge= @diffs.size
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index ec1838eb489..61e04dce5ab 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -5,10 +5,8 @@
.merge-request{'data-url' => merge_request_path(@merge_request)}
.merge-request-details.issuable-details
= render "projects/merge_requests/show/mr_title"
- %hr
= render "projects/merge_requests/show/mr_box"
- %hr
- .append-bottom-20.mr-source-target
+ .append-bottom-20.mr-source-target.prepend-top-default
- if @merge_request.open?
.pull-right
- if @merge_request.source_branch_exists?
@@ -39,20 +37,17 @@
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- if @commits.present?
- %ul.nav.nav-tabs.merge-request-tabs
+ %ul.merge-request-tabs
%li.notes-tab
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#notes', action: 'notes', toggle: 'tab'} do
- = icon('comments')
Discussion
%span.badge= @merge_request.mr_and_commit_notes.user.count
%li.commits-tab
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#commits', action: 'commits', toggle: 'tab'} do
- = icon('history')
Commits
%span.badge= @commits.size
%li.diffs-tab
= link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#diffs', action: 'diffs', toggle: 'tab'} do
- = icon('list-alt')
Changes
%span.badge= @merge_request.diffs.size
diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
index db1575f899a..f18cf96c17d 100644
--- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -11,12 +11,12 @@
%pre.dark
- if @merge_request.for_fork?
:preserve
- git fetch #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch}
- git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} FETCH_HEAD
+ git fetch #{h @merge_request.source_project.http_url_to_repo} #{h @merge_request.source_branch}
+ git checkout -b #{h @merge_request.source_project_path}-#{h @merge_request.source_branch} FETCH_HEAD
- else
:preserve
git fetch origin
- git checkout -b #{@merge_request.source_branch} origin/#{@merge_request.source_branch}
+ git checkout -b #{h @merge_request.source_branch} origin/#{h @merge_request.source_branch}
%p
%strong Step 2.
Review the changes locally
@@ -27,18 +27,18 @@
%pre.dark
- if @merge_request.for_fork?
:preserve
- git checkout #{@merge_request.target_branch}
- git merge --no-ff #{@merge_request.source_project_path}-#{@merge_request.source_branch}
+ git checkout #{h @merge_request.target_branch}
+ git merge --no-ff #{h @merge_request.source_project_path}-#{h @merge_request.source_branch}
- else
:preserve
- git checkout #{@merge_request.target_branch}
- git merge --no-ff #{@merge_request.source_branch}
+ git checkout #{h @merge_request.target_branch}
+ git merge --no-ff #{h @merge_request.source_branch}
%p
%strong Step 4.
Push the result of the merge to GitLab
%pre.dark
:preserve
- git push origin #{@merge_request.target_branch}
+ git push origin #{h @merge_request.target_branch}
- unless @merge_request.can_be_merged_by?(current_user)
%p
Note that pushing to GitLab requires write access to this repository.
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index e3cd4346872..b4f62a75890 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,11 +1,12 @@
-%h2.issue-title
- = gfm escape_once(@merge_request.title)
+.gray-content-block.middle-block
+ %h2.issue-title
+ = gfm escape_once(@merge_request.title)
-%div
- - if @merge_request.description.present?
- .description{class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : ''}
- .wiki
- = preserve do
- = markdown(@merge_request.description)
- %textarea.hidden.js-task-list-field
- = @merge_request.description
+ %div
+ - if @merge_request.description.present?
+ .description{class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : ''}
+ .wiki
+ = preserve do
+ = markdown(@merge_request.description)
+ %textarea.hidden.js-task-list-field
+ = @merge_request.description
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 9a1eb36fc88..2bf9cd597a4 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,10 +1,11 @@
-%h4.page-title
+.page-title
.issue-box{ class: issue_box_class(@merge_request) }
= @merge_request.state_human_name
- Merge Request ##{@merge_request.iid}
- %small.creator
+ %span.issue-id Merge Request ##{@merge_request.iid}
+ %span.creator
+ &middot;
+ created by #{link_to_member(@project, @merge_request.author, size: 24)}
&middot;
- created by #{link_to_member(@project, @merge_request.author)}
= time_ago_with_tooltip(@merge_request.created_at)
- if @merge_request.updated_at != @merge_request.created_at
%span
diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml
index b61e193fc42..613525437ab 100644
--- a/app/views/projects/merge_requests/widget/open/_accept.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml
@@ -9,7 +9,7 @@
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= check_box_tag :should_remove_source_branch
Remove source branch
- .accept-control
+ .accept-control.right
= link_to "#", class: "modify-merge-commit-link js-toggle-button" do
= icon('edit')
Modify commit message
diff --git a/app/views/projects/milestones/_milestone.html.haml b/app/views/projects/milestones/_milestone.html.haml
index 2ce5358fa74..5e93d55b1fb 100644
--- a/app/views/projects/milestones/_milestone.html.haml
+++ b/app/views/projects/milestones/_milestone.html.haml
@@ -1,28 +1,34 @@
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) }
- .pull-right
- - if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
- = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-sm edit-milestone-link btn-grouped" do
- %i.fa.fa-pencil-square-o
- Edit
- = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-sm btn-close"
- = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-sm btn-remove" do
- %i.fa.fa-trash-o
- Remove
+ .row
+ .col-sm-6
+ %strong
+ = link_to_gfm truncate(milestone.title, length: 100), namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
- %h4
- = link_to_gfm truncate(milestone.title, length: 100), namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
- - if milestone.expired? and not milestone.closed?
- %span.cred (Expired)
- %small
- = milestone.expires_at
+ .col-sm-6
+ .pull-right.light #{milestone.percent_complete}% complete
.row
.col-sm-6
= link_to namespace_project_issues_path(milestone.project.namespace, milestone.project, milestone_title: milestone.title) do
= pluralize milestone.issues.count, 'Issue'
- &nbsp;
+ &middot;
= link_to namespace_project_merge_requests_path(milestone.project.namespace, milestone.project, milestone_title: milestone.title) do
= pluralize milestone.merge_requests.count, 'Merge Request'
- &nbsp;
- %span.light #{milestone.percent_complete}% complete
.col-sm-6
= milestone_progress_bar(milestone)
+
+ .row
+ .col-sm-6
+ - if milestone.expired? and not milestone.closed?
+ %span.cred (Expired)
+ - if milestone.expires_at
+ %span
+ = milestone.expires_at
+ .col-sm-6
+ - if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
+ = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-xs edit-milestone-link btn-grouped" do
+ %i.fa.fa-pencil-square-o
+ Edit
+ = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close"
+ = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-xs btn-remove" do
+ %i.fa.fa-trash-o
+ Remove
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 995eecd7830..2b8fd671587 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -1,18 +1,21 @@
- page_title "Milestones"
-.pull-right
- - if can? current_user, :admin_milestone, @project
- = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do
- %i.fa.fa-plus
- New Milestone
= render 'shared/milestones_filter'
+.gray-content-block
+ .pull-right
+ - if can? current_user, :admin_milestone, @project
+ = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do
+ %i.fa.fa-plus
+ New Milestone
+ .oneline
+ Milestone allows you to group issues and set due date for it
+
.milestones
- .panel.panel-default
- %ul.well-list
- = render @milestones
+ %ul.content-list
+ = render @milestones
- - if @milestones.blank?
- %li
- .nothing-here-block No milestones to show
+ - if @milestones.blank?
+ %li
+ .nothing-here-block No milestones to show
= paginate @milestones, theme: "gitlab"
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 636218368cc..bccea21e7a8 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -72,6 +72,11 @@
%i.fa.fa-google
Google Code
+ - if fogbugz_import_enabled?
+ = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do
+ %i.fa.fa-bug
+ Fogbugz
+
- if git_import_enabled?
= link_to "#", class: 'btn js-toggle-button import_git' do
%i.fa.fa-git
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index de75d44fc41..9bfbde02ca2 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -1,11 +1,8 @@
%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)], data: { discussion: note.discussion_id } }
.timeline-entry-inner
.timeline-icon
- - if note.system
- %span= icon('circle')
- - else
- = link_to user_path(note.author) do
- = image_tag avatar_icon(note.author_email), class: 'avatar s40', alt: ''
+ = link_to user_path(note.author) do
+ = image_tag avatar_icon(note.author_email), class: 'avatar s40', alt: ''
.timeline-content
.note-header
- if note_editable?(note)
@@ -22,10 +19,6 @@
%span.note-role.label
= member.human_access
- - if note.system
- = link_to user_path(note.author) do
- = image_tag avatar_icon(note.author_email), class: 'avatar s16', alt: ''
-
= link_to_member(note.project, note.author, avatar: false)
%span.author-username
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index d575891fd46..d5c4ee71978 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -65,9 +65,11 @@
%section
- if prefer_readme?
- = render 'projects/readme'
+ .project-show-readme
+ = render 'projects/readme'
- else
- = render 'projects/activity'
+ .project-show-activity
+ = render 'projects/activity'
- if current_user
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index 28ad272322f..2ca295fc5f3 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -1,13 +1,14 @@
- commit = @repository.commit(tag.target)
%li
- %h4
+ %div
= link_to namespace_project_commits_path(@project.namespace, @project, tag.name), class: "" do
- %i.fa.fa-tag
- = tag.name
+ %strong
+ %i.fa.fa-tag
+ = tag.name
- if tag.message.present?
&nbsp;
= strip_gpg_signature(tag.message)
- .pull-right
+ .controls
- if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-xs'
- if can?(current_user, :admin_project, @project)
@@ -15,8 +16,7 @@
%i.fa.fa-trash-o
- if commit
- %ul.list-unstyled
- = render 'projects/commits/inline_commit', commit: commit, project: @project
+ = render 'projects/branches/commit', commit: commit, project: @project
- else
%p
Cant find HEAD commit for this tag
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index d4652a47cba..1503a4330f4 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -1,21 +1,18 @@
- page_title "Tags"
= render "projects/commits/head"
-%h3.page-title
- Git Tags
+.gray-content-block
- if can? current_user, :push_code, @project
.pull-right
= link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do
%i.fa.fa-add-sign
New tag
-
-%p.light
- Tags give the ability to mark specific points in history as being important
-%hr
+ .oneline
+ Tags give the ability to mark specific points in history as being important
.tags
- unless @tags.empty?
- %ul.bordered-list
+ %ul.content-list
- @tags.each do |tag|
= render 'tag', tag: @repository.find_tag(tag)
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree.html.haml
index 5048154cb2f..367a87927d7 100644
--- a/app/views/projects/tree/_tree.html.haml
+++ b/app/views/projects/tree/_tree.html.haml
@@ -14,7 +14,7 @@
%small
%i.fa.fa-plus
-%div#tree-content-holder.tree-content-holder
+%div#tree-content-holder.tree-content-holder.prepend-top-20
%table#tree-slider{class: "table_#{@hex_path} tree-table" }
%thead
%tr
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 788bb8cf1e2..14f25822259 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,8 +1,15 @@
%span.pull-right
+ - if can?(current_user, :create_wiki, @project)
+ = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new btn-grouped", "data-toggle" => "modal" do
+ %i.fa.fa-plus
+ New Page
+
- if (@page && @page.persisted?)
- = link_to history_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
+ = link_to namespace_project_wiki_history_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
Page History
- if can?(current_user, :create_wiki, @project)
- = link_to edit_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
+ = link_to namespace_project_wiki_edit_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
+
+= render 'projects/wikis/new'
diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml
index 804a1b52dbe..fffb4eb31ab 100644
--- a/app/views/projects/wikis/_nav.html.haml
+++ b/app/views/projects/wikis/_nav.html.haml
@@ -1,19 +1,10 @@
-%ul.nav.nav-tabs
+%ul.center-top-menu
= nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do
= link_to 'Home', namespace_project_wiki_path(@project.namespace, @project, :home)
= nav_link(path: 'wikis#pages') do
- = link_to 'Pages', pages_namespace_project_wikis_path(@project.namespace, @project)
+ = link_to 'Pages', namespace_project_wiki_pages_path(@project.namespace, @project)
= nav_link(path: 'wikis#git_access') do
- = link_to git_access_namespace_project_wikis_path(@project.namespace, @project) do
- %i.fa.fa-download
+ = link_to namespace_project_wikis_git_access_path(@project.namespace, @project) do
Git Access
-
- - if can?(current_user, :create_wiki, @project)
- .pull-right
- = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
- %i.fa.fa-plus
- New Page
-
-= render 'projects/wikis/new'
diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml
index 825f2a161c4..226fd3b2290 100644
--- a/app/views/projects/wikis/git_access.html.haml
+++ b/app/views/projects/wikis/git_access.html.haml
@@ -1,15 +1,16 @@
- page_title "Git Access", "Wiki"
= render 'nav'
-.row
- .col-sm-6
- %h3.page-title
- Git access for
- %strong= @project_wiki.path_with_namespace
+.gray-content-block
+ .row
+ .col-sm-6
+ %h3.page-title
+ Git access for
+ %strong= @project_wiki.path_with_namespace
- .col-sm-6
- = render "shared/clone_panel", project: @project_wiki
+ .col-sm-6
+ = render "shared/clone_panel", project: @project_wiki
-.git-empty
+.git-empty.prepend-top-default
%fieldset
%legend Install Gollum:
%pre.dark
@@ -20,7 +21,7 @@
%pre.dark
:preserve
git clone #{ content_tag(:span, default_url_to_repo(@project_wiki), class: 'clone')}
- cd #{@project_wiki.path}
+ cd #{h @project_wiki.path}
%legend Start Gollum And Edit Locally:
%pre.dark
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index 673ec2d20e5..7c81ad53d32 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -1,8 +1,9 @@
- page_title "History", @page.title, "Wiki"
= render 'nav'
-%h3.page-title
- %span.light History for
- = link_to @page.title, namespace_project_wiki_path(@project.namespace, @project, @page)
+.gray-content-block
+ %h3.page-title
+ %span.light History for
+ = link_to @page.title, namespace_project_wiki_path(@project.namespace, @project, @page)
%table.table
%thead
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
index 890ff1aed73..7fb91507eb2 100644
--- a/app/views/projects/wikis/pages.html.haml
+++ b/app/views/projects/wikis/pages.html.haml
@@ -1,8 +1,9 @@
- page_title "All Pages", "Wiki"
= render 'nav'
-%h3.page-title
- All Pages
-%ul.bordered-list
+.gray-content-block
+ %h3.page-title
+ All Pages
+%ul.content-list
- @wiki_pages.each do |wiki_page|
%li
%h4
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index 5c4dd7f91ae..126810811ec 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -1,25 +1,26 @@
- page_title @page.title, "Wiki"
= render 'nav'
-%h3.page-title
- = @page.title
+
+.gray-content-block
= render 'main_links'
+ %h3.page-title
+ = @page.title.capitalize
-.wiki-last-edit-by
- Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
+ .wiki-last-edit-by
+ Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
- if @page.historical?
.warning_message
This is an old version of this page.
- You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", history_namespace_project_wiki_path(@project.namespace, @project, @page)}.
+ You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", namespace_project_wiki_history_path(@project.namespace, @project, @page)}.
-%hr
-.wiki-holder
+.wiki-holder.prepend-top-default
.wiki
= preserve do
= render_wiki_content(@page)
-%hr
-.wiki-last-edit-by
- Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
+.gray-content-block.footer-block
+ .wiki-last-edit-by
+ Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index f2ba2e15e7b..ea2808045eb 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -7,22 +7,31 @@ class RepositoryImportWorker
def perform(project_id)
project = Project.find(project_id)
- import_result = gitlab_shell.send(:import_repository,
+ unless project.import_url == Project::UNKNOWN_IMPORT_URL
+ import_result = gitlab_shell.send(:import_repository,
project.path_with_namespace,
project.import_url)
- return project.import_fail unless import_result
+ return project.import_fail unless import_result
+ else
+ unless project.create_repository
+ return project.import_fail
+ end
+ end
- data_import_result = if project.import_type == 'github'
- Gitlab::GithubImport::Importer.new(project).execute
- elsif project.import_type == 'gitlab'
- Gitlab::GitlabImport::Importer.new(project).execute
- elsif project.import_type == 'bitbucket'
- Gitlab::BitbucketImport::Importer.new(project).execute
- elsif project.import_type == 'google_code'
- Gitlab::GoogleCodeImport::Importer.new(project).execute
- else
- true
- end
+ 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
return project.import_fail unless data_import_result
Gitlab::BitbucketImport::KeyDeleter.new(project).execute if project.import_type == 'bitbucket'
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index c7b60a1d4b1..9eb99dae456 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -246,6 +246,11 @@ production: &base
# issuer: 'https://gitlab.example.com',
# name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
# } }
+ # - { name: 'crowd',
+ # args: {
+ # crowd_server_url: 'CROWD SERVER URL',
+ # application_name: 'YOUR_APP_NAME',
+ # application_password: 'YOUR_APP_PASSWORD' } }
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index c47e5dab27c..689c3f3049d 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -158,7 +158,7 @@ Settings.gitlab.default_projects_features['snippets'] = false if Settings.
Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
Settings.gitlab['repository_downloads_path'] = File.absolute_path(Settings.gitlab['repository_downloads_path'] || 'tmp/repositories', Rails.root)
Settings.gitlab['restricted_signup_domains'] ||= []
-Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious','google_code','git']
+Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git']
#
# Reply by email
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 091548348b1..2ce24592f8b 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -238,7 +238,7 @@ Devise.setup do |config|
provider_arguments.concat provider['args']
when Hash
# A Hash from the configuration will be passed as is.
- provider_arguments << provider['args']
+ provider_arguments << provider['args'].symbolize_keys
end
config.omniauth provider['name'].to_sym, *provider_arguments
diff --git a/config/routes.rb b/config/routes.rb
index a98c0f8aa77..011af4825fa 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -99,6 +99,15 @@ Gitlab::Application.routes.draw do
get :new_user_map, path: :user_map
post :create_user_map, path: :user_map
end
+
+ resource :fogbugz, only: [:create, :new], controller: :fogbugz do
+ get :status
+ post :callback
+ get :jobs
+
+ get :new_user_map, path: :user_map
+ post :create_user_map, path: :user_map
+ end
end
#
@@ -201,6 +210,8 @@ Gitlab::Application.routes.draw do
resources :services
end
+ resources :labels
+
root to: 'dashboard#index'
end
@@ -406,16 +417,20 @@ Gitlab::Application.routes.draw do
end
end
- resources :wikis, only: [:show, :edit, :destroy, :create], constraints: { id: /[a-zA-Z.0-9_\-\/]+/ } do
- collection do
- get :pages
- put ':id' => 'wikis#update'
- get :git_access
- end
+ WIKI_SLUG_ID = { id: /[a-zA-Z.0-9_\-\/]+/ } unless defined? WIKI_SLUG_ID
- member do
- get 'history'
- end
+ scope do
+ # Order matters to give priority to these matches
+ get '/wikis/git_access', to: 'wikis#git_access'
+ get '/wikis/pages', to: 'wikis#pages', as: 'wiki_pages'
+ post '/wikis', to: 'wikis#create'
+
+ get '/wikis/*id/history', to: 'wikis#history', as: 'wiki_history', constraints: WIKI_SLUG_ID
+ get '/wikis/*id/edit', to: 'wikis#edit', as: 'wiki_edit', constraints: WIKI_SLUG_ID
+
+ get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID
+ delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID
+ put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID
end
resource :repository, only: [:show, :create] do
diff --git a/db/migrate/20150902001023_add_template_to_label.rb b/db/migrate/20150902001023_add_template_to_label.rb
new file mode 100644
index 00000000000..bd381a97b69
--- /dev/null
+++ b/db/migrate/20150902001023_add_template_to_label.rb
@@ -0,0 +1,5 @@
+class AddTemplateToLabel < ActiveRecord::Migration
+ def change
+ add_column :labels, :template, :boolean, default: false
+ end
+end \ No newline at end of file
diff --git a/db/schema.rb b/db/schema.rb
index 36568dd4edd..55cbd8c293e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150824002011) do
+ActiveRecord::Schema.define(version: 20150902001023) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -186,6 +186,7 @@ ActiveRecord::Schema.define(version: 20150824002011) do
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
+ t.boolean "template", default: false
end
add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 52031e9b9a1..ee13b0f2537 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -299,7 +299,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
GitLab Shell is an SSH access and repository management software developed specially for GitLab.
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
- sudo -u git -H bundle exec rake gitlab:shell:install[v2.6.3] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
+ sudo -u git -H bundle exec rake gitlab:shell:install[v2.6.5] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main GitLab config.
# You can review (and modify) the gitlab-shell config as follows:
diff --git a/doc/integration/crowd.md b/doc/integration/crowd.md
new file mode 100644
index 00000000000..2ecc8795ac1
--- /dev/null
+++ b/doc/integration/crowd.md
@@ -0,0 +1,58 @@
+# Crowd OmniAuth Provider
+
+To enable the Crowd OmniAuth provider you must register your application with Crowd. To configure Crowd integration you need an application name and password.
+
+1. On your GitLab server, open the configuration file.
+
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For instalations from source:
+
+ ```sh
+ cd /home/git/gitlab
+
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "crowd",
+ "args" => {
+ "crowd_server_url" => "CROWD",
+ "application_name" => "YOUR_APP_NAME",
+ "application_password" => "YOUR_APP_PASSWORD"
+ }
+ }
+ ]
+ ```
+
+ For installations from source:
+
+ ```
+ - { name: 'crowd',
+ args: {
+ crowd_server_url: 'CROWD SERVER URL',
+ application_name: 'YOUR_APP_NAME',
+ application_password: 'YOUR_APP_PASSWORD' } }
+ ```
+
+1. Change 'YOUR_APP_NAME' to the application name from Crowd applications page.
+
+1. Change 'YOUR_APP_PASSWORD' to the application password you've set.
+
+1. Save the configuration file.
+
+1. Restart GitLab for the changes to take effect.
+
+On the sign in page there should now be a Crowd tab in the sign in form. \ No newline at end of file
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 2010cb9b8a1..c5cecbc2f2d 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -76,6 +76,7 @@ Now we can choose one or more of the Supported Providers below to continue confi
- [Shibboleth](shibboleth.md)
- [Twitter](twitter.md)
- [SAML](saml.md)
+- [Crowd](crowd.md)
## Enable OmniAuth for an Existing User
diff --git a/doc/update/6.x-or-7.x-to-7.14.md b/doc/update/6.x-or-7.x-to-7.14.md
index a1488474f60..5bc1f84270a 100644
--- a/doc/update/6.x-or-7.x-to-7.14.md
+++ b/doc/update/6.x-or-7.x-to-7.14.md
@@ -127,7 +127,7 @@ sudo apt-get install nodejs
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v2.6.4
+sudo -u git -H git checkout v2.6.5
```
## 7. Install libs, migrations, etc.
@@ -167,7 +167,7 @@ git diff 6-0-stable:config/gitlab.yml.example 7.14-stable:config/gitlab.yml.exam
* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-14-stable/config/gitlab.yml.example but with your settings.
* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-14-stable/config/unicorn.rb.example but with your settings.
-* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.6.0/config.yml.example but with your settings.
+* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.6.5/config.yml.example but with your settings.
* Copy rack attack middleware config
```bash
diff --git a/doc/update/7.13-to-7.14.md b/doc/update/7.13-to-7.14.md
index 7c2d3f4498a..6dd9727fb49 100644
--- a/doc/update/7.13-to-7.14.md
+++ b/doc/update/7.13-to-7.14.md
@@ -63,7 +63,7 @@ sudo -u git -H git checkout 7-14-stable-ee
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v2.6.4
+sudo -u git -H git checkout v2.6.5
```
### 5. Install libs, migrations, etc.
diff --git a/doc/workflow/importing/README.md b/doc/workflow/importing/README.md
index 5cde90993d2..7ccf06fbd60 100644
--- a/doc/workflow/importing/README.md
+++ b/doc/workflow/importing/README.md
@@ -3,6 +3,7 @@
1. [Bitbucket](import_projects_from_bitbucket.md)
2. [GitHub](import_projects_from_github.md)
3. [GitLab.com](import_projects_from_gitlab_com.md)
+4. [FogBugz](import_projects_from_fogbugz.md)
4. [SVN](migrating_from_svn.md)
### Note
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png
new file mode 100644
index 00000000000..205c515bd3f
--- /dev/null
+++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_finished.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png
new file mode 100644
index 00000000000..a1e348d46ad
--- /dev/null
+++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_login.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png
new file mode 100644
index 00000000000..ed362846909
--- /dev/null
+++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_fogbogz.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png
new file mode 100644
index 00000000000..d2fbd0267bd
--- /dev/null
+++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_select_project.png
Binary files differ
diff --git a/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png b/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png
new file mode 100644
index 00000000000..b1cc4b58525
--- /dev/null
+++ b/doc/workflow/importing/fogbugz_importer/fogbugz_import_user_map.png
Binary files differ
diff --git a/doc/workflow/importing/import_projects_from_fogbugz.md b/doc/workflow/importing/import_projects_from_fogbugz.md
new file mode 100644
index 00000000000..71af0f9ea44
--- /dev/null
+++ b/doc/workflow/importing/import_projects_from_fogbugz.md
@@ -0,0 +1,29 @@
+# Import your project from FogBugz to GitLab
+
+It only takes a few simple steps to import your project from FogBugz.
+The importer will import all of your cases and comments with original case
+numbers and timestamps. You will also have the opportunity to map FogBugz
+users to GitLab users.
+
+* From your GitLab dashboard click 'New project'
+
+* Click on the 'FogBugz' button
+
+![FogBugz](fogbugz_importer/fogbugz_import_select_fogbogz.png)
+
+* Enter your FogBugz URL, email address, and password.
+
+![Login](fogbugz_importer/fogbugz_import_login.png)
+
+* Create mapping from FogBugz users to GitLab users.
+
+![User Map](fogbugz_importer/fogbugz_import_user_map.png)
+
+* Select the projects you wish to import by clicking the Import buttons
+
+![Import Project](fogbugz_importer/fogbugz_import_select_project.png)
+
+* Once the import has finished click the link to take you to the project
+dashboard. Follow the directions to push your existing repository.
+
+![Finished](fogbugz_importer/fogbugz_import_finished.png)
diff --git a/features/admin/labels.feature b/features/admin/labels.feature
new file mode 100644
index 00000000000..1af0e700bd4
--- /dev/null
+++ b/features/admin/labels.feature
@@ -0,0 +1,38 @@
+Feature: Admin Issues Labels
+ Background:
+ Given I sign in as an admin
+ And I have labels: "bug", "feature", "enhancement"
+ Given I visit admin labels page
+
+ Scenario: I should see labels list
+ Then I should see label 'bug'
+ And I should see label 'feature'
+
+ Scenario: I create new label
+ Given I submit new label 'support'
+ Then I should see label 'support'
+
+ Scenario: I edit label
+ Given I visit 'bug' label edit page
+ When I change label 'bug' to 'fix'
+ Then I should not see label 'bug'
+ Then I should see label 'fix'
+
+ Scenario: I remove label
+ When I remove label 'bug'
+ Then I should not see label 'bug'
+
+ @javascript
+ Scenario: I delete all labels
+ When I delete all labels
+ Then I should see labels help message
+
+ Scenario: I create a label with invalid color
+ Given I visit admin new label page
+ When I submit new label with invalid color
+ Then I should see label color error message
+
+ Scenario: I create a label that already exists
+ Given I visit admin new label page
+ When I submit new label 'bug'
+ Then I should see label exist error message
diff --git a/features/login_form.feature b/features/login_form.feature
new file mode 100644
index 00000000000..b4d95754482
--- /dev/null
+++ b/features/login_form.feature
@@ -0,0 +1,5 @@
+Feature: Login form
+ Scenario: I see crowd form
+ Given Crowd integration enabled
+ When I visit sign in page
+ Then I should see Crowd login form \ No newline at end of file
diff --git a/features/project/wiki.feature b/features/project/wiki.feature
index 2ebfa3c1660..af970ecf2d0 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -91,3 +91,15 @@ Feature: Project Wiki
And I view the page history of a Wiki page that has a path
Then I should see a non-escaped path
And I should see the page history
+
+ @javascript
+ Scenario: View an old page version of a Wiki page
+ Given I create a New page with paths
+ And I click on the "Pages" button
+ And I edit the Wiki page with a path
+ Then I should see a non-escaped path
+ And I should see the Editing page
+ And I change the content
+ Then I click on Page History
+ And I should see the page history
+ And I should see a link with a version ID
diff --git a/features/steps/admin/labels.rb b/features/steps/admin/labels.rb
new file mode 100644
index 00000000000..d64380abf73
--- /dev/null
+++ b/features/steps/admin/labels.rb
@@ -0,0 +1,117 @@
+class Spinach::Features::AdminIssuesLabels < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ step 'I visit \'bug\' label edit page' do
+ visit edit_admin_label_path(bug_label)
+ end
+
+ step 'I visit admin new label page' do
+ visit new_admin_label_path
+ end
+
+ step 'I visit admin labels page' do
+ visit admin_labels_path
+ end
+
+ step 'I remove label \'bug\'' do
+ page.within "#label_#{bug_label.id}" do
+ click_link 'Remove'
+ end
+ end
+
+ step 'I have labels: "bug", "feature", "enhancement"' do
+ ["bug", "feature", "enhancement"].each do |title|
+ Label.create(title: title, template: true)
+ end
+ end
+
+ step 'I delete all labels' do
+ page.within '.labels' do
+ page.all('.btn-remove').each do |remove|
+ remove.click
+ sleep 0.05
+ end
+ end
+ end
+
+ step 'I should see labels help message' do
+ page.within '.labels' do
+ expect(page).to have_content 'There are no any labels yet'
+ end
+ end
+
+ step 'I submit new label \'support\'' do
+ visit new_admin_label_path
+ fill_in 'Title', with: 'support'
+ fill_in 'Background Color', with: '#F95610'
+ click_button 'Save'
+ end
+
+ step 'I submit new label \'bug\'' do
+ visit new_admin_label_path
+ fill_in 'Title', with: 'bug'
+ fill_in 'Background Color', with: '#F95610'
+ click_button 'Save'
+ end
+
+ step 'I submit new label with invalid color' do
+ visit new_admin_label_path
+ fill_in 'Title', with: 'support'
+ fill_in 'Background Color', with: '#12'
+ click_button 'Save'
+ end
+
+ step 'I should see label exist error message' do
+ page.within '.label-form' do
+ expect(page).to have_content 'Title has already been taken'
+ end
+ end
+
+ step 'I should see label color error message' do
+ page.within '.label-form' do
+ expect(page).to have_content 'Color is invalid'
+ end
+ end
+
+ step 'I should see label \'feature\'' do
+ page.within '.manage-labels-list' do
+ expect(page).to have_content 'feature'
+ end
+ end
+
+ step 'I should see label \'bug\'' do
+ page.within '.manage-labels-list' do
+ expect(page).to have_content 'bug'
+ end
+ end
+
+ step 'I should not see label \'bug\'' do
+ page.within '.manage-labels-list' do
+ expect(page).not_to have_content 'bug'
+ end
+ end
+
+ step 'I should see label \'support\'' do
+ page.within '.manage-labels-list' do
+ expect(page).to have_content 'support'
+ end
+ end
+
+ step 'I change label \'bug\' to \'fix\'' do
+ fill_in 'Title', with: 'fix'
+ fill_in 'Background Color', with: '#F15610'
+ click_button 'Save'
+ end
+
+ step 'I should see label \'fix\'' do
+ page.within '.manage-labels-list' do
+ expect(page).to have_content 'fix'
+ end
+ end
+
+ def bug_label
+ Label.templates.find_or_create_by(title: 'bug')
+ end
+end
diff --git a/features/steps/login_form.rb b/features/steps/login_form.rb
new file mode 100644
index 00000000000..b9ff6ae67fd
--- /dev/null
+++ b/features/steps/login_form.rb
@@ -0,0 +1,25 @@
+class Spinach::Features::LoginForm < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedSnippet
+ include SharedUser
+ include SharedSearch
+
+ step 'Crowd integration enabled' do
+ @providers_orig = Gitlab::OAuth::Provider.providers
+ @omniauth_conf_orig = Gitlab.config.omniauth.enabled
+ expect(Gitlab::OAuth::Provider).to receive(:providers).and_return([:crowd])
+ allow_any_instance_of(ApplicationHelper).to receive(:user_omniauth_authorize_path).and_return(root_path)
+ expect(Gitlab.config.omniauth).to receive(:enabled).and_return(true)
+ end
+
+ step 'I should see Crowd login form' do
+ expect(page).to have_selector '#tab-crowd form'
+ Gitlab::OAuth::Provider.stub(:providers).and_return(@providers_orig)
+ Gitlab.config.omniauth.stub(:enabled).and_return(@omniauth_conf_orig)
+ end
+
+ step 'I visit sign in page' do
+ visit new_user_session_path
+ end
+end
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index e7dd20191b7..23e67371f96 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -52,7 +52,6 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I see compared refs' do
- expect(page).to have_content "Compare View"
expect(page).to have_content "Commits (1)"
expect(page).to have_content "Showing 2 changed files"
end
diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb
index eebfaee1ede..02207dbffa6 100644
--- a/features/steps/project/wiki.rb
+++ b/features/steps/project/wiki.rb
@@ -3,7 +3,6 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
include SharedProject
include SharedNote
include SharedPaths
- include WikiHelper
step 'I click on the Cancel button' do
page.within(:css, ".form-actions") do
@@ -165,6 +164,10 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
click_on 'Page History'
end
+ step 'I click on Page History' do
+ click_on 'Page History'
+ end
+
step 'I should see the page history' do
expect(page).to have_content('History for')
end
@@ -174,6 +177,10 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
click_button "Search"
end
+ step 'I should see a link with a version ID' do
+ find('a[href*="?version_id"]')
+ end
+
def wiki
@project_wiki = ProjectWiki.new(project, current_user)
end
diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb
index 92e099315d8..eb2ccd9d01e 100644
--- a/features/steps/shared/active_tab.rb
+++ b/features/steps/shared/active_tab.rb
@@ -6,7 +6,7 @@ module SharedActiveTab
end
def ensure_active_sub_tab(content)
- expect(find('div.content ul.nav-tabs li.active')).to have_content(content)
+ expect(find('div.content ul.center-top-menu li.active')).to have_content(content)
end
def ensure_active_sub_nav(content)
@@ -18,7 +18,7 @@ module SharedActiveTab
end
step 'no other sub tabs should be active' do
- expect(page).to have_selector('div.content ul.nav-tabs li.active', count: 1)
+ expect(page).to have_selector('div.content ul.center-top-menu li.active', count: 1)
end
step 'no other sub navs should be active' do
diff --git a/lib/gitlab/fogbugz_import/client.rb b/lib/gitlab/fogbugz_import/client.rb
new file mode 100644
index 00000000000..431d50882fd
--- /dev/null
+++ b/lib/gitlab/fogbugz_import/client.rb
@@ -0,0 +1,56 @@
+require 'fogbugz'
+
+module Gitlab
+ module FogbugzImport
+ class Client
+ attr_reader :api
+
+ def initialize(options = {})
+ if options[:uri] && options[:token]
+ @api = ::Fogbugz::Interface.new(options)
+ elsif options[:uri] && options[:email] && options[:password]
+ @api = ::Fogbugz::Interface.new(options)
+ @api.authenticate
+ @api
+ end
+ end
+
+ def get_token
+ @api.token
+ end
+
+ def valid?
+ !get_token.blank?
+ end
+
+ def user_map
+ users = {}
+ res = @api.command(:listPeople)
+ res['people']['person'].each do |user|
+ users[user['ixPerson']] = { name: user['sFullName'], email: user['sEmail'] }
+ end
+ users
+ end
+
+ def repos
+ res = @api.command(:listProjects)
+ @repos ||= res['projects']['project'].map { |proj| FogbugzImport::Repository.new(proj) }
+ end
+
+ def repo(id)
+ repos.find { |r| r.id.to_s == id.to_s }
+ end
+
+ def cases(project_id)
+ project_name = repo(project_id).name
+ res = @api.command(:search, q: "project:'#{project_name}'", cols: 'ixPersonAssignedTo,ixPersonOpenedBy,ixPersonClosedBy,sStatus,sPriority,sCategory,fOpen,sTitle,sLatestTextSummary,dtOpened,dtClosed,dtResolved,dtLastUpdated,events')
+ return [] unless res['cases']['count'].to_i > 0
+ res['cases']['case']
+ end
+
+ def categories
+ @api.command(:listCategories)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb
new file mode 100644
index 00000000000..61e08b23543
--- /dev/null
+++ b/lib/gitlab/fogbugz_import/importer.rb
@@ -0,0 +1,298 @@
+module Gitlab
+ module FogbugzImport
+ class Importer
+ attr_reader :project, :repo
+
+ def initialize(project)
+ @project = project
+
+ import_data = project.import_data.try(:data)
+ repo_data = import_data['repo'] if import_data
+ @repo = FogbugzImport::Repository.new(repo_data)
+
+ @known_labels = Set.new
+ end
+
+ def execute
+ return true unless repo.valid?
+
+ data = project.import_data.try(:data)
+
+ client = Gitlab::FogbugzImport::Client.new(token: data['fb_session']['token'], uri: data['fb_session']['uri'])
+
+ @cases = client.cases(@repo.id.to_i)
+ @categories = client.categories
+
+ import_cases
+
+ true
+ end
+
+ private
+
+ def user_map
+ @user_map ||= begin
+ user_map = Hash.new
+ import_data = project.import_data.try(:data)
+ stored_user_map = import_data['user_map'] if import_data
+ user_map.update(stored_user_map) if stored_user_map
+
+ user_map
+ end
+ end
+
+ def import_labels
+ @categories['categories']['category'].each do |label|
+ create_label(label['sCategory'])
+ @known_labels << name
+ end
+ end
+
+ def nice_label_color(name)
+ case name
+ when 'Blocker'
+ '#ff0000'
+ when 'Crash'
+ '#ffcfcf'
+ when 'Major'
+ '#deffcf'
+ when 'Minor'
+ '#cfe9ff'
+ when 'Bug'
+ '#d9534f'
+ when 'Feature'
+ '#44ad8e'
+ when 'Technical Task'
+ '#4b6dd0'
+ else
+ '#e2e2e2'
+ end
+ end
+
+ def create_label(name)
+ color = nice_label_color(name)
+ Label.create!(project_id: project.id, title: name, color: color)
+ end
+
+ def user_info(person_id)
+ user_hash = user_map[person_id.to_s]
+
+ user_name = ''
+ gitlab_id = nil
+
+ unless user_hash.nil?
+ user_name = user_hash['name']
+ if user = User.find_by(id: user_hash['gitlab_user'])
+ user_name = "@#{user.username}"
+ gitlab_id = user.id
+ end
+ end
+
+ { name: user_name, gitlab_id: gitlab_id }
+ end
+
+ def import_cases
+ return unless @cases
+
+ while bug = @cases.shift
+ author = user_info(bug['ixPersonOpenedBy'])[:name]
+ date = DateTime.parse(bug['dtOpened'])
+
+ comments = bug['events']['event']
+
+ content = format_content(opened_content(comments))
+ body = format_issue_body(author, date, content)
+
+ labels = []
+ [bug['sCategory'], bug['sPriority']].each do |label|
+ unless label.blank?
+ labels << label
+ unless @known_labels.include?(label)
+ create_label(label)
+ @known_labels << label
+ end
+ end
+ end
+
+ assignee_id = user_info(bug['ixPersonAssignedTo'])[:gitlab_id]
+ author_id = user_info(bug['ixPersonOpenedBy'])[:gitlab_id] || project.creator_id
+
+ issue = Issue.create!(
+ project_id: project.id,
+ title: bug['sTitle'],
+ description: body,
+ author_id: author_id,
+ assignee_id: assignee_id,
+ state: bug['fOpen'] == 'true' ? 'opened' : 'closed'
+ )
+ issue.add_labels_by_names(labels)
+
+ if issue.iid != bug['ixBug']
+ issue.update_attribute(:iid, bug['ixBug'])
+ end
+
+ import_issue_comments(issue, comments)
+
+ issue.update_attribute(:created_at, date)
+
+ last_update = DateTime.parse(bug['dtLastUpdated'])
+ issue.update_attribute(:updated_at, last_update)
+ end
+ end
+
+ def opened_content(comments)
+ while comment = comments.shift
+ if comment['sVerb'] == 'Opened'
+ return comment['s']
+ end
+ end
+ ''
+ end
+
+ def import_issue_comments(issue, comments)
+ Note.transaction do
+ while comment = comments.shift
+ verb = comment['sVerb']
+
+ next if verb == 'Opened' || verb === 'Closed'
+
+ content = format_content(comment['s'])
+ attachments = format_attachments(comment['rgAttachments'])
+ updates = format_updates(comment)
+
+ next if content.blank? && attachments.empty? && updates.empty?
+
+ author = user_info(comment['ixPerson'])[:name]
+ author_id = user_info(comment['ixPerson'])[:gitlab_id] || project.creator_id
+ date = DateTime.parse(comment['dt'])
+
+ body = format_issue_comment_body(
+ comment['ixBugEvent'],
+ author,
+ date,
+ content,
+ attachments,
+ updates
+ )
+
+ note = Note.create!(
+ project_id: project.id,
+ noteable_type: "Issue",
+ noteable_id: issue.id,
+ author_id: author_id,
+ note: body
+ )
+
+ note.update_attribute(:created_at, date)
+ note.update_attribute(:updated_at, date)
+ end
+ end
+ end
+
+ def linkify_issues(s)
+ s = s.gsub(/([Ii]ssue) ([0-9]+)/, '\1 #\2')
+ s = s.gsub(/([Cc]ase) ([0-9]+)/, '\1 #\2')
+ s
+ end
+
+ def escape_for_markdown(s)
+ s = s.gsub(/^#/, "\\#")
+ s = s.gsub(/^-/, "\\-")
+ s = s.gsub("`", "\\~")
+ s = s.gsub("\r", "")
+ s = s.gsub("\n", " \n")
+ s
+ end
+
+ def format_content(raw_content)
+ return raw_content if raw_content.nil?
+ linkify_issues(escape_for_markdown(raw_content))
+ end
+
+ def format_attachments(raw_attachments)
+ return [] unless raw_attachments
+
+ attachments = case raw_attachments['attachment']
+ when Array
+ raw_attachments['attachment']
+ when Hash
+ [raw_attachments['attachment']]
+ else
+ []
+ end
+
+ attachments.map! { |a| format_attachment(a) }
+ attachments.compact
+ end
+
+ def format_attachment(attachment)
+ link = build_attachment_url(attachment['sURL'])
+
+ res = ::Projects::DownloadService.new(project, link).execute
+
+ return nil if res.nil?
+
+ text = "[#{res['alt']}](#{res['url']})"
+ text = "!#{text}" if res['is_image']
+ text
+ end
+
+ def build_attachment_url(rel_url)
+ data = project.import_data.try(:data)
+ uri = data['fb_session']['uri']
+ token = data['fb_session']['token']
+ "#{uri}/#{rel_url}&token=#{token}"
+ end
+
+ def format_updates(comment)
+ updates = []
+
+ if comment['sChanges']
+ updates << "*Changes: #{linkify_issues(comment['sChanges'].chomp)}*"
+ end
+
+ if comment['evtDescription']
+ updates << "*#{comment['evtDescription']}*"
+ end
+
+ updates
+ end
+
+ def format_issue_body(author, date, content)
+ body = []
+ body << "*By #{author} on #{date} (imported from FogBugz)*"
+ body << '---'
+
+ if content.blank?
+ content = '*(No description has been entered for this issue)*'
+ end
+ body << content
+
+ body.join("\n\n")
+ end
+
+ def format_issue_comment_body(id, author, date, content, attachments, updates)
+ body = []
+ body << "*By #{author} on #{date} (imported from FogBugz)*"
+ body << '---'
+
+ if content.blank?
+ content = "*(No comment has been entered for this change)*"
+ end
+ body << content
+
+ if updates.any?
+ body << '---'
+ body += updates
+ end
+
+ if attachments.any?
+ body << '---'
+ body += attachments
+ end
+
+ body.join("\n\n")
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb
new file mode 100644
index 00000000000..f02ea43910f
--- /dev/null
+++ b/lib/gitlab/fogbugz_import/project_creator.rb
@@ -0,0 +1,38 @@
+module Gitlab
+ module FogbugzImport
+ class ProjectCreator
+ attr_reader :repo, :fb_session, :namespace, :current_user, :user_map
+
+ def initialize(repo, fb_session, namespace, current_user, user_map = nil)
+ @repo = repo
+ @fb_session = fb_session
+ @namespace = namespace
+ @current_user = current_user
+ @user_map = user_map
+ end
+
+ def execute
+ project = ::Projects::CreateService.new(current_user,
+ name: repo.safe_name,
+ path: repo.path,
+ namespace: namespace,
+ creator: current_user,
+ visibility_level: Gitlab::VisibilityLevel::INTERNAL,
+ import_type: 'fogbugz',
+ import_source: repo.name,
+ import_url: Project::UNKNOWN_IMPORT_URL
+ ).execute
+
+ import_data = project.create_import_data(
+ data: {
+ 'repo' => repo.raw_data,
+ 'user_map' => user_map,
+ 'fb_session' => fb_session
+ }
+ )
+
+ project
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/fogbugz_import/repository.rb b/lib/gitlab/fogbugz_import/repository.rb
new file mode 100644
index 00000000000..d1dc63db2b2
--- /dev/null
+++ b/lib/gitlab/fogbugz_import/repository.rb
@@ -0,0 +1,31 @@
+module Gitlab
+ module FogbugzImport
+ class Repository
+ attr_accessor :raw_data
+
+ def initialize(raw_data)
+ @raw_data = raw_data
+ end
+
+ def valid?
+ raw_data.is_a?(Hash)
+ end
+
+ def id
+ raw_data['ixProject']
+ end
+
+ def name
+ raw_data['sProject']
+ end
+
+ def safe_name
+ name.gsub(/[^\s\w.-]/, '')
+ end
+
+ def path
+ safe_name.gsub(/[\s]/, '_')
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb
index 991b70aab6a..ccfdfbe73e8 100644
--- a/lib/gitlab/import_sources.rb
+++ b/lib/gitlab/import_sources.rb
@@ -19,6 +19,7 @@ module Gitlab
'GitLab.com' => 'gitlab',
'Gitorious.org' => 'gitorious',
'Google Code' => 'google_code',
+ 'FogBugz' => 'fogbugz',
'Any repo by URL' => 'git',
}
end
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
index 11b0d44f340..779819bc2bf 100644
--- a/lib/gitlab/url_builder.rb
+++ b/lib/gitlab/url_builder.rb
@@ -23,12 +23,12 @@ module Gitlab
def build_issue_url(id)
issue = Issue.find(id)
- issue_url(issue, host: Gitlab.config.gitlab['url'])
+ issue_url(issue)
end
def build_merge_request_url(id)
merge_request = MergeRequest.find(id)
- merge_request_url(merge_request, host: Gitlab.config.gitlab['url'])
+ merge_request_url(merge_request)
end
def build_note_url(id)
@@ -37,22 +37,18 @@ module Gitlab
namespace_project_commit_url(namespace_id: note.project.namespace,
id: note.commit_id,
project_id: note.project,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
elsif note.for_issue?
issue = Issue.find(note.noteable_id)
issue_url(issue,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
elsif note.for_merge_request?
merge_request = MergeRequest.find(note.noteable_id)
merge_request_url(merge_request,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
elsif note.for_project_snippet?
snippet = Snippet.find(note.noteable_id)
project_snippet_url(snippet,
- host: Gitlab.config.gitlab['url'],
anchor: "note_#{note.id}")
end
end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 17f89c8beb6..7218a4d2f20 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -124,6 +124,15 @@ server {
proxy_connect_timeout 300;
proxy_redirect off;
+ # Do not buffer Git HTTP responses
+ proxy_buffering off;
+
+ # The following settings only work with NGINX 1.7.11 or newer
+ #
+ # # Pass chunked request bodies to gitlab-git-http-server as-is
+ # proxy_request_buffering off;
+ # proxy_http_version 1.1;
+
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 5ba39fc41a4..7dabfba87e2 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -171,6 +171,15 @@ server {
proxy_connect_timeout 300;
proxy_redirect off;
+ # Do not buffer Git HTTP responses
+ proxy_buffering off;
+
+ # The following settings only work with NGINX 1.7.11 or newer
+ #
+ # # Pass chunked request bodies to gitlab-git-http-server as-is
+ # proxy_request_buffering off;
+ # proxy_http_version 1.1;
+
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Ssl on;
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 2b9688c1b40..b8eb13a4fea 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -278,7 +278,7 @@ namespace :gitlab do
fix_and_rerun
end
end
-
+
def check_uploads
print "Uploads directory setup correctly? ... "
@@ -331,15 +331,18 @@ namespace :gitlab do
end
def check_redis_version
- print "Redis version >= 2.0.0? ... "
+ min_redis_version = "2.4.0"
+ print "Redis version >= #{min_redis_version}? ... "
redis_version = run(%W(redis-cli --version))
- if redis_version.try(:match, /redis-cli 2.\d.\d/) || redis_version.try(:match, /redis-cli 3.\d.\d/)
+ redis_version = redis_version.try(:match, /redis-cli (.*)/)
+ if redis_version &&
+ (Gem::Version.new(redis_version[1]) > Gem::Version.new(min_redis_version))
puts "yes".green
else
puts "no".red
try_fixing_it(
- "Update your redis server to a version >= 2.0.0"
+ "Update your redis server to a version >= #{min_redis_version}"
)
for_more_information(
"gitlab-public-wiki/wiki/Trouble-Shooting-Guide in section sidekiq"
@@ -488,7 +491,7 @@ namespace :gitlab do
else
puts "wrong or missing hooks".red
try_fixing_it(
- sudo_gitlab("#{gitlab_shell_path}/bin/create-hooks"),
+ sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')}"),
'Check the hooks_path in config/gitlab.yml',
'Check your gitlab-shell installation'
)
diff --git a/spec/controllers/import/fogbugz_controller_spec.rb b/spec/controllers/import/fogbugz_controller_spec.rb
new file mode 100644
index 00000000000..27b11267d2a
--- /dev/null
+++ b/spec/controllers/import/fogbugz_controller_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+require_relative 'import_spec_helper'
+
+describe Import::FogbugzController do
+ include ImportSpecHelper
+
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET status' do
+ before do
+ @repo = OpenStruct.new(name: 'vim')
+ stub_client(valid?: true)
+ end
+
+ it 'assigns variables' do
+ @project = create(:project, import_type: 'fogbugz', creator_id: user.id)
+ stub_client(repos: [@repo])
+
+ get :status
+
+ expect(assigns(:already_added_projects)).to eq([@project])
+ expect(assigns(:repos)).to eq([@repo])
+ end
+
+ it 'does not show already added project' do
+ @project = create(:project, import_type: 'fogbugz', creator_id: user.id, import_source: 'vim')
+ stub_client(repos: [@repo])
+
+ get :status
+
+ expect(assigns(:already_added_projects)).to eq([@project])
+ expect(assigns(:repos)).to eq([])
+ end
+ end
+end
diff --git a/spec/factories/abuse_reports.rb b/spec/factories/abuse_reports.rb
index 29fcbc5e197..8d287ded292 100644
--- a/spec/factories/abuse_reports.rb
+++ b/spec/factories/abuse_reports.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: abuse_reports
+#
+# id :integer not null, primary key
+# reporter_id :integer
+# user_id :integer
+# message :text
+# created_at :datetime
+# updated_at :datetime
+#
+
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 3b7adfe4398..6080d0ccdef 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -19,6 +19,7 @@
# description :text
# position :integer default(0)
# locked_at :datetime
+# updated_by_id :integer
#
FactoryGirl.define do
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index e1009d5916e..9d777ddfccd 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -15,6 +15,7 @@
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
+# updated_by_id :integer
#
require_relative '../support/repo_helpers'
diff --git a/spec/javascripts/zen_mode_spec.js.coffee b/spec/javascripts/zen_mode_spec.js.coffee
index 1f4ea58ad48..4cb3836755f 100644
--- a/spec/javascripts/zen_mode_spec.js.coffee
+++ b/spec/javascripts/zen_mode_spec.js.coffee
@@ -29,6 +29,11 @@ describe 'ZenMode', ->
enterZen()
expect(Mousetrap.pause).toHaveBeenCalled()
+ it 'removes textarea styling', ->
+ $('textarea').attr('style', 'height: 400px')
+ enterZen()
+ expect('textarea').not.toHaveAttr('style')
+
describe 'in use', ->
beforeEach ->
enterZen()
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index d83004a8388..635a6e2518c 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: abuse_reports
+#
+# id :integer not null, primary key
+# reporter_id :integer
+# user_id :integer
+# message :text
+# created_at :datetime
+# updated_at :datetime
+#
+
require 'rails_helper'
RSpec.describe AbuseReport, type: :model do
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index bc14ff98fd8..de0b2ef4cda 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -22,6 +22,7 @@
# user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
+# import_sources :text
#
require 'spec_helper'
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 9bac451c28c..cf336d82957 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -2,19 +2,20 @@
#
# Table name: issues
#
-# id :integer not null, primary key
-# title :string(255)
-# assignee_id :integer
-# author_id :integer
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# position :integer default(0)
-# branch_name :string(255)
-# description :text
-# milestone_id :integer
-# state :string(255)
-# iid :integer
+# id :integer not null, primary key
+# title :string(255)
+# assignee_id :integer
+# author_id :integer
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# position :integer default(0)
+# branch_name :string(255)
+# description :text
+# milestone_id :integer
+# state :string(255)
+# iid :integer
+# updated_by_id :integer
#
require 'spec_helper'
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index b91687bc09f..17a49013d25 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -19,6 +19,7 @@
# description :text
# position :integer default(0)
# locked_at :datetime
+# updated_by_id :integer
#
require 'spec_helper'
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 331505a01b3..3a0b194ba1e 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -15,6 +15,7 @@
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
+# updated_by_id :integer
#
require 'spec_helper'
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index a46e789eab4..eeb9069aa17 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2,62 +2,58 @@
#
# Table name: users
#
-# id :integer not null, primary key
-# email :string(255) default(""), not null
-# encrypted_password :string(255) default(""), not null
-# reset_password_token :string(255)
-# reset_password_sent_at :datetime
-# remember_created_at :datetime
-# sign_in_count :integer default(0)
-# current_sign_in_at :datetime
-# last_sign_in_at :datetime
-# current_sign_in_ip :string(255)
-# last_sign_in_ip :string(255)
-# created_at :datetime
-# updated_at :datetime
-# name :string(255)
-# admin :boolean default(FALSE), not null
-# projects_limit :integer default(10)
-# skype :string(255) default(""), not null
-# linkedin :string(255) default(""), not null
-# twitter :string(255) default(""), not null
-# authentication_token :string(255)
-# theme_id :integer default(1), not null
-# bio :string(255)
-# failed_attempts :integer default(0)
-# locked_at :datetime
-# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# color_scheme_id :integer default(1), not null
-# notification_level :integer default(1), not null
-# password_expires_at :datetime
-# created_by_id :integer
-# last_credential_check_at :datetime
-# avatar :string(255)
-# confirmation_token :string(255)
-# confirmed_at :datetime
-# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# github_access_token :string(255)
-# gitlab_access_token :string(255)
-# notification_email :string(255)
-# hide_no_password :boolean default(FALSE)
-# password_automatically_set :boolean default(FALSE)
-# bitbucket_access_token :string(255)
-# bitbucket_access_token_secret :string(255)
-# location :string(255)
-# encrypted_otp_secret :string(255)
-# encrypted_otp_secret_iv :string(255)
-# encrypted_otp_secret_salt :string(255)
-# otp_required_for_login :boolean default(FALSE), not null
-# otp_backup_codes :text
-# public_email :string(255) default(""), not null
-# dashboard :integer default(0)
-# project_view :integer default(0)
+# id :integer not null, primary key
+# email :string(255) default(""), not null
+# encrypted_password :string(255) default(""), not null
+# reset_password_token :string(255)
+# reset_password_sent_at :datetime
+# remember_created_at :datetime
+# sign_in_count :integer default(0)
+# current_sign_in_at :datetime
+# last_sign_in_at :datetime
+# current_sign_in_ip :string(255)
+# last_sign_in_ip :string(255)
+# created_at :datetime
+# updated_at :datetime
+# name :string(255)
+# admin :boolean default(FALSE), not null
+# projects_limit :integer default(10)
+# skype :string(255) default(""), not null
+# linkedin :string(255) default(""), not null
+# twitter :string(255) default(""), not null
+# authentication_token :string(255)
+# theme_id :integer default(1), not null
+# bio :string(255)
+# failed_attempts :integer default(0)
+# locked_at :datetime
+# username :string(255)
+# can_create_group :boolean default(TRUE), not null
+# can_create_team :boolean default(TRUE), not null
+# state :string(255)
+# color_scheme_id :integer default(1), not null
+# notification_level :integer default(1), not null
+# password_expires_at :datetime
+# created_by_id :integer
+# last_credential_check_at :datetime
+# avatar :string(255)
+# confirmation_token :string(255)
+# confirmed_at :datetime
+# confirmation_sent_at :datetime
+# unconfirmed_email :string(255)
+# hide_no_ssh_key :boolean default(FALSE)
+# website_url :string(255) default(""), not null
+# notification_email :string(255)
+# hide_no_password :boolean default(FALSE)
+# password_automatically_set :boolean default(FALSE)
+# location :string(255)
+# encrypted_otp_secret :string(255)
+# encrypted_otp_secret_iv :string(255)
+# encrypted_otp_secret_salt :string(255)
+# otp_required_for_login :boolean default(FALSE), not null
+# otp_backup_codes :text
+# public_email :string(255) default(""), not null
+# dashboard :integer default(0)
+# project_view :integer default(0)
#
require 'spec_helper'
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 66cdfd5d758..ff4ed2dd484 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -17,6 +17,14 @@ describe Projects::CreateService do
expect(project.services).not_to be_empty
end
+ it 'creates labels on Project creation if there are templates' do
+ Label.create(title: "bug", template: true)
+ project = create_project(@user, @opts)
+ project.reload
+
+ expect(project.labels).not_to be_empty
+ end
+
context 'user namespace' do
before do
@project = create_project(@user, @opts)
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
new file mode 100644
index 00000000000..f12e09c58c3
--- /dev/null
+++ b/spec/services/projects/download_service_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe Projects::DownloadService do
+ describe 'File service' do
+ before do
+ @user = create :user
+ @project = create :project, creator_id: @user.id, namespace: @user.namespace
+ end
+
+ context 'for a URL that is not on whitelist' do
+ before do
+ url = 'https://code.jquery.com/jquery-2.1.4.min.js'
+ @link_to_file = download_file(@project, url)
+ end
+
+ it { expect(@link_to_file).to eq(nil) }
+ end
+
+ context 'for URLs that are on the whitelist' do
+ before do
+ sham_rack_app = ShamRack.at('mycompany.fogbugz.com').stub
+ sham_rack_app.register_resource('/rails_sample.jpg', File.read(Rails.root + 'spec/fixtures/rails_sample.jpg'), 'image/jpg')
+ sham_rack_app.register_resource('/doc_sample.txt', File.read(Rails.root + 'spec/fixtures/doc_sample.txt'), 'text/plain')
+ end
+
+ after do
+ ShamRack.unmount_all
+ end
+
+ context 'an image file' do
+ before do
+ url = 'http://mycompany.fogbugz.com/rails_sample.jpg'
+ @link_to_file = download_file(@project, url)
+ end
+
+ it { expect(@link_to_file).to have_key('alt') }
+ it { expect(@link_to_file).to have_key('url') }
+ it { expect(@link_to_file).to have_key('is_image') }
+ it { expect(@link_to_file['is_image']).to be true }
+ it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
+ it { expect(@link_to_file['url']).to match('rails_sample.jpg') }
+ it { expect(@link_to_file['alt']).to eq('rails_sample') }
+ end
+
+ context 'a txt file' do
+ before do
+ url = 'http://mycompany.fogbugz.com/doc_sample.txt'
+ @link_to_file = download_file(@project, url)
+ end
+
+ it { expect(@link_to_file).to have_key('alt') }
+ it { expect(@link_to_file).to have_key('url') }
+ it { expect(@link_to_file).to have_key('is_image') }
+ it { expect(@link_to_file['is_image']).to be false }
+ it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
+ it { expect(@link_to_file['url']).to match('doc_sample.txt') }
+ it { expect(@link_to_file['alt']).to eq('doc_sample.txt') }
+ end
+ end
+ end
+
+ def download_file(repository, url)
+ Projects::DownloadService.new(repository, url).execute
+ end
+end