daq_flow 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +62 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +165 -0
  8. data/Rakefile +10 -0
  9. data/bin/daq_flow +23 -0
  10. data/flash_flow.gemspec +28 -0
  11. data/flash_flow.yml.erb.example +42 -0
  12. data/lib/flash_flow.rb +7 -0
  13. data/lib/flash_flow/branch_merger.rb +55 -0
  14. data/lib/flash_flow/cmd_runner.rb +54 -0
  15. data/lib/flash_flow/config.rb +84 -0
  16. data/lib/flash_flow/data.rb +6 -0
  17. data/lib/flash_flow/data/base.rb +89 -0
  18. data/lib/flash_flow/data/bitbucket.rb +152 -0
  19. data/lib/flash_flow/data/branch.rb +124 -0
  20. data/lib/flash_flow/data/collection.rb +211 -0
  21. data/lib/flash_flow/data/github.rb +140 -0
  22. data/lib/flash_flow/data/store.rb +44 -0
  23. data/lib/flash_flow/git.rb +267 -0
  24. data/lib/flash_flow/install.rb +19 -0
  25. data/lib/flash_flow/lock.rb +23 -0
  26. data/lib/flash_flow/merge.rb +6 -0
  27. data/lib/flash_flow/merge/acceptance.rb +154 -0
  28. data/lib/flash_flow/merge/base.rb +116 -0
  29. data/lib/flash_flow/merge_order.rb +27 -0
  30. data/lib/flash_flow/notifier.rb +23 -0
  31. data/lib/flash_flow/options.rb +34 -0
  32. data/lib/flash_flow/resolve.rb +143 -0
  33. data/lib/flash_flow/shadow_repo.rb +44 -0
  34. data/lib/flash_flow/time_helper.rb +32 -0
  35. data/lib/flash_flow/version.rb +4 -0
  36. data/log/.keep +0 -0
  37. data/test/lib/data/test_base.rb +10 -0
  38. data/test/lib/data/test_branch.rb +206 -0
  39. data/test/lib/data/test_collection.rb +308 -0
  40. data/test/lib/data/test_store.rb +70 -0
  41. data/test/lib/lock/test_github.rb +74 -0
  42. data/test/lib/merge/test_acceptance.rb +230 -0
  43. data/test/lib/test_branch_merger.rb +78 -0
  44. data/test/lib/test_config.rb +63 -0
  45. data/test/lib/test_git.rb +73 -0
  46. data/test/lib/test_merge_order.rb +71 -0
  47. data/test/lib/test_notifier.rb +33 -0
  48. data/test/lib/test_resolve.rb +69 -0
  49. data/test/minitest_helper.rb +41 -0
  50. data/update_gem.sh +5 -0
  51. metadata +192 -0
