git_reflow 0.8.9 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/multi-ruby-tests.yml +33 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +2 -0
  5. data/.ruby-version +1 -0
  6. data/Appraisals +1 -6
  7. data/CHANGELOG.md +466 -348
  8. data/Gemfile.lock +99 -72
  9. data/LICENSE +20 -20
  10. data/README.md +481 -0
  11. data/Rakefile +15 -8
  12. data/Workflow +3 -0
  13. data/_config.yml +1 -0
  14. data/bin/console +7 -7
  15. data/bin/setup +6 -6
  16. data/exe/git-reflow +20 -36
  17. data/git_reflow.gemspec +26 -30
  18. data/lib/git_reflow.rb +3 -15
  19. data/lib/git_reflow/config.rb +48 -13
  20. data/lib/git_reflow/git_helpers.rb +69 -22
  21. data/lib/git_reflow/git_server.rb +63 -63
  22. data/lib/git_reflow/git_server/base.rb +68 -68
  23. data/lib/git_reflow/git_server/bit_bucket.rb +101 -101
  24. data/lib/git_reflow/git_server/bit_bucket/pull_request.rb +84 -84
  25. data/lib/git_reflow/git_server/git_hub.rb +53 -41
  26. data/lib/git_reflow/git_server/git_hub/pull_request.rb +16 -14
  27. data/lib/git_reflow/git_server/pull_request.rb +4 -2
  28. data/lib/git_reflow/merge_error.rb +9 -9
  29. data/lib/git_reflow/rspec.rb +3 -2
  30. data/lib/git_reflow/rspec/command_line_helpers.rb +23 -6
  31. data/lib/git_reflow/rspec/stub_helpers.rb +13 -13
  32. data/lib/git_reflow/rspec/workflow_helpers.rb +18 -0
  33. data/lib/git_reflow/sandbox.rb +16 -6
  34. data/lib/git_reflow/version.rb +1 -1
  35. data/lib/git_reflow/workflow.rb +304 -9
  36. data/lib/git_reflow/workflows/FlatMergeWorkflow +38 -0
  37. data/lib/git_reflow/workflows/core.rb +364 -238
  38. data/spec/fixtures/authentication_failure.json +3 -0
  39. data/spec/fixtures/awesome_workflow.rb +3 -7
  40. data/spec/fixtures/git/git_config +7 -7
  41. data/spec/fixtures/issues/comment.json.erb +27 -27
  42. data/spec/fixtures/issues/comments.json +29 -29
  43. data/spec/fixtures/issues/comments.json.erb +15 -15
  44. data/spec/fixtures/pull_requests/comment.json.erb +45 -45
  45. data/spec/fixtures/pull_requests/comments.json +47 -47
  46. data/spec/fixtures/pull_requests/comments.json.erb +15 -15
  47. data/spec/fixtures/pull_requests/commits.json +29 -29
  48. data/spec/fixtures/pull_requests/external_pull_request.json +145 -145
  49. data/spec/fixtures/pull_requests/pull_request.json +142 -142
  50. data/spec/fixtures/pull_requests/pull_request.json.erb +142 -142
  51. data/spec/fixtures/pull_requests/pull_request_branch_nonexistent_error.json +32 -0
  52. data/spec/fixtures/pull_requests/pull_request_exists_error.json +32 -32
  53. data/spec/fixtures/pull_requests/pull_requests.json +136 -136
  54. data/spec/fixtures/repositories/commit.json +53 -53
  55. data/spec/fixtures/repositories/commit.json.erb +53 -53
  56. data/spec/fixtures/repositories/commits.json.erb +13 -13
  57. data/spec/fixtures/repositories/statuses.json +31 -31
  58. data/spec/fixtures/users/user.json +32 -0
  59. data/spec/lib/git_reflow/git_helpers_spec.rb +115 -12
  60. data/spec/lib/git_reflow/git_server/bit_bucket_spec.rb +81 -81
  61. data/spec/lib/git_reflow/git_server/git_hub/pull_request_spec.rb +10 -10
  62. data/spec/lib/git_reflow/git_server/git_hub_spec.rb +77 -3
  63. data/spec/lib/git_reflow/git_server/pull_request_spec.rb +9 -3
  64. data/spec/lib/git_reflow/git_server_spec.rb +101 -101
  65. data/spec/lib/git_reflow/sandbox_spec.rb +1 -1
  66. data/spec/lib/git_reflow/workflow_spec.rb +304 -59
  67. data/spec/lib/git_reflow/workflows/core_spec.rb +225 -67
  68. data/spec/lib/git_reflow/workflows/flat_merge_spec.rb +71 -59
  69. data/spec/lib/git_reflow_spec.rb +2 -25
  70. data/spec/spec_helper.rb +3 -0
  71. data/spec/support/fixtures.rb +54 -54
  72. data/spec/support/github_helpers.rb +99 -109
  73. data/spec/support/mock_pull_request.rb +17 -17
  74. data/spec/support/web_mocks.rb +39 -39
  75. metadata +51 -74
  76. data/README.rdoc +0 -461
  77. data/circle.yml +0 -26
  78. data/lib/git_reflow/commands/deliver.rb +0 -10
  79. data/lib/git_reflow/commands/refresh.rb +0 -20
  80. data/lib/git_reflow/commands/review.rb +0 -13
  81. data/lib/git_reflow/commands/setup.rb +0 -11
  82. data/lib/git_reflow/commands/stage.rb +0 -9
  83. data/lib/git_reflow/commands/start.rb +0 -18
  84. data/lib/git_reflow/commands/status.rb +0 -7
  85. data/lib/git_reflow/os_detector.rb +0 -23
  86. data/lib/git_reflow/workflows/flat_merge.rb +0 -10
  87. data/spec/fixtures/workflow_with_super.rb +0 -8
