estimate 0.0.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/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +36 -0
- data/README.md +21 -0
- data/Rakefile +8 -0
- data/bin/estimate +44 -0
- data/estimate.gemspec +27 -0
- data/lib/estimate.rb +7 -0
- data/lib/estimate/project.rb +78 -0
- data/lib/estimate/tracking_system.rb +9 -0
- data/lib/estimate/version.rb +4 -0
- data/spec/estimate/project_spec.rb +35 -0
- data/spec/estimate/tracking_system_spec.rb +19 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/mocks.rb +25 -0
- metadata +96 -0
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.rvmrc
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: http://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
builder (3.0.0)
|
|
5
|
+
diff-lcs (1.1.3)
|
|
6
|
+
happymapper (0.4.0)
|
|
7
|
+
libxml-ruby (~> 2.0)
|
|
8
|
+
libxml-ruby (2.3.2)
|
|
9
|
+
mime-types (1.18)
|
|
10
|
+
nokogiri (1.5.2)
|
|
11
|
+
pivotal-tracker (0.5.1)
|
|
12
|
+
builder
|
|
13
|
+
builder
|
|
14
|
+
happymapper (>= 0.3.2)
|
|
15
|
+
happymapper (>= 0.3.2)
|
|
16
|
+
nokogiri (>= 1.4.3)
|
|
17
|
+
nokogiri (~> 1.4)
|
|
18
|
+
rest-client (~> 1.6.0)
|
|
19
|
+
rest-client (~> 1.6.0)
|
|
20
|
+
rest-client (1.6.7)
|
|
21
|
+
mime-types (>= 1.16)
|
|
22
|
+
rspec (2.9.0)
|
|
23
|
+
rspec-core (~> 2.9.0)
|
|
24
|
+
rspec-expectations (~> 2.9.0)
|
|
25
|
+
rspec-mocks (~> 2.9.0)
|
|
26
|
+
rspec-core (2.9.0)
|
|
27
|
+
rspec-expectations (2.9.0)
|
|
28
|
+
diff-lcs (~> 1.1.3)
|
|
29
|
+
rspec-mocks (2.9.0)
|
|
30
|
+
|
|
31
|
+
PLATFORMS
|
|
32
|
+
ruby
|
|
33
|
+
|
|
34
|
+
DEPENDENCIES
|
|
35
|
+
pivotal-tracker
|
|
36
|
+
rspec
|
data/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Estimate
|
|
2
|
+
|
|
3
|
+
Do you have a manager that's been nugging you about an end date or a project estimate?
|
|
4
|
+
**Estimate** can solve your problem.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
gem install estimate # install
|
|
10
|
+
|
|
11
|
+
estimate <project_name> -u <username> -p <password> --ssl
|
|
12
|
+
|
|
13
|
+
Usage: estimate <project_name> [options]
|
|
14
|
+
-u, --user STRING Pivotal tracker username
|
|
15
|
+
-p, --pass STRING Pivotal tracker password
|
|
16
|
+
-s, --ssl Use secure connection
|
|
17
|
+
-d, --developers INT Number of developers (default: 2)
|
|
18
|
+
-x, --day_points INT Points allocated to a day (default: 1)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
[](http://travis-ci.org/despo/estimate)
|
data/Rakefile
ADDED
data/bin/estimate
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'optparse'
|
|
3
|
+
|
|
4
|
+
options = {}
|
|
5
|
+
parsed_options = OptionParser.new do |opts|
|
|
6
|
+
opts.banner = "Usage: estimate <project_name> [options]"
|
|
7
|
+
|
|
8
|
+
opts.on('-u', '--user STRING', 'Pivotal tracker username') { |user| options[:username] = user }
|
|
9
|
+
opts.on('-p', '--pass STRING', 'Pivotal tracker password') { |pass| options[:password] = pass }
|
|
10
|
+
opts.on('-s', '--ssl', 'Use secure connection') { options[:ssl] = true }
|
|
11
|
+
|
|
12
|
+
opts.on('-d', '--developers INT', 'Number of developers (default: 2)') do |developers|
|
|
13
|
+
options[:developers] = developers
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
opts.on('-x', '--day_points INT', 'Points allocated to a day (default: 1)') do |day_options|
|
|
17
|
+
options[:day_points] = day_points
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
opts.parse!(ARGV)
|
|
22
|
+
rescue OptionParser::ParseError => e
|
|
23
|
+
warn e.message
|
|
24
|
+
puts opts
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
project = ARGV.first or warn("Which project do you want to estimate?")
|
|
30
|
+
|
|
31
|
+
if !options[:username] or !options[:password]
|
|
32
|
+
warn "No authentication credentials specified"
|
|
33
|
+
exit
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
37
|
+
require 'estimate'
|
|
38
|
+
begin
|
|
39
|
+
Estimate::TrackingSystem.authenticate! options[:username], options[:password], options[:ssl]
|
|
40
|
+
puts Estimate::Project.new(project, options).process!
|
|
41
|
+
rescue Exception => e
|
|
42
|
+
puts "Something went wrong..."
|
|
43
|
+
puts e.message
|
|
44
|
+
end
|
data/estimate.gemspec
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
2
|
+
require "estimate/version"
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = "estimate"
|
|
6
|
+
s.version = Estimate::VERSION
|
|
7
|
+
s.platform = Gem::Platform::RUBY
|
|
8
|
+
s.author = "Despo Pentara"
|
|
9
|
+
s.email = "despo@extractmethod.com"
|
|
10
|
+
s.homepage = "https://github.com/despo/estimate"
|
|
11
|
+
s.summary = "Estimate projects the easy way."
|
|
12
|
+
s.description = %{Have a manager that's been nugging you for a project estimate? Waste no time! Estimate your project now.}
|
|
13
|
+
s.required_ruby_version = '>= 1.9.2'
|
|
14
|
+
|
|
15
|
+
s.licenses = ["MIT"]
|
|
16
|
+
|
|
17
|
+
s.files = `git ls-files`.split("\n")
|
|
18
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
|
+
s.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
s.add_dependency "pivotal-tracker", "~> 0.5.1"
|
|
23
|
+
|
|
24
|
+
s.add_development_dependency "rspec", "~> 2.8.0"
|
|
25
|
+
s.add_development_dependency "rake"
|
|
26
|
+
end
|
|
27
|
+
|
data/lib/estimate.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'pivotal-tracker'
|
|
2
|
+
|
|
3
|
+
module Estimate
|
|
4
|
+
class Project
|
|
5
|
+
|
|
6
|
+
def initialize name, properties={}
|
|
7
|
+
@name = name
|
|
8
|
+
@properties = properties
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def process!
|
|
12
|
+
"""
|
|
13
|
+
Project: #{@name}
|
|
14
|
+
Incomplete stories: #{incomplete_stories.length}
|
|
15
|
+
|
|
16
|
+
And your project end date is.....
|
|
17
|
+
#{display_end_date}
|
|
18
|
+
|
|
19
|
+
You have #{remaining_days} days to complete this project.
|
|
20
|
+
"""
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
WORK_WEEK_DAYS = 5
|
|
25
|
+
|
|
26
|
+
def incomplete_stories
|
|
27
|
+
@stories = @stories || project.stories.all(:story_type => story_points.keys, :current_state => incomplete_stati)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def project
|
|
31
|
+
@project = @project || PivotalTracker::Project.all.select { |x| x.name.eql? @name }.first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def story_points
|
|
35
|
+
{ :feature => 5,
|
|
36
|
+
:bug => 1,
|
|
37
|
+
:chore => 1
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def incomplete_stati
|
|
42
|
+
[ 'unscheduled', 'unstarted', 'started' ]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def display_end_date
|
|
46
|
+
end_date.strftime('%A, %b %d %Y')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def end_date
|
|
50
|
+
DateTime.now + remaining_weeks*7
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def remaining_weeks
|
|
54
|
+
@remaining_weeks = @remaining_weeks || (points/day_points+holidays*developers)/WORK_WEEK_DAYS/developers
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def points
|
|
58
|
+
incomplete_stories.inject(0) { |points, story| points + story_points[story.story_type.to_sym] }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def day_points
|
|
62
|
+
@properties[:day_points] || 1
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def holidays
|
|
66
|
+
5*developers
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def developers
|
|
70
|
+
@properties[:developers] || 2
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def remaining_days
|
|
74
|
+
(end_date-DateTime.now).to_i
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Estimate::Project do
|
|
4
|
+
|
|
5
|
+
context 'properties' do
|
|
6
|
+
it '#developers' do
|
|
7
|
+
project = Estimate::Project.new(:project_name, :developers => 5)
|
|
8
|
+
project.stub(:project => mock_pivotal_project)
|
|
9
|
+
|
|
10
|
+
3.times { project.should_receive(:developers).and_return(5) }
|
|
11
|
+
|
|
12
|
+
project.process!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it '#day_points' do
|
|
16
|
+
project = Estimate::Project.new(:project_name, :day_points => 2)
|
|
17
|
+
project.stub(:project => mock_pivotal_project)
|
|
18
|
+
|
|
19
|
+
project.should_receive(:day_points).and_return(2)
|
|
20
|
+
|
|
21
|
+
project.process!
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "can estimate the project's end date" do
|
|
26
|
+
number_of_stories = 10
|
|
27
|
+
|
|
28
|
+
project = Estimate::Project.new(:project_name)
|
|
29
|
+
mock_incomplete_stories(project, number_of_stories)
|
|
30
|
+
|
|
31
|
+
end_date = (DateTime.now + 7*7).strftime('%A, %b %d %Y')
|
|
32
|
+
|
|
33
|
+
project.process!.should eq process_string(:project_name, number_of_stories, end_date)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Estimate::TrackingSystem do
|
|
4
|
+
|
|
5
|
+
context 'can connect to the tracking system' do
|
|
6
|
+
|
|
7
|
+
it 'can authenticate a user' do
|
|
8
|
+
PivotalTracker::Client.should_receive(:token).with(:username, :password)
|
|
9
|
+
Estimate::TrackingSystem.authenticate! :username, :password
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'can authenticate when ssl authentication is enabled' do
|
|
13
|
+
PivotalTracker::Client.should_receive(:token).with(:username, :password)
|
|
14
|
+
PivotalTracker::Client.should_receive(:use_ssl=).with(true)
|
|
15
|
+
|
|
16
|
+
Estimate::TrackingSystem.authenticate!(:username, :password, true)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
def mock_incomplete_stories project, number_of_stories
|
|
2
|
+
incomplete_stories = number_of_stories.times.map { mock_feature }
|
|
3
|
+
|
|
4
|
+
2.times { project.should_receive(:incomplete_stories).and_return(incomplete_stories) }
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def process_string name, incomplete_stories, end_date
|
|
8
|
+
"""
|
|
9
|
+
Project: #{name}
|
|
10
|
+
Incomplete stories: #{incomplete_stories}
|
|
11
|
+
|
|
12
|
+
And your project end date is.....
|
|
13
|
+
#{end_date}
|
|
14
|
+
|
|
15
|
+
You have 48 days to complete this project.
|
|
16
|
+
"""
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def mock_feature
|
|
20
|
+
mock(:story_type => 'feature')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def mock_pivotal_project
|
|
24
|
+
mock(:pivotal_project, :stories => mock(:all => []))
|
|
25
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: estimate
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Despo Pentara
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-03-24 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: pivotal-tracker
|
|
16
|
+
requirement: &70293662021420 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 0.5.1
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *70293662021420
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: rspec
|
|
27
|
+
requirement: &70293662020720 !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ~>
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 2.8.0
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: *70293662020720
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: rake
|
|
38
|
+
requirement: &70293662020000 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ! '>='
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
type: :development
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *70293662020000
|
|
47
|
+
description: Have a manager that's been nugging you for a project estimate? Waste
|
|
48
|
+
no time! Estimate your project now.
|
|
49
|
+
email: despo@extractmethod.com
|
|
50
|
+
executables:
|
|
51
|
+
- estimate
|
|
52
|
+
extensions: []
|
|
53
|
+
extra_rdoc_files: []
|
|
54
|
+
files:
|
|
55
|
+
- .gitignore
|
|
56
|
+
- .travis.yml
|
|
57
|
+
- Gemfile
|
|
58
|
+
- Gemfile.lock
|
|
59
|
+
- README.md
|
|
60
|
+
- Rakefile
|
|
61
|
+
- bin/estimate
|
|
62
|
+
- estimate.gemspec
|
|
63
|
+
- lib/estimate.rb
|
|
64
|
+
- lib/estimate/project.rb
|
|
65
|
+
- lib/estimate/tracking_system.rb
|
|
66
|
+
- lib/estimate/version.rb
|
|
67
|
+
- spec/estimate/project_spec.rb
|
|
68
|
+
- spec/estimate/tracking_system_spec.rb
|
|
69
|
+
- spec/spec_helper.rb
|
|
70
|
+
- spec/support/mocks.rb
|
|
71
|
+
homepage: https://github.com/despo/estimate
|
|
72
|
+
licenses:
|
|
73
|
+
- MIT
|
|
74
|
+
post_install_message:
|
|
75
|
+
rdoc_options: []
|
|
76
|
+
require_paths:
|
|
77
|
+
- lib
|
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
|
+
none: false
|
|
80
|
+
requirements:
|
|
81
|
+
- - ! '>='
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: 1.9.2
|
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
|
+
none: false
|
|
86
|
+
requirements:
|
|
87
|
+
- - ! '>='
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
requirements: []
|
|
91
|
+
rubyforge_project:
|
|
92
|
+
rubygems_version: 1.8.10
|
|
93
|
+
signing_key:
|
|
94
|
+
specification_version: 3
|
|
95
|
+
summary: Estimate projects the easy way.
|
|
96
|
+
test_files: []
|