daq_flow 1.0.4

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.
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