@@ -1,13 +1,13 @@
1
- module GitReflow
2
- module RSpec
3
- module StubHelpers
4
-
5
- def stub_with_fallback(obj, method)
6
- original_method = obj.method(method)
7
- allow(obj).to receive(method).with(anything()) { |*args| original_method.call(*args) }
8
- return allow(obj).to receive(method)
9
- end
10
-
11
- end
12
- end
13
- end
1
+ module GitReflow
2
+ module RSpec
3
+ module StubHelpers
4
+
5
+ def stub_with_fallback(obj, method)
6
+ original_method = obj.method(method)
7
+ allow(obj).to receive(method).with(anything()) { |*args| original_method.call(*args) }
8
+ return allow(obj).to receive(method)
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module GitReflow
2
+ module RSpec
3
+ # @nodoc
4
+ module WorkflowHelpers
5
+ def use_workflow(path)
6
+ allow(GitReflow::Workflows::Core).to receive(:load_workflow).and_return(
7
+ GitReflow::Workflows::Core.load_raw_workflow(File.read(path))
8
+ )
9
+ end
10
+
11
+ def suppress_loading_of_external_workflows
12
+ allow(GitReflow::Workflows::Core).to receive(:load__workflow).with("#{GitReflow.git_root_dir}/Workflow").and_return(false)
13
+ return if GitReflow::Config.get('reflow.workflow').to_s.empty?
14
+ allow(GitReflow::Workflows::Core).to receive(:load_workflow).with(GitReflow::Config.get('reflow.workflow')).and_return(false)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -4,6 +4,7 @@ module GitReflow
4
4
 
5
5
  COLOR_FOR_LABEL = {
6
6
  notice: :yellow,
7
+ info: :yellow,
7
8
  error: :red,
8
9
  deliver_halted: :red,
9
10
  review_halted: :red,
@@ -11,8 +12,16 @@ module GitReflow
11
12
  plain: :white
12
13
  }
13
14
 
15
+ class CommandError < StandardError;
16
+ attr_reader :output
17
+ def initialize(output, *args)
18
+ @output = output
19
+ super(*args)
20
+ end
21
+ end
22
+
14
23
  def run(command, options = {})
15
- options = { loud: true, blocking: true }.merge(options)
24
+ options = { loud: true, blocking: true, raise: false }.merge(options)
16
25
 
17
26
  GitReflow.logger.debug "Running... #{command}"
18
27
 
@@ -21,12 +30,13 @@ module GitReflow
21
30
  else
