module GitReflow::Workflow::ClassMethods
Public Instance Methods
Stores a Proc to be called once the command successfully finishes
Procs declared with ‘after` are executed sequentially in the order they are defined in a custom Workflow
file.
@param name [Symbol] the name of the method to create
@yield A block to be executed after the given command. These blocks are executed in the context of ‘GitReflow::Workflows::Core`
# File lib/git_reflow/workflow.rb, line 228 def after(name, &block) name = name.to_sym if commands[name].nil? logger.error "Attempted to register (after) callback for non-existing command: #{name}" else logger.debug "(after) callback registered for: #{name}" callbacks[:after][name] ||= [] callbacks[:after][name] << block end end
Stores a Proc to be called once the command successfully finishes
Procs declared with ‘before` are executed sequentially in the order they are defined in a custom Workflow
file.
@param name [Symbol] the name of the method to create
@yield A block to be executed before the given command. These blocks are executed in the context of ‘GitReflow::Workflows::Core`
# File lib/git_reflow/workflow.rb, line 208 def before(name, &block) name = name.to_sym if commands[name].nil? logger.error "Attempted to register (before) callback for non-existing command: #{name}" else logger.debug "(before) callback registered for: #{name}" callbacks[:before][name] ||= [] callbacks[:before][name] << block end end
# File lib/git_reflow/workflow.rb, line 61 def callbacks @callbacks ||= { before: {}, after: {} } end
# File lib/git_reflow/workflow.rb, line 68 def callbacks=(callback_hash) @callbacks = callback_hash end
Creates a singleton method on the included class
This method will take any number of keyword parameters. If @defaults keyword is provided, and the given key(s) in the defaults are not provided as keyword parameters, then it will use the value given in the defaults for that parameter.
@param name [Symbol] the name of the method to create @param defaults [Hash] keyword arguments to provide fallbacks for
@yield [a:, b:, c:, …] Invokes the block with an arbitrary number of keyword arguments
# File lib/git_reflow/workflow.rb, line 150 def command(name, **params, &block) params[:flags] ||= {} params[:switches] ||= {} params[:arguments] ||= {} defaults ||= params[:arguments].merge(params[:flags]).merge(params[:switches]) # Ensure flags and switches use kebab-case kebab_case_keys!(params[:flags]) kebab_case_keys!(params[:switches]) # Register the command with the workflow so that we can properly handle # option parsing from the command line self.commands[name] = params self.command_docs[name] = params logger.debug "adding new command '#{name}' with #{defaults.inspect}" self.define_singleton_method(name) do |args = {}| args_with_defaults = {} args.each do |name, value| if "#{value}".length <= 0 && !defaults[name].nil? args_with_defaults[name] = defaults[name] else args_with_defaults[name] = value end end defaults.each do |name, value| if "#{args_with_defaults[name]}".length <= 0 args_with_defaults[name] = value end end logger.debug "callbacks: #{callbacks.inspect}" Array(callbacks[:before][name]).each do |block| logger.debug "(before) callback running for `#{name}` command..." argument_overrides = block.call(**args_with_defaults) || {} args_with_defaults.merge!(argument_overrides) if argument_overrides.is_a?(Hash) end logger.info "Running command `#{name}` with args: #{args_with_defaults.inspect}..." block.call(**args_with_defaults) Array(callbacks[:after][name]).each do |block| logger.debug "(after) callback running for `#{name}` command..." block.call(**args_with_defaults) end end end
# File lib/git_reflow/workflow.rb, line 53 def command_docs @command_docs ||= {} end
# File lib/git_reflow/workflow.rb, line 57 def command_docs=(command_doc_hash) @command_docs = command_doc_hash end
Creates a singleton method on the included class
This method updates the help text associated with the provided command.
@param name [Symbol] the name of the command to add/update help text for @param defaults [Hash] keyword arguments to provide fallbacks for
# File lib/git_reflow/workflow.rb, line 245 def command_help(name, summary:, arguments: {}, flags: {}, switches: {}, description: "") command_docs[name] = { summary: summary, description: description, arguments: arguments, flags: kebab_case_keys!(flags), switches: kebab_case_keys!(switches) } end
# File lib/git_reflow/workflow.rb, line 45 def commands @commands ||= {} end
# File lib/git_reflow/workflow.rb, line 49 def commands=(command_hash) @commands = command_hash end
Outputs documentation for the provided command
@param name [Symbol] the name of the command to output help text for
# File lib/git_reflow/workflow.rb, line 258 def documentation_for_command(name) name = name.to_sym docs = command_docs[name] if !docs.nil? GitReflow.say "USAGE" GitReflow.say " git-reflow #{name} [command options] #{docs[:arguments].keys.map {|arg| "[#{arg}]" }.join(' ')}" if docs[:arguments].any? GitReflow.say "ARGUMENTS" docs[:arguments].each do |arg_name, arg_desc| default_text = commands[name][:arguments][arg_name].nil? ? "" : "(default: #{commands[name][:arguments][arg_name]}) " GitReflow.say " #{arg_name} – #{default_text}#{arg_desc}" end end if docs[:flags].any? || docs[:switches].any? cmd = commands[name.to_sym] GitReflow.say "COMMAND OPTIONS" docs[:flags].each do |flag_name, flag_desc| flag_names = ["-#{flag_name.to_s[0]}", "--#{flag_name}"] flag_default = cmd[:flags][flag_name] GitReflow.say " #{flag_names} – #{!flag_default.nil? ? "(default: #{flag_default}) " : ""}#{flag_desc}" end docs[:switches].each do |switch_name, switch_desc| switch_names = [switch_name.to_s[0], "-#{switch_name}"].map {|s| "-#{s}" }.join(', ') switch_default = cmd[:switches][switch_name] GitReflow.say " #{switch_names} – #{!switch_default.nil? ? "(default: #{switch_default}) " : ""}#{switch_desc}" end end else help end end
Proxy our Config
class so that it’s available in workflow files
# File lib/git_reflow/workflow.rb, line 73 def git_config GitReflow::Config end
# File lib/git_reflow/workflow.rb, line 77 def git_server GitReflow.git_server end
Outputs documentation for git-reflow
# File lib/git_reflow/workflow.rb, line 293 def help GitReflow.say "NAME" GitReflow.say " git-reflow – Git Reflow manages your git workflow." GitReflow.say "VERSION" GitReflow.say " #{GitReflow::VERSION}" GitReflow.say "USAGE" GitReflow.say " git-reflow command [command options] [arguments...]" GitReflow.say "COMMANDS" command_docs.each do |command_name, command_doc| GitReflow.say " #{command_name}\t– #{command_doc[:summary]}" end end
# File lib/git_reflow/workflow.rb, line 81 def logger(*args) return @logger if defined?(@logger) @logger = GitReflow.try(:logger, *args) || GitReflow::Logger.new(*args) rescue NoMethodError @logger = GitReflow::Logger.new(*args) end
Parses ARGV for the provided git-reflow command name
@param name [Symbol, String] the name of the git-reflow command to parse from ARGV
# File lib/git_reflow/workflow.rb, line 309 def parse_command_options!(name) name = name.to_sym options = {} docs = command_docs[name] OptionParser.new do |opts| opts.banner = "USAGE:\n git-reflow #{name} [command options] #{docs[:arguments].keys.map {|arg| "[#{arg}]" }.join(' ')}" opts.separator "" opts.separator "COMMAND OPTIONS:" if docs[:flags].any? || docs[:switches].any? self.commands[name][:flags].each do |flag_name, flag_default| # There is a bug in Ruby that will not parse the flag value if no # help text is provided. Fallback to the flag name. flag_help = command_docs[name][:flags][flag_name] || flag_name opts.on("-#{flag_name[0]}", "--#{flag_name} #{flag_name.upcase}", flag_help) do |f| options[kebab_to_underscore(flag_name)] = f || flag_default end end self.commands[name][:switches].each do |switch_name, switch_default| # There is a bug in Ruby that will not parse the switch value if no # help text is provided. Fallback to the switch name. switch_help = command_docs[name][:switches][switch_name] || switch_name opts.on("-#{switch_name[0]}", "--[no-]#{switch_name}", switch_help) do |s| options[kebab_to_underscore(switch_name)] = s || switch_default end end end.parse! # Add arguments to optiosn to pass to defined commands commands[name][:arguments].each do |arg_name, arg_default| options[arg_name] = ARGV.shift || arg_default end options rescue OptionParser::InvalidOption documentation_for_command(name) exit 1 end
Loads a pre-defined workflow (FlatMergeWorkflow) from within another Workflow
file
@param name [String] the name of the Workflow
file to use as a basis
# File lib/git_reflow/workflow.rb, line 119 def use(workflow_name) if workflows.key?(workflow_name) logger.debug "Using Workflow: #{workflow_name}" GitReflow::Workflows::Core.load_workflow(workflows[workflow_name]) else logger.error "Tried to use non-existent Workflow: #{workflow_name}" end end
Checks for an installed gem, and if none is installed use bundler’s inline gemfile to install it.
@param name [String] the name of the gem to require as a dependency
# File lib/git_reflow/workflow.rb, line 93 def use_gem(name, *args) run("gem list -ie #{name}", loud: false, raise: true) logger.info "Using installed gem '#{name}' with options: #{args.inspect}" rescue ::GitReflow::Sandbox::CommandError => e abort e.message unless e.output =~ /\Afalse/ logger.info "Installing gem '#{name}' with options: #{args.inspect}" say "Installing gem '#{name}'...", :notice gemfile do source "https://rubygems.org" gem name, *args end end
Use bundler’s inline gemfile to install dependencies. See: bundler.io/v1.16/guides/bundler_in_a_single_file_ruby_script.html
@yield A block to be executed in the context of Bundler’s ‘gemfile` DSL
# File lib/git_reflow/workflow.rb, line 110 def use_gemfile(&block) logger.info "Using a custom gemfile" gemfile(true, &block) end
Keeps track of available workflows when using ‘.use(workflow_name)` Workflow
file
@return [Hash, nil] A hash with [workflow_name, workflow_path] as key/value pairs
# File lib/git_reflow/workflow.rb, line 132 def workflows return @workflows if @workflows workflow_paths = Dir["#{File.dirname(__FILE__)}/workflows/*Workflow"] @workflows = {} workflow_paths.each { |p| @workflows[File.basename(p)] = p } @workflows end
Private Instance Methods
# File lib/git_reflow/workflow.rb, line 349 def kebab_case_keys!(hsh) hsh.keys.each do |key_to_update| hsh[underscore_to_kebab(key_to_update)] = hsh.delete(key_to_update) if key_to_update =~ /_/ end hsh end
# File lib/git_reflow/workflow.rb, line 357 def kebab_to_underscore(sym_or_string) sym_or_string.to_s.gsub('-', '_').to_sym end
# File lib/git_reflow/workflow.rb, line 361 def underscore_to_kebab(sym_or_string) sym_or_string.to_s.gsub('_', '-').to_sym end