summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--CHANGELOG29
-rw-r--r--app/controllers/admin/services_controller.rb51
-rw-r--r--app/helpers/labels_helper.rb19
-rw-r--r--app/models/concerns/mentionable.rb7
-rw-r--r--app/models/external_issue.rb25
-rw-r--r--app/models/project.rb24
-rw-r--r--app/models/project_services/asana_service.rb17
-rw-r--r--app/models/project_services/assembla_service.rb3
-rw-r--r--app/models/project_services/bamboo_service.rb3
-rw-r--r--app/models/project_services/buildbox_service.rb4
-rw-r--r--app/models/project_services/campfire_service.rb3
-rw-r--r--app/models/project_services/ci_service.rb3
-rw-r--r--app/models/project_services/custom_issue_tracker_service.rb3
-rw-r--r--app/models/project_services/emails_on_push_service.rb3
-rw-r--r--app/models/project_services/flowdock_service.rb3
-rw-r--r--app/models/project_services/gemnasium_service.rb3
-rw-r--r--app/models/project_services/gitlab_ci_service.rb3
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb3
-rw-r--r--app/models/project_services/hipchat_service.rb3
-rw-r--r--app/models/project_services/issue_tracker_service.rb15
-rw-r--r--app/models/project_services/jira_service.rb3
-rw-r--r--app/models/project_services/pivotaltracker_service.rb3
-rw-r--r--app/models/project_services/pushover_service.rb3
-rw-r--r--app/models/project_services/redmine_service.rb3
-rw-r--r--app/models/project_services/slack_service.rb3
-rw-r--r--app/models/project_services/teamcity_service.rb3
-rw-r--r--app/models/service.rb22
-rw-r--r--app/views/admin/services/_form.html.haml36
-rw-r--r--app/views/admin/services/edit.html.haml1
-rw-r--r--app/views/admin/services/index.html.haml22
-rw-r--r--app/views/layouts/nav/_admin.html.haml6
-rw-r--r--app/views/profiles/keys/index.html.haml2
-rw-r--r--app/views/projects/labels/_form.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml6
-rw-r--r--config/routes.rb10
-rw-r--r--db/migrate/20150211172122_add_template_to_service.rb5
-rw-r--r--db/migrate/20150211174341_allow_null_in_services_project_id.rb5
-rw-r--r--db/schema.rb5
-rw-r--r--doc/api/groups.md14
-rw-r--r--doc/release/monthly.md9
-rw-r--r--lib/api/group_members.rb24
-rw-r--r--lib/api/helpers.rb5
-rw-r--r--lib/api/project_members.rb12
-rw-r--r--lib/gitlab/reference_extractor.rb2
-rw-r--r--spec/models/service_spec.rb28
-rw-r--r--spec/requests/api/group_members_spec.rb63
47 files changed, 413 insertions, 109 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000000..7e800609e6c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+CHANGELOG merge=union \ No newline at end of file
diff --git a/CHANGELOG b/CHANGELOG
index 286091afacf..9bb75fdf884 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,3 @@
-Note: The upcoming release below contains empty lines.
-This helps to reduce the number of merge conflicts.
-Scroll down to see the released versions of GitLab.
-Please pick a random empty line to add new content.
-
v 7.8.0 (unreleased)
- Replace highlight.js with rouge-fork rugments (Stefan Tatschner)
- Make project search case insensitive (Hannes Rosenögger)
@@ -19,58 +14,36 @@ v 7.8.0 (unreleased)
- Add notes for label changes in issue and merge requests
- Show tags in commit view (Hannes Rosenögger)
- Only count a user's vote once on a merge request or issue (Michael Clarke)
- -
- Increate font size when browse source files and diffs
- Create new file in empty repository using GitLab UI
- -
- Ability to clone project using oauth2 token
- -
- Upgrade Sidekiq gem to version 3.3.0
- Stop git zombie creation during force push check
- Show success/error messages for test setting button in services
- Added Rubocop for code style checks
- Fix commits pagination
- -
- Async load a branch information at the commit page
- Disable blacklist validation for project names
- Allow configuring protection of the default branch upon first push (Marco Wessel)
- -
- Add gitlab.com importer
- Add an ability to login with gitlab.com
- -
- Add a commit calendar to the user profile (Hannes Rosenögger)
- -
- Submit comment on command-enter
- Notify all members of a group when that group is mentioned in a comment, for example: `@gitlab-org` or `@sales`.
- Extend issue clossing pattern to include "Resolve", "Resolves", "Resolved", "Resolving" and "Close"
- -
- Fix long broadcast message cut-off on left sidebar (Visay Keo)
- Add Project Avatars (Steven Thonus and Hannes Rosenögger)
- -
- -
- Password reset token validity increased from 2 hours to 2 days since it is also send on account creation.
- -
- -
+ - Edit group members via API
- Enable raw image paste from clipboard, currently Chrome only (Marco Cyriacks)
- -
- -
- Add action property to merge request hook (Julien Bianchi)
- -
- Remove duplicates from group milestone participants list.
- -
- -
- Add a new API function that retrieves all issues assigned to a single milestone (Justin Whear and Hannes Rosenögger)
- -
- -
- API: Access groups with their path (Julien Bianchi)
- Added link to milestone and keeping resource context on smaller viewports for issues and merge requests (Jason Blanchard)
- -
- Allow notification email to be set separately from primary email.
- -
- API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger)
- -
- Don't have Markdown preview fail for long comments/wiki pages.
- -
- When test web hook - show error message instead of 500 error page if connection to hook url was reset
- Added support for firing system hooks on group create/destroy and adding/removing users to group (Boyan Tabakov)
- Added persistent collapse button for left side nav bar (Jason Blanchard)
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
new file mode 100644
index 00000000000..e80cabd6e18
--- /dev/null
+++ b/app/controllers/admin/services_controller.rb
@@ -0,0 +1,51 @@
+class Admin::ServicesController < Admin::ApplicationController
+ before_filter :service, only: [:edit, :update]
+
+ def index
+ @services = services_templates
+ end
+
+ def edit
+ unless service.present?
+ redirect_to admin_application_settings_services_path,
+ alert: "Service is unknown or it doesn't exist"
+ end
+ end
+
+ def update
+ if service.update_attributes(application_services_params[:service])
+ redirect_to admin_application_settings_services_path,
+ notice: 'Application settings saved successfully'
+ else
+ render :edit
+ end
+ end
+
+ private
+
+ def services_templates
+ templates = []
+
+ Service.available_services_names.each do |service_name|
+ service_template = service_name.concat("_service").camelize.constantize
+ templates << service_template.where(template: true).first_or_create
+ end
+
+ templates
+ end
+
+ def service
+ @service ||= Service.where(id: params[:id], template: true).first
+ end
+
+ def application_services_params
+ params.permit(:id,
+ service: [
+ :title, :token, :type, :active, :api_key, :subdomain,
+ :room, :recipients, :project_url, :webhook,
+ :user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
+ :build_key, :server, :teamcity_url, :build_type,
+ :description, :issues_url, :new_issue_url, :restrict_to_branch
+ ])
+ end
+end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index add0fef512e..49063491abf 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -14,14 +14,27 @@ module LabelsHelper
def suggested_colors
[
- '#D9534F',
- '#F0AD4E',
+ '#0033CC',
'#428BCA',
+ '#44AD8E',
+ '#A8D695',
'#5CB85C',
+ '#69D100',
+ '#004E00',
'#34495E',
'#7F8C8D',
+ '#A295D6',
+ '#5843AD',
'#8E44AD',
- '#FFECDB'
+ '#FFECDB',
+ '#AD4363',
+ '#D10069',
+ '#CC0033',
+ '#FF0000',
+ '#D9534F',
+ '#D1D100',
+ '#F0AD4E',
+ '#AD8D43'
]
end
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index d640728519a..50be458bf24 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -67,9 +67,10 @@ module Mentionable
return [] if text.blank?
ext = Gitlab::ReferenceExtractor.new
ext.analyze(text, p)
- (ext.issues_for +
- ext.merge_requests_for +
- ext.commits_for).uniq - [local_reference]
+
+ (ext.issues_for(p) +
+ ext.merge_requests_for(p) +
+ ext.commits_for(p)).uniq - [local_reference]
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb
new file mode 100644
index 00000000000..50efcb32f1b
--- /dev/null
+++ b/app/models/external_issue.rb
@@ -0,0 +1,25 @@
+class ExternalIssue
+ def initialize(issue_identifier, project)
+ @issue_identifier, @project = issue_identifier, project
+ end
+
+ def to_s
+ @issue_identifier.to_s
+ end
+
+ def id
+ @issue_identifier.to_s
+ end
+
+ def iid
+ @issue_identifier.to_s
+ end
+
+ def ==(other)
+ other.is_a?(self.class) && (to_s == other.to_s)
+ end
+
+ def project
+ @project
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index e53b268c8ea..56e1aa29040 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -353,18 +353,28 @@ class Project < ActiveRecord::Base
end
def build_missing_services
- available_services_names.each do |service_name|
- service = services.find { |service| service.to_param == service_name }
+ services_templates = Service.where(template: true)
+
+ Service.available_services_names.each do |service_name|
+ service = find_service(services, service_name)
# If service is available but missing in db
- # we should create an instance. Ex `create_gitlab_ci_service`
- service = self.send :"create_#{service_name}_service" if service.nil?
+ if service.nil?
+ # We should check if template for the service exists
+ template = find_service(services_templates, service_name)
+
+ if template.nil?
+ # If no template, we should create an instance. Ex `create_gitlab_ci_service`
+ service = self.send :"create_#{service_name}_service"
+ else
+ Service.create_from_template(self.id, template)
+ end
+ end
end
end
- def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla asana
- emails_on_push gemnasium slack pushover buildbox bamboo teamcity jira redmine custom_issue_tracker)
+ def find_service(list, name)
+ list.find { |service| service.to_param == name }
end
def gitlab_ci?
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
index db1e7a2b1cb..66b72572b9c 100644
--- a/app/models/project_services/asana_service.rb
+++ b/app/models/project_services/asana_service.rb
@@ -2,14 +2,15 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# 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)
#
require 'asana'
diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb
index 0b90a14f39c..cf7598f35eb 100644
--- a/app/models/project_services/assembla_service.rb
+++ b/app/models/project_services/assembla_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class AssemblaService < Service
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index 745609e5911..df68803152f 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class BambooService < CiService
diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb
index 0ab67b79fe4..058c890ae45 100644
--- a/app/models/project_services/buildbox_service.rb
+++ b/app/models/project_services/buildbox_service.rb
@@ -5,13 +5,13 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
-
require "addressable/uri"
class BuildboxService < CiService
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index 3116c311052..14b6b87a0b7 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class CampfireService < Service
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index b1d5e49ede3..5a26c25b3c3 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
# Base class for CI services
diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb
index 5845e2d3525..b29d1c86881 100644
--- a/app/models/project_services/custom_issue_tracker_service.rb
+++ b/app/models/project_services/custom_issue_tracker_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class CustomIssueTrackerService < IssueTrackerService
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index b9071b98295..86693ad0c7e 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class EmailsOnPushService < Service
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 86705f5dabd..13e2dfceb1a 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
require "flowdock-git-hook"
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 18fdd204ecd..a2c87ae88f1 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
require "gemnasium/gitlab_service"
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 248f749b310..f4b463e8199 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class GitlabCiService < CiService
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index 25e399883b7..b1eab24df19 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class GitlabIssueTrackerService < IssueTrackerService
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index c4c563b3cca..003e06a4c80 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class HipchatService < Service
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index b19c02bab44..51b2fb3dcc7 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class IssueTrackerService < Service
@@ -77,12 +78,14 @@ class IssueTrackerService < Service
end
def set_project_url
- id = self.project.issues_tracker_id
+ if self.project
+ id = self.project.issues_tracker_id
- if id
- issues_tracker['project_url'].gsub(":issues_tracker_id", id)
- else
- issues_tracker['project_url']
+ if id
+ issues_tracker['project_url'].gsub(":issues_tracker_id", id)
+ end
end
+
+ issues_tracker['project_url']
end
end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 7a32b0e8c2c..a159c287485 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class JiraService < IssueTrackerService
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index 09e114f9cca..287812c57a5 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class PivotaltrackerService < Service
diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb
index a9b23f97ba0..3a3af59390a 100644
--- a/app/models/project_services/pushover_service.rb
+++ b/app/models/project_services/pushover_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class PushoverService < Service
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
index 547b2401832..e1dc10415e0 100644
--- a/app/models/project_services/redmine_service.rb
+++ b/app/models/project_services/redmine_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class RedmineService < IssueTrackerService
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index 963f5440b6f..297d8bbb5d4 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class SlackService < Service
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index 287f5c0e84e..c4b6ef5d9a9 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
class TeamcityService < CiService
diff --git a/app/models/service.rb b/app/models/service.rb
index caabe8e971d..f87d875c10a 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -5,12 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
-#
+# template :boolean default(FALSE)
# To add new service you should build a class inherited from Service
# and implement a set of methods
@@ -25,7 +25,7 @@ class Service < ActiveRecord::Base
belongs_to :project
has_one :service_hook
- validates :project_id, presence: true
+ validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
@@ -33,6 +33,10 @@ class Service < ActiveRecord::Base
active
end
+ def template?
+ template
+ end
+
def category
:common
end
@@ -94,7 +98,15 @@ class Service < ActiveRecord::Base
self.category == :issue_tracker
end
- def self.issue_tracker_service_list
- Service.select(&:issue_tracker?).map{ |s| s.to_param }
+ def self.available_services_names
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla asana
+ emails_on_push gemnasium slack pushover buildbox bamboo teamcity jira redmine custom_issue_tracker)
+ end
+
+ def self.create_from_template(project_id, template)
+ service = template.dup
+ service.template = false
+ service.project_id = project_id
+ service if service.save
end
end
diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml
new file mode 100644
index 00000000000..d8242e37621
--- /dev/null
+++ b/app/views/admin/services/_form.html.haml
@@ -0,0 +1,36 @@
+%h3.page-title
+ = @service.title
+
+%p #{@service.description} template
+
+= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'form-horizontal fieldset-form' } do |f|
+ - if @service.errors.any?
+ #error_explanation
+ .alert.alert-danger
+ - @service.errors.full_messages.each do |msg|
+ %p= msg
+
+ - @service.fields.each do |field|
+ - name = field[:name]
+ - value = @service.send(name) unless field[:type] == 'password'
+ - type = field[:type]
+ - placeholder = field[:placeholder]
+ - choices = field[:choices]
+ - default_choice = field[:default_choice]
+
+ .form-group
+ = f.label name, class: "control-label"
+ .col-sm-10
+ - if type == 'text'
+ = f.text_field name, class: "form-control", placeholder: placeholder
+ - elsif type == 'textarea'
+ = f.text_area name, rows: 5, class: "form-control", placeholder: placeholder
+ - elsif type == 'checkbox'
+ = f.check_box name
+ - elsif type == 'select'
+ = f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
+ - elsif type == 'password'
+ = f.password_field name, class: 'form-control'
+
+ .form-actions
+ = f.submit 'Save', class: 'btn btn-save'
diff --git a/app/views/admin/services/edit.html.haml b/app/views/admin/services/edit.html.haml
new file mode 100644
index 00000000000..bcc5832792f
--- /dev/null
+++ b/app/views/admin/services/edit.html.haml
@@ -0,0 +1 @@
+= render 'form'
diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml
new file mode 100644
index 00000000000..1d3e192a325
--- /dev/null
+++ b/app/views/admin/services/index.html.haml
@@ -0,0 +1,22 @@
+%h3.page-title Service templates
+%p.light Service template allows you to set default values for project services
+
+%table.table
+ %thead
+ %tr
+ %th
+ %th Service
+ %th Desription
+ %th Last edit
+ - @services.sort_by(&:title).each do |service|
+ %tr
+ %td
+ = icon("copy", class: 'clgray')
+ %td
+ = link_to edit_admin_application_settings_service_path(service.id) do
+ %strong= service.title
+ %td
+ = service.description
+ %td.light
+ = time_ago_in_words service.updated_at
+ ago
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index 4813a4f16f5..4f864926d08 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -46,6 +46,12 @@
%span
Applications
+ = nav_link(controller: :application_settings) do
+ = link_to admin_application_settings_services_path, title: 'Service Templates' do
+ %i.fa.fa-copy
+ %span
+ Service Templates
+
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to admin_application_settings_path, title: 'Settings' do
%i.fa.fa-cogs
diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml
index 809953960bb..c83c73ffcf9 100644
--- a/app/views/profiles/keys/index.html.haml
+++ b/app/views/profiles/keys/index.html.haml
@@ -6,7 +6,7 @@
SSH keys allow you to establish a secure connection between your computer and GitLab
%br
Before you can add an SSH key you need to
- = link_to "generate it", help_page_path("ssh", "ssh")
+ = link_to "generate it", help_page_path("ssh", "README")
%hr
= render 'key_table'
diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml
index 72a01e1c271..c7380920b47 100644
--- a/app/views/projects/labels/_form.html.haml
+++ b/app/views/projects/labels/_form.html.haml
@@ -16,7 +16,7 @@
.col-sm-10
.input-group
.input-group-addon.label-color-preview &nbsp;
- = f.text_field :color, placeholder: "#AA33EE", class: "form-control"
+ = f.color_field :color, placeholder: "#AA33EE", class: "form-control"
.help-block
6 character hex values starting with a # sign.
%br
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index dedb060a231..5afc87fb6b1 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -15,8 +15,10 @@
= merge_request.target_branch
.merge-request-info
%span.light= "##{merge_request.iid}"
- - if merge_request.author
- authored by #{link_to_member(merge_request.source_project, merge_request.author)}
+ - if merge_request.assignee
+ assigned to #{link_to_member(merge_request.source_project, merge_request.assignee)}
+ - else
+ Work In Progress
- if merge_request.votes_count > 0
= render 'votes/votes_inline', votable: merge_request
- if merge_request.notes.any?
diff --git a/config/routes.rb b/config/routes.rb
index c8a8415ae77..65786d83566 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -51,7 +51,7 @@ Gitlab::Application.routes.draw do
end
get '/s/:username' => 'snippets#user_index', as: :user_snippets, constraints: { username: /.*/ }
-
+
#
# Import
#
@@ -68,8 +68,8 @@ Gitlab::Application.routes.draw do
get :jobs
end
end
-
-
+
+
#
# Explore area
@@ -131,7 +131,9 @@ Gitlab::Application.routes.draw do
end
end
- resource :application_settings, only: [:show, :update]
+ resource :application_settings, only: [:show, :update] do
+ resources :services
+ end
root to: 'dashboard#index'
end
diff --git a/db/migrate/20150211172122_add_template_to_service.rb b/db/migrate/20150211172122_add_template_to_service.rb
new file mode 100644
index 00000000000..b1bfbc45ee9
--- /dev/null
+++ b/db/migrate/20150211172122_add_template_to_service.rb
@@ -0,0 +1,5 @@
+class AddTemplateToService < ActiveRecord::Migration
+ def change
+ add_column :services, :template, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20150211174341_allow_null_in_services_project_id.rb b/db/migrate/20150211174341_allow_null_in_services_project_id.rb
new file mode 100644
index 00000000000..68f02812791
--- /dev/null
+++ b/db/migrate/20150211174341_allow_null_in_services_project_id.rb
@@ -0,0 +1,5 @@
+class AllowNullInServicesProjectId < ActiveRecord::Migration
+ def change
+ change_column :services, :project_id, :integer, null: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0ac54517ed0..f33766a1fe8 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: 20150209222013) do
+ActiveRecord::Schema.define(version: 20150211174341) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -360,11 +360,12 @@ ActiveRecord::Schema.define(version: 20150209222013) do
create_table "services", force: true do |t|
t.string "type"
t.string "title"
- t.integer "project_id", null: false
+ t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "active", default: false, null: false
t.text "properties"
+ t.boolean "template", default: false
end
add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 9f01b550641..3c1858e697d 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -152,6 +152,20 @@ Parameters:
- `user_id` (required) - The ID of a user to add
- `access_level` (required) - Project access level
+### Edit group team member
+
+Updates a group team member to a specified access level.
+
+```
+PUT /groups/:id/members/:user_id
+```
+
+Parameters:
+
+- `id` (required) - The ID of a group
+- `user_id` (required) - The ID of a group member
+- `access_level` (required) - Project access level
+
### Remove user team member
Removes user from user team.
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 12376d36a9a..c9e6d3426bc 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -87,20 +87,13 @@ asked if there is anything missing.
There are three changelogs that need to be updated: CE, EE and CI.
-Remove the Note text in the stable branches.
-
## Create RC1 (CE, EE, CI)
[Follow this How-to guide](howto_rc1.md) to create RC1.
## Prepare CHANGELOG for next release
-Once the stable branches have been created, update the CHANGELOG in `master` with the upcoming version and add 70 empty
-lines to it. We do this in order to avoid merge conflicts when merging the CHANGELOG.
-
-Make sure that the CHANGELOG im master contains the following disclaimer message:
-
-> Note: The upcoming release contains empty lines to reduce the number of merge conflicts, scroll down to see past releases.
+Once the stable branches have been created, update the CHANGELOG in `master` with the upcoming version.
## QA
diff --git a/lib/api/group_members.rb b/lib/api/group_members.rb
index 4373070083a..c9c9ccbcb2e 100644
--- a/lib/api/group_members.rb
+++ b/lib/api/group_members.rb
@@ -40,6 +40,30 @@ module API
present member.user, with: Entities::GroupMember, group: group
end
+ # Update group member
+ #
+ # Parameters:
+ # id (required) - The ID of a group
+ # user_id (required) - The ID of a group member
+ # access_level (required) - Project access level
+ # Example Request:
+ # PUT /groups/:id/members/:user_id
+ put ':id/members/:user_id' do
+ group = find_group(params[:id])
+ authorize! :manage_group, group
+ required_attributes! [:access_level]
+
+ team_member = group.group_members.find_by(user_id: params[:user_id])
+ not_found!('User can not be found') if team_member.nil?
+
+ if team_member.update_attributes(access_level: params[:access_level])
+ @member = team_member.user
+ present @member, with: Entities::GroupMember, group: group
+ else
+ handle_member_errors team_member.errors
+ end
+ end
+
# Remove member.
#
# Parameters:
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 8fa30460ba6..a50ee4659a3 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -238,5 +238,10 @@ module API
def secret_token
File.read(Rails.root.join('.gitlab_shell_secret'))
end
+
+ def handle_member_errors(errors)
+ error!(errors[:access_level], 422) if errors[:access_level].any?
+ not_found!(errors)
+ end
end
end
diff --git a/lib/api/project_members.rb b/lib/api/project_members.rb
index 1e890f9e199..73cf062155b 100644
--- a/lib/api/project_members.rb
+++ b/lib/api/project_members.rb
@@ -4,14 +4,6 @@ module API
before { authenticate! }
resource :projects do
- helpers do
- def handle_project_member_errors(errors)
- if errors[:access_level].any?
- error!(errors[:access_level], 422)
- end
- not_found!(errors)
- end
- end
# Get a project team members
#
@@ -66,7 +58,7 @@ module API
@member = team_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_project_member_errors team_member.errors
+ handle_member_errors team_member.errors
end
end
@@ -89,7 +81,7 @@ module API
@member = team_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_project_member_errors team_member.errors
+ handle_member_errors team_member.errors
end
end
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 0b9177afa4f..7e5c991a222 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -71,7 +71,7 @@ module Gitlab
if entry_project.nil?
false
else
- project.nil? || project.id == entry_project.id
+ project.nil? || entry_project.default_issues_tracker?
end
end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 1129bd1c76d..9a1248055b1 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -5,11 +5,12 @@
# id :integer not null, primary key
# type :string(255)
# title :string(255)
-# project_id :integer not null
+# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
+# template :boolean default(FALSE)
#
require 'spec_helper'
@@ -59,4 +60,29 @@ describe Service do
end
end
end
+
+ describe "Template" do
+ describe "for pushover service" do
+ let(:service_template) {
+ PushoverService.create(template: true, properties: {device: 'MyDevice', sound: 'mic', priority: 4, api_key: '123456789'})
+ }
+ let(:project) { create(:project) }
+
+ describe 'should be prefilled for projects pushover service' do
+ before do
+ service_template
+ project.build_missing_services
+ end
+
+ it "should have all fields prefilled" do
+ service = project.pushover_service
+ expect(service.template).to eq(false)
+ expect(service.device).to eq('MyDevice')
+ expect(service.sound).to eq('mic')
+ expect(service.priority).to eq(4)
+ expect(service.api_key).to eq('123456789')
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/api/group_members_spec.rb b/spec/requests/api/group_members_spec.rb
index b070bf01dbb..8ba6876a95b 100644
--- a/spec/requests/api/group_members_spec.rb
+++ b/spec/requests/api/group_members_spec.rb
@@ -104,6 +104,69 @@ describe API::API, api: true do
end
end
+ describe 'PUT /groups/:id/members/:user_id' do
+ context 'when not a member of the group' do
+ it 'should return a 409 error if the user is not a group member' do
+ put(
+ api("/groups/#{group_no_members.id}/members/#{developer.id}",
+ owner), access_level: GroupMember::MASTER
+ )
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when a member of the group' do
+ it 'should return ok and update member access level' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{reporter.id}",
+ owner),
+ access_level: GroupMember::MASTER
+ )
+
+ expect(response.status).to eq(200)
+
+ get api("/groups/#{group_with_members.id}/members", owner)
+ json_reporter = json_response.find do |e|
+ e['id'] == reporter.id
+ end
+
+ expect(json_reporter['access_level']).to eq(GroupMember::MASTER)
+ end
+
+ it 'should not allow guest to modify group members' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{developer.id}",
+ guest),
+ access_level: GroupMember::MASTER
+ )
+
+ expect(response.status).to eq(403)
+
+ get api("/groups/#{group_with_members.id}/members", owner)
+ json_developer = json_response.find do |e|
+ e['id'] == developer.id
+ end
+
+ expect(json_developer['access_level']).to eq(GroupMember::DEVELOPER)
+ end
+
+ it 'should return a 400 error when access level is not given' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{master.id}", owner)
+ )
+ expect(response.status).to eq(400)
+ end
+
+ it 'should return a 422 error when access level is not known' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{master.id}", owner),
+ access_level: 1234
+ )
+ expect(response.status).to eq(422)
+ end
+ end
+ end
+
describe "DELETE /groups/:id/members/:user_id" do
context "when not a member of the group" do
it "should not delete guest's membership of group_with_members" do