Class: Fastlane::Actions::CollateJunitReportsAction
- Inherits:
-
Action
- Object
- Action
- Fastlane::Actions::CollateJunitReportsAction
- Defined in:
- lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb
Documentation collapse
- .authors ⇒ Object
- .available_options ⇒ Object
- .category ⇒ Object
-
.description ⇒ Object
:nocov:.
- .details ⇒ Object
- .example_code ⇒ Object
- .is_supported?(platform) ⇒ Boolean
Class Method Summary collapse
- .attribute_sum_string(node1, node2, attribute) ⇒ Object
- .collapse_testcase_multiple_failures_in_testsuite(testsuite) ⇒ Object
- .collate_testsuite(target_testsuite, other_testsuite) ⇒ Object
- .flatten_duplicate_testsuites(report, testsuite) ⇒ Object
- .increment_testable_tries(target_testable, other_testable) ⇒ Object
- .increment_testcase_tries(target_testcase, testcase) ⇒ Object
- .preprocess_testsuites(report, package, combine_multiple_targets) ⇒ Object
- .run(params) ⇒ Object
- .update_testable_counts(testable) ⇒ Object
- .update_testsuite_counts(testsuite) ⇒ Object
- .verbose(message) ⇒ Object
Class Method Details
.attribute_sum_string(node1, node2, attribute) ⇒ Object
162 163 164 165 166 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 162 def self.attribute_sum_string(node1, node2, attribute) value1 = node1.attribute(attribute).value.to_i value2 = node2.attribute(attribute).value.to_i (value1 + value2).to_s end |
.authors ⇒ Object
236 237 238 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 236 def self. ["lyndsey-ferguson/@lyndseydf"] end |
.available_options ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 194 def self. [ FastlaneCore::ConfigItem.new( key: :reports, env_name: 'COLLATE_JUNIT_REPORTS_REPORTS', description: 'An array of junit reports to collate. The first report is used as the base into which other reports are merged in', optional: false, type: Array, verify_block: proc do |reports| UI.user_error!('No junit report files found') if reports.empty? reports.each do |report| UI.user_error!("Error: junit report not found: '#{report}'") unless File.exist?(report) end end ), FastlaneCore::ConfigItem.new( key: :collated_report, env_name: 'COLLATE_JUNIT_REPORTS_COLLATED_REPORT', description: 'The final junit report file where all testcases will be merged into', optional: true, default_value: 'result.xml', type: String ) ] end |
.category ⇒ Object
240 241 242 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 240 def self.category :testing end |
.collapse_testcase_multiple_failures_in_testsuite(testsuite) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 59 def self.collapse_testcase_multiple_failures_in_testsuite(testsuite) testcases_with_failures = REXML::XPath.match(testsuite, 'testcase[failure]') while testcases_with_failures.size > 1 target_testcase = testcases_with_failures.shift name = target_testcase.attribute('name').value classname = target_testcase.attribute('classname').value failures = REXML::XPath.match(testsuite, "testcase[@name='#{name}'][@classname='#{classname}']/failure") next unless failures.size > 1 failures[1..-1].each do |failure| failure_clone = failure.clone failure_clone.text = failure.text target_testcase << failure_clone testsuite.delete_element(failure.parent) testcases_with_failures.delete(failure.parent) end end end |
.collate_testsuite(target_testsuite, other_testsuite) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 104 def self.collate_testsuite(target_testsuite, other_testsuite) other_testsuite.elements.each('testcase') do |testcase| classname = testcase.attribute('classname').value name = testcase.attribute('name').value target_testcase = REXML::XPath.first(target_testsuite, "testcase[@name='#{name}' and @classname='#{classname}']") # Replace target_testcase with testcase if target_testcase verbose(" collate_testsuite with testcase #{name}") verbose(" replacing \"#{target_testcase}\" with \"#{testcase}\"") parent = target_testcase.parent increment_testcase_tries(target_testcase, testcase) unless testcase.root == target_testcase.root parent.insert_after(target_testcase, testcase) parent.delete_element(target_testcase) verbose("") verbose(" target_testcase after replacement \"#{parent}\"") else target_testsuite << testcase end end end |
.description ⇒ Object
:nocov:
178 179 180 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 178 def self.description "🔷 Combines multiple junit report files into one junit report file" end |
.details ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 182 def self.details "The first junit report is used as the base report. Testcases " \ "from other reports are added if they do not already exist, or " \ "if the testcases already exist, they are replaced." \ "" \ "This is done because it is assumed that fragile tests, when " \ "re-run will often succeed due to less interference from other " \ "tests and the subsequent junit reports will have more passed tests." \ "" \ "Inspired by Derek Yang's fastlane-plugin-merge_junit_report" end |
.example_code ⇒ Object
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 220 def self.example_code [ " UI.important( 'example: ' \\ 'collate the xml reports to a temporary file \"result.xml\"' ) reports = Dir['../spec/fixtures/*.xml'].map { |relpath| File.absolute_path(relpath) } collate_junit_reports( reports: reports.sort_by { |f| File.mtime(f) }, collated_report: File.join(Dir.mktmpdir, 'result.xml') ) " ] end |
.flatten_duplicate_testsuites(report, testsuite) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 82 def self.flatten_duplicate_testsuites(report, testsuite) testsuite_name = testsuite.attribute('name').value duplicate_testsuites = REXML::XPath.match(report, "//testsuite[@name='#{testsuite_name}']") if duplicate_testsuites.size > 1 verbose(" > flattening_duplicate_testsuites") duplicate_testsuites.drop(1).each do |duplicate_testsuite| collate_testsuite(testsuite, duplicate_testsuite) duplicate_testsuite.parent.delete_element(duplicate_testsuite) end verbose(" < flattening_duplicate_testsuites") end update_testsuite_counts(testsuite) end |
.increment_testable_tries(target_testable, other_testable) ⇒ Object
125 126 127 128 129 130 131 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 125 def self.increment_testable_tries(target_testable, other_testable) try_count = target_testable.attribute('retries')&.value || 1 other_try_count = other_testable.attribute('retries')&.value || 1 target_testable.add_attribute('retries', (try_count.to_i + other_try_count.to_i).to_s) end |
.increment_testcase_tries(target_testcase, testcase) ⇒ Object
133 134 135 136 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 133 def self.increment_testcase_tries(target_testcase, testcase) try_count = target_testcase.attribute('retries')&.value || 0 testcase.add_attribute('retries', (try_count.to_i + 1).to_s) end |
.is_supported?(platform) ⇒ Boolean
244 245 246 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 244 def self.is_supported?(platform) %i[ios mac].include?(platform) end |
.preprocess_testsuites(report, package, combine_multiple_targets) ⇒ Object
96 97 98 99 100 101 102 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 96 def self.preprocess_testsuites(report, package, combine_multiple_targets) report.elements.each('//testsuite') do |testsuite| flatten_duplicate_testsuites(report, testsuite) collapse_testcase_multiple_failures_in_testsuite(testsuite) testsuite.add_attribute('package', package) if combine_multiple_targets end end |
.run(params) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 6 def self.run(params) report_filepaths = params[:reports] if report_filepaths.size == 1 FileUtils.cp(report_filepaths[0], params[:collated_report]) else verbose("collate_junit_reports with #{report_filepaths}") reports = report_filepaths.map { |report_filepath| REXML::Document.new(File.new(report_filepath)) } packages = reports.map { |r| r.root.attribute('name').value }.uniq combine_multiple_targets = packages.size > 1 # copy any missing testsuites target_report = reports.shift package = target_report.root.attribute('name').value preprocess_testsuites(target_report, package, combine_multiple_targets) reports.each do |report| increment_testable_tries(target_report.root, report.root) package = report.root.attribute('name').value preprocess_testsuites(report, package, combine_multiple_targets) verbose("> collating last report file #{report_filepaths.last}") report.elements.each('//testsuite') do |testsuite| testsuite_name = testsuite.attribute('name').value package_attribute = '' if combine_multiple_targets package_attribute = "@package='#{package}'" end target_testsuite = REXML::XPath.first(target_report, "//testsuite[@name='#{testsuite_name}' #{package_attribute}]") if target_testsuite verbose(" > collating testsuite #{testsuite_name}") collate_testsuite(target_testsuite, testsuite) verbose(" < collating testsuite #{testsuite_name}") else testable = REXML::XPath.first(target_report, "//testsuites") testable << testsuite end end verbose("< collating last report file #{report_filepaths.last}") end target_report.elements.each('//testsuite') do |testsuite| update_testsuite_counts(testsuite) end testable = REXML::XPath.first(target_report, 'testsuites') update_testable_counts(testable) testable.add_attribute('name', packages.to_a.join(', ')) FileUtils.mkdir_p(File.dirname(params[:collated_report])) File.open(params[:collated_report], 'w') do |f| target_report.write(f, 2) end end end |
.update_testable_counts(testable) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 138 def self.update_testable_counts(testable) testsuites = REXML::XPath.match(testable, 'testsuite') test_count = 0 failure_count = 0 testsuites.each do |testsuite| test_count += testsuite.attribute('tests').value.to_i failure_count += testsuite.attribute('failures').value.to_i end testable.add_attribute('tests', test_count.to_s) testable.add_attribute('failures', failure_count.to_s) end |
.update_testsuite_counts(testsuite) ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 150 def self.update_testsuite_counts(testsuite) testcases = REXML::XPath.match(testsuite, 'testcase') testsuite.add_attribute('tests', testcases.size.to_s) failure_count = testcases.reduce(0) do |count, testcase| if REXML::XPath.first(testcase, 'failure') count += 1 end count end testsuite.add_attribute('failures', failure_count.to_s) end |
.verbose(message) ⇒ Object
168 169 170 171 172 |
# File 'lib/fastlane/plugin/test_center/actions/collate_junit_reports.rb', line 168 def self.verbose() return if ENV.fetch('COLLATE_JUNIT_REPORTS_VERBOSITY', 1).to_i.zero? UI.verbose() end |