zenflow 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.zenflow +10 -0
  7. data/CHANGELOG.md +0 -0
  8. data/Gemfile +3 -0
  9. data/Gemfile.lock +95 -0
  10. data/Guardfile +6 -0
  11. data/LICENSE.md +22 -0
  12. data/README.markdown +92 -0
  13. data/VERSION.yml +5 -0
  14. data/bin/zenflow +17 -0
  15. data/lib/zenflow.rb +35 -0
  16. data/lib/zenflow/cli.rb +130 -0
  17. data/lib/zenflow/commands/deploy.rb +33 -0
  18. data/lib/zenflow/commands/feature.rb +10 -0
  19. data/lib/zenflow/commands/hotfix.rb +15 -0
  20. data/lib/zenflow/commands/release.rb +16 -0
  21. data/lib/zenflow/commands/reviews.rb +12 -0
  22. data/lib/zenflow/helpers/ask.rb +66 -0
  23. data/lib/zenflow/helpers/branch.rb +80 -0
  24. data/lib/zenflow/helpers/branch_command.rb +95 -0
  25. data/lib/zenflow/helpers/branch_commands/abort.rb +21 -0
  26. data/lib/zenflow/helpers/branch_commands/branches.rb +21 -0
  27. data/lib/zenflow/helpers/branch_commands/compare.rb +20 -0
  28. data/lib/zenflow/helpers/branch_commands/deploy.rb +29 -0
  29. data/lib/zenflow/helpers/branch_commands/diff.rb +19 -0
  30. data/lib/zenflow/helpers/branch_commands/finish.rb +68 -0
  31. data/lib/zenflow/helpers/branch_commands/review.rb +58 -0
  32. data/lib/zenflow/helpers/branch_commands/start.rb +39 -0
  33. data/lib/zenflow/helpers/branch_commands/update.rb +22 -0
  34. data/lib/zenflow/helpers/changelog.rb +100 -0
  35. data/lib/zenflow/helpers/config.rb +36 -0
  36. data/lib/zenflow/helpers/github.rb +40 -0
  37. data/lib/zenflow/helpers/help.rb +37 -0
  38. data/lib/zenflow/helpers/log.rb +21 -0
  39. data/lib/zenflow/helpers/pull_request.rb +68 -0
  40. data/lib/zenflow/helpers/repo.rb +13 -0
  41. data/lib/zenflow/helpers/shell.rb +89 -0
  42. data/lib/zenflow/helpers/version.rb +87 -0
  43. data/lib/zenflow/version.rb +3 -0
  44. data/spec/fixtures/VERSION.yml +5 -0
  45. data/spec/fixtures/cassettes/create_bad_pull_request.yml +57 -0
  46. data/spec/fixtures/cassettes/create_pull_request.yml +68 -0
  47. data/spec/fixtures/cassettes/existing_pull_request.yml +145 -0
  48. data/spec/fixtures/cassettes/pull_request_by_ref.yml +145 -0
  49. data/spec/fixtures/cassettes/pull_request_find.yml +70 -0
  50. data/spec/fixtures/cassettes/pull_request_for_non-existent_ref.yml +145 -0
  51. data/spec/fixtures/cassettes/pull_request_list.yml +74 -0
  52. data/spec/fixtures/cassettes/unexisting_pull_request.yml +145 -0
  53. data/spec/spec_helper.rb +36 -0
  54. data/spec/support/shared_examples_for_version_number.rb +19 -0
  55. data/spec/zenflow/commands/deploy_spec.rb +48 -0
  56. data/spec/zenflow/commands/feature_spec.rb +11 -0
  57. data/spec/zenflow/commands/hotfix_spec.rb +14 -0
  58. data/spec/zenflow/commands/release_spec.rb +15 -0
  59. data/spec/zenflow/commands/reviews_spec.rb +15 -0
  60. data/spec/zenflow/helpers/ask_spec.rb +115 -0
  61. data/spec/zenflow/helpers/branch_command_spec.rb +310 -0
  62. data/spec/zenflow/helpers/branch_spec.rb +300 -0
  63. data/spec/zenflow/helpers/changelog_spec.rb +188 -0
  64. data/spec/zenflow/helpers/cli_spec.rb +277 -0
  65. data/spec/zenflow/helpers/github_spec.rb +45 -0
  66. data/spec/zenflow/helpers/help_spec.rb +36 -0
  67. data/spec/zenflow/helpers/log_spec.rb +31 -0
  68. data/spec/zenflow/helpers/pull_request_spec.rb +108 -0
  69. data/spec/zenflow/helpers/shell_spec.rb +135 -0
  70. data/spec/zenflow/helpers/version_spec.rb +111 -0
  71. data/zenflow.gemspec +33 -0
  72. metadata +273 -0
