pivotal_doc 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|