Changed state names from integers to strings. This gives more freedom in
modifying the states over time.
Added the new state to the state machine sprints. Added a test to ensure
that a sprint can be moved from proposed to planning state.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/models/sprint.rb | 19 +++++++++++++------
db/migrate/011_create_sprints.rb | 2 +-
test/fixtures/sprints.yml | 9 +++++++++
test/unit/sprint_test.rb | 13 +++++++++++++
4 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/app/models/sprint.rb b/app/models/sprint.rb
index 4cbc86f..239102f 100644
--- a/app/models/sprint.rb
+++ b/app/models/sprint.rb
@@ -73,12 +73,13 @@ class Sprint < ActiveRecord::Base
:dependent => :destroy
has_many :user_stories, :through => :backlog_items, :order => :priority
- STATE_PLANNING=0
- STATE_ACTIVE=1
- STATE_COMPLETED=2
- STATE_CANCELLED=3
+ STATE_PROPOSED='proposed'
+ STATE_PLANNING='planning'
+ STATE_ACTIVE='active'
+ STATE_COMPLETED='completed'
+ STATE_CANCELLED='cancelled'
- STATES = {STATE_PLANNING => "Planning", STATE_ACTIVE =>
"Active", :STATE_COMPLETED => "Completed", STATE_CANCELLED =>
"Cancelled"}
+ STATES = {STATE_PROPOSED => "Proposed", STATE_PLANNING =>
"Planning", STATE_ACTIVE => "Active", :STATE_COMPLETED =>
"Completed", STATE_CANCELLED => "Cancelled"}
named_scope :default, { :order => "starts ASC" }
named_scope :for_product, lambda { |product_id|
@@ -88,6 +89,7 @@ class Sprint < ActiveRecord::Base
named_scope :active, {:conditions => ['state = ?', STATE_ACTIVE]}
state_machine :initial => :planning do
+ state :proposed, :value => STATE_PROPOSED
state :planning, :value => STATE_PLANNING
state :active, :value => STATE_ACTIVE
state :completed, :value => STATE_COMPLETED
@@ -101,11 +103,16 @@ class Sprint < ActiveRecord::Base
end
end
+ event :unplan do
+ transition :planning => :proposed
+ end
+
event :plan do
transition :active => :planning
+ transition :proposed => :planning
def can_fire?(sprint)
- sprint.active? && Sprint.for_product(sprint.product).planned.empty?
+ sprint.proposed? || (sprint.active? &&
Sprint.for_product(sprint.product).planned.empty?)
end
end
diff --git a/db/migrate/011_create_sprints.rb b/db/migrate/011_create_sprints.rb
index ddec513..a3aba41 100644
--- a/db/migrate/011_create_sprints.rb
+++ b/db/migrate/011_create_sprints.rb
@@ -22,7 +22,7 @@ class CreateSprints < ActiveRecord::Migration
t.string :title, :null => false, :limit => 100
t.date :starts, :null => false
t.integer :duration, :null => false, :precision => 2, :scale => 0
- t.integer :state, :null => false, :default => 0
+ t.string :state, :null => false, :limit => 16
t.string :goals, :null => false, :limit => 1000
t.timestamps
diff --git a/test/fixtures/sprints.yml b/test/fixtures/sprints.yml
index d32b34f..06c700c 100644
--- a/test/fixtures/sprints.yml
+++ b/test/fixtures/sprints.yml
@@ -1,3 +1,12 @@
+proposed_sprint:
+ product_id: <%= Fixtures.identify(:projxp_web) %>
+ title: Stuff we're thinking about doing soon.
+ starts: <%= DateTime.now.to_s(:db) %>
+ duration: 28
+ goals: Don't know yet.
+ state: <%= Sprint::STATE_PROPOSED %>
+ team_lead_id: <%= Fixtures.identify(:team_lead) %>
+
planned_sprint:
product_id: <%= Fixtures.identify(:projxp_web) %>
title: Stuff we're going to do next.
diff --git a/test/unit/sprint_test.rb b/test/unit/sprint_test.rb
index 6c7c466..9bd309e 100644
--- a/test/unit/sprint_test.rb
+++ b/test/unit/sprint_test.rb
@@ -26,6 +26,9 @@ class SprintTest < ActiveSupport::TestCase
:goals => "To get stuff done!",
:team_lead => users(:mcpierce)
)
+ @proposed_sprint = sprints(:proposed_sprint)
+ raise "Sprint must be proposed!" unless @proposed_sprint.proposed?
+
@planned_sprint = sprints(:planned_sprint)
raise "Sprint must be in planning!" unless @planned_sprint.planning?
raise "Product must have an active sprint!" if
Sprint.for_product((a)planned_sprint.product).active.empty?
@@ -116,6 +119,16 @@ class SprintTest < ActiveSupport::TestCase
end
end
+ # Ensures that a proposed sprint can be moved to the planning state.
+ def test_can_plan_a_proposed_sprint
+ flunk "A proposed sprint must be able to move to the planning state."
unless @proposed_sprint.can_plan?
+ end
+
+ # Ensures that a planned sprint can be moved back to the proposed state.
+ def test_can_move_a_planned_sprint_to_proposed_state
+ flunk "A planned sprint should be able to go back to the proposed state."
unless @planned_sprint.can_unplan?
+ end
+
# Ensures that nobody can edit a completed sprint.
def test_can_edit_with_completed_sprint
flunk "Completed sprints must not be edited by the team lead." if
@completed_sprint.can_edit?((a)completed_sprint.team_lead)
--
1.6.2.5