Commit 155703c6132a86c13a18dba65da19129f49ea9c9
Exists in
master
and in
4 other branches
Merge branch 'state-machine' of https://github.com/Undev/gitlabhq into Undev-state-machine
Conflicts: app/models/issue.rb app/models/merge_request.rb
Showing
55 changed files
with
511 additions
and
418 deletions
Show diff stats
Gemfile
Gemfile.lock
... | ... | @@ -425,6 +425,7 @@ GEM |
425 | 425 | rack (~> 1.0) |
426 | 426 | tilt (~> 1.1, != 1.3.0) |
427 | 427 | stamp (0.3.0) |
428 | + state_machine (1.1.2) | |
428 | 429 | temple (0.5.5) |
429 | 430 | test_after_commit (0.0.1) |
430 | 431 | therubyracer (0.10.2) |
... | ... | @@ -536,6 +537,7 @@ DEPENDENCIES |
536 | 537 | slim |
537 | 538 | spinach-rails |
538 | 539 | stamp |
540 | + state_machine | |
539 | 541 | test_after_commit |
540 | 542 | therubyracer |
541 | 543 | thin | ... | ... |
app/assets/javascripts/merge_requests.js.coffee
... | ... | @@ -27,7 +27,7 @@ class MergeRequest |
27 | 27 | this.$el.find(selector) |
28 | 28 | |
29 | 29 | initMergeWidget: -> |
30 | - this.showState( @opts.current_state ) | |
30 | + this.showState( @opts.current_status ) | |
31 | 31 | |
32 | 32 | if this.$('.automerge_widget').length and @opts.check_enable |
33 | 33 | $.get @opts.url_to_automerge_check, (data) => | ... | ... |
app/contexts/merge_requests_load_context.rb
... | ... | @@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext |
14 | 14 | end |
15 | 15 | |
16 | 16 | merge_requests = merge_requests.page(params[:page]).per(20) |
17 | - merge_requests = merge_requests.includes(:author, :project).order("closed, created_at desc") | |
17 | + merge_requests = merge_requests.includes(:author, :project).order("state, created_at desc") | |
18 | 18 | |
19 | 19 | # Filter by specific assignee_id (or lack thereof)? |
20 | 20 | if params[:assignee_id].present? | ... | ... |
app/controllers/merge_requests_controller.rb
... | ... | @@ -73,14 +73,14 @@ class MergeRequestsController < ProjectResourceController |
73 | 73 | if @merge_request.unchecked? |
74 | 74 | @merge_request.check_if_can_be_merged |
75 | 75 | end |
76 | - render json: {state: @merge_request.human_state} | |
76 | + render json: {merge_status: @merge_request.human_merge_status} | |
77 | 77 | rescue Gitlab::SatelliteNotExistError |
78 | - render json: {state: :no_satellite} | |
78 | + render json: {merge_status: :no_satellite} | |
79 | 79 | end |
80 | 80 | |
81 | 81 | def automerge |
82 | 82 | return access_denied! unless can?(current_user, :accept_mr, @project) |
83 | - if @merge_request.open? && @merge_request.can_be_merged? | |
83 | + if @merge_request.opened? && @merge_request.can_be_merged? | |
84 | 84 | @merge_request.should_remove_source_branch = params[:should_remove_source_branch] |
85 | 85 | @merge_request.automerge!(current_user) |
86 | 86 | @status = true | ... | ... |
app/controllers/milestones_controller.rb
... | ... | @@ -12,7 +12,7 @@ class MilestonesController < ProjectResourceController |
12 | 12 | |
13 | 13 | def index |
14 | 14 | @milestones = case params[:f] |
15 | - when 'all'; @project.milestones.order("closed, due_date DESC") | |
15 | + when 'all'; @project.milestones.order("state, due_date DESC") | |
16 | 16 | when 'closed'; @project.milestones.closed.order("due_date DESC") |
17 | 17 | else @project.milestones.active.order("due_date ASC") |
18 | 18 | end | ... | ... |
app/helpers/issues_helper.rb
app/helpers/merge_requests_helper.rb
app/models/concerns/issuable.rb
... | ... | @@ -17,10 +17,9 @@ module Issuable |
17 | 17 | validates :project, presence: true |
18 | 18 | validates :author, presence: true |
19 | 19 | validates :title, presence: true, length: { within: 0..255 } |
20 | - validates :closed, inclusion: { in: [true, false] } | |
21 | 20 | |
22 | - scope :opened, -> { where(closed: false) } | |
23 | - scope :closed, -> { where(closed: true) } | |
21 | + scope :opened, -> { with_state(:opened) } | |
22 | + scope :closed, -> { with_state(:closed) } | |
24 | 23 | scope :of_group, ->(group) { where(project_id: group.project_ids) } |
25 | 24 | scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } |
26 | 25 | scope :assigned, ->(u) { where(assignee_id: u.id)} |
... | ... | @@ -62,14 +61,6 @@ module Issuable |
62 | 61 | assignee_id_changed? |
63 | 62 | end |
64 | 63 | |
65 | - def is_being_closed? | |
66 | - closed_changed? && closed | |
67 | - end | |
68 | - | |
69 | - def is_being_reopened? | |
70 | - closed_changed? && !closed | |
71 | - end | |
72 | - | |
73 | 64 | # |
74 | 65 | # Votes |
75 | 66 | # | ... | ... |
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,8 +19,9 @@ |
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 | |
... | ... | @@ -33,4 +34,20 @@ class Issue < ActiveRecord::Base |
33 | 34 | opened.assigned(user) |
34 | 35 | end |
35 | 36 | end |
37 | + | |
38 | + state_machine :state, initial: :opened do | |
39 | + event :close do | |
40 | + transition [:reopened, :opened] => :closed | |
41 | + end | |
42 | + | |
43 | + event :reopen do | |
44 | + transition closed: :reopened | |
45 | + end | |
46 | + | |
47 | + state :opened | |
48 | + | |
49 | + state :reopened | |
50 | + | |
51 | + state :closed | |
52 | + end | |
36 | 53 | end | ... | ... |
app/models/merge_request.rb
... | ... | @@ -9,15 +9,14 @@ |
9 | 9 | # author_id :integer |
10 | 10 | # assignee_id :integer |
11 | 11 | # title :string(255) |
12 | -# closed :boolean default(FALSE), not null | |
12 | +# state :string(255) not null | |
13 | 13 | # created_at :datetime not null |
14 | 14 | # updated_at :datetime not null |
15 | 15 | # st_commits :text(2147483647) |
16 | 16 | # st_diffs :text(2147483647) |
17 | -# merged :boolean default(FALSE), not null | |
18 | -# state :integer default(1), not null | |
19 | -# milestone_id :integer | |
17 | +# merge_status :integer default(1), not null | |
20 | 18 | # |
19 | +# milestone_id :integer | |
21 | 20 | |
22 | 21 | require Rails.root.join("app/models/commit") |
23 | 22 | require Rails.root.join("lib/static_model") |
... | ... | @@ -25,11 +24,33 @@ require Rails.root.join("lib/static_model") |
25 | 24 | class MergeRequest < ActiveRecord::Base |
26 | 25 | include Issuable |
27 | 26 | |
28 | - attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id, | |
29 | - :author_id_of_changes | |
27 | + attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, | |
28 | + :author_id_of_changes, :state_event | |
30 | 29 | |
31 | 30 | attr_accessor :should_remove_source_branch |
32 | 31 | |
32 | + state_machine :state, initial: :opened do | |
33 | + event :close do | |
34 | + transition [:reopened, :opened] => :closed | |
35 | + end | |
36 | + | |
37 | + event :merge do | |
38 | + transition [:reopened, :opened] => :merged | |
39 | + end | |
40 | + | |
41 | + event :reopen do | |
42 | + transition closed: :reopened | |
43 | + end | |
44 | + | |
45 | + state :opened | |
46 | + | |
47 | + state :reopened | |
48 | + | |
49 | + state :closed | |
50 | + | |
51 | + state :merged | |
52 | + end | |
53 | + | |
33 | 54 | BROKEN_DIFF = "--broken-diff" |
34 | 55 | |
35 | 56 | UNCHECKED = 1 |
... | ... | @@ -43,8 +64,13 @@ class MergeRequest < ActiveRecord::Base |
43 | 64 | validates :target_branch, presence: true |
44 | 65 | validate :validate_branches |
45 | 66 | |
67 | + scope :merged, -> { with_state(:merged) } | |
46 | 68 | |
47 | 69 | class << self |
70 | + def find_all_by_branch(branch_name) | |
71 | + where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) | |
72 | + end | |
73 | + | |
48 | 74 | def cared(user) |
49 | 75 | where('assignee_id = :user OR author_id = :user', user: user.id) |
50 | 76 | end |
... | ... | @@ -58,13 +84,13 @@ class MergeRequest < ActiveRecord::Base |
58 | 84 | end |
59 | 85 | end |
60 | 86 | |
61 | - def human_state | |
62 | - states = { | |
87 | + def human_merge_status | |
88 | + merge_statuses = { | |
63 | 89 | CAN_BE_MERGED => "can_be_merged", |
64 | 90 | CANNOT_BE_MERGED => "cannot_be_merged", |
65 | 91 | UNCHECKED => "unchecked" |
66 | 92 | } |
67 | - states[self.state] | |
93 | + merge_statuses[self.merge_status] | |
68 | 94 | end |
69 | 95 | |
70 | 96 | def validate_branches |
... | ... | @@ -79,20 +105,20 @@ class MergeRequest < ActiveRecord::Base |
79 | 105 | end |
80 | 106 | |
81 | 107 | def unchecked? |
82 | - state == UNCHECKED | |
108 | + merge_status == UNCHECKED | |
83 | 109 | end |
84 | 110 | |
85 | 111 | def mark_as_unchecked |
86 | - self.state = UNCHECKED | |
112 | + self.merge_status = UNCHECKED | |
87 | 113 | self.save |
88 | 114 | end |
89 | 115 | |
90 | 116 | def can_be_merged? |
91 | - state == CAN_BE_MERGED | |
117 | + merge_status == CAN_BE_MERGED | |
92 | 118 | end |
93 | 119 | |
94 | 120 | def check_if_can_be_merged |
95 | - self.state = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? | |
121 | + self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? | |
96 | 122 | CAN_BE_MERGED |
97 | 123 | else |
98 | 124 | CANNOT_BE_MERGED |
... | ... | @@ -105,7 +131,7 @@ class MergeRequest < ActiveRecord::Base |
105 | 131 | end |
106 | 132 | |
107 | 133 | def reloaded_diffs |
108 | - if open? && unmerged_diffs.any? | |
134 | + if opened? && unmerged_diffs.any? | |
109 | 135 | self.st_diffs = unmerged_diffs |
110 | 136 | self.save |
111 | 137 | end |
... | ... | @@ -135,10 +161,6 @@ class MergeRequest < ActiveRecord::Base |
135 | 161 | commits.first |
136 | 162 | end |
137 | 163 | |
138 | - def merged? | |
139 | - merged && merge_event | |
140 | - end | |
141 | - | |
142 | 164 | def merge_event |
143 | 165 | self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last |
144 | 166 | end |
... | ... | @@ -153,26 +175,16 @@ class MergeRequest < ActiveRecord::Base |
153 | 175 | |
154 | 176 | def probably_merged? |
155 | 177 | unmerged_commits.empty? && |
156 | - commits.any? && open? | |
157 | - end | |
158 | - | |
159 | - def open? | |
160 | - !closed | |
161 | - end | |
162 | - | |
163 | - def mark_as_merged! | |
164 | - self.merged = true | |
165 | - self.closed = true | |
166 | - save | |
178 | + commits.any? && opened? | |
167 | 179 | end |
168 | 180 | |
169 | 181 | def mark_as_unmergable |
170 | - self.state = CANNOT_BE_MERGED | |
182 | + self.merge_status = CANNOT_BE_MERGED | |
171 | 183 | self.save |
172 | 184 | end |
173 | 185 | |
174 | 186 | def reloaded_commits |
175 | - if open? && unmerged_commits.any? | |
187 | + if opened? && unmerged_commits.any? | |
176 | 188 | self.st_commits = unmerged_commits |
177 | 189 | save |
178 | 190 | end |
... | ... | @@ -188,7 +200,8 @@ class MergeRequest < ActiveRecord::Base |
188 | 200 | end |
189 | 201 | |
190 | 202 | def merge!(user_id) |
191 | - self.mark_as_merged! | |
203 | + self.merge | |
204 | + | |
192 | 205 | Event.create( |
193 | 206 | project: self.project, |
194 | 207 | action: Event::MERGED, | ... | ... |
app/models/milestone.rb
... | ... | @@ -13,19 +13,32 @@ |
13 | 13 | # |
14 | 14 | |
15 | 15 | class Milestone < ActiveRecord::Base |
16 | - attr_accessible :title, :description, :due_date, :closed, :author_id_of_changes | |
16 | + attr_accessible :title, :description, :due_date, :state_event, :author_id_of_changes | |
17 | 17 | attr_accessor :author_id_of_changes |
18 | 18 | |
19 | 19 | belongs_to :project |
20 | 20 | has_many :issues |
21 | 21 | has_many :merge_requests |
22 | 22 | |
23 | - scope :active, -> { where(closed: false) } | |
24 | - scope :closed, -> { where(closed: true) } | |
23 | + scope :active, -> { with_state(:active) } | |
24 | + scope :closed, -> { with_state(:closed) } | |
25 | 25 | |
26 | 26 | validates :title, presence: true |
27 | 27 | validates :project, presence: true |
28 | - validates :closed, inclusion: { in: [true, false] } | |
28 | + | |
29 | + state_machine :state, initial: :active do | |
30 | + event :close do | |
31 | + transition active: :closed | |
32 | + end | |
33 | + | |
34 | + event :activate do | |
35 | + transition closed: :active | |
36 | + end | |
37 | + | |
38 | + state :closed | |
39 | + | |
40 | + state :active | |
41 | + end | |
29 | 42 | |
30 | 43 | def expired? |
31 | 44 | if due_date |
... | ... | @@ -68,17 +81,13 @@ class Milestone < ActiveRecord::Base |
68 | 81 | end |
69 | 82 | |
70 | 83 | def can_be_closed? |
71 | - open? && issues.opened.count.zero? | |
84 | + active? && issues.opened.count.zero? | |
72 | 85 | end |
73 | 86 | |
74 | 87 | def is_empty? |
75 | 88 | total_items_count.zero? |
76 | 89 | end |
77 | 90 | |
78 | - def open? | |
79 | - !closed | |
80 | - end | |
81 | - | |
82 | 91 | def author_id |
83 | 92 | author_id_of_changes |
84 | 93 | 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/activity_observer.rb
... | ... | @@ -20,15 +20,23 @@ class ActivityObserver < ActiveRecord::Observer |
20 | 20 | end |
21 | 21 | end |
22 | 22 | |
23 | - def after_save(record) | |
24 | - if record.changed.include?("closed") && record.author_id_of_changes | |
23 | + def after_close(record, transition) | |
25 | 24 | Event.create( |
26 | 25 | project: record.project, |
27 | 26 | target_id: record.id, |
28 | 27 | target_type: record.class.name, |
29 | - action: (record.closed ? Event::CLOSED : Event::REOPENED), | |
28 | + action: Event::CLOSED, | |
29 | + author_id: record.author_id_of_changes | |
30 | + ) | |
31 | + end | |
32 | + | |
33 | + def after_reopen(record, transition) | |
34 | + Event.create( | |
35 | + project: record.project, | |
36 | + target_id: record.id, | |
37 | + target_type: record.class.name, | |
38 | + action: Event::REOPENED, | |
30 | 39 | author_id: record.author_id_of_changes |
31 | 40 | ) |
32 | - end | |
33 | 41 | end |
34 | 42 | end | ... | ... |
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/observers/merge_request_observer.rb
... | ... | @@ -7,15 +7,20 @@ class MergeRequestObserver < ActiveRecord::Observer |
7 | 7 | end |
8 | 8 | end |
9 | 9 | |
10 | - def after_update(merge_request) | |
10 | + def after_close(merge_request, transition) | |
11 | 11 | send_reassigned_email(merge_request) if merge_request.is_being_reassigned? |
12 | 12 | |
13 | - status = nil | |
14 | - status = 'closed' if merge_request.is_being_closed? | |
15 | - status = 'reopened' if merge_request.is_being_reopened? | |
16 | - if status | |
17 | - Note.create_status_change_note(merge_request, current_user, status) | |
18 | - end | |
13 | + Note.create_status_change_note(merge_request, current_user, merge_request.state) | |
14 | + end | |
15 | + | |
16 | + def after_reopen(merge_request, transition) | |
17 | + send_reassigned_email(merge_request) if merge_request.is_being_reassigned? | |
18 | + | |
19 | + Note.create_status_change_note(merge_request, current_user, merge_request.state) | |
20 | + end | |
21 | + | |
22 | + def after_update(merge_request) | |
23 | + send_reassigned_email(merge_request) if merge_request.is_being_reassigned? | |
19 | 24 | end |
20 | 25 | |
21 | 26 | protected | ... | ... |
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_event: :reopen }, 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_event: :close }, 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_event: :reopen }, 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_event: :close }, 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 | ... | ... |
app/views/merge_requests/_show.html.haml
... | ... | @@ -29,10 +29,10 @@ |
29 | 29 | $(function(){ |
30 | 30 | merge_request = new MergeRequest({ |
31 | 31 | url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", |
32 | - check_enable: #{@merge_request.state == MergeRequest::UNCHECKED ? "true" : "false"}, | |
32 | + check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"}, | |
33 | 33 | url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", |
34 | 34 | ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, |
35 | - current_state: "#{@merge_request.human_state}", | |
35 | + current_status: "#{@merge_request.human_merge_status}", | |
36 | 36 | action: "#{controller.action_name}" |
37 | 37 | }); |
38 | 38 | }); | ... | ... |
app/views/merge_requests/show/_mr_accept.html.haml
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | %strong Only masters can accept MR |
4 | 4 | |
5 | 5 | |
6 | -- if @merge_request.open? && @commits.any? && can?(current_user, :accept_mr, @project) | |
6 | +- if @merge_request.opened? && @commits.any? && can?(current_user, :accept_mr, @project) | |
7 | 7 | .automerge_widget.can_be_merged{style: "display:none"} |
8 | 8 | .alert.alert-success |
9 | 9 | %span | ... | ... |
app/views/merge_requests/show/_mr_box.html.haml
1 | 1 | .ui-box.ui-box-show |
2 | 2 | .ui-box-head |
3 | 3 | %h4.box-title |
4 | - - if @merge_request.merged | |
4 | + - if @merge_request.merged? | |
5 | 5 | .error.status_info |
6 | 6 | %i.icon-ok |
7 | 7 | Merged |
8 | - - elsif @merge_request.closed | |
8 | + - elsif @merge_request.closed? | |
9 | 9 | .error.status_info Closed |
10 | 10 | = gfm escape_once(@merge_request.title) |
11 | 11 | |
... | ... | @@ -21,14 +21,14 @@ |
21 | 21 | %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) |
22 | 22 | |
23 | 23 | |
24 | - - if @merge_request.closed | |
24 | + - if @merge_request.closed? | |
25 | 25 | .ui-box-bottom |
26 | - - if @merge_request.merged? | |
27 | - %span | |
28 | - Merged by #{link_to_member(@project, @merge_request.merge_event.author)} | |
29 | - %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. | |
30 | - - elsif @merge_request.closed_event | |
31 | - %span | |
32 | - Closed by #{link_to_member(@project, @merge_request.closed_event.author)} | |
33 | - %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. | |
26 | + %span | |
27 | + Closed by #{link_to_member(@project, @merge_request.closed_event.author)} | |
28 | + %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. | |
29 | + - if @merge_request.merged? | |
30 | + .ui-box-bottom | |
31 | + %span | |
32 | + Merged by #{link_to_member(@project, @merge_request.merge_event.author)} | |
33 | + %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. | |
34 | 34 | ... | ... |
app/views/merge_requests/show/_mr_ci.html.haml
app/views/merge_requests/show/_mr_title.html.haml
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | |
8 | 8 | %span.pull-right |
9 | 9 | - if can?(current_user, :modify_merge_request, @merge_request) |
10 | - - if @merge_request.open? | |
10 | + - if @merge_request.opened? | |
11 | 11 | .left.btn-group |
12 | 12 | %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} } |
13 | 13 | %i.icon-download-alt |
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 | %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch) |
18 | 18 | %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff) |
19 | 19 | |
20 | - = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {closed: true }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close merge request" | |
20 | + = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn grouped btn-close", title: "Close merge request" | |
21 | 21 | |
22 | 22 | = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do |
23 | 23 | %i.icon-edit | ... | ... |
app/views/milestones/_milestone.html.haml
1 | -%li{class: "milestone milestone-#{milestone.closed ? 'closed' : 'open'}", id: dom_id(milestone) } | |
1 | +%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) } | |
2 | 2 | .pull-right |
3 | - - if can?(current_user, :admin_milestone, milestone.project) and milestone.open? | |
3 | + - if can?(current_user, :admin_milestone, milestone.project) and milestone.active? | |
4 | 4 | = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do |
5 | 5 | %i.icon-edit |
6 | 6 | Edit |
7 | 7 | %h4 |
8 | 8 | = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone) |
9 | - - if milestone.expired? and not milestone.closed | |
9 | + - if milestone.expired? and not milestone.closed? | |
10 | 10 | %span.cred (Expired) |
11 | 11 | %small |
12 | 12 | = milestone.expires_at | ... | ... |
app/views/milestones/show.html.haml
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | ← To milestones list |
10 | 10 | .span6 |
11 | 11 | .pull-right |
12 | - - unless @milestone.closed | |
12 | + - unless @milestone.closed? | |
13 | 13 | = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do |
14 | 14 | %i.icon-plus |
15 | 15 | New Issue |
... | ... | @@ -25,12 +25,12 @@ |
25 | 25 | %hr |
26 | 26 | %p |
27 | 27 | %span All issues for this milestone are closed. You may close milestone now. |
28 | - = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn btn-small btn-remove" | |
28 | + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove" | |
29 | 29 | |
30 | 30 | .ui-box.ui-box-show |
31 | 31 | .ui-box-head |
32 | 32 | %h4.box-title |
33 | - - if @milestone.closed | |
33 | + - if @milestone.closed? | |
34 | 34 | .error.status_info Closed |
35 | 35 | - elsif @milestone.expired? |
36 | 36 | .error.status_info Expired |
... | ... | @@ -63,7 +63,7 @@ |
63 | 63 | %li=link_to('All Issues', '#') |
64 | 64 | %ul.well-list |
65 | 65 | - @issues.each do |issue| |
66 | - %li{data: {closed: issue.closed}} | |
66 | + %li{data: {closed: issue.closed?}} | |
67 | 67 | = link_to [@project, issue] do |
68 | 68 | %span.badge.badge-info ##{issue.id} |
69 | 69 | – |
... | ... | @@ -77,7 +77,7 @@ |
77 | 77 | %li=link_to('All Merge Requests', '#') |
78 | 78 | %ul.well-list |
79 | 79 | - @merge_requests.each do |merge_request| |
80 | - %li{data: {closed: merge_request.closed}} | |
80 | + %li{data: {closed: merge_request.closed?}} | |
81 | 81 | = link_to [@project, merge_request] do |
82 | 82 | %span.badge.badge-info ##{merge_request.id} |
83 | 83 | – | ... | ... |
db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb
0 → 100644
db/migrate/20130218141258_convert_closed_to_state_in_issue.rb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +class ConvertClosedToStateInIssue < ActiveRecord::Migration | |
2 | + def up | |
3 | + Issue.transaction do | |
4 | + Issue.where(closed: true).update_all("state = 'closed'") | |
5 | + Issue.where(closed: false).update_all("state = 'opened'") | |
6 | + end | |
7 | + end | |
8 | + | |
9 | + def down | |
10 | + Issue.transaction do | |
11 | + Issue.where(state: :closed).update_all("closed = 1") | |
12 | + end | |
13 | + end | |
14 | +end | ... | ... |
db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb
0 → 100644
... | ... | @@ -0,0 +1,16 @@ |
1 | +class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration | |
2 | + def up | |
3 | + MergeRequest.transaction do | |
4 | + MergeRequest.where("closed = 1 AND merged = 1").update_all("state = 'merged'") | |
5 | + MergeRequest.where("closed = 1 AND merged = 0").update_all("state = 'closed'") | |
6 | + MergeRequest.where("closed = 0").update_all("state = 'opened'") | |
7 | + end | |
8 | + end | |
9 | + | |
10 | + def down | |
11 | + MergeRequest.transaction do | |
12 | + MergeRequest.where(state: :closed).update_all("closed = 1") | |
13 | + MergeRequest.where(state: :merged).update_all("closed = 1, merged = 1") | |
14 | + end | |
15 | + end | |
16 | +end | ... | ... |
db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +class ConvertClosedToStateInMilestone < ActiveRecord::Migration | |
2 | + def up | |
3 | + Milestone.transaction do | |
4 | + Milestone.where(closed: false).update_all("state = 'opened'") | |
5 | + Milestone.where(closed: false).update_all("state = 'active'") | |
6 | + end | |
7 | + end | |
8 | + | |
9 | + def down | |
10 | + Milestone.transaction do | |
11 | + Milestone.where(state: :closed).update_all("closed = 1") | |
12 | + end | |
13 | + end | |
14 | +end | ... | ... |
db/migrate/20130218141444_remove_merged_from_merge_request.rb
0 → 100644
db/migrate/20130218141536_remove_closed_from_merge_request.rb
0 → 100644
db/migrate/20130218141554_remove_closed_from_milestone.rb
0 → 100644
db/schema.rb
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | # |
12 | 12 | # It's strongly recommended to check this file into your version control system. |
13 | 13 | |
14 | -ActiveRecord::Schema.define(:version => 20130131070232) do | |
14 | +ActiveRecord::Schema.define(:version => 20130218141554) do | |
15 | 15 | |
16 | 16 | create_table "events", :force => true do |t| |
17 | 17 | t.string "target_type" |
... | ... | @@ -37,18 +37,17 @@ ActiveRecord::Schema.define(:version => 20130131070232) do |
37 | 37 | t.integer "assignee_id" |
38 | 38 | t.integer "author_id" |
39 | 39 | t.integer "project_id" |
40 | - t.datetime "created_at", :null => false | |
41 | - t.datetime "updated_at", :null => false | |
42 | - t.boolean "closed", :default => false, :null => false | |
40 | + t.datetime "created_at", :null => false | |
41 | + t.datetime "updated_at", :null => false | |
43 | 42 | t.integer "position", :default => 0 |
44 | 43 | t.string "branch_name" |
45 | 44 | t.text "description" |
46 | 45 | t.integer "milestone_id" |
46 | + t.string "state" | |
47 | 47 | end |
48 | 48 | |
49 | 49 | add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id" |
50 | 50 | add_index "issues", ["author_id"], :name => "index_issues_on_author_id" |
51 | - add_index "issues", ["closed"], :name => "index_issues_on_closed" | |
52 | 51 | add_index "issues", ["created_at"], :name => "index_issues_on_created_at" |
53 | 52 | add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id" |
54 | 53 | add_index "issues", ["project_id"], :name => "index_issues_on_project_id" |
... | ... | @@ -69,25 +68,23 @@ ActiveRecord::Schema.define(:version => 20130131070232) do |
69 | 68 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" |
70 | 69 | |
71 | 70 | create_table "merge_requests", :force => true do |t| |
72 | - t.string "target_branch", :null => false | |
73 | - t.string "source_branch", :null => false | |
74 | - t.integer "project_id", :null => false | |
71 | + t.string "target_branch", :null => false | |
72 | + t.string "source_branch", :null => false | |
73 | + t.integer "project_id", :null => false | |
75 | 74 | t.integer "author_id" |
76 | 75 | t.integer "assignee_id" |
77 | 76 | t.string "title" |
78 | - t.boolean "closed", :default => false, :null => false | |
79 | - t.datetime "created_at", :null => false | |
80 | - t.datetime "updated_at", :null => false | |
77 | + t.datetime "created_at", :null => false | |
78 | + t.datetime "updated_at", :null => false | |
81 | 79 | t.text "st_commits", :limit => 2147483647 |
82 | 80 | t.text "st_diffs", :limit => 2147483647 |
83 | - t.boolean "merged", :default => false, :null => false | |
84 | - t.integer "state", :default => 1, :null => false | |
81 | + t.integer "merge_status", :default => 1, :null => false | |
85 | 82 | t.integer "milestone_id" |
83 | + t.string "state" | |
86 | 84 | end |
87 | 85 | |
88 | 86 | add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" |
89 | 87 | add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" |
90 | - add_index "merge_requests", ["closed"], :name => "index_merge_requests_on_closed" | |
91 | 88 | add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" |
92 | 89 | add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" |
93 | 90 | add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" |
... | ... | @@ -96,13 +93,13 @@ ActiveRecord::Schema.define(:version => 20130131070232) do |
96 | 93 | add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" |
97 | 94 | |
98 | 95 | create_table "milestones", :force => true do |t| |
99 | - t.string "title", :null => false | |
100 | - t.integer "project_id", :null => false | |
96 | + t.string "title", :null => false | |
97 | + t.integer "project_id", :null => false | |
101 | 98 | t.text "description" |
102 | 99 | t.date "due_date" |
103 | - t.boolean "closed", :default => false, :null => false | |
104 | - t.datetime "created_at", :null => false | |
105 | - t.datetime "updated_at", :null => false | |
100 | + t.datetime "created_at", :null => false | |
101 | + t.datetime "updated_at", :null => false | |
102 | + t.string "state" | |
106 | 103 | end |
107 | 104 | |
108 | 105 | add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date" | ... | ... |
features/steps/project/project_issues.rb
... | ... | @@ -122,10 +122,9 @@ class ProjectIssues < Spinach::FeatureSteps |
122 | 122 | |
123 | 123 | And 'project "Shop" have "Release 0.3" closed issue' do |
124 | 124 | project = Project.find_by_name("Shop") |
125 | - create(:issue, | |
125 | + create(:closed_issue, | |
126 | 126 | :title => "Release 0.3", |
127 | 127 | :project => project, |
128 | - :author => project.users.first, | |
129 | - :closed => true) | |
128 | + :author => project.users.first) | |
130 | 129 | end |
131 | 130 | end | ... | ... |
features/steps/project/project_merge_requests.rb
... | ... | @@ -26,7 +26,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps |
26 | 26 | |
27 | 27 | Then 'I should see closed merge request "Bug NS-04"' do |
28 | 28 | mr = MergeRequest.find_by_title("Bug NS-04") |
29 | - mr.closed.should be_true | |
29 | + mr.closed?.should be_true | |
30 | 30 | page.should have_content "Closed by" |
31 | 31 | end |
32 | 32 | |
... | ... | @@ -80,11 +80,10 @@ class ProjectMergeRequests < Spinach::FeatureSteps |
80 | 80 | |
81 | 81 | And 'project "Shop" have "Feature NS-03" closed merge request' do |
82 | 82 | project = Project.find_by_name("Shop") |
83 | - create(:merge_request, | |
83 | + create(:closed_merge_request, | |
84 | 84 | title: "Feature NS-03", |
85 | 85 | project: project, |
86 | - author: project.users.first, | |
87 | - closed: true) | |
86 | + author: project.users.first) | |
88 | 87 | end |
89 | 88 | |
90 | 89 | And 'I switch to the diff tab' do | ... | ... |
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 |
... | ... | @@ -81,7 +80,7 @@ module Gitlab |
81 | 80 | end |
82 | 81 | |
83 | 82 | class MergeRequest < Grape::Entity |
84 | - expose :id, :target_branch, :source_branch, :project_id, :title, :closed, :merged | |
83 | + expose :id, :target_branch, :source_branch, :project_id, :title, :state | |
85 | 84 | expose :author, :assignee, using: Entities::UserBasic |
86 | 85 | end |
87 | 86 | ... | ... |
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 | ... | ... |
lib/api/merge_requests.rb
... | ... | @@ -73,12 +73,12 @@ module Gitlab |
73 | 73 | # target_branch - The target branch |
74 | 74 | # assignee_id - Assignee user ID |
75 | 75 | # title - Title of MR |
76 | - # closed - Status of MR. true - closed | |
76 | + # state_event - Status of MR. (close|reopen|merge) | |
77 | 77 | # Example: |
78 | 78 | # PUT /projects/:id/merge_request/:merge_request_id |
79 | 79 | # |
80 | 80 | put ":id/merge_request/:merge_request_id" do |
81 | - attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :closed] | |
81 | + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event] | |
82 | 82 | merge_request = user_project.merge_requests.find(params[:merge_request_id]) |
83 | 83 | |
84 | 84 | authorize! :modify_merge_request, merge_request | ... | ... |
lib/api/milestones.rb
... | ... | @@ -59,14 +59,14 @@ module Gitlab |
59 | 59 | # title (optional) - The title of a milestone |
60 | 60 | # description (optional) - The description of a milestone |
61 | 61 | # due_date (optional) - The due date of a milestone |
62 | - # closed (optional) - The status of the milestone | |
62 | + # state (optional) - The status of the milestone (close|activate) | |
63 | 63 | # Example Request: |
64 | 64 | # PUT /projects/:id/milestones/:milestone_id |
65 | 65 | put ":id/milestones/:milestone_id" do |
66 | 66 | authorize! :admin_milestone, user_project |
67 | 67 | |
68 | 68 | @milestone = user_project.milestones.find(params[:milestone_id]) |
69 | - attrs = attributes_for_keys [:title, :description, :due_date, :closed] | |
69 | + attrs = attributes_for_keys [:title, :description, :due_date, :state_event] | |
70 | 70 | if @milestone.update_attributes attrs |
71 | 71 | present @milestone, with: Entities::Milestone |
72 | 72 | else | ... | ... |
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 |
... | ... | @@ -67,10 +72,6 @@ FactoryGirl.define do |
67 | 72 | source_branch "master" |
68 | 73 | target_branch "stable" |
69 | 74 | |
70 | - trait :closed do | |
71 | - closed true | |
72 | - end | |
73 | - | |
74 | 75 | # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d) |
75 | 76 | trait :with_diffs do |
76 | 77 | target_branch "master" # pretend bcf03b5d~3 |
... | ... | @@ -85,7 +86,16 @@ FactoryGirl.define do |
85 | 86 | end |
86 | 87 | end |
87 | 88 | |
89 | + trait :closed do | |
90 | + state :closed | |
91 | + end | |
92 | + | |
93 | + trait :reopened do | |
94 | + state :reopened | |
95 | + end | |
96 | + | |
88 | 97 | factory :closed_merge_request, traits: [:closed] |
98 | + factory :reopened_merge_request, traits: [:reopened] | |
89 | 99 | factory :merge_request_with_diffs, traits: [:with_diffs] |
90 | 100 | end |
91 | 101 | |
... | ... | @@ -159,6 +169,12 @@ FactoryGirl.define do |
159 | 169 | factory :milestone do |
160 | 170 | title |
161 | 171 | project |
172 | + | |
173 | + trait :closed do | |
174 | + state :closed | |
175 | + end | |
176 | + | |
177 | + factory :closed_milestone, traits: [:closed] | |
162 | 178 | end |
163 | 179 | |
164 | 180 | factory :system_hook do | ... | ... |
spec/models/concerns/issuable_spec.rb
... | ... | @@ -15,7 +15,6 @@ describe Issue, "Issuable" do |
15 | 15 | it { should validate_presence_of(:author) } |
16 | 16 | it { should validate_presence_of(:title) } |
17 | 17 | it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) } |
18 | - it { should ensure_inclusion_of(:closed).in_array([true, false]) } | |
19 | 18 | end |
20 | 19 | |
21 | 20 | describe "Scope" 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 |
... | ... | @@ -44,34 +44,15 @@ describe Issue do |
44 | 44 | end |
45 | 45 | end |
46 | 46 | |
47 | - describe '#is_being_closed?' do | |
48 | - it 'returns true if the closed attribute has changed and is now true' do | |
49 | - subject.closed = true | |
50 | - subject.is_being_closed?.should be_true | |
51 | - end | |
52 | - it 'returns false if the closed attribute has changed and is now false' do | |
53 | - issue = create(:closed_issue) | |
54 | - issue.closed = false | |
55 | - issue.is_being_closed?.should be_false | |
56 | - end | |
57 | - it 'returns false if the closed attribute has not changed' do | |
58 | - subject.is_being_closed?.should be_false | |
59 | - end | |
60 | - end | |
47 | + describe '#is_being_reassigned?' do | |
48 | + it 'returnes issues assigned to user' do | |
49 | + user = create :user | |
61 | 50 | |
51 | + 2.times do | |
52 | + issue = create :issue, assignee: user | |
53 | + end | |
62 | 54 | |
63 | - describe '#is_being_reopened?' do | |
64 | - it 'returns true if the closed attribute has changed and is now false' do | |
65 | - issue = create(:closed_issue) | |
66 | - issue.closed = false | |
67 | - issue.is_being_reopened?.should be_true | |
68 | - end | |
69 | - it 'returns false if the closed attribute has changed and is now true' do | |
70 | - subject.closed = true | |
71 | - subject.is_being_reopened?.should be_false | |
72 | - end | |
73 | - it 'returns false if the closed attribute has not changed' do | |
74 | - subject.is_being_reopened?.should be_false | |
55 | + Issue.open_for(user).count.should eq 2 | |
75 | 56 | end |
76 | 57 | end |
77 | 58 | end | ... | ... |
spec/models/merge_request_spec.rb
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | # st_commits :text(2147483647) |
16 | 16 | # st_diffs :text(2147483647) |
17 | 17 | # merged :boolean default(FALSE), not null |
18 | -# state :integer default(1), not null | |
18 | +# merge_status :integer default(1), not null | |
19 | 19 | # milestone_id :integer |
20 | 20 | # |
21 | 21 | |
... | ... | @@ -37,6 +37,10 @@ describe MergeRequest do |
37 | 37 | end |
38 | 38 | |
39 | 39 | describe "#mr_and_commit_notes" do |
40 | + | |
41 | + end | |
42 | + | |
43 | + describe "#mr_and_commit_notes" do | |
40 | 44 | let!(:merge_request) { create(:merge_request) } |
41 | 45 | |
42 | 46 | before do |
... | ... | @@ -62,35 +66,4 @@ describe MergeRequest do |
62 | 66 | subject.is_being_reassigned?.should be_false |
63 | 67 | end |
64 | 68 | end |
65 | - | |
66 | - describe '#is_being_closed?' do | |
67 | - it 'returns true if the closed attribute has changed and is now true' do | |
68 | - subject.closed = true | |
69 | - subject.is_being_closed?.should be_true | |
70 | - end | |
71 | - it 'returns false if the closed attribute has changed and is now false' do | |
72 | - merge_request = create(:closed_merge_request) | |
73 | - merge_request.closed = false | |
74 | - merge_request.is_being_closed?.should be_false | |
75 | - end | |
76 | - it 'returns false if the closed attribute has not changed' do | |
77 | - subject.is_being_closed?.should be_false | |
78 | - end | |
79 | - end | |
80 | - | |
81 | - | |
82 | - describe '#is_being_reopened?' do | |
83 | - it 'returns true if the closed attribute has changed and is now false' do | |
84 | - merge_request = create(:closed_merge_request) | |
85 | - merge_request.closed = false | |
86 | - merge_request.is_being_reopened?.should be_true | |
87 | - end | |
88 | - it 'returns false if the closed attribute has changed and is now true' do | |
89 | - subject.closed = true | |
90 | - subject.is_being_reopened?.should be_false | |
91 | - end | |
92 | - it 'returns false if the closed attribute has not changed' do | |
93 | - subject.is_being_reopened?.should be_false | |
94 | - end | |
95 | - end | |
96 | 69 | end | ... | ... |
spec/models/milestone_spec.rb
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | # project_id :integer not null |
8 | 8 | # description :text |
9 | 9 | # due_date :date |
10 | -# closed :boolean default(FALSE), not null | |
10 | +# state :string default(FALSE), not null | |
11 | 11 | # created_at :datetime not null |
12 | 12 | # updated_at :datetime not null |
13 | 13 | # |
... | ... | @@ -27,7 +27,6 @@ describe Milestone do |
27 | 27 | describe "Validation" do |
28 | 28 | it { should validate_presence_of(:title) } |
29 | 29 | it { should validate_presence_of(:project) } |
30 | - it { should ensure_inclusion_of(:closed).in_array([true, false]) } | |
31 | 30 | end |
32 | 31 | |
33 | 32 | let(:milestone) { create(:milestone) } |
... | ... | @@ -41,7 +40,7 @@ describe Milestone do |
41 | 40 | |
42 | 41 | it "should count closed issues" do |
43 | 42 | IssueObserver.current_user = issue.author |
44 | - issue.update_attributes(closed: true) | |
43 | + issue.close | |
45 | 44 | milestone.issues << issue |
46 | 45 | milestone.percent_complete.should == 100 |
47 | 46 | end |
... | ... | @@ -96,7 +95,7 @@ describe Milestone do |
96 | 95 | describe :items_count do |
97 | 96 | before do |
98 | 97 | milestone.issues << create(:issue) |
99 | - milestone.issues << create(:issue, closed: true) | |
98 | + milestone.issues << create(:closed_issue) | |
100 | 99 | milestone.merge_requests << create(:merge_request) |
101 | 100 | end |
102 | 101 | |
... | ... | @@ -110,7 +109,35 @@ describe Milestone do |
110 | 109 | it { milestone.can_be_closed?.should be_true } |
111 | 110 | end |
112 | 111 | |
113 | - describe :open? do | |
114 | - it { milestone.open?.should be_true } | |
112 | + describe :is_empty? do | |
113 | + before do | |
114 | + issue = create :closed_issue, milestone: milestone | |
115 | + merge_request = create :merge_request, milestone: milestone | |
116 | + end | |
117 | + | |
118 | + it 'Should return total count of issues and merge requests assigned to milestone' do | |
119 | + milestone.total_items_count.should eq 2 | |
120 | + end | |
121 | + end | |
122 | + | |
123 | + describe :can_be_closed? do | |
124 | + before do | |
125 | + milestone = create :milestone | |
126 | + create :closed_issue, milestone: milestone | |
127 | + | |
128 | + issue = create :issue | |
129 | + end | |
130 | + | |
131 | + it 'should be true if milestone active and all nestied issues closed' do | |
132 | + milestone.can_be_closed?.should be_true | |
133 | + end | |
134 | + | |
135 | + it 'should be false if milestone active and not all nestied issues closed' do | |
136 | + issue.milestone = milestone | |
137 | + issue.save | |
138 | + | |
139 | + milestone.can_be_closed?.should be_false | |
140 | + end | |
115 | 141 | end |
142 | + | |
116 | 143 | end | ... | ... |
spec/models/project_spec.rb
... | ... | @@ -121,10 +121,7 @@ describe Project do |
121 | 121 | let(:project) { create(:project) } |
122 | 122 | |
123 | 123 | before do |
124 | - @merge_request = create(:merge_request, | |
125 | - project: project, | |
126 | - merged: false, | |
127 | - closed: false) | |
124 | + @merge_request = create(:merge_request, project: project) | |
128 | 125 | @key = create(:key, user_id: project.owner.id) |
129 | 126 | end |
130 | 127 | |
... | ... | @@ -133,8 +130,7 @@ describe Project do |
133 | 130 | @merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" |
134 | 131 | project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/stable", @key.user) |
135 | 132 | @merge_request.reload |
136 | - @merge_request.merged.should be_true | |
137 | - @merge_request.closed.should be_true | |
133 | + @merge_request.merged?.should be_true | |
138 | 134 | end |
139 | 135 | |
140 | 136 | it "should update merge request commits with new one if pushed to source branch" do | ... | ... |
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/observers/merge_request_observer_spec.rb
1 | 1 | require 'spec_helper' |
2 | 2 | |
3 | 3 | describe MergeRequestObserver 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(:mr) { double(:merge_request, id: 42, assignee: assignee, author: author) } | |
4 | + let(:some_user) { create :user } | |
5 | + let(:assignee) { create :user } | |
6 | + let(:author) { create :user } | |
7 | + let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) } | |
8 | + let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author) } | |
9 | + let(:unassigned_mr) { create(:merge_request, author: author) } | |
10 | + let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) } | |
11 | + let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) } | |
8 | 12 | |
9 | 13 | before(:each) { subject.stub(:current_user).and_return(some_user) } |
10 | 14 | |
... | ... | @@ -21,23 +25,21 @@ describe MergeRequestObserver do |
21 | 25 | end |
22 | 26 | |
23 | 27 | it 'sends an email to the assignee' do |
24 | - Notify.should_receive(:new_merge_request_email).with(mr.id) | |
25 | - subject.after_create(mr) | |
28 | + Notify.should_receive(:new_merge_request_email).with(mr_mock.id) | |
29 | + subject.after_create(mr_mock) | |
26 | 30 | end |
27 | 31 | |
28 | 32 | it 'does not send an email to the assignee if assignee created the merge request' do |
29 | 33 | subject.stub(:current_user).and_return(assignee) |
30 | 34 | Notify.should_not_receive(:new_merge_request_email) |
31 | 35 | |
32 | - subject.after_create(mr) | |
36 | + subject.after_create(mr_mock) | |
33 | 37 | end |
34 | 38 | end |
35 | 39 | |
36 | 40 | context '#after_update' do |
37 | 41 | before(:each) do |
38 | - mr.stub(:is_being_reassigned?).and_return(false) | |
39 | - mr.stub(:is_being_closed?).and_return(false) | |
40 | - mr.stub(:is_being_reopened?).and_return(false) | |
42 | + mr_mock.stub(:is_being_reassigned?).and_return(false) | |
41 | 43 | end |
42 | 44 | |
43 | 45 | it 'is called when a merge request is changed' do |
... | ... | @@ -52,97 +54,50 @@ describe MergeRequestObserver do |
52 | 54 | |
53 | 55 | context 'a reassigned email' do |
54 | 56 | it 'is sent if the merge request is being reassigned' do |
55 | - mr.should_receive(:is_being_reassigned?).and_return(true) | |
56 | - subject.should_receive(:send_reassigned_email).with(mr) | |
57 | + mr_mock.should_receive(:is_being_reassigned?).and_return(true) | |
58 | + subject.should_receive(:send_reassigned_email).with(mr_mock) | |
57 | 59 | |
58 | - subject.after_update(mr) | |
60 | + subject.after_update(mr_mock) | |
59 | 61 | end |
60 | 62 | |
61 | 63 | it 'is not sent if the merge request is not being reassigned' do |
62 | - mr.should_receive(:is_being_reassigned?).and_return(false) | |
64 | + mr_mock.should_receive(:is_being_reassigned?).and_return(false) | |
63 | 65 | subject.should_not_receive(:send_reassigned_email) |
64 | 66 | |
65 | - subject.after_update(mr) | |
67 | + subject.after_update(mr_mock) | |
66 | 68 | end |
67 | 69 | end |
68 | 70 | |
71 | + end | |
72 | + | |
73 | + context '#after_close' do | |
69 | 74 | context 'a status "closed"' do |
70 | 75 | it 'note is created if the merge request is being closed' do |
71 | - mr.should_receive(:is_being_closed?).and_return(true) | |
72 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed') | |
73 | - | |
74 | - subject.after_update(mr) | |
75 | - end | |
76 | - | |
77 | - it 'note is not created if the merge request is not being closed' do | |
78 | - mr.should_receive(:is_being_closed?).and_return(false) | |
79 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed') | |
80 | - | |
81 | - subject.after_update(mr) | |
82 | - end | |
83 | - | |
84 | - it 'notification is delivered if the merge request being closed' do | |
85 | - mr.stub(:is_being_closed?).and_return(true) | |
86 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed') | |
87 | - | |
88 | - subject.after_update(mr) | |
89 | - end | |
90 | - | |
91 | - it 'notification is not delivered if the merge request not being closed' do | |
92 | - mr.stub(:is_being_closed?).and_return(false) | |
93 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed') | |
76 | + Note.should_receive(:create_status_change_note).with(assigned_mr, some_user, 'closed') | |
94 | 77 | |
95 | - subject.after_update(mr) | |
78 | + assigned_mr.close | |
96 | 79 | end |
97 | 80 | |
98 | 81 | it 'notification is delivered only to author if the merge request is being closed' do |
99 | - mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil) | |
100 | - mr_without_assignee.stub(:is_being_reassigned?).and_return(false) | |
101 | - mr_without_assignee.stub(:is_being_closed?).and_return(true) | |
102 | - mr_without_assignee.stub(:is_being_reopened?).and_return(false) | |
103 | - Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'closed') | |
82 | + Note.should_receive(:create_status_change_note).with(unassigned_mr, some_user, 'closed') | |
104 | 83 | |
105 | - subject.after_update(mr_without_assignee) | |
84 | + unassigned_mr.close | |
106 | 85 | end |
107 | 86 | end |
87 | + end | |
108 | 88 | |
89 | + context '#after_reopen' do | |
109 | 90 | context 'a status "reopened"' do |
110 | 91 | it 'note is created if the merge request is being reopened' do |
111 | - mr.should_receive(:is_being_reopened?).and_return(true) | |
112 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened') | |
113 | - | |
114 | - subject.after_update(mr) | |
115 | - end | |
116 | - | |
117 | - it 'note is not created if the merge request is not being reopened' do | |
118 | - mr.should_receive(:is_being_reopened?).and_return(false) | |
119 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened') | |
120 | - | |
121 | - subject.after_update(mr) | |
122 | - end | |
123 | - | |
124 | - it 'notification is delivered if the merge request being reopened' do | |
125 | - mr.stub(:is_being_reopened?).and_return(true) | |
126 | - Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened') | |
127 | - | |
128 | - subject.after_update(mr) | |
129 | - end | |
130 | - | |
131 | - it 'notification is not delivered if the merge request is not being reopened' do | |
132 | - mr.stub(:is_being_reopened?).and_return(false) | |
133 | - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened') | |
92 | + Note.should_receive(:create_status_change_note).with(closed_assigned_mr, some_user, 'reopened') | |
134 | 93 | |
135 | - subject.after_update(mr) | |
94 | + closed_assigned_mr.reopen | |
136 | 95 | end |
137 | 96 | |
138 | 97 | it 'notification is delivered only to author if the merge request is being reopened' do |
139 | - mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil) | |
140 | - mr_without_assignee.stub(:is_being_reassigned?).and_return(false) | |
141 | - mr_without_assignee.stub(:is_being_closed?).and_return(false) | |
142 | - mr_without_assignee.stub(:is_being_reopened?).and_return(true) | |
143 | - Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'reopened') | |
98 | + Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, some_user, 'reopened') | |
144 | 99 | |
145 | - subject.after_update(mr_without_assignee) | |
100 | + closed_unassigned_mr.reopen | |
146 | 101 | end |
147 | 102 | end |
148 | 103 | end |
... | ... | @@ -151,23 +106,23 @@ describe MergeRequestObserver do |
151 | 106 | let(:previous_assignee) { double(:user, id: 3) } |
152 | 107 | |
153 | 108 | before(:each) do |
154 | - mr.stub(:assignee_id).and_return(assignee.id) | |
155 | - mr.stub(:assignee_id_was).and_return(previous_assignee.id) | |
109 | + mr_mock.stub(:assignee_id).and_return(assignee.id) | |
110 | + mr_mock.stub(:assignee_id_was).and_return(previous_assignee.id) | |
156 | 111 | end |
157 | 112 | |
158 | 113 | def it_sends_a_reassigned_email_to(recipient) |
159 | - Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id) | |
114 | + Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) | |
160 | 115 | end |
161 | 116 | |
162 | 117 | def it_does_not_send_a_reassigned_email_to(recipient) |
163 | - Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id) | |
118 | + Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) | |
164 | 119 | end |
165 | 120 | |
166 | 121 | it 'sends a reassigned email to the previous and current assignees' do |
167 | 122 | it_sends_a_reassigned_email_to assignee.id |
168 | 123 | it_sends_a_reassigned_email_to previous_assignee.id |
169 | 124 | |
170 | - subject.send(:send_reassigned_email, mr) | |
125 | + subject.send(:send_reassigned_email, mr_mock) | |
171 | 126 | end |
172 | 127 | |
173 | 128 | context 'does not send an email to the user who made the reassignment' do |
... | ... | @@ -176,14 +131,14 @@ describe MergeRequestObserver do |
176 | 131 | it_sends_a_reassigned_email_to previous_assignee.id |
177 | 132 | it_does_not_send_a_reassigned_email_to assignee.id |
178 | 133 | |
179 | - subject.send(:send_reassigned_email, mr) | |
134 | + subject.send(:send_reassigned_email, mr_mock) | |
180 | 135 | end |
181 | 136 | it 'if the user is the previous assignee' do |
182 | 137 | subject.stub(:current_user).and_return(previous_assignee) |
183 | 138 | it_sends_a_reassigned_email_to assignee.id |
184 | 139 | it_does_not_send_a_reassigned_email_to previous_assignee.id |
185 | 140 | |
186 | - subject.send(:send_reassigned_email, mr) | |
141 | + subject.send(:send_reassigned_email, mr_mock) | |
187 | 142 | end |
188 | 143 | end |
189 | 144 | 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/api/merge_requests_spec.rb
... | ... | @@ -43,6 +43,23 @@ describe Gitlab::API do |
43 | 43 | end |
44 | 44 | end |
45 | 45 | |
46 | + describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do | |
47 | + it "should return merge_request" do | |
48 | + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "close" | |
49 | + response.status.should == 200 | |
50 | + json_response['state'].should == 'closed' | |
51 | + end | |
52 | + end | |
53 | + | |
54 | + describe "PUT /projects/:id/merge_request/:merge_request_id to merge MR" do | |
55 | + it "should return merge_request" do | |
56 | + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "merge" | |
57 | + response.status.should == 200 | |
58 | + json_response['state'].should == 'merged' | |
59 | + end | |
60 | + end | |
61 | + | |
62 | + | |
46 | 63 | describe "PUT /projects/:id/merge_request/:merge_request_id" do |
47 | 64 | it "should return merge_request" do |
48 | 65 | put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title" | ... | ... |
spec/requests/api/milestones_spec.rb
... | ... | @@ -44,4 +44,14 @@ describe Gitlab::API do |
44 | 44 | json_response['title'].should == 'updated title' |
45 | 45 | end |
46 | 46 | end |
47 | + | |
48 | + describe "PUT /projects/:id/milestones/:milestone_id to close milestone" do | |
49 | + it "should update a project milestone" do | |
50 | + put api("/projects/#{project.id}/milestones/#{milestone.id}", user), | |
51 | + state_event: 'close' | |
52 | + response.status.should == 200 | |
53 | + | |
54 | + json_response['state'].should == 'closed' | |
55 | + end | |
56 | + end | |
47 | 57 | end | ... | ... |
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' | ... | ... |