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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +22 -0
- data/README.md +165 -0
- data/Rakefile +10 -0
- data/bin/daq_flow +23 -0
- data/flash_flow.gemspec +28 -0
- data/flash_flow.yml.erb.example +42 -0
- data/lib/flash_flow.rb +7 -0
- data/lib/flash_flow/branch_merger.rb +55 -0
- data/lib/flash_flow/cmd_runner.rb +54 -0
- data/lib/flash_flow/config.rb +84 -0
- data/lib/flash_flow/data.rb +6 -0
- data/lib/flash_flow/data/base.rb +89 -0
- data/lib/flash_flow/data/bitbucket.rb +152 -0
- data/lib/flash_flow/data/branch.rb +124 -0
- data/lib/flash_flow/data/collection.rb +211 -0
- data/lib/flash_flow/data/github.rb +140 -0
- data/lib/flash_flow/data/store.rb +44 -0
- data/lib/flash_flow/git.rb +267 -0
- data/lib/flash_flow/install.rb +19 -0
- data/lib/flash_flow/lock.rb +23 -0
- data/lib/flash_flow/merge.rb +6 -0
- data/lib/flash_flow/merge/acceptance.rb +154 -0
- data/lib/flash_flow/merge/base.rb +116 -0
- data/lib/flash_flow/merge_order.rb +27 -0
- data/lib/flash_flow/notifier.rb +23 -0
- data/lib/flash_flow/options.rb +34 -0
- data/lib/flash_flow/resolve.rb +143 -0
- data/lib/flash_flow/shadow_repo.rb +44 -0
- data/lib/flash_flow/time_helper.rb +32 -0
- data/lib/flash_flow/version.rb +4 -0
- data/log/.keep +0 -0
- data/test/lib/data/test_base.rb +10 -0
- data/test/lib/data/test_branch.rb +206 -0
- data/test/lib/data/test_collection.rb +308 -0
- data/test/lib/data/test_store.rb +70 -0
- data/test/lib/lock/test_github.rb +74 -0
- data/test/lib/merge/test_acceptance.rb +230 -0
- data/test/lib/test_branch_merger.rb +78 -0
- data/test/lib/test_config.rb +63 -0
- data/test/lib/test_git.rb +73 -0
- data/test/lib/test_merge_order.rb +71 -0
- data/test/lib/test_notifier.rb +33 -0
- data/test/lib/test_resolve.rb +69 -0
- data/test/minitest_helper.rb +41 -0
- data/update_gem.sh +5 -0
- 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
|