git_reflow 0.7.5 → 0.8.0
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 +4 -4
- data/.gitignore +1 -0
- data/Appraisals +2 -2
- data/CHANGELOG.md +75 -0
- data/Gemfile.lock +34 -35
- data/README.rdoc +187 -60
- data/circle.yml +9 -9
- data/git_reflow.gemspec +8 -8
- data/lib/git_reflow/commands/deliver.rb +1 -9
- data/lib/git_reflow/commands/refresh.rb +23 -0
- data/lib/git_reflow/commands/review.rb +7 -7
- data/lib/git_reflow/commands/setup.rb +7 -3
- data/lib/git_reflow/commands/start.rb +13 -5
- data/lib/git_reflow/git_helpers.rb +22 -23
- data/lib/git_reflow/git_server/bit_bucket/pull_request.rb +4 -4
- data/lib/git_reflow/git_server/bit_bucket.rb +7 -7
- data/lib/git_reflow/git_server/git_hub/pull_request.rb +75 -2
- data/lib/git_reflow/git_server/git_hub.rb +17 -8
- data/lib/git_reflow/git_server/pull_request.rb +73 -5
- data/lib/git_reflow/git_server.rb +3 -3
- data/lib/git_reflow/merge_error.rb +9 -0
- data/lib/git_reflow/sandbox.rb +4 -16
- data/lib/git_reflow/version.rb +1 -1
- data/lib/git_reflow.rb +32 -75
- data/spec/git_reflow_spec.rb +157 -141
- data/spec/lgtm_git_reflow_spec.rb +165 -139
- data/spec/lib/git_reflow/git_helpers_spec.rb +19 -63
- data/spec/lib/git_reflow/git_server_spec.rb +24 -24
- data/spec/lib/git_server/bit_bucket_spec.rb +12 -12
- data/spec/lib/git_server/git_hub/pull_request_spec.rb +7 -5
- data/spec/lib/git_server/git_hub_spec.rb +34 -34
- data/spec/lib/git_server/pull_request_spec.rb +207 -16
- data/spec/support/command_line_helpers.rb +14 -9
- data/spec/support/github_helpers.rb +21 -21
- data/spec/support/rspec_stub_helpers.rb +2 -2
- metadata +18 -16
data/git_reflow.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ensure we require the local version and not one we might have installed already
|
2
2
|
require File.join([File.dirname(__FILE__),'lib','git_reflow/version.rb'])
|
3
|
-
|
3
|
+
Gem::Specification.new do |s|
|
4
4
|
s.name = 'git_reflow'
|
5
5
|
s.version = GitReflow::VERSION
|
6
6
|
s.license = 'MIT'
|
@@ -19,21 +19,21 @@ spec = Gem::Specification.new do |s|
|
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
s.rdoc_options << '--title' << 'git_reflow' << '--main' << 'README.rdoc' << '-ri'
|
21
21
|
|
22
|
-
s.add_development_dependency('appraisal', '1.0
|
23
|
-
s.add_development_dependency('bundler', "~> 1.
|
22
|
+
s.add_development_dependency('appraisal', '2.1.0')
|
23
|
+
s.add_development_dependency('bundler', "~> 1.12")
|
24
24
|
s.add_development_dependency('chronic')
|
25
25
|
s.add_development_dependency('pry-byebug')
|
26
|
-
s.add_development_dependency('rake', "~>
|
26
|
+
s.add_development_dependency('rake', "~> 11.0")
|
27
27
|
s.add_development_dependency('rdoc')
|
28
|
-
s.add_development_dependency('rspec', "~> 3.0")
|
28
|
+
s.add_development_dependency('rspec', "~> 3.4.0")
|
29
29
|
s.add_development_dependency('webmock')
|
30
|
-
s.add_development_dependency('wwtd', '
|
30
|
+
s.add_development_dependency('wwtd', '1.3.0')
|
31
31
|
|
32
32
|
s.add_dependency('colorize', '>= 0.7.0')
|
33
|
-
s.add_dependency('gli', '2.
|
33
|
+
s.add_dependency('gli', '2.14.0')
|
34
34
|
s.add_dependency('highline')
|
35
35
|
s.add_dependency('httpclient')
|
36
|
-
s.add_dependency('github_api', '0.
|
36
|
+
s.add_dependency('github_api', '0.14.0')
|
37
37
|
s.add_dependency('reenhanced_bitbucket_api', '0.3.2')
|
38
38
|
|
39
39
|
s.post_install_message = "You need to setup your GitHub OAuth token\nPlease run 'git-reflow setup'"
|
@@ -3,17 +3,9 @@ long_desc 'merge your feature branch down to your base branch, and cleanup your
|
|
3
3
|
|
4
4
|
command :deliver do |c|
|
5
5
|
c.desc 'merge your feature branch down to your base branch, and cleanup your feature branch'
|
6
|
-
c.arg_name 'base_branch - the branch you want to merge into'
|
7
6
|
c.switch [:f, :'skip-lgtm'], desc: 'skip the lgtm checks and deliver your feature branch'
|
8
7
|
c.action do |global_options,options,args|
|
9
|
-
deliver_options = {
|
10
|
-
case args.length
|
11
|
-
when 2
|
12
|
-
deliver_options['base'] = args[0]
|
13
|
-
deliver_options['head'] = args[1]
|
14
|
-
when 1
|
15
|
-
deliver_options['base'] = args[0]
|
16
|
-
end
|
8
|
+
deliver_options = {:skip_lgtm => options[:'skip-lgtm']}
|
17
9
|
GitReflow.deliver deliver_options
|
18
10
|
end
|
19
11
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
desc 'Updates and synchronizes your base branch and feature branch.'
|
2
|
+
long_desc <<LONGTIME
|
3
|
+
Performs the following:\n
|
4
|
+
\t$ git checkout <base_branch>\n
|
5
|
+
\t$ git pull <remote_location> <base_branch>\n
|
6
|
+
\t$ git checkout <current_branch>\n
|
7
|
+
\t$ git pull origin <current_branch>\n
|
8
|
+
\t$ git merge <base_branch>\n
|
9
|
+
LONGTIME
|
10
|
+
arg_name '[remote_location] - remote repository name to fetch updates from (origin by default), [base_branch] - branch that you want to merge with (master by default)'
|
11
|
+
command :refresh do |c|
|
12
|
+
c.desc 'updates base_branch based on remote and merges the base with your feature_branch'
|
13
|
+
c.flag [:r,:remote], default_value: 'origin'
|
14
|
+
c.flag [:b,:base], default_value: 'master'
|
15
|
+
c.action do |global_options, options, args|
|
16
|
+
refresh_options = {
|
17
|
+
:remote => options[:remote],
|
18
|
+
:base => options[:base]
|
19
|
+
}
|
20
|
+
|
21
|
+
GitReflow.update_feature_branch(refresh_options)
|
22
|
+
end
|
23
|
+
end
|
@@ -3,17 +3,17 @@ arg_name 'Describe arguments to review here'
|
|
3
3
|
command :review do |c|
|
4
4
|
c.desc 'push your latest feature branch changes to your remote repo and create a pull request against the destination branch'
|
5
5
|
c.arg_name '[destination_branch] - the branch you want to merge your feature branch into'
|
6
|
-
c.flag [:t, :title]
|
7
|
-
c.flag [:m, :message]
|
6
|
+
c.flag [:t, :title]
|
7
|
+
c.flag [:m, :message]
|
8
8
|
c.action do |global_options,options,args|
|
9
|
-
if
|
9
|
+
if options[:title] || options[:message]
|
10
10
|
review_options = {
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
:base => args[0],
|
12
|
+
:title => options[:title],
|
13
|
+
:body => options[:message]
|
14
14
|
}
|
15
15
|
else
|
16
|
-
review_options = {
|
16
|
+
review_options = { :base => args[0] }
|
17
17
|
end
|
18
18
|
|
19
19
|
GitReflow.review(review_options)
|
@@ -22,8 +22,12 @@ command :setup do |c|
|
|
22
22
|
menu.choice('BitBucket (team-owned repos only)') { GitReflow::GitServer.connect reflow_options.merge({ provider: 'BitBucket', silent: false }) }
|
23
23
|
end
|
24
24
|
|
25
|
-
GitReflow::Config.
|
26
|
-
GitReflow::Config.
|
27
|
-
|
25
|
+
GitReflow::Config.set "constants.minimumApprovals", ask("Set the minimum number of approvals (leaving blank will require approval from all commenters): "), local: reflow_options[:project_only]
|
26
|
+
GitReflow::Config.set "constants.approvalRegex", GitReflow::GitServer::PullRequest::DEFAULT_APPROVAL_REGEX.to_s, local: reflow_options[:project_only]
|
27
|
+
|
28
|
+
if GitReflow::Config.get('core.editor').length <= 0
|
29
|
+
GitReflow::Config.set('core.editor', GitReflow::DEFAULT_EDITOR, local: reflow_options[:project_only])
|
30
|
+
GitReflow.say "Updated git's editor (via git config key 'core.editor') to: #{GitReflow::DEFAULT_EDITOR}.", :notice
|
31
|
+
end
|
28
32
|
end
|
29
33
|
end
|
@@ -1,19 +1,27 @@
|
|
1
|
+
|
1
2
|
desc 'Start will create a new feature branch and setup remote tracking'
|
2
3
|
long_desc <<LONGTIME
|
3
4
|
Performs the following:\n
|
4
|
-
\t$ git
|
5
|
-
\t$ git
|
5
|
+
\t$ git checkout <base_branch>\n
|
6
|
+
\t$ git pull origin <base_branch>\n
|
7
|
+
\t$ git push origin <base_branch>:refs/heads/[new_feature_branch]\n
|
6
8
|
\t$ git checkout --track -b [new_feature_branch] origin/[new_feature_branch]\n
|
7
9
|
LONGTIME
|
8
10
|
arg_name '[new-feature-branch-name] - name of the new feature branch'
|
9
11
|
command :start do |c|
|
12
|
+
c.flag [:b,:base], default_value: 'master'
|
10
13
|
c.action do |global_options, options, args|
|
11
14
|
if args.empty?
|
12
15
|
raise "usage: git-reflow start [new-branch-name]"
|
13
16
|
else
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
# base_branch is the branch that you want to base your feature branch off of
|
18
|
+
# This command allows you to 'git reflow start' off your base branch
|
19
|
+
base_branch = options[:base]
|
20
|
+
|
21
|
+
GitReflow.run_command_with_label "git checkout #{base_branch}"
|
22
|
+
GitReflow.run_command_with_label "git pull origin #{base_branch}"
|
23
|
+
GitReflow.run_command_with_label "git push origin #{GitReflow.current_branch}:refs/heads/#{args[0]}"
|
24
|
+
GitReflow.run_command_with_label "git checkout --track -b #{args[0]} origin/#{args[0]}"
|
17
25
|
end
|
18
26
|
end
|
19
27
|
end
|
@@ -9,6 +9,10 @@ module GitReflow
|
|
9
9
|
@git_root_dir ||= run('git rev-parse --show-toplevel', loud: false).strip
|
10
10
|
end
|
11
11
|
|
12
|
+
def git_editor_command
|
13
|
+
@git_editor_comand ||= GitReflow::Config.get('core.editor')
|
14
|
+
end
|
15
|
+
|
12
16
|
def remote_user
|
13
17
|
return "" unless "#{GitReflow::Config.get('remote.origin.url')}".length > 0
|
14
18
|
extract_remote_user_and_repo_from_remote_url(GitReflow::Config.get('remote.origin.url'))[:user]
|
@@ -27,43 +31,38 @@ module GitReflow
|
|
27
31
|
run('git log --pretty=format:"%s" --no-merges -n 1', loud: false).strip
|
28
32
|
end
|
29
33
|
|
30
|
-
def push_current_branch
|
31
|
-
|
34
|
+
def push_current_branch(options = {})
|
35
|
+
remote = options[:remote] || "origin"
|
36
|
+
run_command_with_label "git push #{remote} #{current_branch}"
|
32
37
|
end
|
33
38
|
|
34
|
-
def update_current_branch
|
35
|
-
|
36
|
-
|
39
|
+
def update_current_branch(options = {})
|
40
|
+
remote = options[:remote] || "origin"
|
41
|
+
run_command_with_label "git pull #{remote} #{current_branch}"
|
42
|
+
push_current_branch(options)
|
37
43
|
end
|
38
44
|
|
39
45
|
def fetch_destination(destination_branch)
|
40
46
|
run_command_with_label "git fetch origin #{destination_branch}"
|
41
47
|
end
|
42
48
|
|
43
|
-
def update_destination(destination_branch)
|
49
|
+
def update_destination(destination_branch, options = {})
|
44
50
|
origin_branch = current_branch
|
51
|
+
remote = options[:remote] || 'origin'
|
45
52
|
run_command_with_label "git checkout #{destination_branch}"
|
46
|
-
run_command_with_label "git pull
|
53
|
+
run_command_with_label "git pull #{remote} #{destination_branch}"
|
47
54
|
run_command_with_label "git checkout #{origin_branch}"
|
48
55
|
end
|
49
56
|
|
50
|
-
def
|
51
|
-
options[:
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if "#{options[:pull_request_number]}".length > 0
|
56
|
-
message << "\nCloses ##{options[:pull_request_number]}\n"
|
57
|
-
end
|
58
|
-
|
59
|
-
if lgtm_authors = Array(options[:lgtm_authors]) and lgtm_authors.any?
|
60
|
-
message << "\nLGTM given by: @#{lgtm_authors.join(', @')}\n"
|
61
|
-
end
|
57
|
+
def update_feature_branch(options = {})
|
58
|
+
base_branch = options[:base]
|
59
|
+
remote = options[:remote]
|
60
|
+
update_destination(base_branch, options)
|
62
61
|
|
63
|
-
|
64
|
-
run_command_with_label "git
|
65
|
-
|
66
|
-
|
62
|
+
# update feature branch in case there are multiple authors and remote changes
|
63
|
+
run_command_with_label "git pull origin #{current_branch}"
|
64
|
+
# rebase on base branch
|
65
|
+
run_command_with_label "git merge #{base_branch}"
|
67
66
|
end
|
68
67
|
|
69
68
|
def append_to_squashed_commit_message(message = '')
|
@@ -6,10 +6,10 @@ module GitReflow
|
|
6
6
|
class PullRequest < GitReflow::GitServer::PullRequest
|
7
7
|
def initialize(attributes)
|
8
8
|
self.number = attributes.id
|
9
|
-
self.description = attributes.description
|
9
|
+
self.description = attributes.body || attributes.description
|
10
10
|
self.html_url = "#{attributes.source.repository.links.html.href}/pull-request/#{self.number}"
|
11
|
-
self.feature_branch_name = attributes.source.branch.name
|
12
|
-
self.base_branch_name = attributes.destination.branch.name
|
11
|
+
self.feature_branch_name = attributes.source.branch.name[/[^:]+$/]
|
12
|
+
self.base_branch_name = attributes.destination.branch.name[/[^:]+$/]
|
13
13
|
self.build_status = nil
|
14
14
|
self.source_object = attributes
|
15
15
|
end
|
@@ -19,7 +19,7 @@ module GitReflow
|
|
19
19
|
GitReflow.git_server.class.remote_user,
|
20
20
|
GitReflow.git_server.class.remote_repo_name,
|
21
21
|
title: options[:title],
|
22
|
-
|
22
|
+
description: options[:body] || options[:description],
|
23
23
|
source: {
|
24
24
|
branch: { name: GitReflow.git_server.class.current_branch },
|
25
25
|
repository: { full_name: "#{GitReflow.git_server.class.remote_user}/#{GitReflow.git_server.class.remote_repo_name}" }
|
@@ -56,21 +56,21 @@ module GitReflow
|
|
56
56
|
begin
|
57
57
|
if connection and self.class.api_key_setup?
|
58
58
|
unless options[:silent]
|
59
|
-
|
60
|
-
|
59
|
+
GitReflow.say "\nYour BitBucket account was already setup with:"
|
60
|
+
GitReflow.say "\tUser Name: #{self.class.user}"
|
61
61
|
end
|
62
62
|
else
|
63
63
|
self.class.user = options[:user] || ask("Please enter your BitBucket username: ")
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
GitReflow.say "\nIn order to connect your BitBucket account,"
|
65
|
+
GitReflow.say "you'll need to generate an API key for your team"
|
66
|
+
GitReflow.say "Visit #{self.class.site_url}/account/user/#{self.class.remote_user}/api-key/, to generate it\n"
|
67
67
|
self.class.api_key = ask("Please enter your team's API key: ")
|
68
68
|
connection.repos.all(self.class.remote_user).count
|
69
|
-
|
69
|
+
GitReflow.say "Connected to BitBucket\!", :success
|
70
70
|
end
|
71
71
|
rescue ::BitBucket::Error::Unauthorized => e
|
72
72
|
GitReflow::Config.unset('bitbucket.api-key', local: self.class.project_only?)
|
73
|
-
|
73
|
+
GitReflow.say "Invalid API key for team #{self.class.remote_user}.", :error
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -8,8 +8,8 @@ module GitReflow
|
|
8
8
|
self.number = attributes.number
|
9
9
|
self.description = attributes[:body]
|
10
10
|
self.html_url = attributes.html_url
|
11
|
-
self.feature_branch_name = attributes.head.label
|
12
|
-
self.base_branch_name = attributes.base.label
|
11
|
+
self.feature_branch_name = attributes.head.label[/[^:]+$/]
|
12
|
+
self.base_branch_name = attributes.base.label[/[^:]+$/]
|
13
13
|
self.source_object = attributes
|
14
14
|
self.build_status = build.state
|
15
15
|
end
|
@@ -78,6 +78,79 @@ module GitReflow
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
+
def merge!(options = {})
|
82
|
+
|
83
|
+
# fallback to default merge process if user "forces" merge
|
84
|
+
if(options[:skip_lgtm])
|
85
|
+
super options
|
86
|
+
else
|
87
|
+
if deliver?
|
88
|
+
GitReflow.say "Merging pull request ##{self.number}: '#{self.title}', from '#{self.feature_branch_name}' into '#{self.base_branch_name}'", :notice
|
89
|
+
|
90
|
+
unless options[:title] || options[:message]
|
91
|
+
# prompts user for commit_title and commit_message
|
92
|
+
squash_merge_message_file = "#{GitReflow.git_root_dir}/.git/SQUASH_MSG"
|
93
|
+
|
94
|
+
File.open(squash_merge_message_file, 'w') do |file|
|
95
|
+
file.write("#{self.title}\n#{self.commit_message_for_merge}\n")
|
96
|
+
end
|
97
|
+
|
98
|
+
GitReflow.run("#{GitReflow.git_editor_command} #{squash_merge_message_file}", with_system: true)
|
99
|
+
merge_message = File.read(squash_merge_message_file).split(/[\r\n]|\r\n/).map(&:strip)
|
100
|
+
|
101
|
+
title = merge_message.shift
|
102
|
+
|
103
|
+
File.delete(squash_merge_message_file)
|
104
|
+
|
105
|
+
unless merge_message.empty?
|
106
|
+
merge_message.shift if merge_message.first.empty?
|
107
|
+
end
|
108
|
+
|
109
|
+
options[:title] = title
|
110
|
+
options[:body] = "#{merge_message.join("\n")}\n"
|
111
|
+
|
112
|
+
GitReflow.say "\nReview your merge commit message:\n"
|
113
|
+
GitReflow.say "--------\n"
|
114
|
+
GitReflow.say "Title:\n#{options[:title]}\n\n"
|
115
|
+
GitReflow.say "Body:\n#{options[:body]}\n"
|
116
|
+
GitReflow.say "--------\n"
|
117
|
+
end
|
118
|
+
|
119
|
+
merge_response = GitReflow::GitServer::GitHub.connection.pull_requests.merge(
|
120
|
+
"#{GitReflow.git_server.class.remote_user}",
|
121
|
+
"#{GitReflow.git_server.class.remote_repo_name}",
|
122
|
+
"#{self.number}",
|
123
|
+
{
|
124
|
+
"commit_title" => "#{options[:title]}",
|
125
|
+
"commit_message" => "#{options[:body]}",
|
126
|
+
"sha" => "#{self.head.sha}",
|
127
|
+
"squash" => true
|
128
|
+
}
|
129
|
+
)
|
130
|
+
|
131
|
+
if merge_response.success?
|
132
|
+
GitReflow.run_command_with_label "git checkout #{self.base_branch_name}"
|
133
|
+
# Pulls merged changes from remote base_branch
|
134
|
+
GitReflow.run_command_with_label "git pull origin #{self.base_branch_name}"
|
135
|
+
GitReflow.say "Pull request ##{self.number} successfully merged.", :success
|
136
|
+
|
137
|
+
if cleanup_feature_branch?
|
138
|
+
GitReflow.run_command_with_label "git push origin :#{self.feature_branch_name}"
|
139
|
+
GitReflow.run_command_with_label "git branch -D #{self.feature_branch_name}"
|
140
|
+
GitReflow.say "Nice job buddy."
|
141
|
+
else
|
142
|
+
cleanup_failure_message
|
143
|
+
end
|
144
|
+
else
|
145
|
+
GitReflow.say merge_response.to_s, :deliver_halted
|
146
|
+
GitReflow.say "There were problems commiting your feature... please check the errors above and try again.", :error
|
147
|
+
end
|
148
|
+
else
|
149
|
+
GitReflow.say "Merge aborted", :deliver_halted
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
81
154
|
def build
|
82
155
|
github_build_status = GitReflow.git_server.get_build_status(self.head.sha)
|
83
156
|
build_status_object = Struct.new(:state, :description, :url)
|
@@ -86,9 +86,9 @@ module GitReflow
|
|
86
86
|
def authenticate(options = {silent: false})
|
87
87
|
if connection and self.class.oauth_token.length > 0
|
88
88
|
unless options[:silent]
|
89
|
-
|
90
|
-
|
91
|
-
|
89
|
+
GitReflow.say "Your GitHub account was already setup with: "
|
90
|
+
GitReflow.say "\tUser Name: #{self.class.user}"
|
91
|
+
GitReflow.say "\tEndpoint: #{self.class.api_endpoint}"
|
92
92
|
end
|
93
93
|
else
|
94
94
|
begin
|
@@ -107,6 +107,9 @@ module GitReflow
|
|
107
107
|
previous_authorizations = @connection.oauth.all.select {|auth| auth.note == "git-reflow (#{run('hostname', loud: false).strip})" }
|
108
108
|
if previous_authorizations.any?
|
109
109
|
authorization = previous_authorizations.last
|
110
|
+
GitReflow.say "You have previously setup git-reflow on this machine, but we can no longer find the stored token.", :error
|
111
|
+
GitReflow.say "Please visit https://github.com/settings/tokens and delete the token for: git-reflow (#{run('hostname', loud: false).strip})", :notice
|
112
|
+
raise "Setup could not be completed."
|
110
113
|
else
|
111
114
|
authorization = @connection.oauth.create scopes: ['repo'], note: "git-reflow (#{run('hostname', loud: false).strip})"
|
112
115
|
end
|
@@ -115,15 +118,21 @@ module GitReflow
|
|
115
118
|
|
116
119
|
rescue ::Github::Error::Unauthorized => e
|
117
120
|
if e.inspect.to_s.include?('two-factor')
|
118
|
-
|
119
|
-
|
121
|
+
begin
|
122
|
+
# dummy request to trigger a 2FA SMS since a HTTP GET won't do it
|
123
|
+
@connection.oauth.create scopes: ['repo'], note: "thank Github for not making this straightforward"
|
124
|
+
rescue ::Github::Error::Unauthorized
|
125
|
+
ensure
|
126
|
+
two_factor_code = ask("Please enter your two-factor authentication code: ")
|
127
|
+
self.authenticate options.merge({user: gh_user, password: gh_password, two_factor_auth_code: two_factor_code})
|
128
|
+
end
|
120
129
|
else
|
121
|
-
|
130
|
+
GitReflow.say "Github Authentication Error: #{e.inspect}", :error
|
122
131
|
end
|
123
132
|
rescue StandardError => e
|
124
|
-
|
133
|
+
raise "We were unable to authenticate with Github."
|
125
134
|
else
|
126
|
-
|
135
|
+
GitReflow.say "Your GitHub account was successfully setup!", :success
|
127
136
|
end
|
128
137
|
end
|
129
138
|
|
@@ -99,12 +99,12 @@ module GitReflow
|
|
99
99
|
"url" => self.html_url
|
100
100
|
}
|
101
101
|
|
102
|
-
notices =
|
102
|
+
notices = []
|
103
103
|
reviewed_by = []
|
104
104
|
|
105
105
|
# check for CI build status
|
106
106
|
if self.build_status
|
107
|
-
notices << "
|
107
|
+
notices << "Your build status is not successful: #{self.build.url}.\n" unless self.build.state == "success"
|
108
108
|
summary_data.merge!( "Build status" => GitReflow.git_server.colorized_build_description(self.build.state, self.build.description) )
|
109
109
|
end
|
110
110
|
|
@@ -117,9 +117,9 @@ module GitReflow
|
|
117
117
|
reviewed_by.map! { |author| approvals.include?(author.uncolorize) ? author.colorize(:green) : author }
|
118
118
|
end
|
119
119
|
|
120
|
-
notices << "
|
120
|
+
notices << "You still need a LGTM from: #{reviewers_pending_response.join(', ')}\n" if reviewers_pending_response.any?
|
121
121
|
else
|
122
|
-
notices << "
|
122
|
+
notices << "No one has reviewed your pull request.\n"
|
123
123
|
end
|
124
124
|
|
125
125
|
summary_data['reviewed by'] = reviewed_by.join(', ')
|
@@ -130,7 +130,9 @@ module GitReflow
|
|
130
130
|
printf string_format, "#{name}:", summary_data[name]
|
131
131
|
end
|
132
132
|
|
133
|
-
|
133
|
+
notices.each do |notice|
|
134
|
+
GitReflow.say notice, :notice
|
135
|
+
end
|
134
136
|
end
|
135
137
|
|
136
138
|
def method_missing(method_sym, *arguments, &block)
|
@@ -140,6 +142,72 @@ module GitReflow
|
|
140
142
|
super
|
141
143
|
end
|
142
144
|
end
|
145
|
+
|
146
|
+
def commit_message_for_merge
|
147
|
+
message = ""
|
148
|
+
|
149
|
+
if "#{self.description}".length > 0
|
150
|
+
message << "#{self.description}"
|
151
|
+
else
|
152
|
+
message << "#{GitReflow.get_first_commit_message}"
|
153
|
+
end
|
154
|
+
|
155
|
+
message << "\nMerges ##{self.number}\n"
|
156
|
+
|
157
|
+
if lgtm_authors = Array(self.approvals) and lgtm_authors.any?
|
158
|
+
message << "\nLGTM given by: @#{lgtm_authors.join(', @')}\n"
|
159
|
+
end
|
160
|
+
|
161
|
+
"#{message}\n"
|
162
|
+
end
|
163
|
+
|
164
|
+
def cleanup_feature_branch?
|
165
|
+
GitReflow::Config.get('reflow.always-cleanup') == "true" || (ask "Would you like to push this branch to your remote repo and cleanup your feature branch? ") =~ /^y/i
|
166
|
+
end
|
167
|
+
|
168
|
+
def deliver?
|
169
|
+
GitReflow::Config.get('reflow.always-deliver') == "true" || (ask "This is the current status of your Pull Request. Are you sure you want to deliver? ") =~ /^y/i
|
170
|
+
end
|
171
|
+
|
172
|
+
def cleanup_failure_message
|
173
|
+
GitReflow.say "Cleanup halted. Local changes were not pushed to remote repo.", :deliver_halted
|
174
|
+
GitReflow.say "To reset and go back to your branch run \`git reset --hard origin/#{self.base_branch_name} && git checkout #{self.feature_branch_name}\`"
|
175
|
+
end
|
176
|
+
|
177
|
+
def merge!(options = {})
|
178
|
+
if deliver?
|
179
|
+
|
180
|
+
GitReflow.say "Merging pull request ##{self.number}: '#{self.title}', from '#{self.feature_branch_name}' into '#{self.base_branch_name}'", :notice
|
181
|
+
|
182
|
+
GitReflow.update_current_branch
|
183
|
+
GitReflow.fetch_destination(self.base_branch_name)
|
184
|
+
|
185
|
+
message = commit_message_for_merge
|
186
|
+
|
187
|
+
GitReflow.run_command_with_label "git checkout #{self.base_branch_name}"
|
188
|
+
GitReflow.run_command_with_label "git pull origin #{self.base_branch_name}"
|
189
|
+
GitReflow.run_command_with_label "git merge --squash #{self.feature_branch_name}"
|
190
|
+
|
191
|
+
GitReflow.append_to_squashed_commit_message(message) if message.length > 0
|
192
|
+
|
193
|
+
if GitReflow.run_command_with_label 'git commit', with_system: true
|
194
|
+
GitReflow.say "Pull request ##{self.number} successfully merged.", :success
|
195
|
+
|
196
|
+
if cleanup_feature_branch?
|
197
|
+
GitReflow.run_command_with_label "git push origin #{self.base_branch_name}"
|
198
|
+
GitReflow.run_command_with_label "git push origin :#{self.feature_branch_name}"
|
199
|
+
GitReflow.run_command_with_label "git branch -D #{self.feature_branch_name}"
|
200
|
+
GitReflow.say "Nice job buddy."
|
201
|
+
else
|
202
|
+
cleanup_failure_message
|
203
|
+
end
|
204
|
+
else
|
205
|
+
GitReflow.say "There were problems commiting your feature... please check the errors above and try again.", :error
|
206
|
+
end
|
207
|
+
else
|
208
|
+
GitReflow.say "Merge aborted", :deliver_halted
|
209
|
+
end
|
210
|
+
end
|
143
211
|
end
|
144
212
|
end
|
145
213
|
end
|
@@ -17,7 +17,7 @@ module GitReflow
|
|
17
17
|
provider.authenticate(options.keep_if {|key, value| key == :silent })
|
18
18
|
provider
|
19
19
|
rescue ConnectionError => e
|
20
|
-
|
20
|
+
GitReflow.say "Error connecting to #{provider_name}: #{e.message}", :error
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -32,11 +32,11 @@ module GitReflow
|
|
32
32
|
begin
|
33
33
|
provider_class_for(provider)
|
34
34
|
rescue ConnectionError => e
|
35
|
-
|
35
|
+
GitReflow.say e.message, :error
|
36
36
|
nil
|
37
37
|
end
|
38
38
|
else
|
39
|
-
|
39
|
+
GitReflow.say "Reflow hasn't been setup yet. Run 'git reflow setup' to continue", :notice
|
40
40
|
nil
|
41
41
|
end
|
42
42
|
end
|
data/lib/git_reflow/sandbox.rb
CHANGED
@@ -7,7 +7,8 @@ module GitReflow
|
|
7
7
|
error: :red,
|
8
8
|
deliver_halted: :red,
|
9
9
|
review_halted: :red,
|
10
|
-
success: :green
|
10
|
+
success: :green,
|
11
|
+
plain: :white
|
11
12
|
}
|
12
13
|
|
13
14
|
def run(command, options = {})
|
@@ -32,25 +33,12 @@ module GitReflow
|
|
32
33
|
|
33
34
|
def say(message, label_type = :plain)
|
34
35
|
if COLOR_FOR_LABEL[label_type]
|
35
|
-
|
36
|
+
label = (label_type.to_s == "plain") ? "" : "[#{ label_type.to_s.gsub('_', ' ').colorize(COLOR_FOR_LABEL[label_type]) }] "
|
37
|
+
puts "#{label}#{message}"
|
36
38
|
else
|
37
39
|
puts message
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
# WARNING: this currently only supports OS X and UBUNTU
|
42
|
-
def ask_to_open_in_browser(url)
|
43
|
-
if OS.unix?
|
44
|
-
open_in_browser = ask "Would you like to open it in your browser? "
|
45
|
-
if open_in_browser =~ /^y/i
|
46
|
-
if OS.mac?
|
47
|
-
run "open #{url}"
|
48
|
-
else
|
49
|
-
run "xdg-open #{url}"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
43
|
end
|
56
44
|
end
|
data/lib/git_reflow/version.rb
CHANGED