module Fastlane::Actions
Constants
- ARGS_MAP
- GIT_MERGE_COMMIT_FILTERING_OPTIONS
Public Class Methods
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 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
# 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
# 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
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
@!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
# 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
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
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 43 def self.executed_actions @executed_actions ||= [] end
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 167 def self.formerly_bundled_actions ["xcake"] end
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
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
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
# 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
# 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
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
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
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
# 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
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
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
# 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
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
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
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
# 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
# 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
# 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
# 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
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
# 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
# File fastlane/lib/fastlane/actions/actions_helper.rb, line 28 def self.reset_aliases @alias_actions = nil end
# 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
# 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
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
@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
# 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
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
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
# 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