summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock8
-rw-r--r--app/assets/stylesheets/application.scss3
-rw-r--r--app/assets/stylesheets/generic/jquery.scss20
-rw-r--r--app/assets/stylesheets/jquery.ui.gitlab.css257
-rw-r--r--app/assets/stylesheets/main/fonts.scss1
-rw-r--r--app/helpers/merge_requests_helper.rb2
-rw-r--r--app/services/notification_service.rb78
-rw-r--r--app/views/projects/issues/_head.html.haml5
-rw-r--r--app/views/projects/merge_requests/branch_from.js.haml2
-rw-r--r--config/application.rb1
-rw-r--r--doc/README.md40
-rw-r--r--doc/install/installation.md1
-rw-r--r--doc/integration/external-issue-tracker.md2
-rw-r--r--doc/workflow/README.md2
-rw-r--r--doc/workflow/project_features.md35
-rw-r--r--lib/tasks/gitlab/check.rake24
-rw-r--r--lib/tasks/gitlab/info.rake1
-rwxr-xr-xscript/background_jobs2
-rw-r--r--spec/services/notification_service_spec.rb35
21 files changed, 210 insertions, 314 deletions
diff --git a/CHANGELOG b/CHANGELOG
index d936986a779..1b742a4d9b2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,7 @@ v 6.8.0
- Drop all tables before restoring a Postgres backup
- Make the repository downloads path configurable
- Create branches via API (sponsored by O'Reilly Media)
+ - Changed permission of gitlab-satellites directory not to be world accessible
v 6.7.2
- Fix upgrader script
diff --git a/Gemfile b/Gemfile
index 397165f668f..ab8a27a8571 100644
--- a/Gemfile
+++ b/Gemfile
@@ -12,8 +12,6 @@ gem "rails", "~> 4.0.0"
gem "protected_attributes"
gem 'rails-observers'
-gem 'actionpack-page_caching'
-gem 'actionpack-action_caching'
# Default values for AR models
gem "default_value_for", "~> 3.0.0"
@@ -102,7 +100,7 @@ gem "acts-as-taggable-on"
# Background jobs
gem 'slim'
gem 'sinatra', require: nil
-gem 'sidekiq'
+gem 'sidekiq', '2.17.0'
# HTTP requests
gem "httparty"
diff --git a/Gemfile.lock b/Gemfile.lock
index 1a0bce98ac5..4acdb539f09 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -27,10 +27,6 @@ GEM
erubis (~> 2.7.0)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
- actionpack-action_caching (1.1.0)
- actionpack (>= 4.0.0, < 5.0)
- actionpack-page_caching (1.0.2)
- actionpack (>= 4.0.0, < 5)
activemodel (4.0.3)
activesupport (= 4.0.3)
builder (~> 3.1.0)
@@ -567,8 +563,6 @@ PLATFORMS
DEPENDENCIES
ace-rails-ap
- actionpack-action_caching
- actionpack-page_caching
acts-as-taggable-on
annotate (~> 2.6.0.beta2)
asciidoctor
@@ -653,7 +647,7 @@ DEPENDENCIES
select2-rails
settingslogic
shoulda-matchers (~> 2.1.0)
- sidekiq
+ sidekiq (= 2.17.0)
simplecov
sinatra
six
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 4b7103010bb..eb5d17651b1 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -2,7 +2,7 @@
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
- *= require jquery.ui.gitlab
+ *= require jquery.ui.datepicker
*= require jquery.atwho
*= require select2
*= require highlightjs.min
@@ -43,6 +43,7 @@
@import "generic/forms.scss";
@import "generic/selects.scss";
@import "generic/highlight.scss";
+@import "generic/jquery.scss";
/**
* Page specific styles (issues, projects etc):
diff --git a/app/assets/stylesheets/generic/jquery.scss b/app/assets/stylesheets/generic/jquery.scss
new file mode 100644
index 00000000000..423cb906d0a
--- /dev/null
+++ b/app/assets/stylesheets/generic/jquery.scss
@@ -0,0 +1,20 @@
+.ui-widget {
+ font-family: $regular_font;
+ font-size: $font-size-base;
+
+ &.ui-datepicker-inline {
+ border: 1px solid #DDD;
+ padding: 10px;
+ width: 270px;
+
+ .ui-datepicker-header {
+ background: #EEE;
+ border-color: #DDD;
+ }
+
+ .ui-datepicker-calendar td a {
+ padding: 5px;
+ text-align: center;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/jquery.ui.gitlab.css b/app/assets/stylesheets/jquery.ui.gitlab.css
deleted file mode 100644
index 5c51600ba67..00000000000
--- a/app/assets/stylesheets/jquery.ui.gitlab.css
+++ /dev/null
@@ -1,257 +0,0 @@
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
-
-
-/*
- * jQuery UI CSS Framework 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-family: Arial,sans-serif; font-size: 1.1em; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Arial,sans-serif; font-size: 1em; }
-.ui-widget-content { border: 1px solid #CCC; background: #ffffff; color: #4F4F4F; }
-.ui-widget-content a { color: #4F4F4F; }
-.ui-widget-header { border: 1px solid #B6B6B6; color: #4F4F4F; font-weight: bold; }
-.ui-widget-header {
- background: #ededed url(bg_fallback.png) 0 0 repeat-x; /* Old browsers */
- background: -moz-linear-gradient(top, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* IE10+ */
- background: linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* W3C */
-}
-.ui-widget-header a { color: #4F4F4F; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #B6B6B6; font-weight: normal; color: #4F4F4F; }
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
- background: #ededed url(bg_fallback.png) 0 0 repeat-x; /* Old browsers */
- background: -moz-linear-gradient(top, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* IE10+ */
- background: linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* W3C */
- -webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
- -moz-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
- box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
-}
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #4F4F4F; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #9D9D9D; font-weight: normal; color: #313131; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #313131; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
- outline: none;
- color: #1c4257; border: 1px solid #7096ab;
- background: #ededed url(bg_fallback.png) 0 -50px repeat-x; /* Old browsers */
- background: -moz-linear-gradient(top, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */
- background: linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* W3C */
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
-}
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #313131; text-decoration: none; }
-.ui-widget :active { outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { border: 1px solid #d2dbf4; background: #f4f8fd; color: #0d2054; -moz-border-radius: 0 !important; -webkit-border-radius: 0 !important; border-radius: 0 !important; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { border: 1px solid #e2d0d0; background: #fcf0f0; color: #280b0b; -moz-border-radius: 0 !important; -webkit-border-radius: 0 !important; border-radius: 0 !important; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: url(ui-icons_222222_256x240.png); }
-.ui-widget-content .ui-icon {background-image: url(ui-icons_222222_256x240.png); }
-.ui-widget-header .ui-icon {background-image: url(ui-icons_222222_256x240.png); }
-.ui-state-default .ui-icon { background-image: url(ui-icons_454545_256x240.png); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(ui-icons_454545_256x240.png); }
-.ui-state-active .ui-icon {background-image: url(ui-icons_454545_256x240.png); }
-.ui-state-highlight .ui-icon {background-image: url(ui-icons_454545_256x240.png); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon { background: url(icon_sprite.png) -16px 0 no-repeat !important; }
-.ui-state-highlight .ui-icon, .ui-state-error .ui-icon { margin-top: -1px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); }
-.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
-/*
- * jQuery UI Selectable 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
-/*
- * jQuery UI Autocomplete 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete {
- position: absolute; cursor: default; z-index: 3;
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
- border-radius: 0;
- -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
- -webkit-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
- box-shadow: 0 1px 5px rgba(0,0,0,0.3);
-}
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
- list-style:none;
- padding: 1px;
- margin: 0;
- display:block;
- float: left;
-}
-.ui-menu .ui-menu {
- margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
- margin:0;
- padding: 0;
- zoom: 1;
- float: left;
- clear: left;
- width: 100%;
-}
-.ui-menu .ui-menu-item a {
- text-decoration:none;
- display:block;
- padding:.2em .4em;
- line-height:1.5;
- zoom:1;
- color: #666;
- font-size: 13px;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
- font-weight: normal;
- margin: -1px;
- background: #D9EDF7;
- color: #3A89A3;
- text-shadow: 0px 1px 1px #fff;
- border: none;
- border: 1px solid #ADE;
- cursor: pointer;
- font-weight: bold;
-}
-
-/*
- * jQuery UI Datepicker 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker {
- width: 17em;
- padding: 0;
- display: none;
- border-color: #DDDDDD;
- border: none;
- box-shadow: none;
-}
-.ui-datepicker .ui-datepicker-header {
- position:relative;
- padding:.35em 0;
- border: none;
- border-bottom: 1px solid #B6B6B6;
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
- border-radius: 0;
- margin-bottom: 10px;
- border: 1px solid #bbb;
- -webkit-box-shadow: 0 0 0 3px #F1F1F1;
- -moz-box-shadow: 0 0 0 3px #f1f1f1;
- -ms-box-shadow: 0 0 0 3px #f1f1f1;
- -o-box-shadow: 0 0 0 3px #f1f1f1;
- box-shadow: 0 0 0 3px #F1F1F1;
-}
-
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 6px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { border: 1px none; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev span { background-position: 0px -32px !important; }
-.ui-datepicker .ui-datepicker-next span { background-position: -16px -32px !important; }
-.ui-datepicker .ui-datepicker-prev-hover span { background-position: 0px -48px !important; }
-.ui-datepicker .ui-datepicker-next-hover span { background-position: -16px -48px !important; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; background: url(icon_sprite.png) no-repeat; }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; font-size: 12px; text-shadow: 0 1px 0 rgba(255,255,255,0.6); }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month,
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
-.ui-datepicker td { border: 0; padding: 1px; line-height: 24px; background-color: #FFF!important; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-.ui-datepicker table .ui-state-highlight { border-color: #ADE; }
-.ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; }
-.ui-datepicker-calendar .ui-state-active { background: #D9EDF7; border-color: #ADE; color: #3A89A3; font-weight: bold; text-shadow: 0 1px 1px #fff; }
diff --git a/app/assets/stylesheets/main/fonts.scss b/app/assets/stylesheets/main/fonts.scss
index 8cc9986415c..d90274a0db9 100644
--- a/app/assets/stylesheets/main/fonts.scss
+++ b/app/assets/stylesheets/main/fonts.scss
@@ -1,2 +1,3 @@
/** Typo **/
$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
+$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index ba25a87f392..00ec34ae547 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -20,7 +20,7 @@ module MergeRequestsHelper
target_project_id: target_project.id,
source_branch: event.branch_name,
target_branch: target_project.repository.root_ref,
- title: event.branch_name.humanize
+ title: event.branch_name.titleize.humanize
}
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index d85398809c2..06140c5afeb 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -178,29 +178,29 @@ class NotificationService
# Get project users with WATCH notification level
def project_watchers(project)
- # Gather all user ids that have WATCH notification setting for project
- project_notification_uids = project_notification_list(project, Notification::N_WATCH)
+ project_members = users_project_notification(project)
- # Gather all user ids that have WATCH notification setting for group
- group_notification_uids = group_notification_list(project, Notification::N_WATCH)
+ users_with_project_level_global = users_project_notification(project, Notification::N_GLOBAL)
+ users_with_group_level_global = users_group_notification(project, Notification::N_GLOBAL)
+ users = users_with_global_level_watch([users_with_project_level_global, users_with_group_level_global].flatten.uniq)
- # Gather all user ids that have GLOBAL setting
- global_notification_uids = global_notification_list(project)
+ users_with_project_setting = select_users_project_setting(project, users_with_project_level_global, users)
+ users_with_group_setting = select_users_group_setting(project, project_members, users_with_group_level_global, users)
- project_and_group_uids = [project_notification_uids, group_notification_uids].flatten.uniq
- group_and_project_watchers = User.where(id: project_and_group_uids)
-
- # Find all users that have WATCH as their GLOBAL setting
- global_watchers = User.where(id: global_notification_uids, notification_level: Notification::N_WATCH)
-
- [group_and_project_watchers, global_watchers].flatten.uniq
+ User.where(id: users_with_project_setting.concat(users_with_group_setting).uniq).to_a
end
- def project_notification_list(project, notification_level)
- project.users_projects.where(notification_level: notification_level).pluck(:user_id)
+ def users_project_notification(project, notification_level=nil)
+ project_members = project.users_projects
+
+ if notification_level
+ project_members.where(notification_level: notification_level).pluck(:user_id)
+ else
+ project_members.pluck(:user_id)
+ end
end
- def group_notification_list(project, notification_level)
+ def users_group_notification(project, notification_level)
if project.group
project.group.users_groups.where(notification_level: notification_level).pluck(:user_id)
else
@@ -208,11 +208,47 @@ class NotificationService
end
end
- def global_notification_list(project)
- [
- project_notification_list(project, Notification::N_GLOBAL),
- group_notification_list(project, Notification::N_GLOBAL)
- ].flatten
+ def users_with_global_level_watch(ids)
+ User.where(
+ id: ids,
+ notification_level: Notification::N_WATCH
+ ).pluck(:id)
+ end
+
+ # Build a list of users based on project notifcation settings
+ def select_users_project_setting(project, global_setting, users_global_level_watch)
+ users = users_project_notification(project, Notification::N_WATCH)
+
+ # If project setting is global, add to watch list if global setting is watch
+ global_setting.each do |user_id|
+ if users_global_level_watch.include?(user_id)
+ users << user_id
+ end
+ end
+
+ users
+ end
+
+ # Build a list of users based on group notifcation settings
+ def select_users_group_setting(project, project_members, global_setting, users_global_level_watch)
+ uids = users_group_notification(project, Notification::N_WATCH)
+
+ # Group setting is watch, add to users list if user is not project member
+ users = []
+ uids.each do |user_id|
+ if project_members.exclude?(user_id)
+ users << user_id
+ end
+ end
+
+ # Group setting is global, add to users list if global setting is watch
+ global_setting.each do |user_id|
+ if project_members.exclude?(user_id) && users_global_level_watch.include?(user_id)
+ users << user_id
+ end
+ end
+
+ users
end
# Remove users with disabled notifications from array
diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml
index 0b7697622b0..f1e866c8e9d 100644
--- a/app/views/projects/issues/_head.html.haml
+++ b/app/views/projects/issues/_head.html.haml
@@ -20,6 +20,11 @@
= form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
.append-right-10.hidden-xs.hidden-sm
= search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
+ = hidden_field_tag :state, params['state']
+ = hidden_field_tag :scope, params['scope']
+ = hidden_field_tag :assignee_id, params['assignee_id']
+ = hidden_field_tag :milestone_id, params['milestone_id']
+ = hidden_field_tag :label_id, params['label_id']
- if can? current_user, :write_issue, @project
= link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
%i.icon-plus
diff --git a/app/views/projects/merge_requests/branch_from.js.haml b/app/views/projects/merge_requests/branch_from.js.haml
index 1b1082baafe..693c2057a0f 100644
--- a/app/views/projects/merge_requests/branch_from.js.haml
+++ b/app/views/projects/merge_requests/branch_from.js.haml
@@ -3,5 +3,5 @@
var mrTitle = $('#merge_request_title');
if(mrTitle.val().length == 0) {
- mrTitle.val("#{params[:ref].humanize}");
+ mrTitle.val("#{params[:ref].titleize.humanize}");
}
diff --git a/config/application.rb b/config/application.rb
index f7791b47b04..3933c046af0 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -63,6 +63,7 @@ module Gitlab
config.assets.enabled = true
config.assets.paths << Emoji.images_path
config.assets.precompile << "emoji/*.png"
+ config.assets.precompile << "print.css"
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
diff --git a/doc/README.md b/doc/README.md
index d85a2d854d3..dfa3211d01b 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -1,18 +1,24 @@
-## The GitLab Documentation covers the following subjects
+**User documentation**
-+ [API](api/README.md)
-+ [Development](development/README.md)
-+ [Install](install/README.md)
-+ [Integration](integration/external-issue-tracker.md)
-+ [Legal](legal/README.md)
-+ [Markdown](markdown/markdown.md)
-+ [Permissions](permissions/permissions.md)
-+ [Public access](public_access/public_access.md)
-+ [Raketasks](raketasks/README.md)
-+ [Release](release/README.md)
-+ [Security](security/README.md)
-+ [SSH](ssh/README.md)
-+ [System hooks](system_hooks/system_hooks.md)
-+ [Update](update/README.md)
-+ [Web hooks](web_hooks/web_hooks.md)
-+ [Workflow](workflow/workflow.md)
++ [API](api/README.md) Explore how you can access GitLab via a simple and powerful API.
++ [Markdown](markdown/markdown.md) Learn what you can do with GitLab's advanced formatting system.
++ [Permissions](permissions/permissions.md) Learn what each role in a project (guest/reporter/developer/master/owner) can do.
++ [Public access](public_access/public_access.md) Learn how you can allow public and internal access to a project.
++ [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
++ [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
++ [Workflow](workflow/workflow.md) Learn how to use Git and GitLab together.
+
+**Administrator documentation**
+
++ [Install](install/README.md) Requirements, directory structures and manual installation.
++ [Integration](integration/external-issue-tracker.md) How to integrate JIRA and Redmine.
++ [Raketasks](raketasks/README.md) Explore what GitLab has in store for you to make administration easier.
++ [System hooks](system_hooks/system_hooks.md) Let GitLab notify you when certain management tasks need to be carried out.
++ [Security](security/README.md) Learn what you can do to further secure your GitLab instance.
++ [Update](update/README.md) Update guides to upgrade your installation.
+
+**Contributor documentation**
+
++ [Development](development/README.md) Explains the architecture and the guidelines for shell commands.
++ [Legal](legal/README.md) Contributor license agreements.
++ [Release](release/README.md) How to make the monthly and security releases.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index addb21b50e0..efcba2f69bf 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -202,6 +202,7 @@ You can change `6-6-stable` to `master` if you want the *bleeding edge* version,
# Create directory for satellites
sudo -u git -H mkdir /home/git/gitlab-satellites
+ sudo chmod o-rwx /home/git/gitlab-satellites
# Create directories for sockets/pids and make sure GitLab can write to them
sudo -u git -H mkdir tmp/pids/
diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md
index 3212ebd64b5..6b34826da52 100644
--- a/doc/integration/external-issue-tracker.md
+++ b/doc/integration/external-issue-tracker.md
@@ -2,7 +2,7 @@ GitLab has a great issue tracker but you can also use an external issue tracker
- the 'Issues' link on the GitLab project pages takes you to the appropriate JIRA issue index;
- clicking 'New issue' on the project dashboard creates a new JIRA issue;
-- textual references to PROJECT-1234 in comments, commit messages get turned into HTML links to the corresponding JIRA issue.
+- To reference JIRA issue PROJECT-1234 in comments, use syntax #PROJECT-1234. Commit messages get turned into HTML links to the corresponding JIRA issue.
![jira screenshot](jira-intergration-points.png)
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
new file mode 100644
index 00000000000..efc28d06e71
--- /dev/null
+++ b/doc/workflow/README.md
@@ -0,0 +1,2 @@
++ [Workflow](workflow/workflow.md)
++ [Project Features](workflow/project_features.md)
diff --git a/doc/workflow/project_features.md b/doc/workflow/project_features.md
new file mode 100644
index 00000000000..25fe4032570
--- /dev/null
+++ b/doc/workflow/project_features.md
@@ -0,0 +1,35 @@
+When in a Project -> Settings, you will find Features on the bottom of the page that you can toggle.
+Below you will find a more elaborate explanation of each of these.
+
+
+## Issues
+
+Issues is a really powerful, but lightweight issue tracking system.
+You can make tickets, assign them to people, file them under milestones, order them with labels and have discussion in them.
+They integrate deeply into GitLab and are easily referenced from anywhere by using # and the issuenumber.
+At GitLab.com, we use this for all our project management needs.
+
+## Merge Requests
+
+Using a merge request, you can review and discuss code before it is merged in the branch of your code.
+As with issues, it can be assigned; people, issues, etc. can be refereced; milestones attached.
+We see it as an integral part of working together on code and couldn't work without it.
+
+
+## Wiki
+
+This is a separate system for documentation, built right into GitLab.
+It is source controlled and is very convenient if you don't want to keep you documentation in your source code, but you do want to keep it in your GitLab project.
+
+
+## Wall
+
+For simple, project specific conversations, the wall can be used.
+It's very lightweight and simple and works well if you're not interested in using issues, but still want to occasionally communicate within a project.
+
+
+## Snippets
+
+Snippets are little bits of code or text.
+This is a nice place to put code or text that is used semi-regularly within the project, but does not belong in source control.
+For example, a specific config file that is used by > the team that is only valid for the people that work on the code.
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 3b9b2531bf7..e9258cc626b 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -342,6 +342,7 @@ namespace :gitlab do
check_repo_base_is_not_symlink
check_repo_base_user_and_group
check_repo_base_permissions
+ check_satellites_permissions
check_update_hook_is_up_to_date
check_repos_update_hooks_is_link
check_gitlab_shell_self_test
@@ -443,6 +444,29 @@ namespace :gitlab do
end
end
+ def check_satellites_permissions
+ print "Satellites access is drwxr-x---? ... "
+
+ satellites_path = Gitlab.config.satellites.path
+ unless File.exists?(satellites_path)
+ puts "can't check because of previous errors".magenta
+ return
+ end
+
+ if File.stat(satellites_path).mode.to_s(8).ends_with?("0750")
+ puts "yes".green
+ else
+ puts "no".red
+ try_fixing_it(
+ "sudo chmod u+rwx,g+rx,o-rwx #{satellites_path}",
+ )
+ for_more_information(
+ see_installation_guide_section "GitLab"
+ )
+ fix_and_rerun
+ end
+ end
+
def check_repo_base_user_and_group
gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user
gitlab_shell_owner_group = Gitlab.config.gitlab_shell.owner_group
diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake
index 690f414f3b3..72452e1d8ea 100644
--- a/lib/tasks/gitlab/info.rake
+++ b/lib/tasks/gitlab/info.rake
@@ -24,6 +24,7 @@ namespace :gitlab do
puts "Gem Version:\t#{gem_version || "unknown".red}"
puts "Bundler Version:#{bunder_version || "unknown".red}"
puts "Rake Version:\t#{rake_version || "unknown".red}"
+ puts "Sidekiq Version:#{Sidekiq::VERSION}"
# check database adapter
diff --git a/script/background_jobs b/script/background_jobs
index 52732f5532b..e0140e9689b 100755
--- a/script/background_jobs
+++ b/script/background_jobs
@@ -37,7 +37,7 @@ function start_no_deamonize
function start_sidekiq
{
- bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e $RAILS_ENV -P $sidekiq_pidfile $@ >> $sidekiq_logfile 2>&1
+ bundle exec sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e $RAILS_ENV -P $sidekiq_pidfile $@ >> $sidekiq_logfile 2>&1
}
function load_ok
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index fbd73a7086f..0c25f7a71d0 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -57,15 +57,42 @@ describe NotificationService do
Notify.should_not_receive(:note_issue_email)
notification.new_note(mentioned_note)
end
+ end
- def should_email(user_id)
- Notify.should_receive(:note_issue_email).with(user_id, note.id)
+ describe 'new note on issue in project that belongs to a group' do
+ let(:group) { create(:group) }
+
+ before do
+ note.project.namespace_id = group.id
+ note.project.group.add_user(@u_watcher, UsersGroup::MASTER)
+ note.project.save
+ user_project = note.project.users_projects.find_by_user_id(@u_watcher.id)
+ user_project.notification_level = Notification::N_PARTICIPATING
+ user_project.save
+ user_group = note.project.group.users_groups.find_by_user_id(@u_watcher.id)
+ user_group.notification_level = Notification::N_GLOBAL
+ user_group.save
end
- def should_not_email(user_id)
- Notify.should_not_receive(:note_issue_email).with(user_id, note.id)
+ it do
+ should_email(note.noteable.author_id)
+ should_email(note.noteable.assignee_id)
+ should_email(@u_mentioned.id)
+ should_not_email(@u_watcher.id)
+ should_not_email(note.author_id)
+ should_not_email(@u_participating.id)
+ should_not_email(@u_disabled.id)
+ notification.new_note(note)
end
end
+
+ def should_email(user_id)
+ Notify.should_receive(:note_issue_email).with(user_id, note.id)
+ end
+
+ def should_not_email(user_id)
+ Notify.should_not_receive(:note_issue_email).with(user_id, note.id)
+ end
end
context 'commit note' do