pivotal_doc 1.4.0 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/pivotal_doc.rb +0 -3
- data/lib/pivotal_doc/generator.rb +7 -13
- data/lib/pivotal_doc/generators/base.rb +6 -4
- data/lib/pivotal_doc/generators/csv.rb +1 -1
- data/lib/pivotal_doc/generators/html.rb +1 -1
- data/lib/pivotal_doc/sprint.rb +55 -12
- data/lib/pivotal_doc/work.rb +0 -19
- data/pivotal_doc.gemspec +2 -7
- data/spec/lib/generator_spec.rb +12 -38
- data/spec/lib/generators/base_spec.rb +7 -7
- data/spec/lib/generators/csv_spec.rb +4 -4
- data/spec/lib/generators/html_spec.rb +3 -3
- data/spec/lib/sprint_spec.rb +73 -26
- data/spec/support/mocks_helper.rb +8 -7
- data/templates/output.haml +9 -33
- data/templates/release.haml +30 -0
- data/templates/sprint.haml +25 -48
- metadata +4 -9
- data/lib/pivotal_doc/generators/sprint.rb +0 -18
- data/lib/pivotal_doc/release.rb +0 -36
- data/spec/lib/generators/sprint_spec.rb +0 -40
- data/spec/lib/release_spec.rb +0 -92
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.4.
|
1
|
+
1.4.1
|
data/lib/pivotal_doc.rb
CHANGED
@@ -16,13 +16,10 @@ require File.join('pivotal_doc/exceptions')
|
|
16
16
|
require File.join('pivotal_doc/generator')
|
17
17
|
|
18
18
|
#Core classes
|
19
|
-
require File.join('pivotal_doc/work')
|
20
|
-
require File.join('pivotal_doc/release')
|
21
19
|
require File.join('pivotal_doc/sprint')
|
22
20
|
|
23
21
|
#Generators
|
24
22
|
require File.join('pivotal_doc/generators', 'base')
|
25
23
|
require File.join('pivotal_doc/generators', 'html')
|
26
24
|
require File.join('pivotal_doc/generators', 'csv')
|
27
|
-
require File.join('pivotal_doc/generators', 'sprint')
|
28
25
|
|
@@ -1,15 +1,13 @@
|
|
1
1
|
module PivotalDoc
|
2
2
|
class Generator
|
3
3
|
class << self
|
4
|
-
#TODO: Clean this mutatant up
|
5
4
|
def generate(format, settings={})
|
6
5
|
raise FormatNotSupported.new(format) unless generators.has_key?(format)
|
7
6
|
config= PivotalDoc::Configuration.new(settings)
|
8
7
|
config.authenticate!
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
(generator || generators[format]).new(release, config.settings).render_doc
|
8
|
+
sprints= collect_sprints!(config)
|
9
|
+
sprints.each do |sprint|
|
10
|
+
generators[format].new(sprint, config.settings).render_doc
|
13
11
|
end
|
14
12
|
true
|
15
13
|
end
|
@@ -18,17 +16,13 @@ module PivotalDoc
|
|
18
16
|
{ :html=>Generators::HTML, :csv=>Generators::CSV }
|
19
17
|
end
|
20
18
|
|
21
|
-
def
|
22
|
-
|
19
|
+
def collect_sprints!(config)
|
20
|
+
sprints= []
|
23
21
|
config.projects.each do |name, _attrs|
|
24
22
|
project= PT::Project.find(_attrs['id'].to_i)
|
25
|
-
|
26
|
-
releases << Sprint.new(project)
|
27
|
-
else
|
28
|
-
releases << Release.new(project)
|
29
|
-
end
|
23
|
+
sprints << PivotalDoc::Sprint.new(project, _attrs['current'])
|
30
24
|
end
|
31
|
-
return
|
25
|
+
return sprints
|
32
26
|
end
|
33
27
|
end
|
34
28
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module PivotalDoc
|
2
2
|
module Generators
|
3
3
|
class Base
|
4
|
-
|
5
|
-
|
4
|
+
TEMPLATE_PATH= "#{PROJECT_ROOT}/templates"
|
5
|
+
|
6
|
+
def initialize(sprint, options={})
|
7
|
+
@sprint= sprint
|
6
8
|
@options= options
|
7
9
|
end
|
8
10
|
|
@@ -13,7 +15,7 @@ module PivotalDoc
|
|
13
15
|
def output_file
|
14
16
|
name= @options['output_file']
|
15
17
|
unless name
|
16
|
-
name=@
|
18
|
+
name=@sprint.release_name || @sprint.project_name || self.object_id.to_s
|
17
19
|
name.gsub!(/\//, '') and name.gsub!(/\s/,'')
|
18
20
|
end
|
19
21
|
File.join(output_path, (name + output_ext))
|
@@ -40,7 +42,7 @@ module PivotalDoc
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def template
|
43
|
-
path= File.join(
|
45
|
+
path= File.join(TEMPLATE_PATH, template_name)
|
44
46
|
raise TemplateNonExistent.new(template_name) unless File.exists?(path)
|
45
47
|
@template ||= File.read(path)
|
46
48
|
end
|
data/lib/pivotal_doc/sprint.rb
CHANGED
@@ -1,24 +1,67 @@
|
|
1
1
|
module PivotalDoc
|
2
|
-
class Sprint
|
3
|
-
|
2
|
+
class Sprint
|
3
|
+
attr_reader :project, :iteration
|
4
|
+
|
5
|
+
def initialize(project, current=false)
|
6
|
+
@project= project
|
7
|
+
@current= current
|
8
|
+
@iteration= (@current) ? current_iteration : latest_iteration
|
9
|
+
end
|
10
|
+
|
11
|
+
def current?
|
12
|
+
@current
|
13
|
+
end
|
4
14
|
|
5
|
-
|
6
|
-
|
15
|
+
def project_name
|
16
|
+
@project.name
|
17
|
+
end
|
18
|
+
|
19
|
+
def features
|
20
|
+
self.stories + self.bugs + self.chores
|
21
|
+
end
|
22
|
+
|
23
|
+
def stories
|
24
|
+
@stories ||= filter_stories
|
25
|
+
end
|
7
26
|
|
8
|
-
def
|
9
|
-
@
|
10
|
-
|
27
|
+
def bugs
|
28
|
+
@bugs ||= filter_stories('bug')
|
29
|
+
end
|
30
|
+
|
31
|
+
def chores
|
32
|
+
@chores ||= filter_stories('chore')
|
33
|
+
end
|
34
|
+
|
35
|
+
def release
|
36
|
+
@release ||= self.iteration.stories.detect{|s| s.story_type.downcase=='release'} if self.iteration.stories
|
11
37
|
end
|
12
|
-
|
13
|
-
def name; nil end
|
14
38
|
|
15
|
-
def
|
16
|
-
|
39
|
+
def release_name
|
40
|
+
release.name if release.respond_to?(:name)
|
17
41
|
end
|
18
42
|
|
43
|
+
def latest_iteration
|
44
|
+
PT::Iteration.done(@project, :offset=>'-1').first
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_iteration
|
48
|
+
PT::Iteration.current(@project)
|
49
|
+
end
|
50
|
+
|
51
|
+
[:stories, :bugs, :chores].each do |m|
|
52
|
+
define_method("accepted_#{m}") do
|
53
|
+
self.send(m).reject{|s| s.current_state.downcase != 'accepted' }
|
54
|
+
end
|
55
|
+
define_method("#{m}_delivered") do
|
56
|
+
self.send("accepted_#{m}".to_sym).size
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
19
60
|
private
|
20
61
|
def filter_stories(type='feature')
|
21
|
-
self.iteration.stories.reject
|
62
|
+
self.iteration.stories.reject do |s|
|
63
|
+
s.story_type.downcase != type
|
64
|
+
end
|
22
65
|
end
|
23
66
|
end
|
24
67
|
end
|
data/lib/pivotal_doc/work.rb
CHANGED
@@ -1,23 +1,4 @@
|
|
1
1
|
module PivotalDoc
|
2
2
|
module Work
|
3
|
-
def project_name
|
4
|
-
@project.name
|
5
|
-
end
|
6
|
-
|
7
|
-
def features
|
8
|
-
self.stories + self.bugs + self.chores
|
9
|
-
end
|
10
|
-
|
11
|
-
def stories
|
12
|
-
@stories ||= filter_stories
|
13
|
-
end
|
14
|
-
|
15
|
-
def bugs
|
16
|
-
@bugs ||= filter_stories('bug')
|
17
|
-
end
|
18
|
-
|
19
|
-
def chores
|
20
|
-
@chores ||= filter_stories('chore')
|
21
|
-
end
|
22
3
|
end
|
23
4
|
end
|
data/pivotal_doc.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{pivotal_doc}
|
8
|
-
s.version = "1.4.
|
8
|
+
s.version = "1.4.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tim Linquist"]
|
@@ -51,8 +51,6 @@ Gem::Specification.new do |s|
|
|
51
51
|
"lib/pivotal_doc/generators/base.rb",
|
52
52
|
"lib/pivotal_doc/generators/csv.rb",
|
53
53
|
"lib/pivotal_doc/generators/html.rb",
|
54
|
-
"lib/pivotal_doc/generators/sprint.rb",
|
55
|
-
"lib/pivotal_doc/release.rb",
|
56
54
|
"lib/pivotal_doc/sprint.rb",
|
57
55
|
"lib/pivotal_doc/work.rb",
|
58
56
|
"pivotal_doc.gemspec",
|
@@ -66,8 +64,6 @@ Gem::Specification.new do |s|
|
|
66
64
|
"spec/lib/generators/base_spec.rb",
|
67
65
|
"spec/lib/generators/csv_spec.rb",
|
68
66
|
"spec/lib/generators/html_spec.rb",
|
69
|
-
"spec/lib/generators/sprint_spec.rb",
|
70
|
-
"spec/lib/release_spec.rb",
|
71
67
|
"spec/lib/sprint_spec.rb",
|
72
68
|
"spec/spec.opts",
|
73
69
|
"spec/spec_helper.rb",
|
@@ -76,6 +72,7 @@ Gem::Specification.new do |s|
|
|
76
72
|
"templates/fancy.haml",
|
77
73
|
"templates/output.csv",
|
78
74
|
"templates/output.haml",
|
75
|
+
"templates/release.haml",
|
79
76
|
"templates/sprint.haml"
|
80
77
|
]
|
81
78
|
s.homepage = %q{http://github.com/timo3377/pivotal_doc}
|
@@ -89,8 +86,6 @@ Gem::Specification.new do |s|
|
|
89
86
|
"spec/lib/generators/base_spec.rb",
|
90
87
|
"spec/lib/generators/csv_spec.rb",
|
91
88
|
"spec/lib/generators/html_spec.rb",
|
92
|
-
"spec/lib/generators/sprint_spec.rb",
|
93
|
-
"spec/lib/release_spec.rb",
|
94
89
|
"spec/lib/sprint_spec.rb",
|
95
90
|
"spec/spec_helper.rb",
|
96
91
|
"spec/support/mocks_helper.rb",
|
data/spec/lib/generator_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe PivotalDoc::Generator do
|
|
13
13
|
|
14
14
|
describe "Configuring" do
|
15
15
|
before(:each) do
|
16
|
-
PivotalDoc::Generator.stub!(:
|
16
|
+
PivotalDoc::Generator.stub!(:collect_sprints!).and_return([])
|
17
17
|
end
|
18
18
|
it "should create a config object from the settings" do
|
19
19
|
settings= {}
|
@@ -28,48 +28,28 @@ describe PivotalDoc::Generator do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe "
|
31
|
+
describe "sprints" do
|
32
32
|
before(:each) do
|
33
|
-
@
|
34
|
-
PivotalDoc::
|
33
|
+
@sprint= mocks_helper(:sprint)
|
34
|
+
PivotalDoc::Sprint.stub!(:new).and_return(@sprint)
|
35
35
|
end
|
36
36
|
|
37
|
-
it "should create a
|
37
|
+
it "should create a sprint for each project" do
|
38
38
|
PT::Iteration.stub!(:current).and_return(mocks_helper(:iteration))
|
39
39
|
@config.projects.each do |name, settings|
|
40
|
-
PT::Project.should_receive(:find).with(settings['id'].to_i).and_return(@
|
41
|
-
end
|
42
|
-
releases= PivotalDoc::Generator.collect_releases!(@config)
|
43
|
-
releases.size.should eql(@config.projects.size)
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "current" do
|
47
|
-
it "create a current iteration for the release if current is set for the project" do
|
48
|
-
PT::Project.stub!(:find).and_return(@release.project)
|
49
|
-
iteration= mocks_helper(:iteration)
|
50
|
-
PT::Iteration.should_receive(:current).exactly(:once).and_return(iteration)
|
51
|
-
PivotalDoc::Generator.collect_releases!(@config)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "create a sprint for the current iteration instead of a release" do
|
55
|
-
PT::Project.stub!(:find).and_return(@release.project)
|
56
|
-
iteration= mocks_helper(:iteration)
|
57
|
-
PT::Iteration.stub!(:current).and_return(iteration)
|
58
|
-
releases= PivotalDoc::Generator.collect_releases!(@config)
|
59
|
-
releases.last.should be_an_instance_of(PivotalDoc::Sprint)
|
40
|
+
PT::Project.should_receive(:find).with(settings['id'].to_i).and_return(@sprint.project)
|
60
41
|
end
|
42
|
+
sprints= PivotalDoc::Generator.collect_sprints!(@config)
|
43
|
+
sprints.size.should eql(@config.projects.size)
|
61
44
|
end
|
62
45
|
end
|
63
46
|
|
64
47
|
describe "generation" do
|
65
48
|
before(:each) do
|
66
49
|
@config.stub!(:authenticate!).and_return(true)
|
67
|
-
@
|
68
|
-
PT::
|
69
|
-
@sprint = PivotalDoc::Sprint.new(@release.project)
|
70
|
-
PT::Project.stub!(:find).and_return(@release.project)
|
50
|
+
@sprint = mocks_helper(:sprint)
|
51
|
+
PT::Project.stub!(:find).and_return(@sprint.project)
|
71
52
|
PivotalDoc::Sprint.stub!(:new).and_return(@sprint)
|
72
|
-
PivotalDoc::Release.stub!(:new).and_return(@release)
|
73
53
|
end
|
74
54
|
|
75
55
|
describe "Formattting" do
|
@@ -78,15 +58,9 @@ describe PivotalDoc::Generator do
|
|
78
58
|
@html_gen= PivotalDoc::Generators::HTML.new({})
|
79
59
|
@html_gen.stub!(:render_doc)
|
80
60
|
end
|
81
|
-
|
82
|
-
sprint_generator= mock('PivotalDoc::Generators::Sprint')
|
83
|
-
@sprint.generator(:html).should_receive(:new).exactly(:once).with(@sprint, @config.settings).and_return(sprint_generator)
|
84
|
-
sprint_generator.should_receive(:render_doc)
|
85
|
-
PivotalDoc::Generator.generate(:html)
|
86
|
-
end
|
61
|
+
|
87
62
|
it "should render the release with the specified format and custom settings" do
|
88
|
-
|
89
|
-
PivotalDoc::Generators::HTML.should_receive(:new).with(@release, @config.settings).and_return(@html_gen)
|
63
|
+
PivotalDoc::Generators::HTML.should_receive(:new).with(@sprint, @config.settings).and_return(@html_gen)
|
90
64
|
PivotalDoc::Generator.generate(:html)
|
91
65
|
end
|
92
66
|
it "should raise an error if the specified format isn't supported" do
|
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe PivotalDoc::Generators::Base do
|
4
4
|
before(:each) do
|
5
|
-
@
|
6
|
-
@base= PivotalDoc::Generators::Base.new(@
|
5
|
+
@sprint= mocks_helper(:sprint)
|
6
|
+
@base= PivotalDoc::Generators::Base.new(@sprint)
|
7
7
|
end
|
8
8
|
it "should raise an exception if the template doesn't exist" do
|
9
9
|
@base.stub!(:template_name).and_return('non-existent.txt')
|
@@ -21,24 +21,24 @@ describe PivotalDoc::Generators::Base do
|
|
21
21
|
|
22
22
|
describe "options" do
|
23
23
|
it "should be a fully qualified file" do
|
24
|
-
base= PivotalDoc::Generators::Base.new(@
|
24
|
+
base= PivotalDoc::Generators::Base.new(@sprint, {:output_file=>'my_file'})
|
25
25
|
f= File.open(base.output_file, 'w')
|
26
26
|
f.should be_an_instance_of(File)
|
27
27
|
File.delete(f.path)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should use the output_file if present" do
|
31
|
-
base= PivotalDoc::Generators::Base.new(@
|
31
|
+
base= PivotalDoc::Generators::Base.new(@sprint, {'output_file'=>'my_file'})
|
32
32
|
base.output_file.should =~ /\/my_file/
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should default the output_file to the release's name (unique filename for multiple projects)" do
|
36
|
-
base= PivotalDoc::Generators::Base.new(@
|
37
|
-
base.output_file.should =~ /\/#{@
|
36
|
+
base= PivotalDoc::Generators::Base.new(@sprint)
|
37
|
+
base.output_file.should =~ /\/#{@sprint.release_name}/
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should use the output_path if present" do
|
41
|
-
base= PivotalDoc::Generators::Base.new(@
|
41
|
+
base= PivotalDoc::Generators::Base.new(@sprint, {'output_path'=>'my_path'})
|
42
42
|
base.output_path.should =~ /^my_path/
|
43
43
|
end
|
44
44
|
|
@@ -2,8 +2,8 @@ require File.dirname(__FILE__) + '/../../spec_helper'
|
|
2
2
|
|
3
3
|
describe PivotalDoc::Generators::CSV do
|
4
4
|
before(:each) do
|
5
|
-
@
|
6
|
-
@csv= PivotalDoc::Generators::CSV.new(@
|
5
|
+
@sprint= mocks_helper(:sprint)
|
6
|
+
@csv= PivotalDoc::Generators::CSV.new(@sprint)
|
7
7
|
end
|
8
8
|
|
9
9
|
after(:each) do
|
@@ -15,7 +15,7 @@ describe PivotalDoc::Generators::CSV do
|
|
15
15
|
@csv.render_doc
|
16
16
|
output= File.read(@csv.output_file)
|
17
17
|
output.should =~ /#{PivotalDoc::Generators::CSV::COLUMNS.join(',')}/
|
18
|
-
@
|
18
|
+
@sprint.features.each{|f| output =~ @csv.fields(f) }
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should read the file contents" do
|
@@ -27,7 +27,7 @@ describe PivotalDoc::Generators::CSV do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it "include each field" do
|
30
|
-
fields= @csv.fields(@
|
30
|
+
fields= @csv.fields(@sprint.features.first)
|
31
31
|
fields.should be_an_instance_of(Array)
|
32
32
|
fields.should have(PivotalDoc::Generators::CSV::COLUMNS.size).items
|
33
33
|
end
|
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe PivotalDoc::Generators::HTML do
|
4
4
|
before(:each) do
|
5
|
-
@
|
6
|
-
@html= PivotalDoc::Generators::HTML.new(@
|
5
|
+
@sprint= mocks_helper(:sprint)
|
6
|
+
@html= PivotalDoc::Generators::HTML.new(@sprint)
|
7
7
|
@engine= Haml::Engine.new('')
|
8
8
|
end
|
9
9
|
|
@@ -24,7 +24,7 @@ describe PivotalDoc::Generators::HTML do
|
|
24
24
|
|
25
25
|
it "should use the template_name if specified" do
|
26
26
|
options= {'template_name'=>'fancy.html'}
|
27
|
-
html= PivotalDoc::Generators::HTML.new(@
|
27
|
+
html= PivotalDoc::Generators::HTML.new(@sprint, options)
|
28
28
|
html.template_name.should eql(options['template_name'])
|
29
29
|
end
|
30
30
|
|
data/spec/lib/sprint_spec.rb
CHANGED
@@ -3,42 +3,89 @@ require 'spec_helper'
|
|
3
3
|
describe PivotalDoc::Sprint do
|
4
4
|
before(:each) do
|
5
5
|
@project= PT::Project.new
|
6
|
-
@
|
7
|
-
PT::Iteration.stub!(:
|
6
|
+
@latest_iteration, @current_iteration = PT::Iteration.new, PT::Iteration.new
|
7
|
+
PT::Iteration.stub!(:done).and_return([@latest_iteration])
|
8
8
|
@sprint= PivotalDoc::Sprint.new(@project)
|
9
9
|
end
|
10
10
|
|
11
|
-
it "
|
12
|
-
|
11
|
+
it "should get the last 'done' iteration for the project" do
|
12
|
+
PT::Iteration.should_receive(:done).with(@project, :offset=>'-1').and_return([@latest_iteration])
|
13
|
+
@sprint.latest_iteration.should eql(@latest_iteration)
|
13
14
|
end
|
14
15
|
|
15
|
-
it "
|
16
|
-
|
16
|
+
it "should get the current iteration for the project" do
|
17
|
+
PT::Iteration.should_receive(:current).and_return(@current_iteration)
|
18
|
+
@sprint.current_iteration.should eql(@current_iteration)
|
17
19
|
end
|
18
|
-
|
19
|
-
|
20
|
-
@sprint.generator(:unknown).should be_nil
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "stories" do
|
20
|
+
|
21
|
+
describe "an iteration" do
|
24
22
|
before(:each) do
|
25
|
-
@
|
26
|
-
@sprint.iteration.stub!(:stories).and_return(@stories)
|
23
|
+
@sprint.stub!(:latest_iteration).and_return(@latest_iteration)
|
27
24
|
end
|
28
|
-
|
29
|
-
it "should
|
30
|
-
|
31
|
-
|
25
|
+
|
26
|
+
it "should default the iteration to the latest_iteration (last 'done') if current isn't set" do
|
27
|
+
PT::Iteration.should_receive(:done).and_return([@latest_iteration])
|
28
|
+
sprint= PivotalDoc::Sprint.new(@project)
|
29
|
+
sprint.iteration.should eql(@latest_iteration)
|
32
30
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
|
32
|
+
describe "release of sprint" do
|
33
|
+
before(:each) do
|
34
|
+
@stories= PTApiHelpers::mock_stories
|
35
|
+
@release= PTApiHelpers::mock_actual_release
|
36
|
+
@latest_iteration.stub!(:stories).and_return(@stories)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should find the \"release\" if there is one" do
|
40
|
+
@latest_iteration.should_receive(:stories).and_return(@stories)
|
41
|
+
@sprint.release.story_type.should eql('release')
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should know the name of the release" do
|
45
|
+
@sprint.release_name.should eql(@release.name)
|
46
|
+
end
|
37
47
|
end
|
38
48
|
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
describe "stories" do
|
50
|
+
before(:each) do
|
51
|
+
@stories= PTApiHelpers::mock_stories
|
52
|
+
@latest_iteration.stub!(:stories).and_return(@stories)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should get the stories only" do
|
56
|
+
@latest_iteration.should_receive(:stories).and_return(@stories)
|
57
|
+
@sprint.stories.each{|s| s.story_type.downcase.should eql('feature') }
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should get the bugs only" do
|
61
|
+
@latest_iteration.should_receive(:stories).and_return(@stories)
|
62
|
+
@sprint.bugs.each{|b| b.story_type.downcase.should eql('bug') }
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should get the chores only" do
|
66
|
+
@latest_iteration.should_receive(:stories).and_return(@stories)
|
67
|
+
@sprint.chores.each{|c| c.story_type.downcase.should eql('chore') }
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "finished work" do
|
71
|
+
[:stories, :chores, :bugs].each do |m|
|
72
|
+
it "should know the #{m} delivered in this release" do
|
73
|
+
@sprint.send("#{m}_delivered").should eql(@sprint.send("accepted_#{m}").size)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should only get the \"delivered\" stories" do
|
78
|
+
@sprint.accepted_stories.each{|s| s.current_state.downcase.should eql('accepted')}
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should only get the \"delivered\" bugs" do
|
82
|
+
@sprint.accepted_bugs.each{|b| b.current_state.downcase.should eql('accepted')}
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should only get the \"accepted\" chores" do
|
86
|
+
@sprint.accepted_chores.each{|c| c.current_state.downcase.should eql('accepted')}
|
87
|
+
end
|
88
|
+
end
|
42
89
|
end
|
43
|
-
end
|
90
|
+
end
|
44
91
|
end
|
@@ -5,12 +5,13 @@ module MocksHelper
|
|
5
5
|
end
|
6
6
|
|
7
7
|
private
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
def sprint
|
9
|
+
PT::Iteration.stub!(:current).and_return(iteration)
|
10
|
+
sprint= PivotalDoc::Sprint.new(project, iteration)
|
11
|
+
sprint.stub!(:stories).and_return(PTApiHelpers::mock_stories)
|
12
|
+
sprint.stub!(:bugs).and_return(PTApiHelpers::mock_bugs)
|
13
|
+
sprint.stub!(:chores).and_return(PTApiHelpers::mock_chores)
|
14
|
+
sprint
|
14
15
|
end
|
15
16
|
|
16
17
|
def project
|
@@ -23,7 +24,7 @@ module MocksHelper
|
|
23
24
|
|
24
25
|
def mocks
|
25
26
|
@@mocks= {
|
26
|
-
:
|
27
|
+
:sprint=>sprint,
|
27
28
|
:project=>project,
|
28
29
|
:iteration=>iteration
|
29
30
|
}
|
data/templates/output.haml
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
%html
|
3
3
|
%head
|
4
4
|
%meta{'http-equiv' => 'Content-Type', :content => 'text/html;charset=utf-8'}
|
5
|
-
%title=
|
5
|
+
%title= sprint.release_name
|
6
6
|
%style{:type => "text/css", :media => "screen"}
|
7
7
|
:plain
|
8
8
|
p,div,h1,h2,h3,h4,h5,h6,span,a {font-family: Arial}
|
@@ -19,35 +19,11 @@
|
|
19
19
|
div.item {padding-left: .4em}
|
20
20
|
div.item_info {padding-left: .4em}
|
21
21
|
%body
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
%
|
29
|
-
|
30
|
-
.item
|
31
|
-
%h4= "Story ##{story.id} - #{story.name}"
|
32
|
-
.item_info
|
33
|
-
%p= "Requestor: #{story.requested_by}"
|
34
|
-
%p= "Completed By: #{story.owned_by}"
|
35
|
-
%p= "Description: #{story.description}"
|
36
|
-
#bugs
|
37
|
-
%h3 Bug Fixes
|
38
|
-
- release.bugs.each do |bug|
|
39
|
-
.item
|
40
|
-
%h4= "Bug ##{bug.id} - #{bug.name}"
|
41
|
-
.item_info
|
42
|
-
%p= "Requestor: #{bug.requested_by}"
|
43
|
-
%p= "Completed By: #{bug.owned_by}"
|
44
|
-
%p= "Description: #{bug.description}"
|
45
|
-
#chores
|
46
|
-
%h3 Miscellaneous Chores
|
47
|
-
- release.chores.each do |chore|
|
48
|
-
.item
|
49
|
-
%h4= "Chore ##{chore.id} - #{chore.name}"
|
50
|
-
.item_info
|
51
|
-
%p= "Requestor: #{chore.requested_by}"
|
52
|
-
%p= "Completed By: #{chore.owned_by}"
|
53
|
-
%p= "Description: #{chore.description}"
|
22
|
+
#doc
|
23
|
+
#info
|
24
|
+
- path= PivotalDoc::Generators::Base::TEMPLATE_PATH
|
25
|
+
- if sprint.current?
|
26
|
+
%p= Haml::Engine.new(File.read(path + '/sprint.haml')).render(Object.new, {:sprint=>sprint})
|
27
|
+
- else
|
28
|
+
%p= Haml::Engine.new(File.read(path + '/release.haml')).render(Object.new, {:sprint=>sprint})
|
29
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
%h2= "Announcing the \"#{sprint.release_name}\" release for the #{sprint.project_name} project"
|
2
|
+
%p
|
3
|
+
= "This sprint began on #{sprint.iteration.start.fancy_format} and was completed on #{sprint.iteration.finish.fancy_format}. It includes #{sprint.stories_delivered} new stories, #{sprint.bugs_delivered} bug fixes, and #{sprint.chores_delivered} miscellaneous chores."
|
4
|
+
#stories
|
5
|
+
%h3 Accepted Stories
|
6
|
+
- sprint.accepted_stories.each do |story|
|
7
|
+
.item
|
8
|
+
%h4= "Story ##{story.id} - #{story.name}"
|
9
|
+
.item_info
|
10
|
+
%p= "Requestor: #{story.requested_by}"
|
11
|
+
%p= "Completed By: #{story.owned_by}"
|
12
|
+
%p= "Description: #{story.description}"
|
13
|
+
#bugs
|
14
|
+
%h3 Bug Fixes
|
15
|
+
- sprint.accepted_bugs.each do |bug|
|
16
|
+
.item
|
17
|
+
%h4= "Bug ##{bug.id} - #{bug.name}"
|
18
|
+
.item_info
|
19
|
+
%p= "Requestor: #{bug.requested_by}"
|
20
|
+
%p= "Completed By: #{bug.owned_by}"
|
21
|
+
%p= "Description: #{bug.description}"
|
22
|
+
#chores
|
23
|
+
%h3 Miscellaneous Chores
|
24
|
+
- sprint.accepted_chores.each do |chore|
|
25
|
+
.item
|
26
|
+
%h4= "Chore ##{chore.id} - #{chore.name}"
|
27
|
+
.item_info
|
28
|
+
%p= "Requestor: #{chore.requested_by}"
|
29
|
+
%p= "Completed By: #{chore.owned_by}"
|
30
|
+
%p= "Description: #{chore.description}"
|
data/templates/sprint.haml
CHANGED
@@ -1,48 +1,25 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
%
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
p
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
}
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
%
|
25
|
-
|
26
|
-
%h3 Proposed Stories
|
27
|
-
- sprint.stories.each do |story|
|
28
|
-
.item
|
29
|
-
%h4= "Story ##{story.id} - #{story.name}"
|
30
|
-
.item_info
|
31
|
-
%p= "Requestor: #{story.requested_by}"
|
32
|
-
%p= "Description: #{story.description}"
|
33
|
-
#bugs
|
34
|
-
%h3 Bug Fixes
|
35
|
-
- sprint.bugs.each do |bug|
|
36
|
-
.item
|
37
|
-
%h4= "Bug ##{bug.id} - #{bug.name}"
|
38
|
-
.item_info
|
39
|
-
%p= "Requestor: #{bug.requested_by}"
|
40
|
-
%p= "Description: #{bug.description}"
|
41
|
-
#chores
|
42
|
-
%h3 Miscellaneous Chores
|
43
|
-
- sprint.chores.each do |chore|
|
44
|
-
.item
|
45
|
-
%h4= "Chore ##{chore.id} - #{chore.name}"
|
46
|
-
.item_info
|
47
|
-
%p= "Requestor: #{chore.requested_by}"
|
48
|
-
%p= "Description: #{chore.description}"
|
1
|
+
%h2= "This sprint begins on #{sprint.iteration.start.fancy_format} and ends on #{sprint.iteration.finish.fancy_format}."
|
2
|
+
#stories
|
3
|
+
%h3 Proposed Stories
|
4
|
+
- sprint.stories.each do |story|
|
5
|
+
.item
|
6
|
+
%h4= "Story ##{story.id} - #{story.name}"
|
7
|
+
.item_info
|
8
|
+
%p= "Requestor: #{story.requested_by}"
|
9
|
+
%p= "Description: #{story.description}"
|
10
|
+
#bugs
|
11
|
+
%h3 Bug Fixes
|
12
|
+
- sprint.bugs.each do |bug|
|
13
|
+
.item
|
14
|
+
%h4= "Bug ##{bug.id} - #{bug.name}"
|
15
|
+
.item_info
|
16
|
+
%p= "Requestor: #{bug.requested_by}"
|
17
|
+
%p= "Description: #{bug.description}"
|
18
|
+
#chores
|
19
|
+
%h3 Miscellaneous Chores
|
20
|
+
- sprint.chores.each do |chore|
|
21
|
+
.item
|
22
|
+
%h4= "Chore ##{chore.id} - #{chore.name}"
|
23
|
+
.item_info
|
24
|
+
%p= "Requestor: #{chore.requested_by}"
|
25
|
+
%p= "Description: #{chore.description}"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pivotal_doc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 1.4.
|
9
|
+
- 1
|
10
|
+
version: 1.4.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tim Linquist
|
@@ -218,8 +218,6 @@ files:
|
|
218
218
|
- lib/pivotal_doc/generators/base.rb
|
219
219
|
- lib/pivotal_doc/generators/csv.rb
|
220
220
|
- lib/pivotal_doc/generators/html.rb
|
221
|
-
- lib/pivotal_doc/generators/sprint.rb
|
222
|
-
- lib/pivotal_doc/release.rb
|
223
221
|
- lib/pivotal_doc/sprint.rb
|
224
222
|
- lib/pivotal_doc/work.rb
|
225
223
|
- pivotal_doc.gemspec
|
@@ -233,8 +231,6 @@ files:
|
|
233
231
|
- spec/lib/generators/base_spec.rb
|
234
232
|
- spec/lib/generators/csv_spec.rb
|
235
233
|
- spec/lib/generators/html_spec.rb
|
236
|
-
- spec/lib/generators/sprint_spec.rb
|
237
|
-
- spec/lib/release_spec.rb
|
238
234
|
- spec/lib/sprint_spec.rb
|
239
235
|
- spec/spec.opts
|
240
236
|
- spec/spec_helper.rb
|
@@ -243,6 +239,7 @@ files:
|
|
243
239
|
- templates/fancy.haml
|
244
240
|
- templates/output.csv
|
245
241
|
- templates/output.haml
|
242
|
+
- templates/release.haml
|
246
243
|
- templates/sprint.haml
|
247
244
|
has_rdoc: true
|
248
245
|
homepage: http://github.com/timo3377/pivotal_doc
|
@@ -285,8 +282,6 @@ test_files:
|
|
285
282
|
- spec/lib/generators/base_spec.rb
|
286
283
|
- spec/lib/generators/csv_spec.rb
|
287
284
|
- spec/lib/generators/html_spec.rb
|
288
|
-
- spec/lib/generators/sprint_spec.rb
|
289
|
-
- spec/lib/release_spec.rb
|
290
285
|
- spec/lib/sprint_spec.rb
|
291
286
|
- spec/spec_helper.rb
|
292
287
|
- spec/support/mocks_helper.rb
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module PivotalDoc
|
2
|
-
module Generators
|
3
|
-
class Sprint < Base
|
4
|
-
def initialize(sprint, options={})
|
5
|
-
@sprint=sprint
|
6
|
-
super(@sprint, options)
|
7
|
-
end
|
8
|
-
def template_name
|
9
|
-
@options['template_name'] || 'sprint.haml'
|
10
|
-
end
|
11
|
-
def output_ext; '.html' end
|
12
|
-
def render_doc
|
13
|
-
html= Haml::Engine.new(template).render(Object.new, {:sprint=>@sprint})
|
14
|
-
super(html)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/pivotal_doc/release.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
module PivotalDoc
|
2
|
-
class Release
|
3
|
-
include Work
|
4
|
-
|
5
|
-
attr_reader :project
|
6
|
-
attr_reader :iteration
|
7
|
-
|
8
|
-
def initialize(project, iteration=nil)
|
9
|
-
@project= project
|
10
|
-
@iteration= (iteration || latest_iteration)
|
11
|
-
end
|
12
|
-
|
13
|
-
def me
|
14
|
-
@me ||= self.iteration.stories.detect{|s| s.story_type.downcase=='release'} if self.iteration.stories
|
15
|
-
end
|
16
|
-
|
17
|
-
def name
|
18
|
-
me.name if me.respond_to?(:name)
|
19
|
-
end
|
20
|
-
|
21
|
-
def latest_iteration
|
22
|
-
PT::Iteration.done(@project, :offset=>'-1').first
|
23
|
-
end
|
24
|
-
|
25
|
-
[:stories, :bugs, :chores].each do |m|
|
26
|
-
define_method("#{m}_delivered") { self.send(m).size }
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
def filter_stories(type='feature')
|
31
|
-
self.iteration.stories.reject do |s|
|
32
|
-
s.story_type.downcase != type || s.current_state.downcase != 'accepted'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe PivotalDoc::Generators::Sprint do
|
4
|
-
before(:each) do
|
5
|
-
@release= mocks_helper(:release)
|
6
|
-
@sprint= PivotalDoc::Generators::Sprint.new(@release)
|
7
|
-
@engine= Haml::Engine.new('')
|
8
|
-
end
|
9
|
-
|
10
|
-
after(:each) do
|
11
|
-
File.delete(@sprint.output_file) if File.exists?(@sprint.output_file)
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should open the output file and write the compiled haml (html)" do
|
15
|
-
Haml::Engine.stub!(:new).and_return(@engine)
|
16
|
-
@engine.stub!(:render).and_return('compiled haml')
|
17
|
-
@sprint.render_doc
|
18
|
-
File.read(@sprint.output_file).should eql('compiled haml')
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should read the file contents" do
|
22
|
-
@sprint.template.should be_an_instance_of(String)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should use the template_name if specified" do
|
26
|
-
options= {'template_name'=>'fancy.sprint.html'}
|
27
|
-
html= PivotalDoc::Generators::HTML.new(@release, options)
|
28
|
-
html.template_name.should eql(options['template_name'])
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should know its template name" do
|
32
|
-
@sprint.template_name.should =~ /\.haml$/
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should render the release doc" do
|
36
|
-
Haml::Engine.should_receive(:new).with(@sprint.template).and_return(@engine)
|
37
|
-
@engine.should_receive(:render)
|
38
|
-
@sprint.render_doc
|
39
|
-
end
|
40
|
-
end
|
data/spec/lib/release_spec.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe PivotalDoc::Release do
|
4
|
-
before(:each) do
|
5
|
-
@project= PT::Project.new
|
6
|
-
@latest_iteration= PT::Iteration.new
|
7
|
-
PT::Iteration.stub!(:done).and_return([@latest_iteration])
|
8
|
-
@release= PivotalDoc::Release.new(@project)
|
9
|
-
end
|
10
|
-
|
11
|
-
it "should get the last 'done' iteration for the project" do
|
12
|
-
PT::Iteration.should_receive(:done).with(@project, :offset=>'-1')
|
13
|
-
@release.latest_iteration
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "the latest iteration" do
|
17
|
-
before(:each) do
|
18
|
-
@release.stub!(:latest_iteration).and_return(@latest_iteration)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should use the iteration if specified" do
|
22
|
-
backlog= PTApiHelpers::mock_object('iterations')
|
23
|
-
release= PivotalDoc::Release.new(@project, backlog)
|
24
|
-
release.iteration.should eql(backlog)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should default the iteration to the latest_iteration (last 'done') if one isn't specified" do
|
28
|
-
PT::Iteration.should_receive(:done).and_return([@latest_iteration])
|
29
|
-
release= PivotalDoc::Release.new(@project)
|
30
|
-
release.iteration.should eql(@latest_iteration)
|
31
|
-
end
|
32
|
-
|
33
|
-
describe "release of (me)" do
|
34
|
-
before(:each) do
|
35
|
-
@stories= PTApiHelpers::mock_stories
|
36
|
-
@me= PTApiHelpers::mock_actual_release
|
37
|
-
@latest_iteration.stub!(:stories).and_return(@stories)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should find the \"release\" if there is one" do
|
41
|
-
@latest_iteration.should_receive(:stories).and_return(@stories)
|
42
|
-
@release.me.story_type.should eql('release')
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should know the name of the release" do
|
46
|
-
@release.name.should eql(@me.name)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "stories" do
|
51
|
-
before(:each) do
|
52
|
-
@stories= PTApiHelpers::mock_stories
|
53
|
-
@latest_iteration.stub!(:stories).and_return(@stories)
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should get the stories only" do
|
57
|
-
@latest_iteration.should_receive(:stories).and_return(@stories)
|
58
|
-
@release.stories.each{|s| s.story_type.downcase.should eql('feature') }
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should get the bugs only" do
|
62
|
-
@latest_iteration.should_receive(:stories).and_return(@stories)
|
63
|
-
@release.bugs.each{|b| b.story_type.downcase.should eql('bug') }
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should get the chores only" do
|
67
|
-
@latest_iteration.should_receive(:stories).and_return(@stories)
|
68
|
-
@release.chores.each{|c| c.story_type.downcase.should eql('chore') }
|
69
|
-
end
|
70
|
-
|
71
|
-
describe "finished work" do
|
72
|
-
[:stories, :chores, :bugs].each do |m|
|
73
|
-
it "should know the #{m} delivered in this release" do
|
74
|
-
@release.send("#{m}_delivered").should eql(@release.send(m).size)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should only get the \"delivered\" stories" do
|
79
|
-
@release.stories.each{|s| s.current_state.downcase.should eql('accepted')}
|
80
|
-
end
|
81
|
-
|
82
|
-
it "should only get the \"delivered\" bugs" do
|
83
|
-
@release.bugs.each{|b| b.current_state.downcase.should eql('accepted')}
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should only get the \"accepted\" chores" do
|
87
|
-
@release.chores.each{|c| c.current_state.downcase.should eql('accepted')}
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|