flash_flow 1.3.2.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +13 -8
- data/bin/flash_flow +4 -4
- data/flash_flow.gemspec +1 -0
- data/flash_flow.yml.erb.example +7 -0
- data/lib/flash_flow.rb +2 -2
- data/lib/flash_flow/config.rb +2 -1
- data/lib/flash_flow/data/base.rb +30 -14
- data/lib/flash_flow/git.rb +21 -12
- data/lib/flash_flow/issue_tracker.rb +1 -1
- data/lib/flash_flow/merge.rb +8 -0
- data/lib/flash_flow/merge/acceptance.rb +156 -0
- data/lib/flash_flow/merge/base.rb +81 -0
- data/lib/flash_flow/merge/master.rb +126 -0
- data/lib/flash_flow/{merge_master → merge}/merge_status.html.erb +0 -0
- data/lib/flash_flow/{merge_master → merge}/release_graph.rb +1 -1
- data/lib/flash_flow/{merge_master → merge}/status.rb +3 -3
- data/lib/flash_flow/merge_order.rb +1 -2
- data/lib/flash_flow/notifier/hipchat.rb +5 -7
- data/lib/flash_flow/release.rb +20 -0
- data/lib/flash_flow/release/percy_client.rb +67 -0
- data/lib/flash_flow/shadow_repo.rb +1 -0
- data/lib/flash_flow/version.rb +1 -1
- data/test/lib/merge/test_acceptance.rb +191 -0
- data/test/lib/{merge_master → merge}/test_release_graph.rb +2 -2
- data/test/lib/{merge_master → merge}/test_status.rb +4 -4
- data/test/lib/release/test_percy_client.rb +92 -0
- data/test/lib/test_merge_order.rb +1 -3
- metadata +33 -13
- data/lib/flash_flow/deploy.rb +0 -295
- data/lib/flash_flow/merge_master.rb +0 -6
- data/test/lib/test_deploy.rb +0 -186
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a41f62720b6a1d95aac60bc4275d5711b4ab82e3
|
4
|
+
data.tar.gz: 88ca498a5fef9fbec2d48bb12ea0c973123cf15f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d6d4dc8b130952e6c002af7d5f524f35464f2359e88b5c7b01cdae49f8fc63cb11a8c5e97b681c4be509ca9851a50d0040ff60129843c163e01ea1ee115b7ab
|
7
|
+
data.tar.gz: d6f2cf9bcd93e7cf2a169b138a3fadc56b9494702d4bd36a347e9fe9d2b6404022d05e92eb58d987ec53f84484e14f0b6cc11d900f60ab33e98b7a1012ae7492
|
data/Gemfile.lock
CHANGED
@@ -4,6 +4,7 @@ PATH
|
|
4
4
|
flash_flow (1.3.2.1)
|
5
5
|
hipchat (~> 1.5)
|
6
6
|
octokit (~> 4.1)
|
7
|
+
percy-client
|
7
8
|
pivotal-tracker (~> 0.5)
|
8
9
|
ruby-graphviz (> 0)
|
9
10
|
|
@@ -20,7 +21,7 @@ GEM
|
|
20
21
|
crack (0.4.3)
|
21
22
|
safe_yaml (~> 1.0.0)
|
22
23
|
debugger-linecache (1.2.0)
|
23
|
-
domain_name (0.5.
|
24
|
+
domain_name (0.5.20160615)
|
24
25
|
unf (>= 0.0.5, < 1.0.0)
|
25
26
|
faraday (0.9.2)
|
26
27
|
multipart-post (>= 1.2, < 3)
|
@@ -29,11 +30,12 @@ GEM
|
|
29
30
|
mimemagic
|
30
31
|
http-cookie (1.0.2)
|
31
32
|
domain_name (~> 0.5)
|
32
|
-
httparty (0.
|
33
|
-
json (~> 1.8)
|
33
|
+
httparty (0.14.0)
|
34
34
|
multi_xml (>= 0.5.2)
|
35
|
-
|
36
|
-
mime-types (
|
35
|
+
httpclient (2.8.0)
|
36
|
+
mime-types (3.1)
|
37
|
+
mime-types-data (~> 3.2015)
|
38
|
+
mime-types-data (3.2016.0521)
|
37
39
|
mimemagic (0.3.1)
|
38
40
|
mini_portile2 (2.1.0)
|
39
41
|
minitest (5.3.5)
|
@@ -48,6 +50,9 @@ GEM
|
|
48
50
|
nokogiri (~> 1.5)
|
49
51
|
octokit (4.3.0)
|
50
52
|
sawyer (~> 0.7.0, >= 0.5.3)
|
53
|
+
percy-client (1.6.0)
|
54
|
+
faraday (>= 0.9)
|
55
|
+
httpclient (>= 2.6)
|
51
56
|
pivotal-tracker (0.5.13)
|
52
57
|
builder
|
53
58
|
crack
|
@@ -56,10 +61,10 @@ GEM
|
|
56
61
|
rest-client (>= 1.8.0)
|
57
62
|
pkg-config (1.1.7)
|
58
63
|
rake (10.4.2)
|
59
|
-
rest-client (
|
64
|
+
rest-client (2.0.0)
|
60
65
|
http-cookie (>= 1.0.2, < 2.0)
|
61
|
-
mime-types (>= 1.16, <
|
62
|
-
netrc (~> 0.
|
66
|
+
mime-types (>= 1.16, < 4.0)
|
67
|
+
netrc (~> 0.8)
|
63
68
|
ruby-graphviz (1.2.2)
|
64
69
|
safe_yaml (1.0.4)
|
65
70
|
sawyer (0.7.0)
|
data/bin/flash_flow
CHANGED
@@ -25,12 +25,12 @@ case
|
|
25
25
|
when options[:resolve_manual]
|
26
26
|
FlashFlow::Resolve.new(FlashFlow::Config.configuration.git, FlashFlow::Config.configuration.branch_info_file, logger: FlashFlow::Config.configuration.logger).manual_instructions
|
27
27
|
when options[:merge_status]
|
28
|
-
FlashFlow::
|
28
|
+
FlashFlow::Merge::Status.new(FlashFlow::Config.configuration.issue_tracker, FlashFlow::Config.configuration.branches, FlashFlow::Config.configuration.branch_info_file, FlashFlow::Config.configuration.git, logger: FlashFlow::Config.configuration.logger).status
|
29
29
|
when options[:merge_status_html]
|
30
|
-
FlashFlow::
|
30
|
+
FlashFlow::Merge::Status.new(FlashFlow::Config.configuration.issue_tracker, FlashFlow::Config.configuration.branches, FlashFlow::Config.configuration.branch_info_file, FlashFlow::Config.configuration.git, logger: FlashFlow::Config.configuration.logger).status_html
|
31
31
|
when options[:release_branches]
|
32
|
-
FlashFlow::
|
32
|
+
FlashFlow::Merge::Master.new(options).run
|
33
33
|
else
|
34
|
-
FlashFlow::
|
34
|
+
FlashFlow::Merge::Acceptance.new(options).run
|
35
35
|
FlashFlow::IssueTracker::Base.new(FlashFlow::Config.configuration.issue_tracker).stories_pushed
|
36
36
|
end
|
data/flash_flow.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency 'hipchat', "~> 1.5"
|
22
22
|
spec.add_dependency 'pivotal-tracker', "~> 0.5"
|
23
23
|
spec.add_dependency 'ruby-graphviz', "> 0"
|
24
|
+
spec.add_dependency 'percy-client'
|
24
25
|
|
25
26
|
spec.add_development_dependency "bundler", "~> 1.6"
|
26
27
|
spec.add_development_dependency "rake", "> 0"
|
data/flash_flow.yml.erb.example
CHANGED
@@ -82,3 +82,10 @@ branch_info_file: 'your/random/file'
|
|
82
82
|
# unmergeable_label: unmergeable
|
83
83
|
# do_not_merge_label: 'do not merge'
|
84
84
|
# shippable_label: 'shippable'
|
85
|
+
|
86
|
+
#release:
|
87
|
+
# class:
|
88
|
+
# name: 'FlashFlow::Release::Percy'
|
89
|
+
# token: <%= ENV['PERCY_TOKEN'] %>
|
90
|
+
# repo: # Your github repo. For example, the flash_flow repo is 'flashfunders/flash_flow'
|
91
|
+
# api_url: 'https://percy.io/api/v1/'
|
data/lib/flash_flow.rb
CHANGED
@@ -3,7 +3,7 @@ module FlashFlow; end
|
|
3
3
|
require 'flash_flow/options'
|
4
4
|
require 'flash_flow/install'
|
5
5
|
require 'flash_flow/config'
|
6
|
-
require 'flash_flow/deploy'
|
7
6
|
require 'flash_flow/issue_tracker'
|
8
7
|
require 'flash_flow/resolve'
|
9
|
-
require 'flash_flow/
|
8
|
+
require 'flash_flow/merge'
|
9
|
+
require 'flash_flow/release'
|
data/lib/flash_flow/config.rb
CHANGED
@@ -16,7 +16,7 @@ module FlashFlow
|
|
16
16
|
end
|
17
17
|
|
18
18
|
ATTRIBUTES = [
|
19
|
-
:git, :branch_info_file, :log_file, :notifier, :issue_tracker, :lock, :branches
|
19
|
+
:git, :branch_info_file, :log_file, :notifier, :issue_tracker, :lock, :branches, :release
|
20
20
|
]
|
21
21
|
|
22
22
|
attr_reader *ATTRIBUTES
|
@@ -55,6 +55,7 @@ module FlashFlow
|
|
55
55
|
issue_tracker: nil,
|
56
56
|
lock: nil,
|
57
57
|
branches: nil,
|
58
|
+
release: nil
|
58
59
|
}
|
59
60
|
end
|
60
61
|
|
data/lib/flash_flow/data/base.rb
CHANGED
@@ -13,6 +13,8 @@ module FlashFlow
|
|
13
13
|
:remove_from_merge, :add_to_merge, :failures, :successes, :removals, :set_resolutions,
|
14
14
|
:to_a, :code_reviewed?, :branch_link
|
15
15
|
|
16
|
+
attr_reader :collection
|
17
|
+
|
16
18
|
def initialize(branch_config, filename, git, opts={})
|
17
19
|
@git = git
|
18
20
|
@store = Store.new(filename, git, opts)
|
@@ -20,14 +22,23 @@ module FlashFlow
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def initialize_collection(branch_config, remotes)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
stored_collection = Collection.from_hash(remotes, stored_branches)
|
26
|
+
|
27
|
+
if ! branch_config.empty?
|
28
|
+
collection = Collection.fetch(remotes, branch_config)
|
29
|
+
# Order matters. We are marking the PRs as current, not the branches stored in the json
|
30
|
+
collection.mark_all_as_current
|
31
|
+
collection.reverse_merge(stored_collection)
|
32
|
+
|
33
|
+
else
|
34
|
+
collection = stored_collection
|
35
|
+
collection.mark_all_as_current
|
36
|
+
collection
|
37
|
+
end
|
27
38
|
end
|
28
39
|
|
29
40
|
def version
|
30
|
-
|
41
|
+
stored_data['version']
|
31
42
|
end
|
32
43
|
|
33
44
|
def save!
|
@@ -37,24 +48,29 @@ module FlashFlow
|
|
37
48
|
def to_hash
|
38
49
|
{
|
39
50
|
'version' => FlashFlow::VERSION,
|
40
|
-
'branches' =>
|
51
|
+
'branches' => @collection.to_hash,
|
52
|
+
'releases' => releases
|
41
53
|
}
|
42
54
|
end
|
43
55
|
|
44
|
-
def
|
45
|
-
@
|
56
|
+
def stored_branches
|
57
|
+
@stored_branches ||= stored_data['branches'] || {}
|
46
58
|
end
|
47
59
|
|
48
|
-
def
|
49
|
-
@
|
50
|
-
|
60
|
+
def releases
|
61
|
+
@releases ||= stored_data['releases'] || []
|
62
|
+
end
|
51
63
|
|
52
|
-
|
53
|
-
|
64
|
+
def merged_branches
|
65
|
+
@collection.reverse_merge(Collection.from_hash({}, stored_branches))
|
66
|
+
end
|
67
|
+
|
68
|
+
def stored_data
|
69
|
+
@stored_data ||= @store.get
|
54
70
|
end
|
55
71
|
|
56
72
|
def saved_branches
|
57
|
-
Collection.from_hash(@git.remotes,
|
73
|
+
Collection.from_hash(@git.remotes, stored_branches).to_a
|
58
74
|
end
|
59
75
|
end
|
60
76
|
end
|
data/lib/flash_flow/git.rb
CHANGED
@@ -63,9 +63,13 @@ module FlashFlow
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
def
|
66
|
+
def branch_contains?(branch, ref)
|
67
67
|
run("branch --contains #{ref}", log: CmdRunner::LOG_CMD)
|
68
|
-
last_stdout.split("\n").detect { |str| str[2..-1] ==
|
68
|
+
last_stdout.split("\n").detect { |str| str[2..-1] == branch }
|
69
|
+
end
|
70
|
+
|
71
|
+
def master_branch_contains?(ref)
|
72
|
+
branch_contains?(master_branch, ref)
|
69
73
|
end
|
70
74
|
|
71
75
|
def in_original_merge_branch
|
@@ -197,7 +201,7 @@ module FlashFlow
|
|
197
201
|
run("push #{'-f' if force} #{merge_remote} #{branch}")
|
198
202
|
end
|
199
203
|
|
200
|
-
def
|
204
|
+
def copy_temp_to_branch(branch, squash_message = nil)
|
201
205
|
run("checkout #{temp_merge_branch}")
|
202
206
|
run("merge --strategy=ours --no-edit #{branch}")
|
203
207
|
run("checkout #{branch}")
|
@@ -232,6 +236,20 @@ module FlashFlow
|
|
232
236
|
end
|
233
237
|
end
|
234
238
|
|
239
|
+
def temp_merge_branch
|
240
|
+
"flash_flow/#{merge_branch}"
|
241
|
+
end
|
242
|
+
|
243
|
+
def get_sha(branch)
|
244
|
+
run("rev-parse #{branch}")
|
245
|
+
last_stdout.strip if last_success?
|
246
|
+
end
|
247
|
+
|
248
|
+
def branch_exists?(branch)
|
249
|
+
run("rev-parse --verify #{branch}")
|
250
|
+
last_success?
|
251
|
+
end
|
252
|
+
|
235
253
|
private
|
236
254
|
|
237
255
|
def squash_commits(branch, commit_message)
|
@@ -249,14 +267,5 @@ module FlashFlow
|
|
249
267
|
run("commit -m '#{commit_message}'")
|
250
268
|
end
|
251
269
|
|
252
|
-
def branch_exists?(branch)
|
253
|
-
run("rev-parse --verify #{branch}")
|
254
|
-
last_success?
|
255
|
-
end
|
256
|
-
|
257
|
-
def temp_merge_branch
|
258
|
-
"flash_flow/#{merge_branch}"
|
259
|
-
end
|
260
|
-
|
261
270
|
end
|
262
271
|
end
|
@@ -59,7 +59,7 @@ module FlashFlow
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def get_branches
|
62
|
-
branch_info_store = Data::Base.new(
|
62
|
+
branch_info_store = Data::Base.new({}, Config.configuration.branch_info_file, git, logger: Config.configuration.logger)
|
63
63
|
|
64
64
|
branch_info_store.saved_branches
|
65
65
|
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'flash_flow/merge/base'
|
2
|
+
|
3
|
+
module FlashFlow
|
4
|
+
module Merge
|
5
|
+
class Acceptance < Base
|
6
|
+
|
7
|
+
def initialize(opts={})
|
8
|
+
super(opts)
|
9
|
+
|
10
|
+
@data = Data::Base.new(Config.configuration.branches, Config.configuration.branch_info_file, @git, logger: logger)
|
11
|
+
|
12
|
+
@do_not_merge = opts[:do_not_merge]
|
13
|
+
@force = opts[:force]
|
14
|
+
@rerere_forget = opts[:rerere_forget]
|
15
|
+
@stories = [opts[:stories]].flatten.compact
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
check_version
|
20
|
+
check_repo
|
21
|
+
puts "Building #{@local_git.merge_branch}... Log can be found in #{FlashFlow::Config.configuration.log_file}"
|
22
|
+
logger.info "\n\n### Beginning #{@local_git.merge_branch} merge ###\n\n"
|
23
|
+
|
24
|
+
begin
|
25
|
+
open_pull_request
|
26
|
+
|
27
|
+
@lock.with_lock do
|
28
|
+
@git.fetch(@git.merge_remote)
|
29
|
+
@git.in_original_merge_branch do
|
30
|
+
@git.initialize_rerere
|
31
|
+
end
|
32
|
+
|
33
|
+
@git.reset_temp_merge_branch
|
34
|
+
@git.in_temp_merge_branch do
|
35
|
+
merge_branches(@data.mergeable) do |branch, merger|
|
36
|
+
process_result(branch, merger)
|
37
|
+
end
|
38
|
+
commit_branch_info
|
39
|
+
commit_rerere
|
40
|
+
end
|
41
|
+
|
42
|
+
@git.copy_temp_to_branch(@git.merge_branch, commit_message)
|
43
|
+
@git.delete_temp_merge_branch
|
44
|
+
@git.push(@git.merge_branch, true)
|
45
|
+
end
|
46
|
+
|
47
|
+
print_errors
|
48
|
+
logger.info "### Finished #{@local_git.merge_branch} merge ###"
|
49
|
+
rescue Lock::Error, OutOfSyncWithRemote => e
|
50
|
+
puts 'Failure!'
|
51
|
+
puts e.message
|
52
|
+
ensure
|
53
|
+
@local_git.run("checkout #{@local_git.working_branch}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def commit_branch_info
|
58
|
+
@stories.each do |story_id|
|
59
|
+
@data.add_story(@git.merge_remote, @git.working_branch, story_id)
|
60
|
+
end
|
61
|
+
@data.save!
|
62
|
+
end
|
63
|
+
|
64
|
+
def commit_rerere
|
65
|
+
current_branches = @data.to_a.select { |branch| !@git.master_branch_contains?(branch.sha) && (Time.now - branch.updated_at < two_weeks) }
|
66
|
+
current_rereres = current_branches.map { |branch| branch.resolutions.to_h.values }.flatten
|
67
|
+
|
68
|
+
@git.commit_rerere(current_rereres)
|
69
|
+
end
|
70
|
+
|
71
|
+
def two_weeks
|
72
|
+
60 * 60 * 24 * 14
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_result(branch, merger)
|
76
|
+
case merger.result
|
77
|
+
when :deleted
|
78
|
+
@data.mark_deleted(branch)
|
79
|
+
@notifier.deleted_branch(branch) unless is_working_branch(branch)
|
80
|
+
|
81
|
+
when :success
|
82
|
+
branch.sha = merger.sha
|
83
|
+
@data.mark_success(branch)
|
84
|
+
@data.set_resolutions(branch, merger.resolutions)
|
85
|
+
|
86
|
+
when :conflict
|
87
|
+
if is_working_branch(branch)
|
88
|
+
@data.mark_failure(branch, merger.conflict_sha)
|
89
|
+
else
|
90
|
+
@data.mark_failure(branch, nil)
|
91
|
+
@notifier.merge_conflict(branch)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def is_working_branch(branch)
|
97
|
+
branch.ref == @git.working_branch
|
98
|
+
end
|
99
|
+
|
100
|
+
def open_pull_request
|
101
|
+
return false if [@local_git.master_branch, @local_git.merge_branch].include?(@local_git.working_branch)
|
102
|
+
|
103
|
+
# TODO - This should use the actual remote for the branch we're on
|
104
|
+
@local_git.push(@local_git.working_branch, @force)
|
105
|
+
raise OutOfSyncWithRemote.new("Your branch is out of sync with the remote. If you want to force push, run 'flash_flow -f'") unless @local_git.last_success?
|
106
|
+
|
107
|
+
# TODO - This should use the actual remote for the branch we're on
|
108
|
+
if @do_not_merge
|
109
|
+
@data.remove_from_merge(@local_git.merge_remote, @local_git.working_branch)
|
110
|
+
else
|
111
|
+
@data.add_to_merge(@local_git.merge_remote, @local_git.working_branch)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def print_errors
|
116
|
+
puts format_errors
|
117
|
+
end
|
118
|
+
|
119
|
+
def format_errors
|
120
|
+
errors = []
|
121
|
+
branch_not_merged = nil
|
122
|
+
@data.failures.each do |branch|
|
123
|
+
if branch.ref == @local_git.working_branch
|
124
|
+
branch_not_merged = "ERROR: Your branch did not merge to #{@local_git.merge_branch}. Run 'flash_flow --resolve', fix the merge conflict(s) and then re-run this script\n"
|
125
|
+
else
|
126
|
+
errors << "WARNING: Unable to merge branch #{branch.remote}/#{branch.ref} to #{@local_git.merge_branch} due to conflicts."
|
127
|
+
end
|
128
|
+
end
|
129
|
+
errors << branch_not_merged if branch_not_merged
|
130
|
+
|
131
|
+
if errors.empty?
|
132
|
+
"Success!"
|
133
|
+
else
|
134
|
+
errors.join("\n")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def commit_message
|
139
|
+
message =<<-EOS
|
140
|
+
Flash Flow run from branch: #{@local_git.working_branch}
|
141
|
+
|
142
|
+
Merged branches:
|
143
|
+
#{@data.successes.empty? ? 'None' : @data.successes.sort_by(&:merge_order).map(&:ref).join("\n")}
|
144
|
+
|
145
|
+
Failed branches:
|
146
|
+
#{@data.failures.empty? ? 'None' : @data.failures.map(&:ref).join("\n")}
|
147
|
+
|
148
|
+
Removed branches:
|
149
|
+
#{@data.removals.empty? ? 'None' : @data.removals.map(&:ref).join("\n")}
|
150
|
+
EOS
|
151
|
+
message.gsub(/'/, '')
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|