Skip to content

Commit c1a2c17

Browse files
authored
Merge pull request #64 from a7ex/feature/replace-XcresultKit
Replace XCResultKit in order to support Swift testing fully
2 parents 29d7f08 + 6552701 commit c1a2c17

218 files changed

Lines changed: 4198 additions & 718 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ iOSInjectionProject/
9292

9393
# Compiled app, ready for notarization
9494
product/
95+
AgentNotes/
96+
TestResults/
97+
CLAUDE.md
9598

9699

97100
.scannerwork/

.swiftformat

Lines changed: 126 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,135 @@
1-
--swiftversion 5.9
1+
# old format options:
2+
# --disable wrapMultilineStatementBraces
3+
# --disable redundantSelf
4+
# --disable preferForLoop
25

6+
--swiftversion 6.2
7+
8+
--acronyms ID,URL,UUID
39
--allman false
4-
--assetliterals visual-width
5-
--beforemarks
6-
--binarygrouping none
7-
--categorymark "MARK: %c"
8-
--classthreshold 0
9-
--closingparen balanced
10-
# --commas always
11-
--conflictmarkers reject
12-
--decimalgrouping none
13-
--elseposition same-line
14-
--emptybraces no-space
15-
--enumthreshold 0
16-
--exponentcase lowercase
17-
--exponentgrouping disabled
18-
--extensionacl on-extension
19-
--extensionlength 0
20-
--extensionmark "MARK: - %t + %c"
21-
--fractiongrouping disabled
10+
--allow-partial-wrapping true
11+
--anonymous-for-each convert
12+
--asset-literals visual-width
13+
--async-capturing
14+
--before-marks
15+
--binary-grouping none
16+
--blank-line-after-switch-case multiline-only
17+
--call-site-paren default
18+
--category-mark "MARK: %c"
19+
--class-threshold 0
20+
--closing-paren balanced
21+
--closure-void remove
22+
--complex-attributes preserve
23+
--computed-var-attributes preserve
24+
--conditional-assignment always
25+
--conflict-markers reject
26+
--date-format system
27+
--decimal-grouping none
28+
--default-test-suite-attributes
29+
--doc-comments preserve
30+
--else-position same-line
31+
--empty-braces no-space
32+
--enum-namespaces always
33+
--enum-threshold 0
34+
--equatable-macro none
35+
--exponent-case lowercase
36+
--exponent-grouping disabled
37+
--extension-acl on-extension
38+
--extension-mark "MARK: - %t + %c"
39+
--extension-threshold 0
40+
--file-macro "#file"
41+
--fraction-grouping disabled
2242
--fragment false
23-
--funcattributes preserve
24-
--groupedextension "MARK: %c"
25-
--guardelse auto
26-
--header ignore
27-
--hexgrouping none
28-
--hexliteralcase uppercase
43+
--func-attributes preserve
44+
--generic-types
45+
--group-blank-lines true
46+
--grouped-extension "MARK: %c"
47+
--guard-else auto
48+
--header "// new header text"
49+
--hex-grouping none
50+
--hex-literal-case uppercase
2951
--ifdef indent
30-
--importgrouping alpha
52+
--import-grouping alpha
3153
--indent 4
32-
--indentcase false
33-
--lifecycle
54+
--indent-case false
55+
--indent-strings false
56+
--inferred-types always
57+
--init-coder-nil false
58+
--language-mode 0
59+
--lifecycle
60+
--line-after-marks true
61+
--line-between-guards false
3462
--linebreaks lf
35-
--markextensions always
36-
--marktypes always
37-
--maxwidth none
38-
--modifierorder
39-
--nevertrailing compactMap,map,flatMap
40-
--nospaceoperators
41-
--nowrapoperators
42-
--octalgrouping none
43-
--operatorfunc spaced
44-
--organizetypes actor,class,enum,struct
45-
--patternlet inline
63+
--mark-categories true
64+
--mark-class-threshold 0
65+
--mark-enum-threshold 0
66+
--mark-extension-threshold 0
67+
--mark-extensions always
68+
--mark-struct-threshold 0
69+
--mark-types always
70+
--markdown-files ignore
71+
--max-width none
72+
--modifier-order
73+
--never-trailing compactMap,flatMap,map
74+
--nil-init remove
75+
--no-space-operators
76+
--no-wrap-operators
77+
--non-complex-attributes
78+
--octal-grouping none
79+
--operator-func spaced
80+
--organization-mode visibility
81+
--organize-types actor,class,enum,struct
82+
--pattern-let hoist
83+
--prefer-synthesized-init-for-internal-structs never
84+
--preserve-acronyms
85+
--preserve-decls
86+
--preserved-property-types Package
87+
--property-types inferred
4688
--ranges spaced
47-
--redundanttype inferred
89+
--redundant-async tests-only
90+
--redundant-throws tests-only
4891
--self remove
49-
--selfrequired
92+
--self-required
5093
--semicolons never
51-
--shortoptionals always
52-
--smarttabs enabled
53-
--stripunusedargs closure-only
54-
--structthreshold 0
55-
--tabwidth unspecified
56-
--trailingclosures
57-
--trimwhitespace always
58-
--typeattributes preserve
59-
--typemark "MARK: - %t"
60-
--varattributes preserve
61-
--voidtype void
62-
--wraparguments before-first
63-
--wrapcollections before-first
64-
--wrapconditions preserve
65-
--wrapparameters before-first
66-
--wrapreturntype preserve
67-
--xcodeindentation disabled
68-
--yodaswap always
69-
--disable redundantReturn,wrapMultilineStatementBraces,trailingCommas,preferKeyPath
94+
--short-optionals always
95+
--single-line-for-each ignore
96+
--smart-tabs enabled
97+
--some-any true
98+
--sort-swiftui-properties none
99+
--sorted-patterns
100+
--stored-var-attributes preserve
101+
--strip-unused-args closure-only
102+
--struct-threshold 0
103+
--swift-version 6.2
104+
--tab-width unspecified
105+
--throw-capturing
106+
--timezone system
107+
--trailing-closures
108+
--trailing-commas always
109+
--trim-whitespace always
110+
--type-attributes preserve
111+
--type-blank-lines remove
112+
--type-body-marks preserve
113+
--type-delimiter space-after
114+
--type-mark "MARK: - %t"
115+
--type-marks
116+
--type-order
117+
--url-macro none
118+
--visibility-marks
119+
--visibility-order
120+
--void-type Void
121+
--wrap-arguments before-first
122+
--wrap-collections before-first
123+
--wrap-conditions preserve
124+
--wrap-effects preserve
125+
--wrap-enum-cases always
126+
--wrap-parameters before-first
127+
--wrap-return-type preserve
128+
--wrap-string-interpolation default
129+
--wrap-ternary default
130+
--wrap-type-aliases preserve
131+
--xcode-indentation disabled
132+
--xctest-symbols
133+
--yoda-swap always
134+
--disable docComments,docCommentsBeforeModifiers,fileHeader,opaqueGenericParameters,preferKeyPath,redundantReturn,trailingCommas,wrapMultilineStatementBraces
135+
--enable isEmpty,privateStateVariables,propertyTypes,unusedPrivateDeclarations

