module Fastlane::Actions

Constants

ARGS_MAP
GIT_MERGE_COMMIT_FILTERING_OPTIONS

Public Class Methods

action_class_ref(action_name) click to toggle source

Returns the class ref to the action based on the action name Returns nil if the action is not available

# File fastlane/lib/fastlane/actions/actions_helper.rb, line 100
def self.action_class_ref(action_name)
  class_name = action_name.to_s.fastlane_class + 'Action'
  class_ref = nil
  begin
    class_ref = Fastlane::Actions.const_get(class_name)
  rescue NameError
    return nil
  end
  return class_ref
end
add_modified_files(files) click to toggle source

Add an array of paths relative to the repo root or absolute paths that have been modified by an action.

:files: An array of paths relative to the repo root or absolute paths

# File fastlane/lib/fastlane/actions/commit_version_bump.rb, line 14
def add_modified_files(files)
  modified_files = lane_context[SharedValues::MODIFIED_FILES] || Set.new
  modified_files += files
  lane_context[SharedValues::MODIFIED_FILES] = modified_files
end
alias_actions() click to toggle source
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 32
def self.alias_actions
  unless @alias_actions
    @alias_actions = {}
    ActionsList.all_actions do |action, name|
      next unless action.respond_to?(:aliases)
      @alias_actions[name] = action.aliases
    end
  end
  @alias_actions
end
authors() click to toggle source
# File fastlane/lib/assets/custom_action_template.rb, line 63
def self.authors
  # So no one will ever forget your contribution to fastlane :) You are awesome btw!
  ["Your GitHub/Twitter Name"]
end
available_options() click to toggle source
# File fastlane/lib/assets/custom_action_template.rb, line 31
def self.available_options
  # Define all options your action supports.

  # Below a few examples
  [
    FastlaneCore::ConfigItem.new(key: :api_token,
                                 env_name: "FL_[[NAME_UP]]_API_TOKEN", # The name of the environment variable
                                 description: "API Token for [[NAME_CLASS]]", # a short description of this parameter
                                 verify_block: proc do |value|
                                    UI.user_error!("No API token for [[NAME_CLASS]] given, pass using `api_token: 'token'`") unless (value and not value.empty?)
                                    # UI.user_error!("Couldn't find file at path '#{value}'") unless File.exist?(value)
                                 end),
    FastlaneCore::ConfigItem.new(key: :development,
                                 env_name: "FL_[[NAME_UP]]_DEVELOPMENT",
                                 description: "Create a development certificate instead of a distribution one",
                                 is_string: false, # true: verifies the input is a string, false: every kind of value
                                 default_value: false) # the default value if the user didn't provide one
  ]
end
clear_lane_context() click to toggle source

Used in tests to get a clear lane before every test

# File fastlane/lib/fastlane/actions/actions_helper.rb, line 53
def self.clear_lane_context
  @lane_context = nil
end
description() click to toggle source

@!group Documentation

# File fastlane/lib/assets/custom_action_template.rb, line 21
def self.description
  "A short description with <= 80 characters of what this action does"
end
details() click to toggle source
# File fastlane/lib/assets/custom_action_template.rb, line 25
def self.details
  # Optional:
  # this is your chance to provide a more detailed description of this action
  "You can use this action to do cool things..."
end
execute_action(step_name) { || ... } click to toggle source

Pass a block which should be tracked. One block = one testcase @param step_name (String) the name of the currently built code (e.g. snapshot, sigh, …)

This might be nil, in which case the step is not printed out to the terminal
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 60
def self.execute_action(step_name)
  start = Time.now # before the raise block, since `start` is required in the ensure block
  UI.crash!("No block given") unless block_given?

  error = nil
  exc = nil

  begin
    UI.header("Step: " + step_name) if step_name
    yield
  rescue => ex
    exc = ex
    error = caller.join("\n") + "\n\n" + ex.to_s
  end
ensure
  # This is also called, when the block has a return statement
  if step_name
    duration = Time.now - start

    executed_actions << {
      name: step_name,
      error: error,
      time: duration
    }
  end

  raise exc if exc
end
executed_actions() click to toggle source
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 43
def self.executed_actions
  @executed_actions ||= []
end
formerly_bundled_actions() click to toggle source
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 167
def self.formerly_bundled_actions
  ["xcake"]
end
get_all_official_actions() click to toggle source

returns a list of official integrations rubocop:disable Naming/AccessorMethodName

# File fastlane/lib/fastlane/actions/actions_helper.rb, line 91
def self.get_all_official_actions
  Dir[File.expand_path('*.rb', File.dirname(__FILE__))].collect do |file|
    File.basename(file).gsub('.rb', '').to_sym
  end