22
31
  output = %x{#{command}}
23
32
 
24
- if options[:blocking] == true && !$?.success?
25
- abort "\"#{command}\" failed to run."
26
- else
27
- puts output if options[:loud] == true
28
- output
33
+ if !$?.success?
34
+ raise CommandError.new(output, "\"#{command}\" failed to run.") if options[:raise] == true
35
+ abort "\"#{command}\" failed to run." if options[:blocking] == true
29
36
  end
37
+
38
+ puts output if options[:loud] == true
39
+ output
30
40
  end
31
41
  end
32
42
 
@@ -1,3 +1,3 @@
1
1
  module GitReflow
2
- VERSION = "0.8.9"
2
+ VERSION = "0.9.3"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require 'git_reflow/sandbox'
2
2
  require 'git_reflow/git_helpers'
3
+ require 'bundler/inline'
3
4
 
4
5
  module GitReflow
5
6
  module Workflow
@@ -9,20 +10,128 @@ module GitReflow
9
10
 
10
11
  # @nodoc
11
12
  def self.current
12
- workflow_file = GitReflow::Config.get('reflow.workflow')
13
- if workflow_file.length > 0 and File.exists?(workflow_file)
14
- GitReflow.logger.debug "Using workflow: #{workflow_file}"
15
- eval(File.read(workflow_file))
16
- else
17
- GitReflow.logger.debug "Using core workflow..."
18
- GitReflow::Workflows::Core
13
+ return @current unless @current.nil?
14
+ # First look for a "Workflow" file in the current directory, then check
15
+ # for a global Workflow file stored in git-reflow git config.
16
+ loaded_local_workflow = GitReflow::Workflows::Core.load_workflow "#{GitReflow.git_root_dir}/Workflow"
17
+ loaded_global_workflow = false
18
+
19
+ unless loaded_local_workflow
20
+ loaded_global_workflow = GitReflow::Workflows::Core.load_workflow GitReflow::Config.get('reflow.workflow')
19
21
  end
22
+
23
+ @current = GitReflow::Workflows::Core
24
+ end
25
+
26
+ # @nodoc
27
+ # This is primarily a helper method for tests. Due to the nature of how the
28
+ # tests load many different workflows, this helps start fresh and isolate
29
+ # the scenario at hand.
30
+ def self.reset!
31
+ GitReflow.logger.debug "Resetting GitReflow workflow..."
32
+ current.commands = {}
33
+ current.callbacks = { before: {}, after: {}}
34
+ @current = nil
35
+ # We'll need to reload the core class again in order to clear previously
36
+ # eval'd content in the context of the class
37
+ load File.expand_path('../workflows/core.rb', __FILE__)
20
38
  end
21
39
 
22
40
  module ClassMethods
23
41
  include GitReflow::Sandbox
24
42
  include GitReflow::GitHelpers
25
43
 
44
+ def commands
45
+ @commands ||= {}
46
+ end
47
+
48
+ def commands=(command_hash)
49
+ @commands = command_hash
50
+ end
51
+
52
+ def command_docs
53
+ @command_docs ||= {}
54
+ end
55
+
56
+ def command_docs=(command_doc_hash)
57
+ @command_docs = command_doc_hash
58
+ end
59
+
60
+ def callbacks
61
+ @callbacks ||= {
62
+ before: {},
63
+ after: {}
64
+ }
65
+ end
66
+
67
+ def callbacks=(callback_hash)
68
+ @callbacks = callback_hash
69
+ end
70
+
71
+ # Proxy our Config class so that it's available in workflow files
72
+ def git_config
73
+ GitReflow::Config
74
+ end
75
+
76
+ def git_server
77
+ GitReflow.git_server
78
+ end
79
+
80
+ def logger
81
+ GitReflow.logger
82
+ end
83
+
84
+ # Checks for an installed gem, and if none is installed use bundler's
85
+ # inline gemfile to install it.
86
+ #
87
+ # @param name [String] the name of the gem to require as a dependency
88
+ def use_gem(name, *args)
89
+ run("gem list -ie #{name}", loud: false, raise: true)
90
+ logger.info "Using installed gem '#{name}' with options: #{args.inspect}"
91
+ rescue ::GitReflow::Sandbox::CommandError => e
92
+ abort e.message unless e.output =~ /\Afalse/
93
+ logger.info "Installing gem '#{name}' with options: #{args.inspect}"
94
+ say "Installing gem '#{name}'...", :notice
95
+ gemfile do
96
+ source "https://rubygems.org"
97
+ gem name, *args
98
+ end
99
+ end
100
+
101
+ # Use bundler's inline gemfile to install dependencies.
102
+ # See: https://bundler.io/v1.16/guides/bundler_in_a_single_file_ruby_script.html
103
+ #
104
+ # @yield A block to be executed in the context of Bundler's `gemfile` DSL
105
+ def use_gemfile(&block)
106
+ logger.info "Using a custom gemfile"
107
+ gemfile(true, &block)
108
+ end
109
+
110
+ # Loads a pre-defined workflow (FlatMergeWorkflow) from within another
111
+ # Workflow file
112
+ #
113
+ # @param name [String] the name of the Workflow file to use as a basis
114
+ def use(workflow_name)
115
+ if workflows.key?(workflow_name)
116
+ GitReflow.logger.debug "Using Workflow: #{workflow_name}"
117
+ GitReflow::Workflows::Core.load_workflow(workflows[workflow_name])
118
+ else
119
+ GitReflow.logger.error "Tried to use non-existent Workflow: #{workflow_name}"
120
+ end
121
+ end
122
+
123
+ # Keeps track of available workflows when using `.use(workflow_name)`
124
+ # Workflow file
125
+ #
126
+ # @return [Hash, nil] A hash with [workflow_name, workflow_path] as key/value pairs
127
+ def workflows
128
+ return @workflows if @workflows
129
+ workflow_paths = Dir["#{File.dirname(__FILE__)}/workflows/*Workflow"]
130
+ @workflows = {}
131
+ workflow_paths.each { |p| @workflows[File.basename(p)] = p }
132
+ @workflows
133
+ end
134
+
26
135
  # Creates a singleton method on the inlcuded class
27
136
  #
28
137
  # This method will take any number of keyword parameters. If @defaults keyword is provided, and the given
@@ -34,11 +143,24 @@ module GitReflow
34
143
  #
35
144
  # @yield [a:, b:, c:, ...] Invokes the block with an arbitrary number of keyword arguments
36
145
  def command(name, **params, &block)
37
- defaults = params[:defaults] || {}
146
+ params[:flags] ||= {}
147
+ params[:switches] ||= {}
148
+ params[:arguments] ||= {}
149
+ defaults ||= params[:arguments].merge(params[:flags]).merge(params[:switches])
150
+
151
+ # Ensure flags and switches use kebab-case
152
+ kebab_case_keys!(params[:flags])
153
+ kebab_case_keys!(params[:switches])
154
+
155
+ # Register the command with the workflow so that we can properly handle
156
+ # option parsing from the command line
157
+ self.commands[name] = params
158
+ self.command_docs[name] = params
159
+
38
160
  self.define_singleton_method(name) do |**args|
39
161
  args_with_defaults = {}
40
162
  args.each do |name, value|
41
- if "#{value}".length <= 0
163
+ if "#{value}".length <= 0 && !defaults[name].nil?
42
164
  args_with_defaults[name] = defaults[name]
43
165
  else
44
166
  args_with_defaults[name] = value
@@ -51,9 +173,182 @@ module GitReflow
51
173
  end
52
174
  end
53
175
 
176
+ GitReflow.logger.debug "callbacks: #{callbacks.inspect}"
177
+ Array(callbacks[:before][name]).each do |block|
178
+ GitReflow.logger.debug "(before) callback running for `#{name}` command..."
179
+ argument_overrides = block.call(**args_with_defaults) || {}
180
+ args_with_defaults.merge!(argument_overrides) if argument_overrides.is_a?(Hash)
181
+ end
182
+
183
+ GitReflow.logger.info "Running command `#{name}` with args: #{args_with_defaults.inspect}..."
54
184
  block.call(**args_with_defaults)
185
+
186
+ Array(callbacks[:after][name]).each do |block|
187
+ GitReflow.logger.debug "(after) callback running for `#{name}` command..."
188
+ block.call(**args_with_defaults)
189
+ end
190
+ end
191
+ end
192
+
193
+ # Stores a Proc to be called once the command successfully finishes
194
+ #
195
+ # Procs declared with `before` are executed sequentially in the order they are defined in a custom Workflow
196
+ # file.
197
+ #
198
+ # @param name [Symbol] the name of the method to create
199
+ #
200
+ # @yield A block to be executed before the given command. These blocks
201
+ # are executed in the context of `GitReflow::Workflows::Core`
202
+ def before(name, &block)
203
+ name = name.to_sym
204
+ if commands[name].nil?
205
+ GitReflow.logger.error "Attempted to register (before) callback for non-existing command: #{name}"
206
+ else
207
+ GitReflow.logger.debug "(before) callback registered for: #{name}"
208
+ callbacks[:before][name] ||= []
209
+ callbacks[:before][name] << block
55
210
  end
56
211
  end
212
+
213
+ # Stores a Proc to be called once the command successfully finishes
214
+ #
215
+ # Procs declared with `after` are executed sequentially in the order they are defined in a custom Workflow
216
+ # file.
217
+ #
218
+ # @param name [Symbol] the name of the method to create
219
+ #
220
+ # @yield A block to be executed after the given command. These blocks
221
+ # are executed in the context of `GitReflow::Workflows::Core`
222
+ def after(name, &block)
223
+ name = name.to_sym
224
+ if commands[name].nil?
225
+ GitReflow.logger.error "Attempted to register (after) callback for non-existing command: #{name}"
226
+ else
227
+ GitReflow.logger.debug "(after) callback registered for: #{name}"
228
+ callbacks[:after][name] ||= []
229
+ callbacks[:after][name] << block
230
+ end
231
+ end
232
+
233
+ # Creates a singleton method on the inlcuded class
234
+ #
235
+ # This method updates the help text associated with the provided command.
236
+ #
237
+ # @param name [Symbol] the name of the command to add/update help text for
238
+ # @param defaults [Hash] keyword arguments to provide fallbacks for
239
+ def command_help(name, summary:, arguments: {}, flags: {}, switches: {}, description: "")
240
+ command_docs[name] = {
241
+ summary: summary,
242
+ description: description,
243
+ arguments: arguments,
244
+ flags: kebab_case_keys!(flags),
245
+ switches: kebab_case_keys!(switches)
246
+ }
247
+ end
248
+
249
+ # Outputs documentation for the provided command
250
+ #
251
+ # @param name [Symbol] the name of the command to output help text for
252
+ def documentation_for_command(name)
253
+ name = name.to_sym
254
+ docs = command_docs[name]
255
+ if !docs.nil?
256
+ GitReflow.say "USAGE"
257
+ GitReflow.say " git-reflow #{name} [command options] #{docs[:arguments].keys.map {|arg| "[#{arg}]" }.join(' ')}"
258
+ if docs[:arguments].any?
259
+ GitReflow.say "ARGUMENTS"
260
+ docs[:arguments].each do |arg_name, arg_desc|
261
+ default_text = commands[name][:arguments][arg_name].nil? ? "" : "(default: #{commands[name][:arguments][arg_name]}) "
262
+ GitReflow.say " #{arg_name} – #{default_text}#{arg_desc}"
263
+ end
264
+ end
265
+ if docs[:flags].any? || docs[:switches].any?
266
+ cmd = commands[name.to_sym]
267
+ GitReflow.say "COMMAND OPTIONS"
268
+ docs[:flags].each do |flag_name, flag_desc|
269
+ flag_names = ["-#{flag_name.to_s[0]}", "--#{flag_name}"]
270
+ flag_default = cmd[:flags][flag_name]
271
+
272
+ GitReflow.say " #{flag_names} – #{!flag_default.nil? ? "(default: #{flag_default}) " : ""}#{flag_desc}"
273
+ end
274
+ docs[:switches].each do |switch_name, switch_desc|
275
+ switch_names = [switch_name.to_s[0], "-#{switch_name}"].map {|s| "-#{s}" }.join(', ')
276
+ switch_default = cmd[:switches][switch_name]
277
+
278
+ GitReflow.say " #{switch_names} – #{!switch_default.nil? ? "(default: #{switch_default}) " : ""}#{switch_desc}"
279
+ end
280
+ end
281
+ else
282
+ help
283
+ end
284
+ end
285
+
286
+ # Outputs documentation for git-reflow
287
+ def help
288
+ GitReflow.say "NAME"
289
+ GitReflow.say " git-reflow – Git Reflow manages your git workflow."
290
+ GitReflow.say "VERSION"
291
+ GitReflow.say " #{GitReflow::VERSION}"
292
+ GitReflow.say "USAGE"
293
+ GitReflow.say " git-reflow command [command options] [arguments...]"
294
+ GitReflow.say "COMMANDS"
295
+ command_docs.each do |command_name, command_doc|
296
+ GitReflow.say " #{command_name}\t– #{command_doc[:summary]}"
297
+ end
298
+ end
299
+
300
+ # Parses ARGV for the provided git-reflow command name
301
+ #
302
+ # @param name [Symbol, String] the name of the git-reflow command to parse from ARGV
303
+ def parse_command_options!(name)
304
+ name = name.to_sym
305
+ options = {}
306
+ docs = command_docs[name]
307
+ OptionParser.new do |opts|
308
+ opts.banner = "USAGE:\n git-reflow #{name} [command options] #{docs[:arguments].keys.map {|arg| "[#{arg}]" }.join(' ')}"
309
+ opts.separator ""
310
+ opts.separator "COMMAND OPTIONS:" if docs[:flags].any? || docs[:switches].any?
311
+
312
+ self.commands[name][:flags].each do |flag_name, flag_default|
313
+ opts.on("-#{flag_name[0]}", "--#{flag_name} #{flag_name.upcase}", command_docs[name][:flags][flag_name]) do |f|
314
+ options[kebab_to_underscore(flag_name)] = f || flag_default
315
+ end
316
+ end
317
+
318
+ self.commands[name][:switches].each do |switch_name, switch_default|
319
+ opts.on("-#{switch_name[0]}", "--[no-]#{switch_name}", command_docs[name][:switches][switch_name]) do |s|
320
+ options[kebab_to_underscore(switch_name)] = s || switch_default
321
+ end
322
+ end
323
+ end.parse!
324
+
325
+ # Add arguments to optiosn to pass to defined commands
326
+ commands[name][:arguments].each do |arg_name, arg_default|
327
+ options[arg_name] = ARGV.shift || arg_default
328
+ end
329
+ options
330
+ rescue OptionParser::InvalidOption
331
+ documentation_for_command(name)
332
+ exit 1
333
+ end
334
+
335
+ private
336
+
337
+ def kebab_case_keys!(hsh)
338
+ hsh.keys.each do |key_to_update|
339
+ hsh[underscore_to_kebab(key_to_update)] = hsh.delete(key_to_update) if key_to_update =~ /_/
340
+ end
341
+
342
+ hsh
343
+ end
344
+
345
+ def kebab_to_underscore(sym_or_string)
346
+ sym_or_string.to_s.gsub('-', '_').to_sym
347
+ end
348
+
349
+ def underscore_to_kebab(sym_or_string)
350
+ sym_or_string.to_s.gsub('_', '-').to_sym
351
+ end
57
352
  end
58
353
  end
59
354
  end
@@ -0,0 +1,38 @@
1
+ command(:deliver, arguments: { base: "master" }, flags: { merge_method: "merge" }, switches: { force: false, skip_lgtm: false }) do |**params|
2
+ params[:force] = params[:force] || params[:skip_lgtm]
3
+ begin
4
+ existing_pull_request = git_server.find_open_pull_request( from: current_branch, to: params[:base] )
5
+
6
+ if existing_pull_request.nil?
7
+ say "No pull request exists for #{remote_user}:#{current_branch}\nPlease submit your branch for review first with \`git reflow review\`", :deliver_halted
8
+ else
9
+
10
+ if existing_pull_request.good_to_merge?(force: params[:force])
11
+ # displays current status and prompts user for confirmation
12
+ self.status destination_branch: params[:base]
13
+ existing_pull_request.merge!(params)
14
+ else
15
+ say existing_pull_request.rejection_message, :deliver_halted
16
+ end
17
+
18
+ end
19
+
20
+ rescue Github::Error::UnprocessableEntity => e
21
+ say "Github Error: #{e.inspect}", :error
22
+ end
23
+ end
24
+ command_help(
25
+ :deliver,
26
+ summary: "deliver your feature branch",
27
+ arguments: {
28
+ base: "the branch to merge this feature into"
29
+ },
30
+ flags: {
31
+ merge_method: "how you want your feature branch merged ('merge', 'squash', 'rebase')"
32
+ },
33
+ switches: {
34
+ force: "skip the lgtm checks and deliver your feature branch",
35
+ skip_lgtm: "skip the lgtm checks and deliver your feature branch"
36
+ },
37
+ description: "merge your feature branch down to your base branch, and cleanup your feature branch"
38
+ )