diff options
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 - = 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 |