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,44 @@
1
+ require 'logger'
2
+
3
+ require 'flash_flow/git'
4
+
5
+ module FlashFlow
6
+ class ShadowGit < Git
7
+
8
+ def initialize(config, logger=nil)
9
+ super
10
+
11
+ # create_shadow_repo
12
+ # @cmd_runner.dir = flash_flow_dir
13
+
14
+ run("clean -x -f")
15
+ run("fetch #{remote}")
16
+ run("remote prune #{remote}")
17
+ run("reset --hard HEAD")
18
+ end
19
+
20
+ def create_shadow_repo
21
+ unless Dir.exists?(flash_flow_dir)
22
+ @cmd_runner.run("mkdir -p #{flash_flow_dir}")
23
+ @cmd_runner.run("cp -R #{current_dir} #{flash_flow_base_dir}")
24
+ end
25
+ end
26
+
27
+ FLASH_FLOW_BASE = '.flash_flow'
28
+ def flash_flow_base_dir
29
+ if current_dir =~ /\.flash_flow/
30
+ "#{current_dir.split(FLASH_FLOW_BASE).first}#{FLASH_FLOW_BASE}"
31
+ else
32
+ "#{current_dir}/../#{FLASH_FLOW_BASE}"
33
+ end
34
+ end
35
+
36
+ def current_dir
37
+ Dir.getwd
38
+ end
39
+
40
+ def flash_flow_dir
41
+ @flash_flow_dir ||= flash_flow_base_dir + "/#{File.basename(current_dir)}"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ require 'time'
2
+
3
+ module FlashFlow
4
+ module TimeHelper
5
+
6
+ def with_time_zone(tz_name)
7
+ prev_tz = ENV['TZ']
8
+ ENV['TZ'] = tz_name
9
+ yield
10
+ ensure
11
+ ENV['TZ'] = prev_tz
12
+ end
13
+
14
+ def massage_time(time)
15
+ case time
16
+ when Time
17
+ time
18
+ when NilClass
19
+ Time.now
20
+ else
21
+ Time.parse(time)
22
+ end
23
+ end
24
+
25
+ def two_weeks
26
+ 60 * 60 * 24 * 14
27
+ end
28
+
29
+ module_function :with_time_zone, :massage_time, :two_weeks
30
+
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ module FlashFlow
2
+ VERSION = '1.0.4'
3
+ GIT_VERSION = '2.0.0'
4
+ end
File without changes
@@ -0,0 +1,10 @@
1
+ require 'minitest_helper'
2
+ require 'flash_flow/data/store'
3
+
4
+ module FlashFlow
5
+ module Data
6
+ class TestBase < Minitest::Test
7
+ # Embarrassingly lazy. Write some tests.
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,206 @@
1
+ require 'minitest_helper'
2
+ require 'flash_flow/data/store'
3
+
4
+ module FlashFlow
5
+ module Data
6
+ class TestBranch < Minitest::Test
7
+
8
+ def test_merge_returns_self_if_other_is_nil
9
+ branch = Branch.from_hash(branch_hash)
10
+ assert_equal(branch.merge(nil), branch)
11
+ end
12
+
13
+ def test_merge_keeps_the_oldest_created_at
14
+ new_branch = Branch.from_hash(branch_hash)
15
+ old_branch = Branch.from_hash(branch_hash)
16
+ old_branch.created_at -= 1000
17
+
18
+ assert_equal(new_branch.merge(old_branch).created_at, old_branch.created_at)
19
+ assert_equal(old_branch.merge(new_branch).created_at, old_branch.created_at)
20
+ end
21
+
22
+ def test_merge_handles_nil_stories
23
+ new_branch = Branch.from_hash(branch_hash)
24
+ old_branch = Branch.from_hash(branch_hash)
25
+
26
+ new_branch.stories = nil
27
+ old_branch.stories = ['456', '789']
28
+
29
+ assert_equal(old_branch.merge(new_branch).stories, ['456', '789'])
30
+ assert_equal(new_branch.merge(old_branch).stories, ['456', '789'])
31
+ end
32
+
33
+ def test_merge_unions_the_stories
34
+ new_branch = Branch.from_hash(branch_hash)
35
+ old_branch = Branch.from_hash(branch_hash)
36
+
37
+ new_branch.stories = ['123', '456']
38
+ old_branch.stories = ['456', '789']
39
+
40
+ assert_equal(new_branch.merge(old_branch).stories, ['123', '456', '789'])
41
+ end
42
+
43
+ def test_merge_uses_other_status
44
+ new_branch = Branch.from_hash(branch_hash)
45
+ old_branch = Branch.from_hash(branch_hash)
46
+
47
+ old_branch.success!
48
+ new_branch.fail!
49
+ old_branch.merge(new_branch)
50
+
51
+ assert(old_branch.fail?)
52
+ assert(new_branch.fail?)
53
+ end
54
+
55
+ def test_merge_sets_updated_at
56
+ new_branch = Branch.from_hash(branch_hash)
57
+ old_branch = Branch.from_hash(branch_hash)
58
+
59
+ original_updated_at = new_branch.updated_at
60
+
61
+ assert(old_branch.merge(new_branch).updated_at > original_updated_at)
62
+ end
63
+
64
+ def test_merge_sets_created_at_if_not_set
65
+ new_branch = Branch.from_hash(branch_hash)
66
+ old_branch = Branch.from_hash(branch_hash)
67
+
68
+ new_branch.created_at = old_branch.created_at = nil
69
+
70
+ assert_in_delta(old_branch.merge(new_branch).created_at.to_i, Time.now.to_i, 100)
71
+ end
72
+
73
+ def test_from_hash
74
+ branch = Branch.from_hash(branch_hash)
75
+ assert_equal(branch.ref, branch_hash['ref'])
76
+ assert_equal(branch.status, branch_hash['status'])
77
+ assert_equal(branch.stories, branch_hash['stories'])
78
+ assert_equal(branch.metadata, branch_hash['metadata'])
79
+ end
80
+
81
+ def test_from_hash_conflict_sha
82
+ branch = Branch.from_hash(branch_hash)
83
+ assert_equal(branch.conflict_sha, 'conflict_sha')
84
+
85
+ hash = branch_hash.merge({ 'conflict_sha' => nil, 'metadata' => { 'conflict_sha' => 'another_sha' } })
86
+ branch = Branch.from_hash(hash)
87
+ assert_equal(branch.conflict_sha, 'another_sha')
88
+
89
+ hash = branch_hash.merge({ 'conflict_sha' => nil})
90
+ branch = Branch.from_hash(hash)
91
+ assert_equal(branch.conflict_sha, nil)
92
+ end
93
+
94
+ def test_from_hash_with_time_objects
95
+ branch_hash['updated_at'] = Time.now - 200
96
+ branch_hash['created_at'] = Time.now - 200
97
+ branch = Branch.from_hash(branch_hash)
98
+ assert_equal(branch.updated_at, branch_hash['updated_at'])
99
+ assert_equal(branch.created_at, branch_hash['created_at'])
100
+ end
101
+
102
+ def test_from_hash_with_nil_times
103
+ time = Time.parse('2015-05-22 09:47:07 -0700')
104
+ branch_hash['updated_at'] = branch_hash['created_at'] = nil
105
+ Time.stub(:now, time) do
106
+ branch = Branch.from_hash(branch_hash)
107
+
108
+ assert_equal(branch.updated_at, time)
109
+ assert_equal(branch.created_at, time)
110
+ end
111
+ end
112
+
113
+ def test_from_hash_with_string_times
114
+ time = Time.parse('2015-05-22 09:47:07 -0700')
115
+ branch_hash['updated_at'] = '2015-05-22 09:47:07 -0700'
116
+ branch_hash['created_at'] = '2015-05-22 09:47:07 -0700'
117
+ branch = Branch.from_hash(branch_hash)
118
+ assert_equal(branch.updated_at, time)
119
+ assert_equal(branch.created_at, time)
120
+ end
121
+
122
+ def test_double_equals
123
+ branch1 = Branch.from_hash(branch_hash)
124
+ branch2 = Branch.from_hash(branch_hash)
125
+ assert(branch1 == branch2)
126
+
127
+ branch1.ref = 'different ref'
128
+ refute(branch1 == branch2)
129
+ end
130
+
131
+ def test_to_hash
132
+ branch1 = Branch.from_hash(branch_hash)
133
+ assert_equal(branch1.to_hash, branch_hash)
134
+ end
135
+
136
+ def test_success
137
+ branch = Branch.new(1)
138
+
139
+ branch.success!
140
+ assert(branch.success?)
141
+
142
+ branch.fail!
143
+ refute(branch.success?)
144
+ end
145
+
146
+ def test_fail
147
+ branch = Branch.new(1)
148
+
149
+ branch.fail!
150
+ assert(branch.fail?)
151
+
152
+ branch.success!
153
+ refute(branch.fail?)
154
+ end
155
+
156
+ def test_removed
157
+ branch = Branch.new(1)
158
+
159
+ branch.removed!
160
+ assert(branch.removed?)
161
+
162
+ branch.success!
163
+ refute(branch.removed?)
164
+ end
165
+
166
+ def test_deleted
167
+ branch = Branch.new(1)
168
+
169
+ branch.deleted!
170
+ assert(branch.deleted?)
171
+
172
+ branch.success!
173
+ refute(branch.deleted?)
174
+ end
175
+
176
+ def test_unknown
177
+ branch = Branch.new(1)
178
+
179
+ branch.unknown!
180
+ assert(branch.unknown?)
181
+
182
+ branch.success!
183
+ refute(branch.unknown?)
184
+ end
185
+
186
+ private
187
+
188
+ def branch_hash
189
+ @branch_hash ||= {
190
+ 'ref' => 'branch 1',
191
+ 'sha' => 'random_sha',
192
+ 'status' => 'success',
193
+ 'merge_order' => nil,
194
+ 'resolutions' => {},
195
+ 'stories' => ['123'],
196
+ 'conflict_sha' => 'conflict_sha',
197
+ 'metadata' => {
198
+ 'some' => 'data'
199
+ },
200
+ 'updated_at' => Time.now - 1000,
201
+ 'created_at' => Time.now - 1000,
202
+ }
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,308 @@
1
+ require 'minitest_helper'
2
+
3
+ module FlashFlow
4
+ module Data
5
+ class TestCollection < Minitest::Test
6
+
7
+ def setup_fake_branches
8
+ Object.send(:remove_const, :FakeBranches) if Object.const_defined?(:FakeBranches)
9
+
10
+ fake_branches_class = Class.new do
11
+ @branches = Minitest::Mock.new
12
+ def self.new(opts=nil); @branches; end
13
+ def self.branches; @branches; end
14
+ end
15
+ Object.const_set('FakeBranches', fake_branches_class)
16
+ end
17
+
18
+ def setup
19
+ setup_fake_branches
20
+ @fake_branches = FakeBranches.branches
21
+ @branch = Branch.new('some_branch')
22
+ @collection = Collection.new({ 'class' => { 'name' => 'FakeBranches' }})
23
+ end
24
+
25
+ def test_from_hash_set_branches
26
+ hash = { 'some_branch' => Branch.new('some_branch') }
27
+ assert_equal(Collection.from_hash(hash).branches, hash)
28
+ end
29
+
30
+ def test_fetch_calls_collection_class
31
+ @fake_branches.expect(:fetch, [], [])
32
+ @collection.fetch
33
+
34
+ @fake_branches.verify
35
+ end
36
+
37
+ def test_fetch_returns_nil_if_no_collection_class
38
+ assert_nil(@collection.fetch)
39
+ end
40
+
41
+ def test_fetch_maps_collection_class_to_branches
42
+ branch = Data::Branch.new('some_branch')
43
+ @fake_branches.expect(:fetch, [Branch.from_hash({'ref' => branch.ref })], [])
44
+ @collection.fetch
45
+
46
+ assert_equal(@collection.branches.values, [branch])
47
+ @fake_branches.verify
48
+ end
49
+
50
+ def test_reverse_merge_when_old_is_empty
51
+ @collection.mark_success(@branch)
52
+
53
+ merged = @collection.reverse_merge(Collection.from_hash({}))
54
+ assert_equal(['some_branch'], merged.to_h.keys)
55
+ assert(merged.get('some_branch').success?)
56
+ end
57
+
58
+ def test_reverse_merge_old_marks_old_branches
59
+ @collection.mark_success(@branch)
60
+
61
+ merged = @collection.reverse_merge(Collection.from_hash(old_branches))
62
+ assert(merged.get('some_old_branch').unknown?)
63
+ end
64
+
65
+ def test_reverse_merge_old_adds_new_stories
66
+ @collection.mark_success(@branch)
67
+ @collection.add_story('some_branch', '456')
68
+ merged = @collection.reverse_merge(Collection.from_hash(old_branches))
69
+
70
+ assert_equal(['222', '456'], merged.get('some_branch').stories)
71
+ end
72
+
73
+ def test_reverse_merge_old_uses_old_created_at
74
+ @collection.add_to_merge('some_old_branch')
75
+ @collection.add_to_merge('some_new_branch')
76
+ old_branch_collection = Collection.from_hash(old_branches)
77
+ merged = @collection.reverse_merge(old_branch_collection)
78
+
79
+ assert_equal(old_branch_collection.get('some_branch').created_at, merged.get('some_branch').created_at)
80
+ # Assert the new branch is created_at within the last minute
81
+ assert(merged.get('some_new_branch').created_at > (Time.now - 60))
82
+ end
83
+
84
+ def test_reverse_merge_old_uses_new_status
85
+ @collection.mark_failure(old_branches['some_branch'])
86
+ merged = @collection.reverse_merge(Collection.from_hash(old_branches))
87
+
88
+ assert(merged.get('some_branch').fail?)
89
+ end
90
+
91
+ def test_fetch_returns_a_collection_instance
92
+ FakeBranches.branches.expect(:fetch, [])
93
+ collection = Collection.fetch({ 'class' => { 'name' => 'FakeBranches' }})
94
+ assert(collection.is_a?(Collection))
95
+ end
96
+
97
+ def test_add_to_merge_new_branch
98
+ @collection.add_to_merge('some_branch')
99
+ assert_equal(@collection.get('some_branch').ref, 'some_branch')
100
+ end
101
+
102
+ def test_add_to_merge_existing_branch
103
+ @collection.mark_failure(@branch)
104
+ @collection.add_to_merge(@branch.ref)
105
+
106
+ assert_equal(@collection.get(@branch.ref), @branch)
107
+ end
108
+
109
+ def test_add_to_merge_calls_branches_class
110
+ @fake_branches.expect(:add_to_merge, true, [@branch])
111
+ @collection.add_to_merge(@branch.ref)
112
+
113
+ @fake_branches.verify
114
+ end
115
+
116
+ def test_remove_from_merge_new_branch
117
+ @collection.remove_from_merge(@branch.ref)
118
+ assert(@collection.get(@branch.ref).removed?)
119
+ end
120
+
121
+ def test_remove_from_merge_existing_branch
122
+ @collection.mark_success(@branch)
123
+ assert(@collection.get(@branch.ref).success?)
124
+ @collection.remove_from_merge(@branch.ref)
125
+ assert(@collection.get(@branch.ref).removed?)
126
+ end
127
+
128
+ def test_remove_from_merge_calls_branches_class
129
+ @fake_branches.expect(:remove_from_merge, true, [@branch])
130
+ @collection.remove_from_merge(@branch.ref)
131
+ @fake_branches.verify
132
+ end
133
+
134
+ def test_mark_success_new_branch
135
+ @collection.mark_success(@branch)
136
+ assert(@collection.get(@branch.ref).success?)
137
+ end
138
+
139
+ def test_mark_success_existing_branch
140
+ branch = @collection.add_to_merge(@branch.ref)
141
+ @collection.mark_failure(branch)
142
+ @collection.mark_success(branch)
143
+ assert(@collection.get(@branch.ref).success?)
144
+ end
145
+
146
+ def test_mark_success_calls_branches_class
147
+ @fake_branches.expect(:mark_success, true, [@branch])
148
+ @collection.mark_success(@branch)
149
+ @fake_branches.verify
150
+ end
151
+
152
+ def test_mark_failure_existing_branch
153
+ branch = @collection.add_to_merge(@branch.ref)
154
+ @collection.mark_success(branch)
155
+ @collection.mark_failure(branch)
156
+ assert(@collection.get(@branch.ref).fail?)
157
+ end
158
+
159
+ def test_mark_failure_new_branch
160
+ @collection.mark_failure(@branch)
161
+ assert(@branch.fail?)
162
+ end
163
+
164
+ def test_mark_failure_calls_branches_class
165
+ @fake_branches.expect(:mark_failure, true, [@branch])
166
+ @collection.mark_failure(@branch)
167
+ @fake_branches.verify
168
+ end
169
+
170
+ def test_mark_deleted_new_branch
171
+ @collection.mark_deleted(@branch)
172
+ assert(@collection.get(@branch.ref).deleted?)
173
+ end
174
+
175
+ def test_mark_deleted_existing_branch
176
+ branch = @collection.add_to_merge(@branch.ref)
177
+ @collection.mark_failure(branch)
178
+ @collection.mark_deleted(branch)
179
+ assert(@collection.get(@branch.ref).deleted?)
180
+ end
181
+
182
+ def test_mark_deleted_calls_branches_class
183
+ @fake_branches.expect(:mark_deleted, true, [@branch])
184
+ @collection.mark_deleted(@branch)
185
+ @fake_branches.verify
186
+ end
187
+
188
+ def test_add_story
189
+ @collection.add_to_merge('some_branch')
190
+ @collection.add_story('some_branch', '999')
191
+ assert_equal(@collection.get('some_branch').stories, ['999'])
192
+ end
193
+
194
+ def test_add_story_calls_branches_class
195
+ @fake_branches.expect(:add_story, true, [@branch, '999'])
196
+ @collection.add_to_merge('some_branch')
197
+ @collection.add_story('some_branch', '999')
198
+ @fake_branches.verify
199
+ end
200
+
201
+ def test_code_reviewd_returns_true
202
+ collection = Collection.new({})
203
+ assert(collection.code_reviewed?(@branch))
204
+ end
205
+
206
+ def test_code_reviewd_calls_branches_class
207
+ @fake_branches.expect(:code_reviewed?, true, [@branch])
208
+ @collection.code_reviewed?(@branch)
209
+ @fake_branches.verify
210
+ end
211
+
212
+ def test_branch_link_returns_nil
213
+ collection = Collection.new({})
214
+ assert_nil(collection.branch_link(@branch))
215
+ end
216
+
217
+ def test_branch_link_calls_branches_class
218
+ @fake_branches.expect(:branch_link, 'http://link_to_branch.com', [@branch])
219
+ assert_equal('http://link_to_branch.com', @collection.branch_link(@branch))
220
+ @fake_branches.verify
221
+ end
222
+
223
+ def test_current_branches
224
+ branch1 = Branch.new('111')
225
+ branch2 = Branch.new('222')
226
+ branch3 = Branch.new('333')
227
+ branch2.current_record = true
228
+ @collection.mark_success(branch1)
229
+ @collection.mark_success(branch2)
230
+ @collection.mark_success(branch3)
231
+
232
+ assert_equal(@collection.current_branches, [branch2])
233
+ end
234
+
235
+ def test_mark_all_as_current
236
+ branch1 = Branch.new('111')
237
+ branch2 = Branch.new('222')
238
+ branch3 = Branch.new('333')
239
+ branch2.current_record = true
240
+ @collection.mark_success(branch1)
241
+ @collection.mark_success(branch2)
242
+ @collection.mark_success(branch3)
243
+
244
+ assert_equal(@collection.current_branches, [branch2])
245
+
246
+ @collection.mark_all_as_current
247
+
248
+ assert_equal(@collection.current_branches, [branch1, branch2, branch3])
249
+ end
250
+
251
+ def test_failures
252
+ mark_branches
253
+
254
+ assert_equal(@collection.failures, [fail1, fail2])
255
+ end
256
+
257
+ def test_successes
258
+ mark_branches
259
+
260
+ assert_equal(@collection.successes, [success1, success2])
261
+ end
262
+
263
+ def test_removals
264
+ mark_branches
265
+
266
+ assert_equal(@collection.removals, [removed1])
267
+ end
268
+
269
+ private
270
+
271
+ def mark_branches
272
+ @collection.mark_failure(fail1)
273
+ @collection.mark_success(success1)
274
+ @collection.mark_failure(fail2)
275
+ @removed1 = @collection.remove_from_merge(removed1.ref)
276
+ @collection.mark_success(success2)
277
+ @collection.mark_all_as_current
278
+ end
279
+
280
+ def fail1
281
+ @fail1 ||= Branch.new('111')
282
+ end
283
+
284
+ def fail2
285
+ @fail2 ||= Branch.new('333')
286
+ end
287
+
288
+ def success1
289
+ @success1 ||= Branch.new('222')
290
+ end
291
+
292
+ def success2
293
+ @success2 ||= Branch.new('555')
294
+ end
295
+
296
+ def removed1
297
+ @removed1 ||= Branch.new('444')
298
+ end
299
+
300
+ def old_branches
301
+ @old_branches ||= {
302
+ 'some_old_branch' => Branch.from_hash({'ref' => 'some_old_branch', 'created_at' => (Time.now - 3600), 'stories' => ['111']}),
303
+ 'some_branch' => Branch.from_hash({'ref' => 'some_branch', 'status' => 'success', 'created_at' => (Time.now - 1800), 'stories' => ['222']})
304
+ }
305
+ end
306
+ end
307
+ end
308
+ end