Commit 1644117a1ac45bd7d250e7bced929a00a3befe5e
1 parent
0b512af8
Exists in
master
and in
4 other branches
Issue uses StateMachine now
Showing
13 changed files
with
134 additions
and
135 deletions
Show diff stats
app/helpers/issues_helper.rb
app/models/issue.rb
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # project_id :integer |
| 10 | 10 | # created_at :datetime not null |
| 11 | 11 | # updated_at :datetime not null |
| 12 | -# closed :boolean default(FALSE), not null | |
| 12 | +# state :string default(FALSE), not null | |
| 13 | 13 | # position :integer default(0) |
| 14 | 14 | # branch_name :string(255) |
| 15 | 15 | # description :text |
| ... | ... | @@ -19,11 +19,29 @@ |
| 19 | 19 | class Issue < ActiveRecord::Base |
| 20 | 20 | include Issuable |
| 21 | 21 | |
| 22 | - attr_accessible :title, :assignee_id, :closed, :position, :description, | |
| 23 | - :milestone_id, :label_list, :author_id_of_changes | |
| 22 | + attr_accessible :title, :assignee_id, :position, :description, | |
| 23 | + :milestone_id, :label_list, :author_id_of_changes, | |
| 24 | + :state_event | |
| 24 | 25 | |
| 25 | 26 | acts_as_taggable_on :labels |
| 26 | 27 | |
| 28 | + state_machine :state, :initial => :opened do | |
| 29 | + event :close do | |
| 30 | + transition [:reopened, :opened] => :closed | |
| 31 | + end | |
| 32 | + | |
| 33 | + event :reopen do | |
| 34 | + transition :closed => :reopened | |
| 35 | + end | |
| 36 | + | |
| 37 | + state :opened | |
| 38 | + | |
| 39 | + state :reopened | |
| 40 | + | |
| 41 | + state :closed | |
| 42 | + end | |
| 43 | + | |
| 44 | + | |
| 27 | 45 | def self.open_for(user) |
| 28 | 46 | opened.assigned(user) |
| 29 | 47 | end | ... | ... |
app/models/project.rb
| ... | ... | @@ -43,7 +43,7 @@ class Project < ActiveRecord::Base |
| 43 | 43 | |
| 44 | 44 | has_many :events, dependent: :destroy |
| 45 | 45 | has_many :merge_requests, dependent: :destroy |
| 46 | - has_many :issues, dependent: :destroy, order: "closed, created_at DESC" | |
| 46 | + has_many :issues, dependent: :destroy, order: "state, created_at DESC" | |
| 47 | 47 | has_many :milestones, dependent: :destroy |
| 48 | 48 | has_many :users_projects, dependent: :destroy |
| 49 | 49 | has_many :notes, dependent: :destroy | ... | ... |
app/observers/issue_observer.rb
| ... | ... | @@ -7,22 +7,31 @@ class IssueObserver < ActiveRecord::Observer |
| 7 | 7 | end |
| 8 | 8 | end |
| 9 | 9 | |
| 10 | - def after_update(issue) | |
| 10 | + def after_close(issue, transition) | |
| 11 | 11 | send_reassigned_email(issue) if issue.is_being_reassigned? |
| 12 | 12 | |
| 13 | - status = nil | |
| 14 | - status = 'closed' if issue.is_being_closed? | |
| 15 | - status = 'reopened' if issue.is_being_reopened? | |
| 16 | - if status | |
| 17 | - Note.create_status_change_note(issue, current_user, status) | |
| 18 | - [issue.author, issue.assignee].compact.each do |recipient| | |
| 19 | - Notify.delay.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) | |
| 20 | - end | |
| 21 | - end | |
| 13 | + create_note(issue) | |
| 14 | + end | |
| 15 | + | |
| 16 | + def after_reopen(issue, transition) | |
| 17 | + send_reassigned_email(issue) if issue.is_being_reassigned? | |
| 18 | + | |
| 19 | + create_note(issue) | |
| 20 | + end | |
| 21 | + | |
| 22 | + def after_update(issue) | |
| 23 | + send_reassigned_email(issue) if issue.is_being_reassigned? | |
| 22 | 24 | end |
| 23 | 25 | |
| 24 | 26 | protected |
| 25 | 27 | |
| 28 | + def create_note(issue) | |
| 29 | + Note.create_status_change_note(issue, current_user, issue.state) | |
| 30 | + [issue.author, issue.assignee].compact.each do |recipient| | |
| 31 | + Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) | |
| 32 | + end | |
| 33 | + end | |
| 34 | + | |
| 26 | 35 | def send_reassigned_email(issue) |
| 27 | 36 | recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } |
| 28 | 37 | ... | ... |
app/views/issues/_show.html.haml
| ... | ... | @@ -8,10 +8,10 @@ |
| 8 | 8 | %i.icon-comment |
| 9 | 9 | = issue.notes.count |
| 10 | 10 | - if can? current_user, :modify_issue, issue |
| 11 | - - if issue.closed | |
| 12 | - = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {closed: false }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true | |
| 11 | + - if issue.closed? | |
| 12 | + = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state: :reopened }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true | |
| 13 | 13 | - else |
| 14 | - = link_to 'Close', project_issue_path(issue.project, issue, issue: {closed: true }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true | |
| 14 | + = link_to 'Close', project_issue_path(issue.project, issue, issue: {state: :closed }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true | |
| 15 | 15 | = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do |
| 16 | 16 | %i.icon-edit |
| 17 | 17 | Edit | ... | ... |
app/views/issues/show.html.haml
| ... | ... | @@ -7,10 +7,10 @@ |
| 7 | 7 | |
| 8 | 8 | %span.pull-right |
| 9 | 9 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user |
| 10 | - - if @issue.closed | |
| 11 | - = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped reopen_issue" | |
| 10 | + - if @issue.closed? | |
| 11 | + = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state: :reopened }, status_only: true), method: :put, class: "btn grouped reopen_issue" | |
| 12 | 12 | - else |
| 13 | - = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" | |
| 13 | + = link_to 'Close', project_issue_path(@project, @issue, issue: {state: :closed }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" | |
| 14 | 14 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user |
| 15 | 15 | = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do |
| 16 | 16 | %i.icon-edit |
| ... | ... | @@ -27,7 +27,7 @@ |
| 27 | 27 | .ui-box.ui-box-show |
| 28 | 28 | .ui-box-head |
| 29 | 29 | %h4.box-title |
| 30 | - - if @issue.closed | |
| 30 | + - if @issue.closed? | |
| 31 | 31 | .error.status_info Closed |
| 32 | 32 | = gfm escape_once(@issue.title) |
| 33 | 33 | ... | ... |
lib/api/entities.rb
| ... | ... | @@ -35,12 +35,11 @@ module Gitlab |
| 35 | 35 | class Group < Grape::Entity |
| 36 | 36 | expose :id, :name, :path, :owner_id |
| 37 | 37 | end |
| 38 | - | |
| 38 | + | |
| 39 | 39 | class GroupDetail < Group |
| 40 | 40 | expose :projects, using: Entities::Project |
| 41 | 41 | end |
| 42 | 42 | |
| 43 | - | |
| 44 | 43 | class RepoObject < Grape::Entity |
| 45 | 44 | expose :name, :commit |
| 46 | 45 | expose :protected do |repo, options| |
| ... | ... | @@ -63,7 +62,7 @@ module Gitlab |
| 63 | 62 | class Milestone < Grape::Entity |
| 64 | 63 | expose :id |
| 65 | 64 | expose (:project_id) {|milestone| milestone.project.id} |
| 66 | - expose :title, :description, :due_date, :closed, :updated_at, :created_at | |
| 65 | + expose :title, :description, :due_date, :state, :updated_at, :created_at | |
| 67 | 66 | end |
| 68 | 67 | |
| 69 | 68 | class Issue < Grape::Entity |
| ... | ... | @@ -73,7 +72,7 @@ module Gitlab |
| 73 | 72 | expose :label_list, as: :labels |
| 74 | 73 | expose :milestone, using: Entities::Milestone |
| 75 | 74 | expose :assignee, :author, using: Entities::UserBasic |
| 76 | - expose :closed, :updated_at, :created_at | |
| 75 | + expose :state, :updated_at, :created_at | |
| 77 | 76 | end |
| 78 | 77 | |
| 79 | 78 | class SSHKey < Grape::Entity | ... | ... |
lib/api/issues.rb
| ... | ... | @@ -69,14 +69,14 @@ module Gitlab |
| 69 | 69 | # assignee_id (optional) - The ID of a user to assign issue |
| 70 | 70 | # milestone_id (optional) - The ID of a milestone to assign issue |
| 71 | 71 | # labels (optional) - The labels of an issue |
| 72 | - # closed (optional) - The state of an issue (0 = false, 1 = true) | |
| 72 | + # state (optional) - The state of an issue (close|reopen) | |
| 73 | 73 | # Example Request: |
| 74 | 74 | # PUT /projects/:id/issues/:issue_id |
| 75 | 75 | put ":id/issues/:issue_id" do |
| 76 | 76 | @issue = user_project.issues.find(params[:issue_id]) |
| 77 | 77 | authorize! :modify_issue, @issue |
| 78 | 78 | |
| 79 | - attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :closed] | |
| 79 | + attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event] | |
| 80 | 80 | attrs[:label_list] = params[:labels] if params[:labels].present? |
| 81 | 81 | IssueObserver.current_user = current_user |
| 82 | 82 | if @issue.update_attributes attrs | ... | ... |
spec/factories.rb
| ... | ... | @@ -54,10 +54,15 @@ FactoryGirl.define do |
| 54 | 54 | project |
| 55 | 55 | |
| 56 | 56 | trait :closed do |
| 57 | - closed true | |
| 57 | + state :closed | |
| 58 | + end | |
| 59 | + | |
| 60 | + trait :reopened do | |
| 61 | + state :reopened | |
| 58 | 62 | end |
| 59 | 63 | |
| 60 | 64 | factory :closed_issue, traits: [:closed] |
| 65 | + factory :reopened_issue, traits: [:reopened] | |
| 61 | 66 | end |
| 62 | 67 | |
| 63 | 68 | factory :merge_request do | ... | ... |
spec/models/issue_spec.rb
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # project_id :integer |
| 10 | 10 | # created_at :datetime not null |
| 11 | 11 | # updated_at :datetime not null |
| 12 | -# closed :boolean default(FALSE), not null | |
| 12 | +# state :string default(FALSE), not null | |
| 13 | 13 | # position :integer default(0) |
| 14 | 14 | # branch_name :string(255) |
| 15 | 15 | # description :text | ... | ... |
spec/observers/issue_observer_spec.rb
| 1 | 1 | require 'spec_helper' |
| 2 | 2 | |
| 3 | 3 | describe IssueObserver do |
| 4 | - let(:some_user) { double(:user, id: 1) } | |
| 5 | - let(:assignee) { double(:user, id: 2) } | |
| 6 | - let(:author) { double(:user, id: 3) } | |
| 7 | - let(:issue) { double(:issue, id: 42, assignee: assignee, author: author) } | |
| 4 | + let(:some_user) { create :user } | |
| 5 | + let(:assignee) { create :user } | |
| 6 | + let(:author) { create :user } | |
| 7 | + let(:mock_issue) { double(:issue, id: 42, assignee: assignee, author: author) } | |
| 8 | + let(:assigned_issue) { create(:issue, assignee: assignee, author: author) } | |
| 9 | + let(:unassigned_issue) { create(:issue, author: author) } | |
| 10 | + let(:closed_assigned_issue) { create(:closed_issue, assignee: assignee, author: author) } | |
| 11 | + let(:closed_unassigned_issue) { create(:closed_issue, author: author) } | |
| 12 | + | |
| 8 | 13 | |
| 9 | 14 | before(:each) { subject.stub(:current_user).and_return(some_user) } |
| 10 | 15 | |
| ... | ... | @@ -21,137 +26,91 @@ describe IssueObserver do |
| 21 | 26 | end |
| 22 | 27 | |
| 23 | 28 | it 'sends an email to the assignee' do |
| 24 | - Notify.should_receive(:new_issue_email).with(issue.id) | |
| 29 | + Notify.should_receive(:new_issue_email).with(mock_issue.id) | |
| 25 | 30 | |
| 26 | - subject.after_create(issue) | |
| 31 | + subject.after_create(mock_issue) | |
| 27 | 32 | end |
| 28 | 33 | |
| 29 | 34 | it 'does not send an email to the assignee if assignee created the issue' do |
| 30 | 35 | subject.stub(:current_user).and_return(assignee) |
| 31 | 36 | Notify.should_not_receive(:new_issue_email) |
| 32 | 37 | |
| 33 | - subject.after_create(issue) | |
| 38 | + subject.after_create(mock_issue) | |
| 34 | 39 | end |
| 35 | 40 | end |
| 36 | 41 | |
| 37 | - context '#after_update' do | |
| 38 | - before(:each) do | |
| 39 | - issue.stub(:is_being_reassigned?).and_return(false) | |
| 40 | - issue.stub(:is_being_closed?).and_return(false) | |
| 41 | - issue.stub(:is_being_reopened?).and_return(false) | |
| 42 | - end | |
| 43 | - | |
| 44 | - it 'is called when an issue is changed' do | |
| 45 | - changed = create(:issue, project: create(:project)) | |
| 46 | - subject.should_receive(:after_update) | |
| 47 | - | |
| 48 | - Issue.observers.enable :issue_observer do | |
| 49 | - changed.description = 'I changed' | |
| 50 | - changed.save | |
| 51 | - end | |
| 52 | - end | |
| 53 | - | |
| 54 | - context 'a reassigned email' do | |
| 55 | - it 'is sent if the issue is being reassigned' do | |
| 56 | - issue.should_receive(:is_being_reassigned?).and_return(true) | |
| 57 | - subject.should_receive(:send_reassigned_email).with(issue) | |
| 58 | - | |
| 59 | - subject.after_update(issue) | |
| 60 | - end | |
| 61 | - | |
| 62 | - it 'is not sent if the issue is not being reassigned' do | |
| 63 | - issue.should_receive(:is_being_reassigned?).and_return(false) | |
| 64 | - subject.should_not_receive(:send_reassigned_email) | |
| 65 | - | |
| 66 | - subject.after_update(issue) | |
| 67 | - end | |
| 68 | - end | |
| 69 | - | |
| 42 | + context '#after_close' do | |
| 70 | 43 | context 'a status "closed"' do |
| 71 | 44 | it 'note is created if the issue is being closed' do |
| 72 | - issue.should_receive(:is_being_closed?).and_return(true) | |
| 73 | - Notify.should_receive(:issue_status_changed_email).twice | |
| 74 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed') | |
| 75 | - | |
| 76 | - subject.after_update(issue) | |
| 77 | - end | |
| 78 | - | |
| 79 | - it 'note is not created if the issue is not being closed' do | |
| 80 | - issue.should_receive(:is_being_closed?).and_return(false) | |
| 81 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed') | |
| 45 | + Note.should_receive(:create_status_change_note).with(assigned_issue, some_user, 'closed') | |
| 82 | 46 | |
| 83 | - subject.after_update(issue) | |
| 47 | + assigned_issue.close | |
| 84 | 48 | end |
| 85 | 49 | |
| 86 | 50 | it 'notification is delivered if the issue being closed' do |
| 87 | - issue.stub(:is_being_closed?).and_return(true) | |
| 88 | 51 | Notify.should_receive(:issue_status_changed_email).twice |
| 89 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed') | |
| 90 | 52 | |
| 91 | - subject.after_update(issue) | |
| 92 | - end | |
| 93 | - | |
| 94 | - it 'notification is not delivered if the issue not being closed' do | |
| 95 | - issue.stub(:is_being_closed?).and_return(false) | |
| 96 | - Notify.should_not_receive(:issue_status_changed_email) | |
| 97 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed') | |
| 98 | - | |
| 99 | - subject.after_update(issue) | |
| 53 | + assigned_issue.close | |
| 100 | 54 | end |
| 101 | 55 | |
| 102 | 56 | it 'notification is delivered only to author if the issue being closed' do |
| 103 | - issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil) | |
| 104 | - issue_without_assignee.stub(:is_being_reassigned?).and_return(false) | |
| 105 | - issue_without_assignee.stub(:is_being_closed?).and_return(true) | |
| 106 | - issue_without_assignee.stub(:is_being_reopened?).and_return(false) | |
| 107 | 57 | Notify.should_receive(:issue_status_changed_email).once |
| 108 | - Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'closed') | |
| 58 | + Note.should_receive(:create_status_change_note).with(unassigned_issue, some_user, 'closed') | |
| 109 | 59 | |
| 110 | - subject.after_update(issue_without_assignee) | |
| 60 | + unassigned_issue.close | |
| 111 | 61 | end |
| 112 | 62 | end |
| 113 | 63 | |
| 114 | 64 | context 'a status "reopened"' do |
| 115 | 65 | it 'note is created if the issue is being reopened' do |
| 66 | + Note.should_receive(:create_status_change_note).with(closed_assigned_issue, some_user, 'reopened') | |
| 67 | + | |
| 68 | + closed_assigned_issue.reopen | |
| 69 | + end | |
| 70 | + | |
| 71 | + it 'notification is delivered if the issue being reopened' do | |
| 116 | 72 | Notify.should_receive(:issue_status_changed_email).twice |
| 117 | - issue.should_receive(:is_being_reopened?).and_return(true) | |
| 118 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened') | |
| 119 | 73 | |
| 120 | - subject.after_update(issue) | |
| 74 | + closed_assigned_issue.reopen | |
| 121 | 75 | end |
| 122 | 76 | |
| 123 | - it 'note is not created if the issue is not being reopened' do | |
| 124 | - issue.should_receive(:is_being_reopened?).and_return(false) | |
| 125 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened') | |
| 77 | + it 'notification is delivered only to author if the issue being reopened' do | |
| 78 | + Notify.should_receive(:issue_status_changed_email).once | |
| 79 | + Note.should_receive(:create_status_change_note).with(closed_unassigned_issue, some_user, 'reopened') | |
| 126 | 80 | |
| 127 | - subject.after_update(issue) | |
| 81 | + closed_unassigned_issue.reopen | |
| 128 | 82 | end |
| 83 | + end | |
| 84 | + end | |
| 129 | 85 | |
| 130 | - it 'notification is delivered if the issue being reopened' do | |
| 131 | - issue.stub(:is_being_reopened?).and_return(true) | |
| 132 | - Notify.should_receive(:issue_status_changed_email).twice | |
| 133 | - Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened') | |
| 86 | + context '#after_update' do | |
| 87 | + before(:each) do | |
| 88 | + mock_issue.stub(:is_being_reassigned?).and_return(false) | |
| 89 | + end | |
| 90 | + | |
| 91 | + it 'is called when an issue is changed' do | |
| 92 | + changed = create(:issue, project: create(:project)) | |
| 93 | + subject.should_receive(:after_update) | |
| 134 | 94 | |
| 135 | - subject.after_update(issue) | |
| 95 | + Issue.observers.enable :issue_observer do | |
| 96 | + changed.description = 'I changed' | |
| 97 | + changed.save | |
| 136 | 98 | end |
| 99 | + end | |
| 137 | 100 | |
| 138 | - it 'notification is not delivered if the issue not being reopened' do | |
| 139 | - issue.stub(:is_being_reopened?).and_return(false) | |
| 140 | - Notify.should_not_receive(:issue_status_changed_email) | |
| 141 | - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened') | |
| 101 | + context 'a reassigned email' do | |
| 102 | + it 'is sent if the issue is being reassigned' do | |
| 103 | + mock_issue.should_receive(:is_being_reassigned?).and_return(true) | |
| 104 | + subject.should_receive(:send_reassigned_email).with(mock_issue) | |
| 142 | 105 | |
| 143 | - subject.after_update(issue) | |
| 106 | + subject.after_update(mock_issue) | |
| 144 | 107 | end |
| 145 | 108 | |
| 146 | - it 'notification is delivered only to author if the issue being reopened' do | |
| 147 | - issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil) | |
| 148 | - issue_without_assignee.stub(:is_being_reassigned?).and_return(false) | |
| 149 | - issue_without_assignee.stub(:is_being_closed?).and_return(false) | |
| 150 | - issue_without_assignee.stub(:is_being_reopened?).and_return(true) | |
| 151 | - Notify.should_receive(:issue_status_changed_email).once | |
| 152 | - Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'reopened') | |
| 109 | + it 'is not sent if the issue is not being reassigned' do | |
| 110 | + mock_issue.should_receive(:is_being_reassigned?).and_return(false) | |
| 111 | + subject.should_not_receive(:send_reassigned_email) | |
| 153 | 112 | |
| 154 | - subject.after_update(issue_without_assignee) | |
| 113 | + subject.after_update(mock_issue) | |
| 155 | 114 | end |
| 156 | 115 | end |
| 157 | 116 | end |
| ... | ... | @@ -160,23 +119,23 @@ describe IssueObserver do |
| 160 | 119 | let(:previous_assignee) { double(:user, id: 3) } |
| 161 | 120 | |
| 162 | 121 | before(:each) do |
| 163 | - issue.stub(:assignee_id).and_return(assignee.id) | |
| 164 | - issue.stub(:assignee_id_was).and_return(previous_assignee.id) | |
| 122 | + mock_issue.stub(:assignee_id).and_return(assignee.id) | |
| 123 | + mock_issue.stub(:assignee_id_was).and_return(previous_assignee.id) | |
| 165 | 124 | end |
| 166 | 125 | |
| 167 | 126 | def it_sends_a_reassigned_email_to(recipient) |
| 168 | - Notify.should_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id) | |
| 127 | + Notify.should_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) | |
| 169 | 128 | end |
| 170 | 129 | |
| 171 | 130 | def it_does_not_send_a_reassigned_email_to(recipient) |
| 172 | - Notify.should_not_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id) | |
| 131 | + Notify.should_not_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) | |
| 173 | 132 | end |
| 174 | 133 | |
| 175 | 134 | it 'sends a reassigned email to the previous and current assignees' do |
| 176 | 135 | it_sends_a_reassigned_email_to assignee.id |
| 177 | 136 | it_sends_a_reassigned_email_to previous_assignee.id |
| 178 | 137 | |
| 179 | - subject.send(:send_reassigned_email, issue) | |
| 138 | + subject.send(:send_reassigned_email, mock_issue) | |
| 180 | 139 | end |
| 181 | 140 | |
| 182 | 141 | context 'does not send an email to the user who made the reassignment' do |
| ... | ... | @@ -185,14 +144,14 @@ describe IssueObserver do |
| 185 | 144 | it_sends_a_reassigned_email_to previous_assignee.id |
| 186 | 145 | it_does_not_send_a_reassigned_email_to assignee.id |
| 187 | 146 | |
| 188 | - subject.send(:send_reassigned_email, issue) | |
| 147 | + subject.send(:send_reassigned_email, mock_issue) | |
| 189 | 148 | end |
| 190 | 149 | it 'if the user is the previous assignee' do |
| 191 | 150 | subject.stub(:current_user).and_return(previous_assignee) |
| 192 | 151 | it_sends_a_reassigned_email_to assignee.id |
| 193 | 152 | it_does_not_send_a_reassigned_email_to previous_assignee.id |
| 194 | 153 | |
| 195 | - subject.send(:send_reassigned_email, issue) | |
| 154 | + subject.send(:send_reassigned_email, mock_issue) | |
| 196 | 155 | end |
| 197 | 156 | end |
| 198 | 157 | end | ... | ... |
spec/requests/api/issues_spec.rb
| ... | ... | @@ -54,14 +54,24 @@ describe Gitlab::API do |
| 54 | 54 | end |
| 55 | 55 | end |
| 56 | 56 | |
| 57 | - describe "PUT /projects/:id/issues/:issue_id" do | |
| 57 | + describe "PUT /projects/:id/issues/:issue_id to update only title" do | |
| 58 | 58 | it "should update a project issue" do |
| 59 | 59 | put api("/projects/#{project.id}/issues/#{issue.id}", user), |
| 60 | - title: 'updated title', labels: 'label2', closed: 1 | |
| 60 | + title: 'updated title' | |
| 61 | 61 | response.status.should == 200 |
| 62 | + | |
| 62 | 63 | json_response['title'].should == 'updated title' |
| 64 | + end | |
| 65 | + end | |
| 66 | + | |
| 67 | + describe "PUT /projects/:id/issues/:issue_id to update state and label" do | |
| 68 | + it "should update a project issue" do | |
| 69 | + put api("/projects/#{project.id}/issues/#{issue.id}", user), | |
| 70 | + labels: 'label2', state_event: "close" | |
| 71 | + response.status.should == 200 | |
| 72 | + | |
| 63 | 73 | json_response['labels'].should == ['label2'] |
| 64 | - json_response['closed'].should be_true | |
| 74 | + json_response['state'].should eq "closed" | |
| 65 | 75 | end |
| 66 | 76 | end |
| 67 | 77 | ... | ... |
spec/requests/issues_spec.rb
| ... | ... | @@ -58,8 +58,7 @@ describe "Issues" do |
| 58 | 58 | |
| 59 | 59 | it "should be able to search on different statuses" do |
| 60 | 60 | issue = Issue.first # with title 'foobar' |
| 61 | - issue.closed = true | |
| 62 | - issue.save | |
| 61 | + issue.close | |
| 63 | 62 | |
| 64 | 63 | visit project_issues_path(project) |
| 65 | 64 | click_link 'Closed' | ... | ... |