end
git_author() click to toggle source

@deprecated Use git_author_email instead Get the author email of the last git commit DEPRECATED: Use git_author_email instead.

# File fastlane/lib/fastlane/helper/git_helper.rb, line 88
def self.git_author
  UI.deprecated('`git_author` is deprecated. Please use `git_author_email` instead.')
  git_author_email
end
git_author_email() click to toggle source

Get the author email of the last git commit

# File fastlane/lib/fastlane/helper/git_helper.rb, line 94
def self.git_author_email
  s = last_git_commit_formatted_with('%ae')
  return s if s.to_s.length > 0
  return nil
end
git_branch() click to toggle source

Returns the current git branch, or “HEAD” if it's not checked out to any branch Can be replaced using the environment variable `GIT_BRANCH`

# File fastlane/lib/fastlane/helper/git_helper.rb, line 124
def self.git_branch
  env_name = SharedValues::GIT_BRANCH_ENV_VARS.find { |env_var| FastlaneCore::Env.truthy?(env_var) }
  ENV.fetch(env_name.to_s) do
    self.git_branch_name_using_HEAD
  end
end
git_branch_name_using_HEAD() click to toggle source

Returns the checked out git branch name or “HEAD” if you're in detached HEAD state

# File fastlane/lib/fastlane/helper/git_helper.rb, line 132
def self.git_branch_name_using_HEAD
  # Rescues if not a git repo or no commits in a git repo
  Actions.sh("git rev-parse --abbrev-ref HEAD", log: false).chomp
rescue => err
  UI.verbose("Error getting git branch: #{err.message}")
  nil
end
git_log_between(pretty_format, from, to, merge_commit_filtering, date_format = nil, ancestry_path) click to toggle source
# File fastlane/lib/fastlane/helper/git_helper.rb, line 12
def self.git_log_between(pretty_format, from, to, merge_commit_filtering, date_format = nil, ancestry_path)
  command = %w(git log)
  command << "--pretty=#{pretty_format}"
  command << "--date=#{date_format}" if date_format
  command << '--ancestry-path' if ancestry_path
  command << "#{from}...#{to}"
  command << git_log_merge_commit_filtering_option(merge_commit_filtering)
  # "*command" syntax expands "command" array into variable arguments, which
  # will then be individually shell-escaped by Actions.sh.
  Actions.sh(*command.compact, log: false).chomp
rescue
  nil
end
git_log_last_commits(pretty_format, commit_count, merge_commit_filtering, date_format = nil, ancestry_path) click to toggle source
# File fastlane/lib/fastlane/helper/git_helper.rb, line 26
def self.git_log_last_commits(pretty_format, commit_count, merge_commit_filtering, date_format = nil, ancestry_path)
  command = %w(git log)
  command << "--pretty=#{pretty_format}"
  command << "--date=#{date_format}" if date_format
  command << '--ancestry-path' if ancestry_path
  command << '-n' << commit_count.to_s
  command << git_log_merge_commit_filtering_option(merge_commit_filtering)
  Actions.sh(*command.compact, log: false).chomp
rescue
  nil
end
git_remote_branch_name(remote_name) click to toggle source

Returns the default git remote branch name

# File fastlane/lib/fastlane/helper/git_helper.rb, line 141
def self.git_remote_branch_name(remote_name)
  # Rescues if not a git repo or no remote repo
  if remote_name
    Actions.sh("git remote show #{remote_name} | grep 'HEAD branch' | sed 's/.*: //'", log: false).chomp
  else
    # Query git for the current remote head
    Actions.sh("variable=$(git remote) && git remote show $variable | grep 'HEAD branch' | sed 's/.*: //'", log: false).chomp
  end
rescue => err
  UI.verbose("Error getting git default remote branch: #{err.message}")
  nil
end
is_class_action?(class_ref) click to toggle source

Returns a boolean indicating whether the class reference is a Fastlane::Action

# File fastlane/lib/fastlane/actions/actions_helper.rb, line 173
def self.is_class_action?(class_ref)
  return false if class_ref.nil?
  is_an_action = class_ref < Fastlane::Action
  return is_an_action || false
end
is_deprecated?(class_ref) click to toggle source

Returns a boolean indicating if the class reference is a deprecated Fastlane::Action

# File fastlane/lib/fastlane/actions/actions_helper.rb, line 181
def self.is_deprecated?(class_ref)
  is_class_action?(class_ref) && class_ref.category == :deprecated
