class Danger::DangerXcodeSummary

Shows all build errors, warnings and unit tests results generated from `xcodebuild`. You need to use the `xcresult` produced by Xcode 11. It's located in the Derived Data folder. @example Showing summary

xcode_summary.report 'build.xcresult'

@example Filtering warnings in Pods

xcode_summary.ignored_files = '**/Pods/**'
xcode_summary.report 'build.xcresult'

@see diogot/danger-xcode_summary @tags xcode, xcodebuild, format

Constants

Location
Result

Attributes

ignored_files[RW]

A globbed string or array of strings which should match the files that you want to ignore warnings on. Defaults to nil. An example would be `'/Pods/'` to ignore warnings in Pods that your project uses.

@param [String or [String]] value @return [[String]]

ignored_results[RW]

A block that filters specific results. An example would be `lambda { |result| result.message.start_with?('ld') }` to ignore results for ld_warnings.

@param [Block value @return [Block]

ignores_warnings[RW]

Defines if warnings should be included or not Defaults to `false`. @param [Boolean] value @return [Boolean]

inline_mode[RW]

Defines if using inline comment or not. Defaults to `false`. @param [Boolean] value @return [Boolean]

project_root[RW]

The project root, which will be used to make the paths relative. Defaults to `pwd`. @param [String] value @return [String]

Public Instance Methods

plugin() click to toggle source

Pick a Dangerfile plugin for a chosen request_source and cache it based on github.com/danger/danger/blob/master/lib/danger/plugin_support/plugin.rb#L31

# File lib/xcode_summary/plugin.rb, line 83
def plugin
  plugins = Plugin.all_plugins.select { |plugin| Dangerfile.essential_plugin_classes.include? plugin }
  @plugin ||= plugins.select { |p| p.method_defined? :html_link }.map { |p| p.new(@dangerfile) }.compact.first
end
report(file_path) click to toggle source

Reads a `.xcresult` and reports it.

@param [String] file_path Path for xcresult bundle. @return [void]

# File lib/xcode_summary/plugin.rb, line 93
def report(file_path)
  if File.exist?(file_path)
    xcode_summary = XCResult::Parser.new(path: file_path)
    format_summary(xcode_summary)
  else
    fail 'summary file not found'
  end
end
warning_error_count(file_path) click to toggle source

Reads a `.xcresult` and reports its warning and error count.

@param [String] file_path Path for xcresult bundle. @return [String] JSON string with warningCount and errorCount

# File lib/xcode_summary/plugin.rb, line 106
def warning_error_count(file_path)
  if File.exist?(file_path)
    xcode_summary = XCResult::Parser.new(path: file_path)
    warning_count = 0
    error_count = 0
    xcode_summary.actions_invocation_record.actions.each do |action|
      warning_count += warnings(action).count
      error_count += errors(action).count
    end
    result = { warnings: warning_count, errors: error_count }
    result.to_json
  else
    fail 'summary file not found'
  end
end

Private Instance Methods

errors(action) click to toggle source
# File lib/xcode_summary/plugin.rb, line 159
def errors(action)
  errors = [
    action.action_result.issues.error_summaries,
    action.build_result.issues.error_summaries
  ].flatten.compact.map do |summary|
    result = Result.new(summary.message, parse_location(summary.document_location_in_creating_workspace))
    Result.new(format_warning(result), result.location)
  end

  test_failures = [
    action.action_result.issues.test_failure_summaries,
    action.build_result.issues.test_failure_summaries
  ].flatten.compact.map do |summary|
    result = Result.new(summary.message, parse_location(summary.document_location_in_creating_workspace))
    Result.new(format_test_failure(result, summary.producing_target, summary.test_case_name),
               result.location)
  end

  results = (errors + test_failures).uniq.reject { |result| result.message.nil? }
  results.delete_if(&ignored_results)
end
escape_reason(reason) click to toggle source
# File lib/xcode_summary/plugin.rb, line 212
def escape_reason(reason)
  reason.gsub('>', '\>').gsub('<', '\<')
end
format_path(file_path, line) click to toggle source
# File lib/xcode_summary/plugin.rb, line 192
def format_path(file_path, line)
  if plugin
    path = file_path
    path += "#L#{line}" if line
    plugin.html_link(path)
  else
    file_path
  end
end
format_summary(xcode_summary) click to toggle source
# File lib/xcode_summary/plugin.rb, line 124
def format_summary(xcode_summary)
  xcode_summary.actions_invocation_record.actions.each do |action|
    warnings(action).each do |result|
      if inline_mode && result.location
        warn(result.message, sticky: false, file: result.location.file_path, line: result.location.line)
      else
        warn(result.message, sticky: false)
      end
    end
    # rubocop:disable Lint/UnreachableLoop
    errors(action).each do |result|
      if inline_mode && result.location
        fail(result.message, sticky: false, file: result.location.file_path, line: result.location.line)
      else
        fail(result.message, sticky: false)
      end
    end
    # rubocop:enable Lint/UnreachableLoop
  end
end
format_test_failure(result, producing_target, test_case_name) click to toggle source
# File lib/xcode_summary/plugin.rb, line 227
def format_test_failure(result, producing_target, test_case_name)
  path = result.location.file_path
  path_link = format_path(path, result.location.line)
  suite_name = "#{producing_target}.#{test_case_name}"
  "**#{suite_name}**: #{escape_reason(result.message)}  <br />  #{path_link}"
end
format_warning(result) click to toggle source
# File lib/xcode_summary/plugin.rb, line 216
def format_warning(result)
  return escape_reason(result.message) if result.location.nil?

  path = result.location.file_path
  return nil if should_ignore_warning?(path)

  path_link = format_path(path, result.location.line)

  "**#{path_link}**: #{escape_reason(result.message)}"
end
parse_location(document_location) click to toggle source
# File lib/xcode_summary/plugin.rb, line 181
def parse_location(document_location)
  return nil if document_location.nil?

  file_path = document_location.url.gsub('file://', '').split('#').first
  file_name = file_path.split('/').last
  fragment = document_location.url.split('#').last
  params = CGI.parse(fragment).transform_values(&:first)
  line = params['StartingLineNumber'].to_i + 1 # StartingLineNumber is 0-based, but we need a 1-based value
  Location.new(file_name, relative_path(file_path), line)
end
relative_path(path) click to toggle source
# File lib/xcode_summary/plugin.rb, line 202
def relative_path(path)
  return nil if project_root.nil?

  path.gsub(project_root, '')
end
should_ignore_warning?(path) click to toggle source
# File lib/xcode_summary/plugin.rb, line 208
def should_ignore_warning?(path)
  ignored_files.any? { |pattern| File.fnmatch(pattern, path) }
end
warnings(action) click to toggle source
# File lib/xcode_summary/plugin.rb, line 145
def warnings(action)
  return [] if ignores_warnings

  warnings = [
    action.action_result.issues.warning_summaries,
    action.build_result.issues.warning_summaries
  ].flatten.compact.map do |summary|
    result = Result.new(summary.message, parse_location(summary.document_location_in_creating_workspace))
    Result.new(format_warning(result), result.location)
  end
  warnings = warnings.uniq.reject { |result| result.message.nil? }
  warnings.delete_if(&ignored_results)
end