.swiftpm/xcode/xcshareddata/xcschemes/xcresultparser.xcscheme

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@
8282
argument = "/Users/alex/xcodebuild_result.xcresult"
8383
isEnabled = "NO">
8484
</CommandLineArgument>
85+
<CommandLineArgument
86+
argument = "/Users/alex/Work/__OwnProjects/myGithub/xcresultparser/Tests/XcresultparserTests/TestAssets/parametrized.xcresult"
87+
isEnabled = "YES">
88+
</CommandLineArgument>
8589
<CommandLineArgument
8690
argument = "-d"
8791
isEnabled = "NO">
@@ -120,7 +124,7 @@
120124
</CommandLineArgument>
121125
<CommandLineArgument
122126
argument = "-o html"
123-
isEnabled = "NO">
127+
isEnabled = "YES">
124128
</CommandLineArgument>
125129
<CommandLineArgument
126130
argument = "-t FRBNetworking"
@@ -144,7 +148,7 @@
144148
</CommandLineArgument>
145149
<CommandLineArgument
146150
argument = "-h"
147-
isEnabled = "YES">
151+
isEnabled = "NO">
148152
</CommandLineArgument>
149153
<CommandLineArgument
150154
argument = "-o md"

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## Version 2.0.0-beta - 2026-02-21
8+
### CHANGES:
9+
- Replace XCResultKit usage with direct `xcresulttool` and `xccov` parsing using local `Codable` models.
10+
- Remove XCResultKit as a package dependency from `Package.swift`.
11+
- Migrate JUnit, summary/test formatting, coverage formatting, and issues JSON paths to the new model/tooling layer.
12+
- Keep output compatibility where possible while aligning with modern `xcresulttool` payloads.
13+
- Raise the minimum supported platform to macOS 12.
14+
- Keep expected failures as a distinct state in human-readable outputs, while emitting them as passing test cases in JUnit/Sonar XML for compatibility.
15+
- Treat unknown `--coverage-targets` values as an error instead of silently producing empty coverage output.
16+
717
## Version 1.9.4 - 2025-12-19
818
### CHANGES:
919
Previously, we were only ever parsing the first failure for a test and passing that to the JUnit representation.

CommandlineTool/main.swift

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import ArgumentParser
99
import Foundation
1010
import XcresultparserLib
1111

12-
private let marketingVersion = "1.9.4"
12+
private let marketingVersion = "2.0.0-beta"
1313

