xcode_log_parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 327e465ed6cd7b416a3231550945fde0169c0e8a
4
+ data.tar.gz: 209b2b02ba3fcb4dc89fcab11d0c5a1bd4aa6e07
5
+ SHA512:
6
+ metadata.gz: f0ddca6c1f941a10e2868af51f44cf6062a79083e478dfe43a3ca36bbdfec13ac358d4f9afee6c1c8b5b89bb2ebafa42ad4a91d9b4340177c9656d9a5c5ccf21
7
+ data.tar.gz: 66b94209c25218b59e2d8bddd2144c7f76198f488fd96f24a88ef7a76290980037c77df8cf4eb698e1311d0018edc0263adb720ec95ac135b6a5c39573ca7841
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Felix Krause
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,45 @@
1
+ # xcode_log_parser
2
+
3
+ This is an alternative approach to generate JUnit files for your CI (e.g. Jenkins) without parsing the `xcodebuild` output, but the resulting Xcode `plist` files.
4
+
5
+ ## Installation
6
+
7
+ Add this to your `Gemfile`
8
+ ```
9
+ gem xcode_log_parser
10
+ ```
11
+ and run
12
+ ```
13
+ bundle install
14
+ ```
15
+
16
+ Alternatively you can install the gem system-wide using `sudo gem install xcode_log_parser`.
17
+
18
+ ## Usage
19
+
20
+ If you use `fastlane`, check out the official [fastlane plugin](https://github.com/KrauseFx/xcode_log_parser/tree/master/fastlane-plugin-xcode_log_parser#readme) on how to use `xcode_log_parser` in `fastlane`.
21
+
22
+ #### Run tests
23
+
24
+ ```
25
+ cd [project]
26
+ scan --derived_data_path "output"
27
+ ```
28
+
29
+ #### Convert the plist files to junit
30
+
31
+ ```
32
+ xcode_log_parser
33
+ ```
34
+
35
+ You can also pass a custom directory containing the plist files
36
+
37
+ ```
38
+ xcode_log_parser --path ./something
39
+ ```
40
+
41
+ For more information run
42
+
43
+ ```
44
+ xcode_log_parser --help
45
+ ````
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.expand_path("../../lib", __FILE__)
3
+
4
+ require 'xcode_log_parser'
5
+ require 'xcode_log_parser/commands_generator'
6
+ XcodeLogParser::CommandsGenerator.start
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <% number_of_tests = 0 %>
3
+ <% number_of_failures = 0 %>
4
+ <% @results.each { |a| number_of_tests += a[:number_of_tests] } %>
5
+ <% @results.each { |a| number_of_failures += a[:number_of_failures] } %>
6
+
7
+ <testsuites tests="<%= number_of_tests %>" failures="<%= number_of_failures %>">
8
+ <% @results.each do |testsuite| %>
9
+ <testsuite name=<%= testsuite[:target_name].encode(:xml => :attr) %> tests="<%= testsuite[:number_of_tests] %>" failures="<%= testsuite[:number_of_failures] %>">
10
+ <% testsuite[:tests].each do |test| %>
11
+ <testcase classname=<%= test[:test_group].encode(:xml => :attr) %> name=<%= test[:name].encode(:xml => :attr) %>>
12
+ <% (test[:failures] || []).each do |failure| %>
13
+ <failure message=<%= failure[:failure_message].encode(:xml => :attr) %>>
14
+ </failure>
15
+ <% end %>
16
+ </testcase>
17
+ <% end %>
18
+ </testsuite>
19
+ <% end %>
20
+ </testsuites>
@@ -0,0 +1,10 @@
1
+ require 'fastlane_core'
2
+
3
+ require 'xcode_log_parser/version'
4
+ require 'xcode_log_parser/options'
5
+ require 'xcode_log_parser/test_parser'
6
+ require 'xcode_log_parser/junit_generator'
7
+
8
+ module XcodeLogParser
9
+ UI = FastlaneCore::UI
10
+ end
@@ -0,0 +1,43 @@
1
+ require 'commander'
2
+
3
+ HighLine.track_eof = false
4
+
5
+ module XcodeLogParser
6
+ class CommandsGenerator
7
+ include Commander::Methods
8
+
9
+ def self.start
10
+ self.new.run
11
+ end
12
+
13
+ def run
14
+ program :version, XcodeLogParser::VERSION
15
+ program :description, XcodeLogParser::DESCRIPTION
16
+ program :help, 'Author', 'Felix Krause <xcode_log_parser@krausefx.com>'
17
+ program :help, 'Website', 'https://fastlane.tools'
18
+ program :help, 'GitHub', 'https://github.com/KrauseFx/xcode_log_parser'
19
+ program :help_formatter, :compact
20
+
21
+ global_option('--verbose', 'Shows a more verbose output') { $verbose = true }
22
+
23
+ always_trace!
24
+
25
+ FastlaneCore::CommanderGenerator.new.generate(XcodeLogParser::Options.available_options)
26
+
27
+ command :run do |c|
28
+ c.syntax = 'xcode_log_parser'
29
+ c.description = XcodeLogParser::DESCRIPTION
30
+
31
+ c.action do |args, options|
32
+ options = FastlaneCore::Configuration.create(XcodeLogParser::Options.available_options, options.__hash__)
33
+ FastlaneCore::PrintTable.print_values(config: options, title: "Summary for xcode_log_parser #{XcodeLogParser::VERSION}") if $verbose
34
+ XcodeLogParser::TestParser.auto_convert(options[:path])
35
+ end
36
+ end
37
+
38
+ default_command :run
39
+
40
+ run!
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ module XcodeLogParser
2
+ class JunitGenerator
3
+ attr_accessor :results
4
+
5
+ def initialize(results)
6
+ self.results = results
7
+ end
8
+
9
+ def generate
10
+ # JUnit file documentation: http://llg.cubic.org/docs/junit/
11
+ # And http://nelsonwells.net/2012/09/how-jenkins-ci-parses-and-displays-junit-output/
12
+ # And http://windyroad.com.au/dl/Open%20Source/JUnit.xsd
13
+
14
+ lib_path = FastlaneCore::Helper.gem_path("xcode_log_parser")
15
+ xml_path = File.join(lib_path, "lib/assets/junit.xml.erb")
16
+ xml = ERB.new(File.read(xml_path), nil, '<>').result(binding) # http://www.rrn.dk/rubys-erb-templating-system
17
+
18
+ xml = xml.gsub('system_', 'system-').delete("\e") # Jenkins can not parse 'ESC' symbol
19
+
20
+ # We have to manuall clear empty lines
21
+ # They may contain white spaces
22
+ clean_xml = []
23
+ xml.each_line do |row|
24
+ clean_xml << row.delete("\n") if row.strip.to_s.length > 0
25
+ end
26
+ return clean_xml.join("\n")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module XcodeLogParser
2
+ class Options
3
+ def self.available_options
4
+ @options ||= [
5
+ FastlaneCore::ConfigItem.new(key: :path,
6
+ short_option: "-p",
7
+ env_name: "XCODE_LOG_PARSER_PATH",
8
+ default_value: ".",
9
+ description: "Path to the directory that should be converted",
10
+ verify_block: proc do |value|
11
+ v = File.expand_path(value.to_s)
12
+ UI.user_error!("Path '#{v}' is not a directory or can't be found") unless File.directory?(v)
13
+ end)
14
+ ]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,113 @@
1
+ module XcodeLogParser
2
+ class TestParser
3
+ attr_accessor :data
4
+
5
+ attr_accessor :file_content
6
+
7
+ attr_accessor :raw_json
8
+
9
+ def self.auto_convert(containing_dir)
10
+ files = Dir["#{containing_dir}/**/Logs/Test/*TestSummaries.plist"]
11
+ files += Dir["#{containing_dir}/Test/*TestSummaries.plist"]
12
+ files += Dir["#{containing_dir}/*TestSummaries.plist"]
13
+
14
+ UI.user_error!("No test result files found in directory '#{containing_dir}'") if files.empty?
15
+
16
+ return files.collect do |path|
17
+ to_path = path.gsub(".plist", ".junit")
18
+ File.write(to_path, XcodeLogParser::TestParser.new(path).to_junit)
19
+ puts "Successfully generated '#{to_path}'"
20
+ to_path
21
+ end
22
+ end
23
+
24
+ def initialize(path)
25
+ path = File.expand_path(path)
26
+ UI.user_error!("File not found at path '#{path}'") unless File.exist?(path)
27
+
28
+ self.file_content = File.read(path)
29
+ self.raw_json = Plist.parse_xml(self.file_content)
30
+ return if self.raw_json["FormatVersion"].to_s.length == 0 # maybe that's a useless plist file
31
+
32
+ ensure_file_valid!
33
+ parse_content
34
+ end
35
+
36
+ # Returns the JUnit report as String
37
+ def to_junit
38
+ JunitGenerator.new(self.data).generate
39
+ end
40
+
41
+ private
42
+
43
+ def ensure_file_valid!
44
+ format_version = self.raw_json["FormatVersion"]
45
+ UI.user_error!("Format version '#{format_version}' is not supported") unless format_version == "1.2"
46
+ end
47
+
48
+ # Convert the Hashes and Arrays in something more useful
49
+ def parse_content
50
+ def unfold_tests(data)
51
+ # `data` looks like this
52
+ # => [{"Subtests"=>
53
+ # [{"Subtests"=>
54
+ # [{"Subtests"=>
55
+ # [{"TestIdentifier"=>"Unit/testExample()",
56
+ # "TestName"=>"testExample()",
57
+ # "TestObjectClass"=>"IDESchemeActionTestSummary",
58
+ # "TestStatus"=>"Success",
59
+ # "TestSummaryGUID"=>"4A24BFED-03E6-4FBE-BC5E-2D80023C06B4"},
60
+ # {"FailureSummaries"=>
61
+ # [{"FileName"=>"/Users/krausefx/Developer/themoji/Unit/Unit.swift",
62
+ # "LineNumber"=>34,
63
+ # "Message"=>"XCTAssertTrue failed - ",
64
+ # "PerformanceFailure"=>false}],
65
+ # "TestIdentifier"=>"Unit/testExample2()",
66
+
67
+ tests = []
68
+ data.each do |current_hash|
69
+ if current_hash["Subtests"]
70
+ tests += unfold_tests(current_hash["Subtests"])
71
+ end
72
+ if current_hash["TestStatus"]
73
+ tests << current_hash
74
+ end
75
+ end
76
+ return tests
77
+ end
78
+
79
+ self.data = self.raw_json["TestableSummaries"].collect do |testable_summary|
80
+ summary_row = {
81
+ project_path: testable_summary["ProjectPath"],
82
+ target_name: testable_summary["TargetName"],
83
+ test_name: testable_summary["TestName"],
84
+ tests: unfold_tests(testable_summary["Tests"]).collect do |current_test|
85
+ current_row = {
86
+ identifier: current_test["TestIdentifier"],
87
+ test_group: current_test["TestIdentifier"].split("/")[0..-2].join("."),
88
+ name: current_test["TestName"],
89
+ object_class: current_test["TestObjectClass"],
90
+ status: current_test["TestStatus"],
91
+ guid: current_test["TestSummaryGUID"]
92
+ }
93
+ if current_test["FailureSummaries"]
94
+ current_row[:failures] = current_test["FailureSummaries"].collect do |current_failure|
95
+ {
96
+ file_name: current_failure['FileName'],
97
+ line_number: current_failure['LineNumber'],
98
+ message: current_failure['Message'],
99
+ performance_failure: current_failure['PerformanceFailure'],
100
+ failure_message: "#{current_failure['Message']}#{current_failure['FileName']}:#{current_failure['LineNumber']}"
101
+ }
102
+ end
103
+ end
104
+ current_row
105
+ end
106
+ }
107
+ summary_row[:number_of_tests] = summary_row[:tests].count
108
+ summary_row[:number_of_failures] = summary_row[:tests].find_all { |a| (a[:failures] || []).count > 0 }.count
109
+ summary_row
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,4 @@
1
+ module XcodeLogParser
2
+ VERSION = "0.1.0"
3
+ DESCRIPTION = "Parse and convert Xcode Log Parser"
4
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xcode_log_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Felix Krause
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fastlane_core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.48.1
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.48.1
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: plist
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: 3.1.0
40
+ - - <
41
+ - !ruby/object:Gem::Version
42
+ version: 4.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - '>='
48
+ - !ruby/object:Gem::Version
49
+ version: 3.1.0
50
+ - - <
51
+ - !ruby/object:Gem::Version
52
+ version: 4.0.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: bundler
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rake
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: pry
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: rspec
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 3.1.0
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ version: 3.1.0
109
+ - !ruby/object:Gem::Dependency
110
+ name: rubocop
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ~>
114
+ - !ruby/object:Gem::Version
115
+ version: 0.38.0
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ~>
121
+ - !ruby/object:Gem::Version
122
+ version: 0.38.0
123
+ description: Parse and convert Xcode Log Parser
124
+ email:
125
+ - fastlane@krausefx.com
126
+ executables:
127
+ - xcode_log_parser
128
+ extensions: []
129
+ extra_rdoc_files: []
130
+ files:
131
+ - lib/assets/junit.xml.erb
132
+ - lib/xcode_log_parser/commands_generator.rb
133
+ - lib/xcode_log_parser/junit_generator.rb
134
+ - lib/xcode_log_parser/options.rb
135
+ - lib/xcode_log_parser/test_parser.rb
136
+ - lib/xcode_log_parser/version.rb
137
+ - lib/xcode_log_parser.rb
138
+ - README.md
139
+ - LICENSE
140
+ - bin/xcode_log_parser
141
+ homepage: https://fastlane.tools
142
+ licenses:
143
+ - MIT
144
+ metadata: {}
145
+ post_install_message:
146
+ rdoc_options: []
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - '>='
152
+ - !ruby/object:Gem::Version
153
+ version: 2.0.0
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ requirements: []
160
+ rubyforge_project:
161
+ rubygems_version: 2.0.14.1
162
+ signing_key:
163
+ specification_version: 4
164
+ summary: Parse and convert Xcode Log Parser
165
+ test_files: []
166
+ has_rdoc: