module GitReflow::Workflow::ClassMethods

Public Instance Methods

after(name, &block) click to toggle source

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
before(name, &block) click to toggle source

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
callbacks() click to toggle source
# File lib/git_reflow/workflow.rb, line 61
def callbacks
  @callbacks ||= {
    before: {},
    after: {}
  }
end
callbacks=(callback_hash) click to toggle source
# File lib/git_reflow/workflow.rb, line 68
def callbacks=(callback_hash)
  @callbacks = callback_hash
end
command(name, **params, &block) click to toggle source

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
command_docs() click to toggle source
# File lib/git_reflow/workflow.rb, line 53
def command_docs
  @command_docs ||= {}
end
command_docs=(command_doc_hash) click to toggle source
# File lib/git_reflow/workflow.rb, line 57
def command_docs=(command_doc_hash)
  @command_docs = command_doc_hash
end
command_help(name, summary:, arguments: {}, flags: {}, switches: {}, description: "") click to toggle source

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
commands() click to toggle source
# File lib/git_reflow/workflow.rb, line 45
def commands
  @commands ||= {}
end
commands=(command_hash) click to toggle source
# File lib/git_reflow/workflow.rb, line 49
def commands=(command_hash)
  @commands = command_hash
end
documentation_for_command(name) click to toggle source

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
git_config() click to toggle source

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
git_server() click to toggle source
# File lib/git_reflow/workflow.rb, line 77
def git_server
  GitReflow.git_server
end
help() click to toggle source

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
logger(*args) click to toggle source
# 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
parse_command_options!(name) click to toggle source

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
use(workflow_name) click to toggle source

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
use_gem(name, *args) click to toggle source

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_gemfile(&block) click to toggle source

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
workflows() click to toggle source

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

kebab_case_keys!(hsh) click to toggle source
# 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
kebab_to_underscore(sym_or_string) click to toggle source
# File lib/git_reflow/workflow.rb, line 357
def kebab_to_underscore(sym_or_string)
  sym_or_string.to_s.gsub('-', '_').to_sym
end
underscore_to_kebab(sym_or_string) click to toggle source
# File lib/git_reflow/workflow.rb, line 361
def underscore_to_kebab(sym_or_string)
  sym_or_string.to_s.gsub('_', '-').to_sym
end