1414
struct xcresultparser: ParsableCommand {
1515
static let configuration = CommandConfiguration(
@@ -31,7 +31,7 @@ struct xcresultparser: ParsableCommand {
3131
@Option(name: [.customShort("e"), .customLong("excluded-path")], help: "Specify which path names to exclude. You can use more than one -e option to specify a list of path patterns to exclude. This option only has effect, if the format is either 'cobertura' or 'xml' with the --coverage (-c) option for a code coverage report or if the format is one of 'warnings', 'errors' or 'warnings-and-errors'.")
3232
var excludedPaths: [String] = []
3333

34-
@Option(name: .shortAndLong, help: "The fields in the summary. Default is all: errors|warnings|analyzerWarnings|tests|failed|skipped")
34+
@Option(name: .shortAndLong, help: "The fields in the summary. Default is all: errors|warnings|analyzerWarnings|tests|failed|skipped|duration|date")
3535
var summaryFields: String?
3636

3737
@Flag(name: .shortAndLong, help: "Whether to print coverage data.")
@@ -91,82 +91,70 @@ struct xcresultparser: ParsableCommand {
9191
}
9292

9393
private func outputSonarXML(for xcresult: String) throws {
94-
guard let converter = SonarCoverageConverter(
94+
let converter = try SonarCoverageConverter(
9595
with: URL(fileURLWithPath: xcresult),
9696
projectRoot: projectRoot ?? "",
9797
coverageTargets: coverageTargets,
9898
excludedPaths: excludedPaths,
9999
strictPathnames: strictPathnames == 1
100-
) else {
101-
throw ParseError.argumentError
102-
}
100+
)
103101
let rslt = try converter.xmlString(quiet: quiet == 1)
104102
writeToStdOut(rslt)
105103
}
106104

107105
private func outputCoberturaXML(for xcresult: String) throws {
108-
guard let converter = CoberturaCoverageConverter(
106+
let converter = try CoberturaCoverageConverter(
109107
with: URL(fileURLWithPath: xcresult),
110108
projectRoot: projectRoot ?? "",
111109
coverageTargets: coverageTargets,
112110
excludedPaths: excludedPaths,
113111
strictPathnames: strictPathnames == 1
114-
) else {
115-
throw ParseError.argumentError
116-
}
112+
)
117113
let rslt = try converter.xmlString(quiet: quiet == 1)
118114
writeToStdOut(rslt)
119115
}
120116

121117
private func outputIssuesJSON(for xcresult: String, format: OutputFormat) throws {
122-
guard let converter = IssuesJSON(
118+
let converter = try IssuesJSON(
123119
with: URL(fileURLWithPath: xcresult),
124120
projectRoot: projectRoot ?? "",
125121
excludedPaths: excludedPaths
126-
) else {
127-
throw ParseError.argumentError
128-
}
122+
)
129123
let rslt = try converter.jsonString(format: format, quiet: quiet == 1)
130124
writeToStdOut(rslt)
131125
}
132126

133127
private func outputTargetNames(for xcresult: String) throws {
134-
guard let converter = SonarCoverageConverter(
128+
let converter = try SonarCoverageConverter(
135129
with: URL(fileURLWithPath: xcresult),
136130
projectRoot: projectRoot ?? "",
137-
coverageTargets: coverageTargets,
131+
coverageTargets: [],
138132
strictPathnames: strictPathnames == 1
139-
) else {
140-
throw ParseError.argumentError
141-
}
133+
)
142134
writeToStdOut(converter.targetsInfo)
143135
}
144136

145137
private func outputJUnitXML(
146138
for xcresult: String,
147139
with format: TestReportFormat
148140
) throws {
149-
guard let junitXML = JunitXML(
141+
let junitXML = try JunitXML(
150142
with: URL(fileURLWithPath: xcresult),
151143
projectRoot: projectRoot ?? "",
152144
format: format
153-
) else {
154-
throw ParseError.argumentError
155-
}
145+
)
156146
writeToStdOut(junitXML.xmlString)
157147
}
158148

159149
private func outputDescription(for xcresult: String) throws {
160-
guard let resultParser = XCResultFormatter(
150+
let resultParser = try XCResultFormatter(
161151
with: URL(fileURLWithPath: xcresult),
162152
formatter: outputFormatter,
163153
coverageTargets: coverageTargets,
164154
failedTestsOnly: failedTestsOnly == 1,
165-
summaryFields: summaryFields ?? "errors|warnings|analyzerWarnings|tests|failed|skipped",
155+
summaryFields: summaryFields ?? "errors|warnings|analyzerWarnings|tests|failed|skipped|duration|date",
166156
coverageReportFormat: CoverageReportFormat(string: coverageReportFormat)
167-
) else {
168-
throw ParseError.argumentError
169-
}
157+
)
170158
writeToStdOutLn(resultParser.documentPrefix(title: "XCResults"))
171159
writeToStdOutLn(resultParser.summary)
172160
if noTestResult == 0 {

Package.resolved

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)