Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss8
-rw-r--r--app/controllers/application_controller.rb5
-rw-r--r--app/controllers/projects/labels_controller.rb13
-rw-r--r--app/models/merge_request.rb7
-rw-r--r--app/models/project.rb5
-rw-r--r--app/views/projects/issues/index.html.haml3
-rw-r--r--app/views/projects/merge_requests/_form.html.haml38
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml6
-rw-r--r--app/views/projects/merge_requests/_show.html.haml1
-rw-r--r--app/views/projects/merge_requests/index.html.haml3
-rw-r--r--app/views/projects/merge_requests/show/_participants.html.haml11
-rw-r--r--app/views/shared/_project_filter.html.haml2
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/api/merge_requests.rb4
-rw-r--r--spec/requests/api/projects_spec.rb52
15 files changed, 142 insertions, 17 deletions
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 5dcfc449b42..2d9a5e4bbe6 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -73,6 +73,10 @@
.merge-request-info {
color: #999;
+
+ .merge-request-labels {
+ display: inline-block;
+ }
}
}
}
@@ -111,3 +115,7 @@
}
}
}
+
+.merge-request-show-labels .label {
+ padding: 6px 10px;
+}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index a3f39c23e08..2730e9942ec 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -117,6 +117,11 @@ class ApplicationController < ActionController::Base
return access_denied! unless can?(current_user, :push_code, project)
end
+ def authorize_labels!
+ # Labels should be accessible for issues and/or merge requests
+ authorize_read_issue! || authorize_read_merge_request!
+ end
+
def access_denied!
render "errors/access_denied", layout: "errors", status: 404
end
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 0166ca9ff00..b037cf56502 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -1,8 +1,7 @@
class Projects::LabelsController < Projects::ApplicationController
before_filter :module_enabled
- # Allow read any issue
- before_filter :authorize_read_issue!
+ before_filter :authorize_labels!
respond_to :js, :html
@@ -13,12 +12,18 @@ class Projects::LabelsController < Projects::ApplicationController
def generate
Gitlab::IssuesLabels.generate(@project)
- redirect_to project_issues_path(@project)
+ if params[:redirect] == 'issues'
+ redirect_to project_issues_path(@project)
+ elsif params[:redirect] == 'merge_requests'
+ redirect_to project_merge_requests_path(@project)
+ end
end
protected
def module_enabled
- return render_404 unless @project.issues_enabled
+ unless @project.issues_enabled || @project.merge_requests_enabled
+ return render_404
+ end
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 134a8c8dd40..061537132b3 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -36,7 +36,9 @@ class MergeRequest < ActiveRecord::Base
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
- attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :state_event, :description
+ attr_accessible :title, :assignee_id, :source_project_id, :source_branch,
+ :target_project_id, :target_branch, :milestone_id,
+ :state_event, :description, :label_list
attr_accessor :should_remove_source_branch
@@ -44,6 +46,9 @@ class MergeRequest < ActiveRecord::Base
# It allows us to close or modify broken merge requests
attr_accessor :allow_broken
+ ActsAsTaggableOn.strict_case_match = true
+ acts_as_taggable_on :labels
+
state_machine :state, initial: :opened do
event :close do
transition [:reopened, :opened] => :closed
diff --git a/app/models/project.rb b/app/models/project.rb
index 7ddcc73cf2a..45e950f4807 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -281,8 +281,11 @@ class Project < ActiveRecord::Base
self.id
end
+ # Tags are shared by issues and merge requests
def issues_labels
- @issues_labels ||= (issues_default_labels + issues.tags_on(:labels)).uniq.sort_by(&:name)
+ @issues_labels ||= (issues_default_labels +
+ merge_requests.tags_on(:labels) +
+ issues.tags_on(:labels)).uniq.sort_by(&:name)
end
def issue_exists?(issue_id)
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 5e899d412c6..51a8c911af8 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -1,6 +1,7 @@
= render "head"
.row
.col-md-3
- = render 'shared/project_filter', project_entities_path: project_issues_path(@project), labels: true
+ = render 'shared/project_filter', project_entities_path: project_issues_path(@project),
+ labels: true, redirect: 'issues'
.col-md-9.issues-holder
= render "issues"
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index ddff3dbead8..290a15e2664 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -42,6 +42,15 @@
.col-sm-10= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2'})
+ - if @merge_request.persisted? # Only allow labels on edit to avoid fork vs upstream repo labels issue
+ .form-group
+ = f.label :label_list, class: 'control-label' do
+ %i.icon-tag
+ Labels
+ .col-sm-10
+ = f.text_field :label_list, maxlength: 2000, class: "form-control"
+ %p.hint Separate labels with commas.
+
.form-actions
- if @merge_request.new_record?
= f.submit 'Submit merge request', class: "btn btn-create"
@@ -60,3 +69,32 @@
$('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
e.preventDefault();
});
+
+ $("#merge_request_label_list")
+ .bind( "keydown", function( event ) {
+ if ( event.keyCode === $.ui.keyCode.TAB &&
+ $( this ).data( "autocomplete" ).menu.active ) {
+ event.preventDefault();
+ }
+ })
+ .bind("click", function(event) {
+ $(this).autocomplete("search", "");
+ })
+ .autocomplete({
+ minLength: 0,
+ source: function( request, response ) {
+ response( $.ui.autocomplete.filter(
+ #{raw labels_autocomplete_source}, extractLast( request.term ) ) );
+ },
+ focus: function() {
+ return false;
+ },
+ select: function(event, ui) {
+ var terms = split( this.value );
+ terms.pop();
+ terms.push( ui.item.value );
+ terms.push( "" );
+ this.value = terms.join( ", " );
+ return false;
+ }
+ });
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index d1cab89a35c..c9a80ec22ef 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -31,3 +31,9 @@
.pull-right
%small updated #{time_ago_with_tooltip(merge_request.updated_at, 'bottom', 'merge_request_updated_ago')}
+
+ .merge-request-labels
+ - merge_request.labels.each do |label|
+ %span{class: "label #{label_css_class(label.name)}"}
+ %i.icon-tag
+ = label.name
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index e36a48f62cf..193c600f774 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -4,6 +4,7 @@
= render "projects/merge_requests/show/mr_box"
= render "projects/merge_requests/show/state_widget"
= render "projects/merge_requests/show/commits"
+ = render "projects/merge_requests/show/participants"
- if @commits.present?
%ul.nav.nav-tabs
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 34faebf619c..12a72edb224 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -8,7 +8,8 @@
%hr
.row
.col-md-3
- = render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project)
+ = render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project),
+ labels: true, redirect: 'merge_requests'
.col-md-9
.mr-filters.append-bottom-10
.dropdown.inline
diff --git a/app/views/projects/merge_requests/show/_participants.html.haml b/app/views/projects/merge_requests/show/_participants.html.haml
new file mode 100644
index 00000000000..0dabd965e52
--- /dev/null
+++ b/app/views/projects/merge_requests/show/_participants.html.haml
@@ -0,0 +1,11 @@
+.participants
+ %cite.cgray #{@merge_request.participants.count} participants
+ - @merge_request.participants.each do |participant|
+ = link_to_member(@project, participant, name: false, size: 24)
+
+ .merge-request-show-labels.pull-right
+ - @merge_request.labels.each do |label|
+ %span{class: "label #{label_css_class(label.name)}"}
+ %i.icon-tag
+ = label.name
+ &nbsp;
diff --git a/app/views/shared/_project_filter.html.haml b/app/views/shared/_project_filter.html.haml
index d82b08eeaa2..7936a038be3 100644
--- a/app/views/shared/_project_filter.html.haml
+++ b/app/views/shared/_project_filter.html.haml
@@ -44,7 +44,7 @@
.light-well
Add first label to your issues
%br
- or #{link_to 'generate', generate_project_labels_path(@project), method: :post} default set of labels
+ or #{link_to 'generate', generate_project_labels_path(@project, redirect: redirect), method: :post} default set of labels
%fieldset
- if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any?
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index c1bd6d02c68..457af52fe9d 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -136,6 +136,7 @@ module API
expose :target_branch, :source_branch, :upvotes, :downvotes
expose :author, :assignee, using: Entities::UserBasic
expose :source_project_id, :target_project_id
+ expose :label_list, as: :labels
end
class SSHKey < Grape::Entity
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 7fb135b37b8..017cb1f562e 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -67,6 +67,7 @@ module API
# assignee_id - Assignee user ID
# title (required) - Title of MR
# description - Description of MR
+ # labels (optional) - Labels for MR as a comma-separated list
#
# Example:
# POST /projects/:id/merge_requests
@@ -75,6 +76,7 @@ module API
authorize! :write_merge_request, user_project
required_attributes! [:source_branch, :target_branch, :title]
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description]
+ attrs[:label_list] = params[:labels] if params[:labels].present?
merge_request = ::MergeRequests::CreateService.new(user_project, current_user, attrs).execute
if merge_request.valid?
@@ -95,11 +97,13 @@ module API
# title - Title of MR
# state_event - Status of MR. (close|reopen|merge)
# description - Description of MR
+ # labels (optional) - Labels for a MR as a comma-separated list
# Example:
# PUT /projects/:id/merge_request/:merge_request_id
#
put ":id/merge_request/:merge_request_id" do
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event, :description]
+ attrs[:label_list] = params[:labels] if params[:labels].present?
merge_request = user_project.merge_requests.find(params[:merge_request_id])
authorize! :modify_merge_request, merge_request
merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request)
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 4b8f41a4683..81e6abbb0d7 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -14,6 +14,12 @@ describe API::API, api: true do
let(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
let(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) }
let(:issue_with_labels) { create(:issue, author: user, assignee: user, project: project, :label_list => "label1, label2") }
+ let(:merge_request_with_labels) do
+ create(:merge_request, :simple, author: user, assignee: user,
+ source_project: project, target_project: project, title: 'Test',
+ label_list: 'label3, label4')
+ end
+
describe "GET /projects" do
before { project }
@@ -634,15 +640,45 @@ describe API::API, api: true do
end
end
- describe "GET /projects/:id/labels" do
- before { issue_with_labels }
+ describe 'GET /projects/:id/labels' do
+ context 'with an issue' do
+ before { issue_with_labels }
- it "should return project labels" do
- get api("/projects/#{project.id}/labels", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['name'].should == issue_with_labels.labels.first.name
- json_response.last['name'].should == issue_with_labels.labels.last.name
+ it 'should return project labels' do
+ get api("/projects/#{project.id}/labels", user)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['name'].should == issue_with_labels.labels.first.name
+ json_response.last['name'].should == issue_with_labels.labels.last.name
+ end
+ end
+
+ context 'with a merge request' do
+ before { merge_request_with_labels }
+
+ it 'should return project labels' do
+ get api("/projects/#{project.id}/labels", user)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['name'].should == merge_request_with_labels.labels.first.name
+ json_response.last['name'].should == merge_request_with_labels.labels.last.name
+ end
+ end
+
+ context 'with an issue and a merge request' do
+ before do
+ issue_with_labels
+ merge_request_with_labels
+ end
+
+ it 'should return project labels from both' do
+ get api("/projects/#{project.id}/labels", user)
+ response.status.should == 200
+ json_response.should be_an Array
+ all_labels = issue_with_labels.labels.map(&:name).to_a
+ .concat(merge_request_with_labels.labels.map(&:name).to_a)
+ json_response.map { |e| e['name'] }.should =~ all_labels
+ end
end
end
end