end
is_supported?(platform) click to toggle source
# File fastlane/lib/assets/custom_action_template.rb, line 68
def self.is_supported?(platform)
  # you can do things like
  #
  #  true
  #
  #  platform == :ios
  #
  #  [:ios, :mac].include?(platform)
  #

  platform == :ios
end
lane_context() click to toggle source

The shared hash can be accessed by any action and contains information like the screenshots path or beta URL

# File fastlane/lib/fastlane/actions/actions_helper.rb, line 48
def self.lane_context
  @lane_context ||= SharedValues::LaneContextValues.new
end
last_git_commit() click to toggle source

Returns the unwrapped subject and body of the last commit DEPRECATED: Use last_git_commit_message instead.

# File fastlane/lib/fastlane/helper/git_helper.rb, line 102
def self.last_git_commit
  UI.important('`last_git_commit` is deprecated. Please use `last_git_commit_message` instead.')
  last_git_commit_message
end
last_git_commit_dict() click to toggle source
# File fastlane/lib/fastlane/helper/git_helper.rb, line 62
def self.last_git_commit_dict
  return nil if last_git_commit_formatted_with('%an').nil?

  {
      author: last_git_commit_formatted_with('%an'),
      author_email: last_git_commit_formatted_with('%ae'),
      message: last_git_commit_formatted_with('%B'),
      commit_hash: last_git_commit_formatted_with('%H'),
      abbreviated_commit_hash: last_git_commit_formatted_with('%h')
  }
end
last_git_commit_formatted_with(pretty_format, date_format = nil) click to toggle source

Gets the last git commit information formatted into a String by the provided pretty format String. See the git-log documentation for valid format placeholders

# File fastlane/lib/fastlane/helper/git_helper.rb, line 76
def self.last_git_commit_formatted_with(pretty_format, date_format = nil)
  command = %w(git log -1)
  command << "--pretty=#{pretty_format}"
  command << "--date=#{date_format}" if date_format
  Actions.sh(*command.compact, log: false).chomp
rescue
  nil
end
last_git_commit_hash(short) click to toggle source

Get the hash of the last commit

# File fastlane/lib/fastlane/helper/git_helper.rb, line 115
def self.last_git_commit_hash(short)
  format_specifier = short ? '%h' : '%H'
  string = last_git_commit_formatted_with(format_specifier).to_s
  return string unless string.empty?
  return nil
end
last_git_commit_message() click to toggle source

Returns the unwrapped subject and body of the last commit

# File fastlane/lib/fastlane/helper/git_helper.rb, line 108
def self.last_git_commit_message
  s = (last_git_commit_formatted_with('%B') || "").strip
  return s if s.to_s.length > 0
  nil
end
last_git_tag_hash(tag_match_pattern = nil) click to toggle source
# File fastlane/lib/fastlane/helper/git_helper.rb, line 38
def self.last_git_tag_hash(tag_match_pattern = nil)
  tag_pattern_param = tag_match_pattern ? "=#{tag_match_pattern}" : ''
  Actions.sh('git', 'rev-list', "--tags#{tag_pattern_param}", '--max-count=1').chomp
rescue
  nil
end
last_git_tag_name(match_lightweight = true, tag_match_pattern = nil) click to toggle source
# File fastlane/lib/fastlane/helper/git_helper.rb, line 45
def self.last_git_tag_name(match_lightweight = true, tag_match_pattern = nil)
  hash = last_git_tag_hash(tag_match_pattern)
  # If hash is nil (command fails), "git describe" command below will still
  # run and provide some output, although it's definitely not going to be
  # anything reasonably expected. Bail out early.
  return unless hash

  command = %w(git describe)
  command << '--tags' if match_lightweight
  command << hash
  command << '--match' if tag_match_pattern
  command << tag_match_pattern if tag_match_pattern
  Actions.sh(*command.compact, log: false).chomp
rescue
  nil
end
load_default_actions() click to toggle source
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 111
def self.load_default_actions
  Dir[File.expand_path('*.rb', File.dirname(__FILE__))].each do |file|
    require file
  end