@@ -0,0 +1,36 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ end
5
+
6
+ Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
7
+ require 'zenflow'
8
+ require 'vcr'
9
+
10
+ VCR.configure do |c|
11
+ c.configure_rspec_metadata!
12
+ c.cassette_library_dir = 'spec/fixtures/cassettes'
13
+ c.hook_into :webmock
14
+ c.default_cassette_options = { :record => :new_episodes }
15
+ c.filter_sensitive_data('<GITHUB-USER>'){ Zenflow::Github.user }
16
+ c.filter_sensitive_data('<ZENFLOW-TOKEN>'){ Zenflow::Github.zenflow_token }
17
+ end
18
+
19
+ RSpec.configure do |config|
20
+ config.order = "random"
21
+ config.treat_symbols_as_metadata_keys_with_true_values = true
22
+ config.run_all_when_everything_filtered = true
23
+ config.filter_run :focus => true
24
+
25
+ def capture(stream)
26
+ begin
27
+ stream = stream.to_s
28
+ eval "$#{stream} = StringIO.new"
29
+ yield
30
+ result = eval("$#{stream}").string
31
+ ensure
32
+ eval("$#{stream} = #{stream.upcase}")
33
+ end
34
+ result
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ shared_examples_for "a version" do |version_array|
2
+ it{expect(subject.instance_variable_get('@version')).to(have_key('major'))}
3
+ it{expect(subject.instance_variable_get('@version')).to(have_key('minor'))}
4
+ it{expect(subject.instance_variable_get('@version')).to(have_key('patch'))}
5
+ it{expect(subject.instance_variable_get('@version')).to(have_key('pre'))}
6
+
7
+ it{
8
+ expect(
9
+ subject.instance_variable_get('@version')
10
+ ).to(eq(
11
+ {
12
+ 'major' => version_array[0],
13
+ 'minor' => version_array[1],
14
+ 'patch' => version_array[2],
15
+ 'pre' => version_array[3]
16
+ }
17
+ ) )
18
+ }
19
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zenflow::Deploy do
4
+
5
+ describe "Zenflow.Deploy" do
6
+ context 'with migrations' do
7
+ it 'deploys with migrations' do
8
+ Zenflow::Branch.should_receive(:push).with('some-server')
9
+ Zenflow.should_receive(:Log).with("Deploying with migrations to some-server")
10
+ Zenflow::Shell.should_receive(:run).with("cap some-server deploy:migrations")
11
+ Zenflow::Deploy('some-server', :migrations => true)
12
+ end
13
+ end
14
+
15
+ context 'without migrations' do
16
+ it 'deploys without migrations' do
17
+ Zenflow::Branch.should_receive(:push).with('some-server')
18
+ Zenflow.should_receive(:Log).with("Deploying to some-server")
19
+ Zenflow::Shell.should_receive(:run).with("cap some-server deploy")
20
+ Zenflow::Deploy('some-server')
21
+ end
22
+ end
23
+ end
24
+
25
+ subject {Zenflow::Deploy.new}
26
+
27
+ describe '#qa' do
28
+ it 'Deploys to QA' do
29
+ Zenflow.should_receive(:Deploy).with('qa', {})
30
+ subject.qa
31
+ end
32
+ end
33
+
34
+ describe '#staging' do
35
+ it 'Deploys to staging' do
36
+ Zenflow.should_receive(:Deploy).with('staging', {})
37
+ subject.staging
38
+ end
39
+ end
40
+
41
+ describe '#staging' do
42
+ it 'Deploys to production' do
43
+ Zenflow.should_receive(:Deploy).with('production', {})
44
+ subject.production
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zenflow::Feature do
4
+
5
+ subject { Zenflow::Feature.new }
6
+
7
+ it { expect(subject.flow).to eq("feature") }
8
+ it { expect(subject.branch(:source)).to eq("master") }
9
+ it { expect(subject.branch(:deploy)).to eq("qa") }
10
+
11
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zenflow::Hotfix do
4
+
5
+ subject { Zenflow::Hotfix.new }
6
+
7
+ it { expect(subject.flow).to eq("hotfix") }
8
+ it { expect(subject.branch(:source)).to eq("production") }
9
+ it { expect(subject.branch(:deploy)).to match_array(["staging", "qa"]) }
10
+ it { expect(subject.changelog).to eq(:rotate) }
11
+ it { expect(subject.version).to eq(:patch) }
12
+ it { expect(subject.tag).to be_true }
13
+
14
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zenflow::Release do
4
+
5
+ subject { Zenflow::Release.new }
6
+
7
+ it { expect(subject.flow).to eq("release") }
8
+ it { expect(subject.branch(:source)).to eq("master") }
9
+ it { expect(subject.branch(:destination)).to eq("production") }
10
+ it { expect(subject.branch(:deploy)).to match_array(["staging", "qa"]) }
11
+ it { expect(subject.changelog).to eq(:rotate) }
12
+ it { expect(subject.version).to eq(:minor) }
13
+ it { expect(subject.tag).to be_true }
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zenflow::Reviews do
4
+
5
+ describe "#list" do
6
+ before do
7
+ pull = double
8
+ pull.stub(:[]).with("number").and_return(1)
9
+ pull.stub(:[]).with("head").and_return({ "ref" => "URL" })
10
+ Zenflow::PullRequest.should_receive(:list).and_return([pull])
11
+ end
12
+ it { capture(:stdout) { Zenflow::Reviews.new.invoke(:list) } }
13
+ end
14
+
15
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zenflow do
4
+
5
+ describe "prompt" do
6
+ before do
7
+ Zenflow.stub(:LogToFile)
8
+ $stdin.stub(:gets).and_return("good")
9
+ end
10
+
11
+ it "displays a prompt" do
12
+ Zenflow::Query.should_receive(:print).with(">> How are you? ")
13
+ Zenflow::Ask("How are you?")
14
+ end
15
+
16
+ it "displays a prompt with options" do
17
+ Zenflow::Query.should_receive(:print).with(">> How are you? [good/bad] ")
18
+ Zenflow::Ask("How are you?", options: ["good", "bad"])
19
+ end
20
+
21
+ it "displays a prompt with default" do
22
+ Zenflow::Query.should_receive(:print).with(">> How are you? [good] ")
23
+ Zenflow::Ask("How are you?", default: "good")
24
+ end
25
+
26
+ it "displays a prompt with options and default" do
27
+ Zenflow::Query.should_receive(:print).with(">> How are you? [good/bad] ")
28
+ Zenflow::Ask("How are you?", options: ["good", "bad"], default: "good")
29
+ end
30
+
31
+ context "on error" do
32
+ before(:each) do
33
+ Zenflow::Query.should_receive(:ask_question).at_least(:once).and_return('foo')
34
+ Zenflow::Query.should_receive(:handle_response).once.and_raise('something failed')
35
+ $stdout.should_receive(:puts).once
36
+ end
37
+
38
+ it{expect{Zenflow::Ask('howdy', response: 'foo', error_message: 'something failed')}.to raise_error(/something failed/)}
39
+ end
40
+
41
+ context "on interrupt" do
42
+ before(:each) do
43
+ Zenflow::Query.should_receive(:ask_question).once.and_return('foo')
44
+ Zenflow::Query.should_receive(:handle_response).once.and_raise(Interrupt)
45
+ Zenflow.should_receive(:LogToFile)
46
+ $stdout.should_receive(:puts).at_least(:once)
47
+ end
48
+
49
+ it{expect{Zenflow::Ask('howdy')}.to raise_error(SystemExit)}
50
+ end
51
+ end
52
+
53
+ describe Zenflow::Query do
54
+ describe '.get_response' do
55
+ context 'with a response' do
56
+ it{expect(
57
+ Zenflow::Query.ask_question('foo?', response: 'bar')).to eq('bar')
58
+ }
59
+ end
60
+
61
+ context 'with a response' do
62
+ before(:each) do
63
+ Zenflow::Query.should_receive(:prompt_for_answer).with('foo?',{}).and_return('bar')
64
+ end
65
+
66
+ it{expect(Zenflow::Query.ask_question('foo?')).to eq('bar')}
67
+ end
68
+ end
69
+
70
+ describe '.prompt_for_answer' do
71
+ before(:each) do
72
+ Zenflow::Query.should_receive(:print).with(">> Hi? [yes/bye] ")
73
+ STDIN.should_receive(:gets).and_return("bye")
74
+ end
75
+
76
+ it{expect(
77
+ Zenflow::Query.prompt_for_answer('Hi?', options: ['yes','bye'])
78
+ ).to(
79
+ eq('bye')
80
+ ) }
81
+ end
82
+
83
+ describe '.handle_response' do
84
+ context 'invalid response' do
85
+ before(:each){Zenflow::Query.should_receive(:valid_response?).and_return(false)}
86
+ it{expect{Zenflow::Query.handle_response('foo')}.to raise_error}
87
+ end
88
+
89
+ context 'valid response' do
90
+ before(:each){Zenflow::Query.should_receive(:valid_response?).and_return(true)}
91
+ it{expect(Zenflow::Query.handle_response('foo')).to eq('foo')}
92
+ it{expect(Zenflow::Query.handle_response('Y')).to eq('y')}
93
+ it{expect(Zenflow::Query.handle_response('N')).to eq('n')}
94
+ it{expect(Zenflow::Query.handle_response('', default: 'foo')).to eq('foo')}
95
+ end
96
+ end
97
+
98
+ describe '.valid_response?' do
99
+ it{expect(Zenflow::Query.valid_response?('foo', options: ['foo'])).to eq(true)}
100
+ it{expect(Zenflow::Query.valid_response?('foo', options: ['bar'])).to eq(false)}
101
+ it{expect(Zenflow::Query.valid_response?('foo', validate: /foo/)).to eq(true)}
102
+ it{expect(Zenflow::Query.valid_response?('foo', validate: /bar/)).to eq(false)}
103
+ it{expect(Zenflow::Query.valid_response?('', required: true)).to eq(false)}
104
+ it{expect(Zenflow::Query.valid_response?('foo', required: true)).to eq(true)}
105
+ it{expect(Zenflow::Query.valid_response?('foo', required: false)).to eq(true)}
106
+ it{expect(Zenflow::Query.valid_response?('', required: false)).to eq(true)}
107
+ end
108
+
109
+ describe '.build_error_message' do
110
+ it{expect(Zenflow::Query.build_error_message('foo')).to match(/not a valid response/)}
111
+ it{expect(Zenflow::Query.build_error_message('foo', error_message: 'stupid response.')).to match(/stupid response/)}
112
+ it{expect(Zenflow::Query.build_error_message('foo', required: true)).to match(/must respond/)}
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,310 @@
1
+ require 'spec_helper'
2
+
3
+ module BranchCommandSpec
4
+
5
+ class TestCommand < Zenflow::BranchCommand
6
+ flow "test"
7
+ branch source: "master"
8
+ branch destination: "production"
9
+ branch deploy: "deploy1"
10
+ branch deploy: "deploy2"
11
+ version :patch
12
+ changelog :rotate
13
+ tag true
14
+ end
15
+
16
+ describe "Zenflow::BranchCommand" do
17
+ describe "#branches" do
18
+ before do
19
+ Zenflow.should_receive(:Log).with("Available test branches:")
20
+ Zenflow::Branch.should_receive(:list).with("test").and_return(["YES"])
21
+ Zenflow.should_receive(:Log).with("* YES", indent: true, color: false)
22
+ end
23
+ it { TestCommand.new.invoke(:branches) }
24
+ end
25
+
26
+ describe "#start" do
27
+ context "when online" do
28
+ before do
29
+ Zenflow.should_receive(:Ask).and_return("new-test-branch")
30
+ Zenflow::Branch.should_receive(:update).with("master")
31
+ Zenflow::Branch.should_receive(:create).with("test/new-test-branch", "master")
32
+ Zenflow::Branch.should_receive(:push).with("test/new-test-branch")
33
+ Zenflow::Branch.should_receive(:track).with("test/new-test-branch")
34
+ end
35
+ it { TestCommand.new.invoke(:start) }
36
+ end
37
+
38
+ context "when offline" do
39
+ before do
40
+ Zenflow.should_receive(:Ask).and_return("new-test-branch")
41
+ Zenflow::Branch.should_receive(:checkout).with("master")
42
+ Zenflow::Branch.should_receive(:create).with("test/new-test-branch", "master")
43
+ end
44
+ it { TestCommand.new.invoke(:start, nil, offline: true) }
45
+ end
46
+
47
+ context "when supplying a name" do
48
+ before do
49
+ Zenflow::Branch.should_receive(:update).with("master")
50
+ Zenflow::Branch.should_receive(:create).with("test/new-test-branch", "master")
51
+ Zenflow::Branch.should_receive(:push).with("test/new-test-branch")
52
+ Zenflow::Branch.should_receive(:track).with("test/new-test-branch")
53
+ end
54
+ it { TestCommand.new.invoke(:start, ["new-test-branch"]) }
55
+ end
56
+
57
+ context "when asking for a name" do
58
+ before do
59
+ $stdin.should_receive(:gets).and_return("new-test-branch\n")
60
+ Zenflow::Branch.should_receive(:update).with("master")
61
+ Zenflow::Branch.should_receive(:create).with("test/new-test-branch", "master")
62
+ Zenflow::Branch.should_receive(:push).with("test/new-test-branch")
63
+ Zenflow::Branch.should_receive(:track).with("test/new-test-branch")
64
+ end
65
+ it { expect(capture(:stdout){ TestCommand.new.invoke(:start) }).to eq(">> Name of the test: ") }
66
+ end
67
+ end
68
+
69
+ describe "#deploy" do
70
+ context "when a project is not deployable" do
71
+ before do
72
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
73
+ Zenflow::Config.should_receive(:[]).with(:deployable).and_return(false)
74
+ Zenflow.should_receive(:Log).with("This project is not deployable right now", color: :red)
75
+ end
76
+ it { expect{TestCommand.new.invoke(:deploy)}.to raise_error(SystemExit) }
77
+ end
78
+
79
+ context "without running migrations" do
80
+ before do
81
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
82
+ Zenflow::Config.should_receive(:[]).with(:deployable).and_return(true)
83
+ Zenflow::Branch.should_receive(:update).with("deploy1")
84
+ Zenflow::Branch.should_receive(:update).with("deploy2")
85
+ Zenflow::Branch.should_receive(:merge).with("test/new-test-branch").twice
86
+ Zenflow.should_receive(:Deploy).with("deploy1", {})
87
+ Zenflow.should_receive(:Deploy).with("deploy2", {})
88
+ Zenflow::Branch.should_receive(:checkout).with("test/new-test-branch")
89
+ end
90
+ it { TestCommand.new.invoke(:deploy) }
91
+ end
92
+
93
+ context "when running migrations" do
94
+ before do
95
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
96
+ Zenflow::Config.should_receive(:[]).with(:deployable).and_return(true)
97
+ Zenflow::Branch.should_receive(:update).with("deploy1")
98
+ Zenflow::Branch.should_receive(:update).with("deploy2")
99
+ Zenflow::Branch.should_receive(:merge).with("test/new-test-branch").twice
100
+ Zenflow.should_receive(:Deploy).with("deploy1", { "migrations" => true })
101
+ Zenflow.should_receive(:Deploy).with("deploy2", { "migrations" => true })
102
+ Zenflow::Branch.should_receive(:checkout).with("test/new-test-branch")
103
+ end
104
+ it { TestCommand.new.invoke(:deploy, [], "migrations" => true) }
105
+ end
106
+ end
107
+
108
+ describe "#update" do
109
+ before do
110
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
111
+ Zenflow::Branch.should_receive(:update).with("master")
112
+ Zenflow::Branch.should_receive(:checkout).with("test/new-test-branch")
113
+ Zenflow::Branch.should_receive(:merge).with("master")
114
+ end
115
+ it { TestCommand.new.invoke(:update) }
116
+ end
117
+
118
+ describe "#diff" do
119
+ before do
120
+ Zenflow.should_receive(:Log).with("Displaying diff with master")
121
+ Zenflow::Shell.should_receive(:[]).with("git difftool master")
122
+ end
123
+ it { TestCommand.new.invoke(:diff) }
124
+ end
125
+
126
+ describe "#compare" do
127
+ before do
128
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
129
+ Zenflow.should_receive(:Log).with("Opening GitHub compare view for master...test/new-test-branch")
130
+ Zenflow::Repo.should_receive(:slug).and_return("test-repo")
131
+ Zenflow::Shell.should_receive(:[]).with("open https://github.com/test-repo/compare/master...test/new-test-branch")
132
+ end
133
+ it { TestCommand.new.invoke(:compare) }
134
+ end
135
+
136
+ describe "#review" do
137
+ context "when pull request is found" do
138
+ before do
139
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
140
+ Zenflow::PullRequest.should_receive(:find_by_ref).with("test/new-test-branch").and_return({ html_url: "URL"})
141
+ Zenflow.should_receive(:Log).with("A pull request for test/new-test-branch already exists", color: :red)
142
+ Zenflow.should_receive(:Log).with("URL", indent: true, color: false)
143
+ end
144
+ it { expect{TestCommand.new.invoke(:review)}.to raise_error(SystemExit) }
145
+ end
146
+
147
+ context "with new pull request" do
148
+ before do
149
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
150
+ Zenflow::PullRequest.should_receive(:find_by_ref).with("test/new-test-branch").and_return(false)
151
+ end
152
+
153
+ context "with valid request" do
154
+ before do
155
+ Zenflow.should_receive(:Ask).with("Describe this test:", required: true).and_return("A great test")
156
+ pull = double(valid?: true)
157
+ pull.stub(:[]).with("html_url").and_return("URL")
158
+ Zenflow::PullRequest.should_receive(:create).with(
159
+ base: "master",
160
+ head: "test/new-test-branch",
161
+ title: "test: new-test-branch",
162
+ body: "A great test"
163
+ ).and_return(pull)
164
+ Zenflow.should_receive(:Log).with("Pull request was created!")
165
+ Zenflow.should_receive(:Log).with("URL", indent: true, color: false)
166
+ Zenflow::Shell.should_receive(:[]).with("open URL")
167
+ end
168
+ it { TestCommand.new.invoke(:review) }
169
+ end
170
+
171
+ context "with invalid request" do
172
+ let(:pull){ double(valid?: false) }
173
+
174
+ before do
175
+ Zenflow.should_receive(:Ask).with("Describe this test:", required: true).and_return("A great test")
176
+ Zenflow::PullRequest.should_receive(:create).with(
177
+ base: "master",
178
+ head: "test/new-test-branch",
179
+ title: "test: new-test-branch",
180
+ body: "A great test"
181
+ ).and_return(pull)
182
+ Zenflow.should_receive(:Log).with("There was a problem creating the pull request:", color: :red)
183
+ end
184
+
185
+ it "displays errors" do
186
+ pull.stub(:[]).with("errors").and_return([{"message" => "ERROR"},{"message" => "ERROR"}])
187
+ Zenflow.should_receive(:Log).with("* ERROR", indent: true, color: :red).twice
188
+ TestCommand.new.invoke(:review)
189
+ end
190
+
191
+ it "displays an error message" do
192
+ pull.stub(:[]).with("errors")
193
+ pull.stub(:[]).with("message").and_return("ERROR")
194
+ Zenflow.should_receive(:Log).with("* ERROR", indent: true, color: :red)
195
+ TestCommand.new.invoke(:review)
196
+ end
197
+
198
+ it "handles unexpected failure" do
199
+ pull.stub(:[]).with("errors")
200
+ pull.stub(:[]).with("message")
201
+ Zenflow.should_receive(:Log).with(" * unexpected failure, both 'errors' and 'message' were empty in the response")
202
+ TestCommand.new.invoke(:review)
203
+ end
204
+ end
205
+ end
206
+ end
207
+
208
+ describe "#abort" do
209
+ let(:branch_name){"test/new-test-branch"}
210
+ before {
211
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
212
+ Zenflow::Branch.should_receive(:checkout).with("master")
213
+ }
214
+
215
+ context "when online" do
216
+ before do
217
+ Zenflow::Branch.should_receive(:delete_remote).with(branch_name)
218
+ Zenflow::Branch.should_receive(:delete_local).with(branch_name, force: true)
219
+ end
220
+ it { TestCommand.new.invoke(:abort) }
221
+ end
222
+
223
+ context "when offline" do
224
+ before do
225
+ Zenflow::Branch.should_receive(:delete_local).with(branch_name, force: true)
226
+ end
227
+ it { TestCommand.new.invoke(:abort, [], offline: true) }
228
+ end
229
+ end
230
+
231
+ describe "#finish" do
232
+ before do
233
+ Zenflow::Branch.should_receive(:current).with("test").and_return("new-test-branch")
234
+ end
235
+
236
+ context "with confirmations" do
237
+ it "without deployment to staging" do
238
+ Zenflow::Config.should_receive(:[]).with(:confirm_staging).and_return(true)
239
+ Zenflow.should_receive(:Ask).with("Has this been tested in a staging environment first?", options: ["Y", "n"], default: "Y").and_return("n")
240
+ Zenflow.should_receive(:Log).with("Sorry, deploy to a staging environment first", color: :red)
241
+ expect{TestCommand.new.invoke(:finish)}.to raise_error(SystemExit)
242
+ end
243
+
244
+ it "without review" do
245
+ Zenflow::Config.should_receive(:[]).with(:confirm_staging).and_return(true)
246
+ Zenflow::Config.should_receive(:[]).with(:confirm_review).and_return(true)
247
+ Zenflow.should_receive(:Ask).with("Has this been tested in a staging environment first?", options: ["Y", "n"], default: "Y").and_return("y")
248
+ Zenflow.should_receive(:Ask).with("Has this been code reviewed yet?", options: ["Y", "n"], default: "Y").and_return("n")
249
+ Zenflow.should_receive(:Log).with("Please have someone look at this first", color: :red)
250
+ expect{TestCommand.new.invoke(:finish)}.to raise_error(SystemExit)
251
+ end
252
+ end
253
+
254
+ context "without confirmations" do
255
+ before do
256
+ Zenflow::Config.should_receive(:[]).with(:confirm_staging).and_return(false)
257
+ Zenflow::Config.should_receive(:[]).with(:confirm_review).and_return(false)
258
+ end
259
+
260
+ context "when online" do
261
+ before do
262
+ Zenflow::Branch.should_receive(:update).with("production")
263
+ Zenflow::Branch.should_receive(:checkout).with("test/new-test-branch")
264
+ Zenflow::Branch.should_receive(:merge).with("production")
265
+
266
+ Zenflow::Version.should_receive(:update).with(:patch)
267
+
268
+ Zenflow::Changelog.should_receive(:update).with(rotate: true, name: "new-test-branch").and_return("YES")
269
+
270
+ Zenflow::Branch.should_receive(:checkout).with("master")
271
+ Zenflow::Branch.should_receive(:merge).with("test/new-test-branch")
272
+ Zenflow::Branch.should_receive(:push).with("master")
273
+ Zenflow::Branch.should_receive(:checkout).with("production")
274
+ Zenflow::Branch.should_receive(:merge).with("test/new-test-branch")
275
+ Zenflow::Branch.should_receive(:push).with("production")
276
+
277
+ Zenflow::Branch.should_receive(:tag).with(Zenflow::Version.current.to_s, "YES")
278
+ Zenflow::Branch.should_receive(:push).with(:tags)
279
+
280
+ Zenflow::Branch.should_receive(:delete_remote).with("test/new-test-branch")
281
+ Zenflow::Branch.should_receive(:delete_local).with("test/new-test-branch", force: true)
282
+ end
283
+ it { TestCommand.new.invoke(:finish) }
284
+ end
285
+
286
+ context "when offline" do
287
+ before do
288
+ Zenflow::Branch.should_receive(:checkout).with("test/new-test-branch")
289
+ Zenflow::Branch.should_receive(:merge).with("production")
290
+
291
+ Zenflow::Version.should_receive(:update).with(:patch)
292
+
293
+ Zenflow::Changelog.should_receive(:update).with(rotate: true, name: "new-test-branch").and_return("YES")
294
+
295
+ Zenflow::Branch.should_receive(:checkout).with("master")
296
+ Zenflow::Branch.should_receive(:merge).with("test/new-test-branch")
297
+ Zenflow::Branch.should_receive(:checkout).with("production")
298
+ Zenflow::Branch.should_receive(:merge).with("test/new-test-branch")
299
+
300
+ Zenflow::Branch.should_receive(:tag).with(Zenflow::Version.current.to_s, "YES")
301
+
302
+ Zenflow::Branch.should_receive(:delete_local).with("test/new-test-branch", force: true)
303
+ end
304
+ it { TestCommand.new.invoke(:finish, [], offline: true) }
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ end