diff --git a/Gemfile.lock b/Gemfile.lock index 2bbc5ea..9c90047 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,55 +2,56 @@ PATH remote: . specs: trainer (0.7.0) + fastlane (>= 2.25.0) plist (>= 3.1.0, < 4.0.0) GEM remote: https://rubygems.org/ specs: - CFPropertyList (2.3.5) - activesupport (4.2.8) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.5.1) - public_suffix (~> 2.0, >= 2.0.2) + CFPropertyList (3.0.0) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) ast (2.3.0) + atomos (0.1.2) babosa (1.0.2) - claide (1.0.1) + claide (1.0.2) coderay (1.1.1) colored (1.2) colored2 (3.1.2) - commander-fastlane (4.4.4) + commander-fastlane (4.4.6) highline (~> 1.7.2) + declarative (0.0.10) + declarative-option (0.1.0) diff-lcs (1.3) - domain_name (0.5.20170223) + domain_name (0.5.20180417) unf (>= 0.0.5, < 1.0.0) - dotenv (2.2.0) - excon (0.55.0) - faraday (0.12.0.1) + dotenv (2.4.0) + emoji_regex (0.1.1) + excon (0.62.0) + faraday (0.15.0) multipart-post (>= 1.2, < 3) faraday-cookie_jar (0.0.6) faraday (>= 0.7.4) http-cookie (~> 1.0.0) - faraday_middleware (0.11.0.1) + faraday_middleware (0.12.2) faraday (>= 0.7.4, < 1.0) - fastimage (2.1.0) - fastlane (2.25.0) - activesupport (< 5) + fastimage (2.1.3) + fastlane (2.94.0) + CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) babosa (>= 1.0.2, < 2.0.0) bundler (>= 1.12.0, < 2.0.0) colored - commander-fastlane (>= 4.4.0, < 5.0.0) + commander-fastlane (>= 4.4.6, < 5.0.0) dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (~> 0.1) excon (>= 0.45.0, < 1.0.0) faraday (~> 0.9) faraday-cookie_jar (~> 0.0.6) faraday_middleware (~> 0.9) - fastimage (>= 1.6) - gh_inspector (>= 1.0.1, < 2.0.0) - google-api-client (~> 0.9.2) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-api-client (>= 0.13.1, < 0.14.0) highline (>= 1.7.2, < 2.0.0) json (< 3.0.0) mini_magick (~> 4.5.1) @@ -58,61 +59,60 @@ GEM multi_xml (~> 0.5) multipart-post (~> 2.0.0) plist (>= 3.1.0, < 4.0.0) + public_suffix (~> 2.0.0) rubyzip (>= 1.1.0, < 2.0.0) security (= 0.1.3) - slack-notifier (>= 1.3, < 2.0.0) + simctl (~> 1.6.3) + slack-notifier (>= 2.0.0, < 3.0.0) terminal-notifier (>= 1.6.2, < 2.0.0) terminal-table (>= 1.4.5, < 2.0.0) - tty-screen (~> 0.5.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) - xcodeproj (>= 0.20, < 2.0.0) + xcodeproj (>= 1.5.7, < 2.0.0) xcpretty (>= 0.2.4, < 1.0.0) xcpretty-travis-formatter (>= 0.0.3) - gh_inspector (1.0.3) - google-api-client (0.9.28) - addressable (~> 2.3) + gh_inspector (1.1.3) + google-api-client (0.13.6) + addressable (~> 2.5, >= 2.5.1) googleauth (~> 0.5) - httpclient (~> 2.7) - hurley (~> 0.1) - memoist (~> 0.11) - mime-types (>= 1.6) - representable (~> 2.3.0) - retriable (~> 2.0) - googleauth (0.5.1) - faraday (~> 0.9) - jwt (~> 1.4) + httpclient (>= 2.8.1, < 3.0) + mime-types (~> 3.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + googleauth (0.6.2) + faraday (~> 0.12) + jwt (>= 1.4, < 3.0) logging (~> 2.0) memoist (~> 0.12) multi_json (~> 1.11) os (~> 0.9) signet (~> 0.7) - highline (1.7.8) + highline (1.7.10) http-cookie (1.0.3) domain_name (~> 0.5) httpclient (2.8.3) - hurley (0.2) - i18n (0.8.1) - json (2.0.3) - jwt (1.5.6) + json (2.1.0) + jwt (2.1.0) little-plugger (1.1.4) - logging (2.2.0) + logging (2.2.2) little-plugger (~> 1.1) multi_json (~> 1.10) - memoist (0.15.0) + memoist (0.16.0) method_source (0.8.2) mime-types (3.1) mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mini_magick (4.5.1) - minitest (5.10.1) - multi_json (1.12.1) + multi_json (1.13.1) multi_xml (0.6.0) multipart-post (2.0.0) - nanaimo (0.2.3) + nanaimo (0.2.5) + naturally (2.1.0) os (0.9.6) parser (2.4.0.0) ast (~> 2.2) - plist (3.2.0) + plist (3.4.0) powerpack (0.1.1) pry (0.10.4) coderay (~> 1.1.0) @@ -121,10 +121,12 @@ GEM public_suffix (2.0.5) rainbow (2.2.1) rake (12.0.0) - representable (2.3.0) - uber (~> 0.0.7) - retriable (2.1.0) - rouge (1.11.1) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) + retriable (3.1.1) + rouge (2.0.7) rspec (3.1.0) rspec-core (~> 3.1.0) rspec-expectations (~> 3.1.0) @@ -146,35 +148,38 @@ GEM ruby-progressbar (1.8.1) rubyzip (1.2.1) security (0.1.3) - signet (0.7.3) + signet (0.8.1) addressable (~> 2.3) faraday (~> 0.9) - jwt (~> 1.5) + jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - slack-notifier (1.5.1) + simctl (1.6.4) + CFPropertyList + naturally + slack-notifier (2.3.2) slop (3.6.0) - terminal-notifier (1.7.1) - terminal-table (1.7.3) - unicode-display_width (~> 1.1.1) - thread_safe (0.3.6) - tty-screen (0.5.0) - tzinfo (1.2.3) - thread_safe (~> 0.1) - uber (0.0.15) + terminal-notifier (1.8.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + tty-cursor (0.5.0) + tty-screen (0.6.4) + tty-spinner (0.8.0) + tty-cursor (>= 0.5.0) + uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.2) + unf_ext (0.0.7.5) unicode-display_width (1.1.3) word_wrap (1.0.0) - xcodeproj (1.4.3) - CFPropertyList (~> 2.3.3) - activesupport (>= 3) - claide (>= 1.0.1, < 2.0) + xcodeproj (1.5.7) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.2) + claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.2.3) - xcpretty (0.2.6) - rouge (~> 1.8) - xcpretty-travis-formatter (0.0.4) + nanaimo (~> 0.2.4) + xcpretty (0.2.8) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.0) xcpretty (~> 0.2, >= 0.0.7) PLATFORMS @@ -182,7 +187,6 @@ PLATFORMS DEPENDENCIES bundler - fastlane (>= 2.25.0) pry rake rspec (~> 3.1.0) @@ -190,4 +194,4 @@ DEPENDENCIES trainer! BUNDLED WITH - 1.14.6 + 1.16.1 diff --git a/fastlane-plugin-trainer/lib/fastlane/plugin/trainer/actions/trainer_action.rb b/fastlane-plugin-trainer/lib/fastlane/plugin/trainer/actions/trainer_action.rb index af1dcf7..6dc4522 100644 --- a/fastlane-plugin-trainer/lib/fastlane/plugin/trainer/actions/trainer_action.rb +++ b/fastlane-plugin-trainer/lib/fastlane/plugin/trainer/actions/trainer_action.rb @@ -4,7 +4,7 @@ class TrainerAction < Action def self.run(params) require "trainer" - params[:path] = Actions.lane_context[Actions::SharedValues::SCAN_GENERATED_PLIST_FILE] if Actions.lane_context[Actions::SharedValues::SCAN_GENERATED_PLIST_FILE] + params[:path] ||= Actions.lane_context[Actions::SharedValues::SCAN_GENERATED_PLIST_FILE] if Actions.lane_context[Actions::SharedValues::SCAN_GENERATED_PLIST_FILE] params[:path] ||= Actions.lane_context[Actions::SharedValues::SCAN_DERIVED_DATA_PATH] if Actions.lane_context[Actions::SharedValues::SCAN_DERIVED_DATA_PATH] fail_build = params[:fail_build] diff --git a/lib/assets/junit.xml.erb b/lib/assets/junit.xml.erb index 6b1446a..697a454 100644 --- a/lib/assets/junit.xml.erb +++ b/lib/assets/junit.xml.erb @@ -1,12 +1,29 @@ -<% number_of_tests = 0 %> -<% number_of_failures = 0 %> -<% @results.each { |a| number_of_tests += a[:number_of_tests] } %> -<% @results.each { |a| number_of_failures += a[:number_of_failures] } %> +<% number_of_tests = @results.map {|r| r[:number_of_tests] }.reduce(:+) %> +<% number_of_failures = @results.map {|r| r[:number_of_failures] }.reduce(:+) %> <% @results.each do |testsuite| %> - :attr) %> tests="<%= testsuite[:number_of_tests] %>" failures="<%= testsuite[:number_of_failures] %>" time="<%= testsuite[:duration] %>"> + <% run_destination = testsuite[:run_destination] %> + <% if run_destination %> + <% target_device = run_destination[:target_device] %> + <% package = "#{run_destination[:name]} (#{target_device[:operating_system_version]})" %> + <% package_attr = "package=#{ package.encode(:xml => :attr) }" %> + <% testsuite_name = "#{(testsuite[:target_name].nil? ? testsuite[:test_name] : testsuite[:target_name])} - #{package}" %> + <% else %> + <% package_attr = "" %> + <% testsuite_name = testsuite[:target_name] %> + <% end %> + name=<%= testsuite_name.encode(:xml => :attr) %> tests="<%= testsuite[:number_of_tests] %>" failures="<%= testsuite[:number_of_failures] %>" time="<%= testsuite[:duration] %>"> + <% if run_destination %> + + + + + + + + <% end %> <% testsuite[:tests].each do |test| %> :attr) %> name=<%= test[:name].encode(:xml => :attr) %> time="<%= test[:duration] %>"> <% (test[:failures] || []).each do |failure| %> diff --git a/lib/trainer/test_parser.rb b/lib/trainer/test_parser.rb index 84dc4a0..506576f 100644 --- a/lib/trainer/test_parser.rb +++ b/lib/trainer/test_parser.rb @@ -13,9 +13,7 @@ def self.auto_convert(config) title: "Summary for trainer #{Trainer::VERSION}") containing_dir = config[:path] - files = Dir["#{containing_dir}/**/Logs/Test/*TestSummaries.plist"] - files += Dir["#{containing_dir}/Test/*TestSummaries.plist"] - files += Dir["#{containing_dir}/*TestSummaries.plist"] + files = Dir["#{containing_dir}/**/*_TestSummaries.plist"] files += Dir[containing_dir] if containing_dir.end_with?(".plist") # if it's the exact path to a plist file if files.empty? @@ -104,12 +102,29 @@ def unfold_tests(data) # Convert the Hashes and Arrays in something more useful def parse_content + plist_run_destination = self.raw_json["RunDestination"] + if plist_run_destination + plist_target_device = plist_run_destination["TargetDevice"] + run_destination = { + name: plist_run_destination["Name"], + target_architecture: plist_run_destination["TargetArchitecture"], + target_device: { + identifier: plist_target_device["Identifier"], + name: plist_target_device["Name"], + operating_system_version: plist_target_device["OperatingSystemVersion"] + } + } + else + run_destination = nil + end + self.data = self.raw_json["TestableSummaries"].collect do |testable_summary| summary_row = { project_path: testable_summary["ProjectPath"], target_name: testable_summary["TargetName"], test_name: testable_summary["TestName"], duration: testable_summary["Tests"].map { |current_test| current_test["Duration"] }.inject(:+), + run_destination: run_destination, tests: unfold_tests(testable_summary["Tests"]).collect do |current_test| current_row = { identifier: current_test["TestIdentifier"], diff --git a/spec/fixtures/TestSummaries-NoRunDestination.junit b/spec/fixtures/TestSummaries-NoRunDestination.junit new file mode 100644 index 0000000..0f68222 --- /dev/null +++ b/spec/fixtures/TestSummaries-NoRunDestination.junit @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spec/fixtures/TestSummaries-NoRunDestination.plist b/spec/fixtures/TestSummaries-NoRunDestination.plist new file mode 100644 index 0000000..c6fac89 --- /dev/null +++ b/spec/fixtures/TestSummaries-NoRunDestination.plist @@ -0,0 +1,262 @@ + + + + + FormatVersion + 1.1 + TestableSummaries + + + ProjectPath + Foo.xcodeproj + TargetName + FooTests + TestName + FooTests + TestObjectClass + IDESchemeActionTestableSummary + Tests + + + Duration + 0 + Subtests + + + Duration + 0 + Subtests + + TestIdentifier + Quick.framework + TestName + Quick.framework + TestObjectClass + IDESchemeActionTestSummaryGroup + + + Duration + 0 + Subtests + + + Duration + 0 + Subtests + + + Duration + 0 + TestIdentifier + BarViewControllerTests/testInit_NoPlaces_NoSelection() + TestName + testInit_NoPlaces_NoSelection() + TestObjectClass + IDESchemeActionTestSummary + TestStatus + Success + TestSummaryGUID + CA8D1702-A3E7-48FD-8800-5EF827F29D9F + + + TestIdentifier + BarViewControllerTests + TestName + BarViewControllerTests + TestObjectClass + IDESchemeActionTestSummaryGroup + + + TestIdentifier + FooTests.xctest + TestName + FooTests.xctest + TestObjectClass + IDESchemeActionTestSummaryGroup + + + TestIdentifier + All tests + TestName + All tests + TestObjectClass + IDESchemeActionTestSummaryGroup + + + + + ProjectPath + Foo.xcodeproj + TargetName + FooViewsTests + TestName + FooViewsTests + TestObjectClass + IDESchemeActionTestableSummary + Tests + + + Duration + 0 + Subtests + + + Duration + 0 + Subtests + + + Duration + 0 + Subtests + + + Duration + 0 + TestIdentifier + FooEmptyTableViewHelperTests/testHeaderViewObservation() + TestName + testHeaderViewObservation() + TestObjectClass + IDESchemeActionTestSummary + TestStatus + Success + TestSummaryGUID + DAFAADD3-8495-4E1E-9869-60701DEC5BE2 + + + TestIdentifier + FooEmptyTableViewHelperTests + TestName + FooEmptyTableViewHelperTests + TestObjectClass + IDESchemeActionTestSummaryGroup + + + Duration + 0 + Subtests + + + Duration + 0 + TestIdentifier + UIView_ExtensionsTests/testComplexViewIsVisibleInWindow() + TestName + testComplexViewIsVisibleInWindow() + TestObjectClass + IDESchemeActionTestSummary + TestStatus + Success + TestSummaryGUID + D03219FE-B432-4669-B957-42DA8C6FD99E + + + Duration + 0 + TestIdentifier + UIView_ExtensionsTests/testSimpleViewIsVisibleInWindow() + TestName + testSimpleViewIsVisibleInWindow() + TestObjectClass + IDESchemeActionTestSummary + TestStatus + Success + TestSummaryGUID + F55CD64D-EC8C-4679-BF41-F5ECAA2CB26F + + + TestIdentifier + UIView_ExtensionsTests + TestName + UIView_ExtensionsTests + TestObjectClass + IDESchemeActionTestSummaryGroup + + + TestIdentifier + FooViewsTests.xctest + TestName + FooViewsTests.xctest + TestObjectClass + IDESchemeActionTestSummaryGroup + + + TestIdentifier + All tests + TestName + All tests + TestObjectClass + IDESchemeActionTestSummaryGroup + + + + + ProjectPath + Foo.xcodeproj + TargetName + FooFoundationTests + TestName + FooFoundationTests + TestObjectClass + IDESchemeActionTestableSummary + Tests + + + Duration + 0 + Subtests + + + Duration + 0 + Subtests + + + Duration + 0 + Subtests + + + Duration + 0 + TestIdentifier + KeyValueObserverDeferredTests/testCancelReleasesObservedObject() + TestName + testCancelReleasesObservedObject() + TestObjectClass + IDESchemeActionTestSummary + TestStatus + Success + TestSummaryGUID + 913E53E7-BD75-4987-B48E-4D08FB2D441B + + + TestIdentifier + KeyValueObserverDeferredTests + TestName + KeyValueObserverDeferredTests + TestObjectClass + IDESchemeActionTestSummaryGroup + + + TestIdentifier + FooFoundationTests.xctest + TestName + FooFoundationTests.xctest + TestObjectClass + IDESchemeActionTestSummaryGroup + + + TestIdentifier + All tests + TestName + All tests + TestObjectClass + IDESchemeActionTestSummaryGroup + + + + + + diff --git a/spec/fixtures/Valid1.junit b/spec/fixtures/Valid1.junit index 9203492..459b402 100644 --- a/spec/fixtures/Valid1.junit +++ b/spec/fixtures/Valid1.junit @@ -1,6 +1,13 @@ - + + + + + + + + diff --git a/spec/fixtures/Valid2.junit b/spec/fixtures/Valid2.junit index 5abdcaf..f8aee14 100644 --- a/spec/fixtures/Valid2.junit +++ b/spec/fixtures/Valid2.junit @@ -1,6 +1,13 @@ - + + + + + + + + diff --git a/spec/junit_generator_spec.rb b/spec/junit_generator_spec.rb index b688e0a..9cad03e 100644 --- a/spec/junit_generator_spec.rb +++ b/spec/junit_generator_spec.rb @@ -6,10 +6,16 @@ expect(tp.to_junit).to eq(junit) end - it "works for a with all tests passing" do + it "works for a plist with all tests passing" do tp = Trainer::TestParser.new("spec/fixtures/Valid2.plist") junit = File.read("spec/fixtures/Valid2.junit") expect(tp.to_junit).to eq(junit) end + + it "works for a plist with multiple test summaries and no run destination" do + tp = Trainer::TestParser.new("spec/fixtures/TestSummaries-NoRunDestination.plist") + junit = File.read("spec/fixtures/TestSummaries-NoRunDestination.junit") + expect(tp.to_junit).to eq(junit) + end end end diff --git a/spec/test_parser_spec.rb b/spec/test_parser_spec.rb index fe5560d..9beb16b 100644 --- a/spec/test_parser_spec.rb +++ b/spec/test_parser_spec.rb @@ -26,15 +26,16 @@ end end - describe "Stores the data in a useful format" do - describe "#tests_successful?" do - it "returns false if tests failed" do - tp = Trainer::TestParser.new("spec/fixtures/Valid1.plist") - expect(tp.tests_successful?).to eq(false) - end + describe "#tests_successful?" do + it "returns false if tests failed" do + tp = Trainer::TestParser.new("spec/fixtures/Valid1.plist") + expect(tp.tests_successful?).to eq(false) end + end - it "works as expected" do + describe "#data" do + + it "parses a single test target's output" do tp = Trainer::TestParser.new("spec/fixtures/Valid1.plist") expect(tp.data).to eq([ { @@ -42,6 +43,15 @@ target_name: "Unit", test_name: "Unit", duration: 0.4, + run_destination: { + name: "iPhone SE", + target_architecture: "x86_64", + target_device: { + identifier: "252CADC1-E488-4506-B293-892F59253C63", + name: "iPhone SE", + operating_system_version: "10.0" + } + }, tests: [ { identifier: "Unit/testExample()", @@ -85,6 +95,75 @@ } ]) end + + it "parses multiple test targets' output without a run destination" do + tp = Trainer::TestParser.new("spec/fixtures/TestSummaries-NoRunDestination.plist") + expect(tp.data).to eq([ + {:project_path=>"Foo.xcodeproj", + :target_name=>"FooTests", + :test_name=>"FooTests", + :run_destination=>nil, + :duration=>0.0, + :tests=> + [ + {:identifier=>"BarViewControllerTests/testInit_NoPlaces_NoSelection()", + :test_group=>"BarViewControllerTests", + :name=>"testInit_NoPlaces_NoSelection()", + :object_class=>"IDESchemeActionTestSummary", + :status=>"Success", + :guid=>"CA8D1702-A3E7-48FD-8800-5EF827F29D9F", + :duration=>0.0}], + :number_of_tests=>1, + :number_of_failures=>0}, + {:project_path=>"Foo.xcodeproj", + :target_name=>"FooViewsTests", + :test_name=>"FooViewsTests", + :run_destination=>nil, + :duration=>0.0, + :tests=> + [ + {:identifier=>"FooEmptyTableViewHelperTests/testHeaderViewObservation()", + :test_group=>"FooEmptyTableViewHelperTests", + :name=>"testHeaderViewObservation()", + :object_class=>"IDESchemeActionTestSummary", + :status=>"Success", + :guid=>"DAFAADD3-8495-4E1E-9869-60701DEC5BE2", + :duration=>0.0}, + {:identifier=>"UIView_ExtensionsTests/testComplexViewIsVisibleInWindow()", + :test_group=>"UIView_ExtensionsTests", + :name=>"testComplexViewIsVisibleInWindow()", + :object_class=>"IDESchemeActionTestSummary", + :status=>"Success", + :guid=>"D03219FE-B432-4669-B957-42DA8C6FD99E", + :duration=>0.0}, + {:identifier=>"UIView_ExtensionsTests/testSimpleViewIsVisibleInWindow()", + :test_group=>"UIView_ExtensionsTests", + :name=>"testSimpleViewIsVisibleInWindow()", + :object_class=>"IDESchemeActionTestSummary", + :status=>"Success", + :guid=>"F55CD64D-EC8C-4679-BF41-F5ECAA2CB26F", + :duration=>0.0}], + :number_of_tests=>3, + :number_of_failures=>0}, + {:project_path=>"Foo.xcodeproj", + :target_name=>"FooFoundationTests", + :test_name=>"FooFoundationTests", + :run_destination=>nil, + :duration=>0.0, + :tests=> + [ + {:identifier=> + "KeyValueObserverDeferredTests/testCancelReleasesObservedObject()", + :test_group=>"KeyValueObserverDeferredTests", + :name=>"testCancelReleasesObservedObject()", + :object_class=>"IDESchemeActionTestSummary", + :status=>"Success", + :guid=>"913E53E7-BD75-4987-B48E-4D08FB2D441B", + :duration=>0.0}], + :number_of_tests=>1, + :number_of_failures=>0} + ]) + end end end end