end
load_external_actions(path) click to toggle source
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 124
def self.load_external_actions(path)
  UI.user_error!("You need to pass a valid path") unless File.exist?(path)

  class_refs = []
  Dir[File.expand_path('*.rb', path)].each do |file|
    begin
      require file
    rescue SyntaxError => ex
      content = File.read(file, encoding: "utf-8")
      ex.to_s.lines
        .collect { |error| error.match(/#{file}:(\d+):(.*)/) }
        .reject(&:nil?)
        .each { |error| UI.content_error(content, error[1]) }
      UI.user_error!("Syntax error in #{File.basename(file)}")
      next
    end

    file_name = File.basename(file).gsub('.rb', '')

    class_name = file_name.fastlane_class + 'Action'
    begin
      class_ref = Fastlane::Actions.const_get(class_name)
      class_refs << class_ref

      if class_ref.respond_to?(:run)
        UI.success("Successfully loaded custom action '#{file}'.") if FastlaneCore::Globals.verbose?
      else
        UI.error("Could not find method 'run' in class #{class_name}.")
        UI.error('For more information, check out the docs: https://docs.fastlane.tools/')
        UI.user_error!("Action '#{file_name}' is damaged!", show_github_issues: true)
      end
    rescue NameError
      # Action not found
      UI.error("Could not find '#{class_name}' class defined.")
      UI.error('For more information, check out the docs: https://docs.fastlane.tools/')
      UI.user_error!("Action '#{file_name}' is damaged!", show_github_issues: true)
    end
  end
  Actions.reset_aliases

  return class_refs
end
load_helpers() click to toggle source

Import all the helpers

# File fastlane/lib/fastlane/actions/actions_helper.rb, line 118
def self.load_helpers
  Dir[File.expand_path('../helper/*.rb', File.dirname(__FILE__))].each do |file|
    require file
  end
end
output() click to toggle source
# File fastlane/lib/assets/custom_action_template.rb, line 51
def self.output
  # Define the shared values you are going to provide
  # Example
  [
    ['[[NAME_UP]]_CUSTOM_VALUE', 'A description of what this value contains']
  ]
end
reset_aliases() click to toggle source
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 28
def self.reset_aliases
  @alias_actions = nil
end
return_value() click to toggle source
# File fastlane/lib/assets/custom_action_template.rb, line 59
def self.return_value
  # If your method provides a return value, you can describe here what it does
end
run(params) click to toggle source
# File fastlane/lib/assets/custom_action_template.rb, line 8
def self.run(params)
  # fastlane will take care of reading in the parameter and fetching the environment variable:
  UI.message "Parameter API Token: #{params[:api_token]}"

  # sh "shellcommand ./path"

  # Actions.lane_context[SharedValues::[[NAME_UP]]_CUSTOM_VALUE] = "my_val"
end
sh(*command, log: true, error_callback: nil, &b) click to toggle source

Execute a shell command This method will output the string and execute it Just an alias for sh_no_action When running this in tests, it will return the actual command instead of executing it @param log [Boolean] should fastlane print out the executed command @param error_callback [Block] a callback invoked with the command output if there is a non-zero exit status

# File fastlane/lib/fastlane/helper/sh_helper.rb, line 11
def self.sh(*command, log: true, error_callback: nil, &b)
  sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
end
sh_control_output(*command, print_command: true, print_command_output: true, error_callback: nil) { |exit_status || $?, result, shell_command| ... } click to toggle source

@param command The command to be executed (variadic) @param print_command [Boolean] Should we print the command that's being executed @param print_command_output [Boolean] Should we print the command output during execution @param error_callback [Block] A block that's called if the command exits with a non-zero status @yield [status, result, cmd] The return status of the command, all output from the command and an equivalent shell command @yieldparam [Process::Status] status A Process::Status indicating the status of the completed command @yieldparam [String] result The complete output to stdout and stderr of the completed command @yieldparam [String] cmd A shell command equivalent to the arguments passed rubocop: disable Metrics/PerceivedComplexity

# File fastlane/lib/fastlane/helper/sh_helper.rb, line 28
def self.sh_control_output(*command, print_command: true, print_command_output: true, error_callback: nil)
  print_command = print_command_output = true if $troubleshoot
  # Set the encoding first, the user might have set it wrong
  previous_encoding = [Encoding.default_external, Encoding.default_internal]
  Encoding.default_external = Encoding::UTF_8
  Encoding.default_internal = Encoding::UTF_8

  # Workaround to support previous Fastlane syntax.
  # This has some limitations. For example, it requires the caller to shell escape
  # everything because of usages like ["ls -la", "/tmp"] instead of ["ls", "-la", "/tmp"].
  command = [command.first.join(" ")] if command.length == 1 && command.first.kind_of?(Array)

  shell_command = shell_command_from_args(*command)
  UI.command(shell_command) if print_command

  result = ''
  exit_status = nil
  if Helper.sh_enabled?
    # The argument list is passed directly to Open3.popen2e, which
    # handles the variadic argument list in the same way as Kernel#spawn.
    # (http://ruby-doc.org/core-2.4.2/Kernel.html#method-i-spawn) or
    # Process.spawn (http://ruby-doc.org/core-2.4.2/Process.html#method-c-spawn).
    #
    # sh "ls -la /Applications/Xcode\ 7.3.1.app"
    # sh "ls", "-la", "/Applications/Xcode 7.3.1.app"
    # sh({ "FOO" => "Hello" }, "echo $FOO")
    Open3.popen2e(*command) do |stdin, io, thread|
      io.sync = true
      io.each do |line|
        UI.command_output(line.strip) if print_command_output
        result << line
      end
      exit_status = thread.value
    end

    # Checking Process::Status#exitstatus instead of #success? makes for more
    # testable code. (Tests mock exitstatus only.) This is also consistent
    # with previous implementations of sh and... probably portable to all
    # relevant platforms.
    if exit_status.exitstatus != 0
      message = if print_command
                  "Exit status of command '#{shell_command}' was #{exit_status.exitstatus} instead of 0."
                else
                  "Shell command exited with exit status #{exit_status.exitstatus} instead of 0."
                end
      message += "\n#{result}" if print_command_output

      if error_callback || block_given?
        UI.error(message)
        # block notified below, on success or failure
        error_callback && error_callback.call(result)
      else
        UI.shell_error!(message)
      end
    end
  else
    result << shell_command # only for the tests
  end

  if block_given?
    # Avoid yielding nil in tests. $? will be meaningless, but calls to
    # it will not crash. There is no Process::Status.new. The alternative
    # is to move this inside the sh_enabled? check and not yield in tests.
    return yield(exit_status || $?, result, shell_command)
  end
  result
rescue => ex
  raise ex
ensure
  Encoding.default_external = previous_encoding.first
  Encoding.default_internal = previous_encoding.last
end
sh_no_action(*command, log: true, error_callback: nil, &b) click to toggle source
# File fastlane/lib/fastlane/helper/sh_helper.rb, line 15
def self.sh_no_action(*command, log: true, error_callback: nil, &b)
  sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
end
shell_command_from_args(*args) click to toggle source

Used to produce a shell command string from a list of arguments that may be passed to methods such as Kernel#system, Kernel#spawn and Open3.popen2e in order to print the command to the terminal. The same *args are passed directly to a system call (Open3.popen2e). This interpretation is not used when executing a command.

@param args Any number of arguments used to construct a command @raise [ArgumentError] If no arguments passed @return [String] A shell command representing the arguments passed in

# File fastlane/lib/fastlane/helper/sh_helper.rb, line 111
def self.shell_command_from_args(*args)
  raise ArgumentError, "sh requires at least one argument" unless args.count > 0

  command = ""

  # Optional initial environment Hash
  if args.first.kind_of?(Hash)
    command = args.shift.map { |k, v| "#{k}=#{v.shellescape}" }.join(" ") + " "
  end

  # Support [ "/usr/local/bin/foo", "foo" ], "-x", ...
  if args.first.kind_of?(Array)
    command += args.shift.first.shellescape + " " + args.shelljoin
    command.chomp!(" ")
  elsif args.count == 1 && args.first.kind_of?(String)
    command += args.first
  else
    command += args.shelljoin
  end

  command
end
verify_gem!(gem_name) click to toggle source

will make sure a gem is installed. If it's not an appropriate error message is shown this will not 'require' the gem

# File fastlane/lib/fastlane/helper/gem_helper.rb, line 5
def self.verify_gem!(gem_name)
  begin
    FastlaneRequire.install_gem_if_needed(gem_name: gem_name, require_gem: false)
    # We don't import this by default, as it's not always the same
    # also e.g. cocoapods is just required and not imported
  rescue Gem::LoadError
    UI.error("Could not find gem '#{gem_name}'")
    UI.error("")
    UI.error("If you installed fastlane using `gem install fastlane` run")
    UI.command("gem install #{gem_name}")
    UI.error("to install the missing gem")
    UI.error("")
    UI.error("If you use a Gemfile add this to your Gemfile:")
    UI.important("  gem '#{gem_name}'")
    UI.error("and run `bundle install`")

    UI.user_error!("You have to install the `#{gem_name}` gem on this machine") unless Helper.test?
  end
  true
end

Private Class Methods

git_log_merge_commit_filtering_option(merge_commit_filtering) click to toggle source
# File fastlane/lib/fastlane/helper/git_helper.rb, line 155
def self.git_log_merge_commit_filtering_option(merge_commit_filtering)
  case merge_commit_filtering
  when :exclude_merges
    "--no-merges"
  when :only_include_merges
    "--merges"
  when :include_merges
    nil
  end
end