@@ -0,0 +1,70 @@
1
+ require 'minitest_helper'
2
+ require 'flash_flow/data/store'
3
+
4
+ module FlashFlow
5
+ module Data
6
+ class TestStore < Minitest::Test
7
+ def setup
8
+ @mock_git = MockGit.new
9
+ @collection = Collection.new
10
+ @branch = Branch.new('some_branch')
11
+ @storage = Store.new('/dev/null', @mock_git)
12
+ end
13
+
14
+ def test_get
15
+ @mock_git.stub(:read_file_from_merge_branch, JSON.pretty_generate(old_branches)) do
16
+ assert_equal(@storage.get, old_branches)
17
+ end
18
+ end
19
+
20
+ def test_write
21
+ str = StringIO.new
22
+ @storage.write(old_branches, str)
23
+
24
+ assert_equal(str.string.strip, JSON.pretty_generate(sorted_branches).strip)
25
+ end
26
+
27
+ private # Helpers
28
+
29
+ def old_branches
30
+ @old_branches ||= {
31
+ 'version' => '1.0.0',
32
+ 'branches' => {
33
+ 'some_old_branch' => {'ref' => 'some_old_branch', 'created_at' => (Time.now - 3600).to_s, 'stories' => ['111']},
34
+ 'some_branch' => {'ref' => 'some_branch', 'status' => 'success', 'created_at' => (Time.now - 1800).to_s, 'stories' => ['222']}
35
+ }
36
+ }
37
+ end
38
+
39
+ def sorted_branches
40
+ @sorted_branches ||= {
41
+ 'branches' => {
42
+ 'some_branch' => {
43
+ 'created_at' => (Time.now - 1800).to_s,
44
+ 'ref' => 'some_branch',
45
+ 'status' => 'success',
46
+ 'stories' => ['222']
47
+ },
48
+ 'some_old_branch' => {
49
+ 'created_at' => (Time.now - 3600).to_s,
50
+ 'ref' => 'some_old_branch',
51
+ 'stories' => ['111']},
52
+ },
53
+ 'version' => '1.0.0',
54
+ }
55
+ end
56
+ end
57
+
58
+ class MockGit
59
+ def read_file_from_merge_branch; end
60
+ def add_and_commit(_,_,_=nil); end
61
+
62
+ def in_dir
63
+ yield
64
+ end
65
+ def in_temp_merge_branch
66
+ yield
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,74 @@
1
+ require 'minitest_helper'
2
+ require 'minitest/stub_any_instance'
3
+
4
+ module FlashFlow
5
+ module Lock
6
+ class TestGithub < Minitest::Test
7
+ class SomeFakeError < RuntimeError;
8
+ end
9
+
10
+ def setup
11
+ @lock = Lock::Github.new(params)
12
+ end
13
+
14
+ def test_raises_without_required_params
15
+ config = params.select { |k, _| k != 'token' }
16
+ assert_raises(Lock::Error) { Lock::Github.new(config) }
17
+
18
+ config = params.select { |k, _| k != 'repo' }
19
+ assert_raises(Lock::Error) { Lock::Github.new(config) }
20
+
21
+ config = params.select { |k, _| k != 'issue_id' }
22
+ assert_raises(Lock::Error) { Lock::Github.new(config) }
23
+ end
24
+
25
+ def test_error_message_when_issue_locked
26
+ @lock.stub(:actor, 'actor') do
27
+ @lock.stub(:issue_locked?, true) do
28
+ @lock.stub(:get_lock_labels, {name: @lock.send(:locked_label)}) do
29
+ assert_raises(FlashFlow::Lock::Error) do
30
+ @lock.with_lock
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def test_with_lock_calls_the_block
38
+ my_mock = Minitest::Mock.new.expect(:block_call, true).expect(:unlock_issue, true)
39
+
40
+ @lock.stub(:issue_locked?, false) do
41
+ @lock.stub(:lock_issue, nil) do
42
+ @lock.stub(:unlock_issue, -> { my_mock.unlock_issue }) do
43
+ @lock.with_lock { my_mock.block_call }
44
+ my_mock.verify
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def test_with_unlock_issue_no_matter_what
51
+ my_mock = Minitest::Mock.new
52
+ .expect(:some_method, true)
53
+ .expect(:actor, 'actor')
54
+
55
+ @lock.stub(:issue_locked?, false) do
56
+ @lock.stub(:lock_issue, nil) do
57
+ @lock.stub(:unlock_issue, -> { my_mock.some_method }) do
58
+ assert_raises(SomeFakeError) do
59
+ @lock.with_lock { raise SomeFakeError }
60
+ my_mock.verify
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def params
70
+ {'token' => '1234567890', 'repo' => 'f/f', 'issue_id' => '123'}
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,230 @@
1
+ require 'minitest_helper'
2
+ require 'minitest/stub_any_instance'
3
+
4
+ module FlashFlow
5
+ module Merge
6
+ class TestAcceptance < Minitest::Test
7
+
8
+ def setup
9
+ reset_config!
10
+ config!(git:
11
+ {
12
+ 'merge_branch' => 'test_acceptance',
13
+ 'remote' => 'test_remote',
14
+ 'master_branch' => 'test_master',
15
+ 'use_rerere' => true
16
+ },
17
+ branches: {}
18
+ )
19
+
20
+ @branch = Data::Branch.from_hash({'ref' => 'pushing_branch', 'status' => 'fail', 'stories' => []})
21
+ @deploy = Acceptance.new
22
+ end
23
+
24
+ def test_version_is_nil
25
+ with_versions('1.1.1', nil) do
26
+ assert_nil(@deploy.check_version)
27
+ end
28
+ end
29
+
30
+ def test_check_version_greater
31
+ with_versions('2.0.0', '1.1.1') do
32
+ assert_nil(@deploy.check_version)
33
+ end
34
+
35
+ with_versions('1.2.0', '1.1.1') do
36
+ assert_nil(@deploy.check_version)
37
+ end
38
+ end
39
+
40
+ def test_check_version_less_raises
41
+ with_versions('1.1.1', '2.1.0') do
42
+ assert_raises(RuntimeError) { @deploy.check_version }
43
+ end
44
+
45
+ with_versions('1.2.0', '2.1.0') do
46
+ assert_raises(RuntimeError) { @deploy.check_version }
47
+ end
48
+ end
49
+
50
+ def test_git_version_is_nil
51
+ with_git_versions(nil, '2.0.0') do
52
+ assert_nil(@deploy.check_git_version)
53
+ end
54
+ end
55
+
56
+ def test_check_git_version_greater
57
+ with_git_versions('3.0.0', '2.0.0') do
58
+ assert_nil(@deploy.check_git_version)
59
+ end
60
+
61
+ with_git_versions('2.15.1', '2.0.0') do
62
+ assert_nil(@deploy.check_git_version)
63
+ end
64
+ end
65
+
66
+ def test_check_git_version_less_raises
67
+ with_git_versions('2.0.0', '2.15.1') do
68
+ assert_output(/Warning/) { @deploy.check_git_version }
69
+ end
70
+
71
+ with_git_versions('1.7.8', '2.15.1') do
72
+ assert_output(/Warning/) { @deploy.check_git_version }
73
+ end
74
+ end
75
+
76
+ def test_print_errors_with_no_errors
77
+ data.expect(:failures, [])
78
+ assert_equal(@deploy.format_errors, 'Success!')
79
+ end
80
+
81
+ def test_print_errors_when_current_branch_cant_merge
82
+ data.expect(:failures, [@branch])
83
+ @branch.fail!('some_random_sha')
84
+
85
+ current_branch_error = "ERROR: Your branch did not merge to test_acceptance. Run 'flash_flow --resolve', fix the merge conflict(s) and then re-run this script\n"
86
+
87
+ @deploy.instance_variable_get('@local_git'.to_sym).stub(:working_branch, 'pushing_branch') do
88
+ assert_equal(current_branch_error, @deploy.format_errors)
89
+ end
90
+ end
91
+
92
+ def test_print_errors_when_another_branch_cant_merge
93
+ data.expect(:failures, [@branch])
94
+
95
+ other_branch_error = "WARNING: Unable to merge branch test_remote/pushing_branch to test_acceptance due to conflicts."
96
+
97
+ assert_equal(@deploy.format_errors, other_branch_error)
98
+ end
99
+
100
+ def test_check_out_to_working_branch
101
+ @deploy.stub(:check_repo, true) do
102
+ @deploy.stub(:check_version, true) do
103
+ Lock::Base.stub_any_instance(:with_lock, -> { raise Lock::Error }) do
104
+ assert_output(/Failure!/) { @deploy.run }
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def test_deleted_branch
111
+ data.expect(:mark_deleted, true, [@branch])
112
+
113
+ notifier.expect(:deleted_branch, true, [@branch])
114
+
115
+ merger.expect(:result, :deleted)
116
+
117
+ @deploy.process_result(@branch, merger)
118
+
119
+ notifier.verify
120
+ data.verify
121
+ merger.verify
122
+ end
123
+
124
+ def test_merge_conflict
125
+ data.expect(:mark_failure, true, [@branch, nil])
126
+
127
+ notifier.expect(:merge_conflict, true, [@branch])
128
+
129
+ merger.expect(:result, :conflict)
130
+
131
+ @deploy.process_result(@branch, merger)
132
+
133
+ notifier.verify
134
+ data.verify
135
+ merger.verify
136
+ end
137
+
138
+ def test_successful_merge
139
+ data.expect(:mark_success, true, [@branch])
140
+ data.expect(:set_resolutions, true, [@branch, {'filename' => ["resolution_sha"]}])
141
+
142
+ merger.
143
+ expect(:result, :success).
144
+ expect(:sha, 'sha').
145
+ expect(:resolutions, {'filename' => ["resolution_sha"]})
146
+
147
+ @deploy.process_result(@branch, merger)
148
+
149
+ data.verify
150
+ merger.verify
151
+ assert_equal(@branch.sha, 'sha')
152
+ end
153
+
154
+ def test_ignore_pushing_master_or_acceptance
155
+ ['test_master', 'test_acceptance'].each do |branch|
156
+ @deploy.instance_variable_get('@local_git'.to_sym).stub(:working_branch, branch) do
157
+ refute(@deploy.open_pull_request)
158
+ end
159
+ end
160
+ end
161
+
162
+ def test_commit_message_ordering
163
+ data
164
+ .expect(:successes, ['data_successes'])
165
+ .expect(:successes, sample_branches)
166
+ .expect(:failures, [])
167
+ .expect(:removals, [])
168
+
169
+ expected_message = sample_branches.sort_by(&:merge_order).map(&:ref).join("\n")
170
+ assert_output(/#{expected_message}/) { print @deploy.commit_message }
171
+ data.verify
172
+ end
173
+
174
+ private
175
+
176
+ def with_versions(current, written)
177
+ original_version = FlashFlow::VERSION
178
+ FlashFlow.send(:remove_const, :VERSION)
179
+ FlashFlow.const_set(:VERSION, current)
180
+ data.expect(:version, written)
181
+ yield
182
+ data.verify
183
+ FlashFlow.send(:remove_const, :VERSION)
184
+ FlashFlow.const_set(:VERSION, original_version)
185
+ end
186
+
187
+ def with_git_versions(running, expected)
188
+ original_version = FlashFlow::GIT_VERSION
189
+ FlashFlow.send(:remove_const, :GIT_VERSION)
190
+ FlashFlow.const_set(:GIT_VERSION, expected)
191
+ local_git.expect(:version, running)
192
+ yield
193
+ local_git.verify
194
+ FlashFlow.send(:remove_const, :GIT_VERSION)
195
+ FlashFlow.const_set(:GIT_VERSION, original_version)
196
+ end
197
+
198
+ def merger
199
+ @merger ||= Minitest::Mock.new
200
+ end
201
+
202
+ def notifier
203
+ return @notifier if @notifier
204
+
205
+ @notifier = Minitest::Mock.new
206
+ @deploy.instance_variable_set('@notifier'.to_sym, @notifier)
207
+ end
208
+
209
+ def data
210
+ return @data if @data
211
+
212
+ @data = Minitest::Mock.new
213
+ @deploy.instance_variable_set('@data'.to_sym, @data)
214
+ end
215
+
216
+ def local_git
217
+ return @local_git if @local_git
218
+
219
+ @local_git = Minitest::Mock.new
220
+ @deploy.instance_variable_set('@local_git'.to_sym, @local_git)
221
+ end
222
+
223
+ def sample_branches
224
+ @sample_branches ||= [Data::Branch.from_hash({'ref' => 'branch3', 'merge_order' => 2}),
225
+ Data::Branch.from_hash({'ref' => 'branch1', 'merge_order' => 3}),
226
+ Data::Branch.from_hash({'ref' => 'branch2', 'merge_order' => 1})]
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,78 @@
1
+ require 'minitest_helper'
2
+ require 'minitest/stub_any_instance'
3
+
4
+ module FlashFlow
5
+ class TestBranchMerger < Minitest::Test
6
+
7
+ def setup
8
+ end
9
+
10
+ def test_deleted_branch
11
+ merger.stub(:sha, nil) do
12
+ merger.do_merge(true)
13
+ assert_equal(merger.result, :deleted)
14
+ end
15
+ end
16
+
17
+ def test_successful_merge
18
+ git.expect(:last_success?, true)
19
+
20
+ merger.stub(:sha, 'some_sha') do
21
+ assert_equal(merger.do_merge(false), :success)
22
+ end
23
+ end
24
+
25
+ def test_successful_rerere
26
+ git.expect(:last_success?, false)
27
+ .expect(:rerere_resolve!, true)
28
+
29
+ merger.stub(:sha, 'some_sha') do
30
+ assert_equal(merger.do_merge(false), :success)
31
+ end
32
+ end
33
+
34
+ def test_rerere_forget
35
+ git.expect(:last_success?, false)
36
+ .expect(:run, true, [ 'rerere forget' ])
37
+ .expect(:run, true, [ 'reset --hard HEAD' ])
38
+ .expect(:run, true, [ 'rev-parse HEAD' ])
39
+ .expect(:last_stdout, 'conflict sha', )
40
+
41
+ merger.stub(:sha, 'some_sha') do
42
+ assert_equal(merger.do_merge(true), :conflict)
43
+ end
44
+ end
45
+
46
+ def test_failed_rerere
47
+ git.expect(:last_success?, false)
48
+ .expect(:rerere_resolve!, false)
49
+ .expect(:run, true, [ 'reset --hard HEAD' ])
50
+ .expect(:run, true, [ 'rev-parse HEAD' ])
51
+ .expect(:last_stdout, 'conflict sha', )
52
+
53
+ merger.stub(:sha, 'some_sha') do
54
+ assert_equal(merger.do_merge(false), :conflict)
55
+ assert_equal(merger.conflict_sha, 'conflict sha')
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def merger
62
+ @merger ||= BranchMerger.new(git, branch)
63
+ end
64
+
65
+ def branch
66
+ @branch ||= Data::Branch.from_hash({'ref' => 'pushing_branch', 'status' => 'fail', 'stories' => []})
67
+ end
68
+
69
+ def git
70
+ return @git if @git
71
+
72
+ @git = Minitest::Mock.new
73
+ @git.expect(:remote, 'origin', [])
74
+ @git.expect(:run, true, ["merge --no-ff origin/#{branch.ref}"])
75
+ end
76
+
77
+ end
78
+ end