flux 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.flux.local.rb.sample +3 -0
- data/.flux.rb.sample +4 -0
- data/Gemfile +2 -0
- data/README.md +52 -2
- data/VERSION +1 -1
- data/flux.gemspec +18 -11
- data/lib/flux.rb +27 -31
- data/lib/flux/cli.rb +3 -0
- data/lib/flux/cli/feature.rb +39 -0
- data/lib/flux/cli/pivotal_tracker.rb +72 -0
- data/lib/flux/cli/review.rb +190 -0
- data/lib/flux/git.rb +81 -0
- data/lib/flux/pivotal_tracker.rb +81 -0
- data/lib/flux/rcs.rb +1 -0
- data/lib/flux/rcs/git.rb +132 -15
- data/lib/flux/util.rb +0 -1
- data/lib/flux/workflows/mojotech.rb +23 -17
- data/spec/flux_spec.rb +17 -28
- metadata +51 -28
- data/.flux +0 -9
- data/.flux.local.sample +0 -3
- data/lib/flux/trackers/pivotal_tracker.rb +0 -146
- data/lib/flux/util/table.rb +0 -99
- data/spec/flux/rcs/git_spec.rb +0 -47
- data/spec/flux/trackers/pivotal_tracker_spec.rb +0 -164
- data/spec/flux/util/table_spec.rb +0 -47
- data/spec/support/matchers/print_table.rb +0 -46
data/spec/flux/rcs/git_spec.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
require 'flux/rcs/git'
|
4
|
-
|
5
|
-
describe Flux::RCS::Branches do
|
6
|
-
include Flux::Util::Output
|
7
|
-
|
8
|
-
it "displays the current branch" do
|
9
|
-
mock(mock_root(Grit::Repo)).head.mock!.name { 'zee_current_branch' }
|
10
|
-
|
11
|
-
retval = nil
|
12
|
-
capture { retval = subject.invoke('branches:current', []) }.
|
13
|
-
should == "zee_current_branch\n"
|
14
|
-
retval.should == 'zee_current_branch'
|
15
|
-
end
|
16
|
-
|
17
|
-
it "creates a branch" do
|
18
|
-
mock(mock_root(Grit::Git)).branch({}, 'new_branch')
|
19
|
-
|
20
|
-
subject.invoke 'branches:create', %w(new_branch)
|
21
|
-
end
|
22
|
-
|
23
|
-
it "creates a public branch" do
|
24
|
-
git = mock_root(Grit::Git)
|
25
|
-
|
26
|
-
mock(git).branch({}, 'new_branch')
|
27
|
-
mock(git).push({}, 'origin', '+new_branch:new_branch')
|
28
|
-
mock(git).branch({:set_upstream => true}, 'new_branch', 'origin/new_branch')
|
29
|
-
|
30
|
-
subject.invoke 'branches:create', %w(new_branch), :public => true
|
31
|
-
end
|
32
|
-
|
33
|
-
it "checks out a branch" do
|
34
|
-
mock(mock_root(Grit::Git)).checkout({}, 'new_branch')
|
35
|
-
|
36
|
-
subject.invoke 'branches:checkout', %w(new_branch)
|
37
|
-
end
|
38
|
-
|
39
|
-
def mock_root(klass)
|
40
|
-
repo_path = File.expand_path(File.dirname(__FILE__) + '/../../../.git')
|
41
|
-
root = Object.new
|
42
|
-
|
43
|
-
mock(klass).new(repo_path) { root }
|
44
|
-
|
45
|
-
root
|
46
|
-
end
|
47
|
-
end
|
@@ -1,164 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
require 'flux/trackers/pivotal_tracker'
|
4
|
-
|
5
|
-
describe Flux::Trackers::PivotalTracker do
|
6
|
-
let(:environment) {
|
7
|
-
{'trackers' => {'project_id' => PROJECT.id,
|
8
|
-
'token' => PROJECT.token,
|
9
|
-
'email' => 'david@mojotech.com'}}
|
10
|
-
}
|
11
|
-
|
12
|
-
before { Flux.environment = environment }
|
13
|
-
|
14
|
-
it "lists stories by iteration" do
|
15
|
-
mock(PivotalTracker::Iteration).current_backlog(fake_project) {
|
16
|
-
[OpenStruct.new(:stories => [
|
17
|
-
OpenStruct.new(:id => 1,
|
18
|
-
:current_state => 'unstarted',
|
19
|
-
:owned_by => '',
|
20
|
-
:name => 'first story')]),
|
21
|
-
OpenStruct.new(:stories => [
|
22
|
-
OpenStruct.new(:id => 2,
|
23
|
-
:current_state => 'started',
|
24
|
-
:owned_by => 'David Leal',
|
25
|
-
:name => 'second story')])]
|
26
|
-
}
|
27
|
-
|
28
|
-
t = [['ID', 'STATE', 'ASSIGNEE', 'STORY'],
|
29
|
-
[1, 'unstarted', '', 'first story'],
|
30
|
-
[2, 'started', 'David Leal', 'second story']]
|
31
|
-
|
32
|
-
lambda { subject.invoke :list }.should print_table(t)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "grabs a story" do
|
36
|
-
prepare_myself
|
37
|
-
|
38
|
-
mock_update(123, 'owned_by' => 'David Leal')
|
39
|
-
|
40
|
-
subject.invoke :grab, [123]
|
41
|
-
end
|
42
|
-
|
43
|
-
it "grabs a story and estimates it" do
|
44
|
-
prepare_myself
|
45
|
-
|
46
|
-
mock_update(123, 'owned_by' => 'David Leal',
|
47
|
-
'estimate' => 2)
|
48
|
-
|
49
|
-
subject.invoke :grab, [123], :estimate => 2
|
50
|
-
end
|
51
|
-
|
52
|
-
[%w(starts started start),
|
53
|
-
%w(finishes finished finish)].each do |(action, state, task)|
|
54
|
-
it "#{action} a story that was already estimated" do
|
55
|
-
s = mock_update(123, 'current_state' => state)
|
56
|
-
s.estimate = 2
|
57
|
-
|
58
|
-
subject.invoke task, [123]
|
59
|
-
end
|
60
|
-
|
61
|
-
it "#{action} a story that needs to be estimated" do
|
62
|
-
mock_update(123, 'current_state' => state, 'estimate' => 2)
|
63
|
-
|
64
|
-
subject.invoke task, [123], :estimate => 2
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
describe "attributes" do
|
69
|
-
it "updates custom attributes" do
|
70
|
-
attrs = {'branch' => 'blah', 'other' => 'yay'}
|
71
|
-
|
72
|
-
mock_find(123)
|
73
|
-
mock(PivotalTracker::Note).new(observe { |h|
|
74
|
-
h[:owner].id == 123 &&
|
75
|
-
h[:text] == YAML.dump(attrs)
|
76
|
-
}).mock!.create
|
77
|
-
|
78
|
-
subject.invoke :update, [123], :attributes => attrs
|
79
|
-
end
|
80
|
-
|
81
|
-
it "updates native attributes" do
|
82
|
-
attrs = {'owner' => 'David Leal',
|
83
|
-
'state' => 'started',
|
84
|
-
'estimate' => 2,
|
85
|
-
'name' => 'My story'}
|
86
|
-
|
87
|
-
mock_update(123,
|
88
|
-
'owned_by' => 'David Leal',
|
89
|
-
'current_state' => 'started',
|
90
|
-
'estimate' => 2,
|
91
|
-
'name' => 'My story')
|
92
|
-
|
93
|
-
subject.invoke :update, [123], :attributes => attrs
|
94
|
-
end
|
95
|
-
|
96
|
-
it "updates valid states only" do
|
97
|
-
attrs = {'state' => 'sitting'}
|
98
|
-
|
99
|
-
s = mock_find(123)
|
100
|
-
|
101
|
-
lambda { subject.invoke :update, [123], :attributes => attrs }.
|
102
|
-
should raise_error(Flux::TrackerError, /Invalid state/)
|
103
|
-
end
|
104
|
-
|
105
|
-
it "updates state when story has estimate" do
|
106
|
-
attrs = {'state' => 'started'}
|
107
|
-
|
108
|
-
s = mock_update(123, 'current_state' => 'started')
|
109
|
-
s.estimate = 2
|
110
|
-
|
111
|
-
subject.invoke :update, [123], :attributes => attrs
|
112
|
-
end
|
113
|
-
|
114
|
-
it "updates state when story estimate is given" do
|
115
|
-
attrs = {'state' => 'started', 'estimate' => 2}
|
116
|
-
|
117
|
-
s = mock_update(123, 'current_state' => 'started',
|
118
|
-
'estimate' => 2)
|
119
|
-
|
120
|
-
subject.invoke :update, [123], :attributes => attrs
|
121
|
-
end
|
122
|
-
|
123
|
-
Flux::Trackers::PivotalTracker::STATES_W_ESTIMATE.each do |state|
|
124
|
-
it "fails to update state `#{state}' if no estimate given" do
|
125
|
-
attrs = {'state' => state}
|
126
|
-
|
127
|
-
s = mock_find(123)
|
128
|
-
|
129
|
-
lambda { subject.invoke :update, [123], :attributes => attrs }.
|
130
|
-
should raise_error(Flux::TrackerError, /Need an estimate/)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def iteration(which, data)
|
136
|
-
mock(PivotalTracker::Iteration).__send__(which, fake_project) {
|
137
|
-
OpenStruct.new(:stories => data.map { |d| OpenStruct.new(d) })
|
138
|
-
}
|
139
|
-
end
|
140
|
-
|
141
|
-
def fake_project
|
142
|
-
OpenStruct.new(:id => PROJECT.id)
|
143
|
-
end
|
144
|
-
|
145
|
-
def fake_story(id)
|
146
|
-
PivotalTracker::Story.new(:id => id, :project_id => PROJECT.id)
|
147
|
-
end
|
148
|
-
|
149
|
-
def mock_find(story_id)
|
150
|
-
fake_story(story_id).tap { |s|
|
151
|
-
mock(PivotalTracker::Story).find(story_id, PROJECT.id) { s }
|
152
|
-
}
|
153
|
-
end
|
154
|
-
|
155
|
-
def mock_update(story_id, attrs)
|
156
|
-
mock_find(story_id).tap { |s| mock(s).update(attrs) }
|
157
|
-
end
|
158
|
-
|
159
|
-
def prepare_myself
|
160
|
-
mock(PivotalTracker::Membership).all(fake_project) {
|
161
|
-
[OpenStruct.new(:name => 'David Leal', :email => 'david@mojotech.com')]
|
162
|
-
}
|
163
|
-
end
|
164
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
describe Flux::Util::Table do
|
4
|
-
let(:body) {
|
5
|
-
[[123, 'unstarted', 'David Leal', 'First story'],
|
6
|
-
[456, 'unscheduled', '', 'Second story']]
|
7
|
-
}
|
8
|
-
|
9
|
-
it "is converted to a string" do
|
10
|
-
t = Flux::Util::Table.new(Thor::Shell::Basic.new,
|
11
|
-
[%w(ID STATE ASSIGNEE STORY)] + body,
|
12
|
-
' ',
|
13
|
-
nil)
|
14
|
-
|
15
|
-
t.to_s.should == <<EOT
|
16
|
-
ID STATE ASSIGNEE STORY
|
17
|
-
123 unstarted David Leal First story
|
18
|
-
456 unscheduled Second story
|
19
|
-
EOT
|
20
|
-
end
|
21
|
-
|
22
|
-
it "aligns its columns to the right" do
|
23
|
-
t = Flux::Util::Table.new(Thor::Shell::Basic.new,
|
24
|
-
[%w(>ID >STATE >ASSIGNEE >STORY)] + body,
|
25
|
-
' ',
|
26
|
-
nil)
|
27
|
-
|
28
|
-
t.to_s.should == <<EOT
|
29
|
-
ID STATE ASSIGNEE STORY
|
30
|
-
123 unstarted David Leal First story
|
31
|
-
456 unscheduled Second story
|
32
|
-
EOT
|
33
|
-
end
|
34
|
-
|
35
|
-
it "truncates lines to a given width" do
|
36
|
-
t = Flux::Util::Table.new(Thor::Shell::Basic.new,
|
37
|
-
[%w(ID STATE ASSIGNEE STORY)] + body,
|
38
|
-
' ',
|
39
|
-
7)
|
40
|
-
|
41
|
-
t.to_s.should == <<EOT
|
42
|
-
ID ...
|
43
|
-
123 ...
|
44
|
-
456 ...
|
45
|
-
EOT
|
46
|
-
end
|
47
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
RSpec::Matchers.define :print_table do |data|
|
2
|
-
class FakeStdout
|
3
|
-
attr_reader :table
|
4
|
-
|
5
|
-
def initialize(stdout)
|
6
|
-
@stdout = stdout
|
7
|
-
end
|
8
|
-
|
9
|
-
def puts(*args)
|
10
|
-
case args.first
|
11
|
-
when Flux::Util::Table
|
12
|
-
@table = args.first
|
13
|
-
else
|
14
|
-
@stdout.puts *args
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def write(data)
|
19
|
-
@stdout.write data
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
match do |block|
|
25
|
-
stdout = $stdout
|
26
|
-
$stdout = @stdout = FakeStdout.new(stdout)
|
27
|
-
|
28
|
-
begin
|
29
|
-
block.call
|
30
|
-
|
31
|
-
@stdout.table.should_not be_nil
|
32
|
-
@stdout.table.data.should == data
|
33
|
-
ensure
|
34
|
-
$stdout = stdout
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
failure_message_for_should do |block|
|
39
|
-
"Expected table:\n\n#{Flux::Util::Table.new(data, ' ', nil)}\n" <<
|
40
|
-
"but got:\n\n#{@stdout.table ? @stdout.table : 'nil'}"
|
41
|
-
end
|
42
|
-
|
43
|
-
failure_message_for_should_not do |block|
|
44
|
-
raise NotImplementedError
|
45
|
-
end
|
46
|
-
end
|