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