diff --git a/CHANGELOG.md b/CHANGELOG.md index a81de142f..7afe7c158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Adding group set incorrect parent in case of complex path [#614](https://github.com/tuist/XcodeProj/pull/614) by [@avdyushin](https://github.com/avdyushin) +- **Breaking** Fixed issue where some schemes could not be deserialized because a buildable reference did not contain a blueprint identifier [#612](https://github.com/tuist/XcodeProj/pull/612) by [@daltonclaybrook](https://github.com/daltonclaybrook) - Added the `com.apple.product-type.driver-extension` and `com.apple.product-type.system-extension` PBXProductType [#618](https://github.com/tuist/XcodeProj/pull/618) by [@vgorloff](https://github.com/vgorloff). ### Changed diff --git a/Fixtures/Schemes/NoBlueprintID.xcscheme b/Fixtures/Schemes/NoBlueprintID.xcscheme new file mode 100644 index 000000000..ef67cbfcf --- /dev/null +++ b/Fixtures/Schemes/NoBlueprintID.xcscheme @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Sources/XcodeProj/Scheme/XCScheme+BuildableReference.swift b/Sources/XcodeProj/Scheme/XCScheme+BuildableReference.swift index 43c8a08a6..0a092295f 100644 --- a/Sources/XcodeProj/Scheme/XCScheme+BuildableReference.swift +++ b/Sources/XcodeProj/Scheme/XCScheme+BuildableReference.swift @@ -23,9 +23,9 @@ extension XCScheme { blueprint = .reference(object.reference) } - private var blueprint: Blueprint - public var blueprintIdentifier: String { - blueprint.string + private var blueprint: Blueprint? + public var blueprintIdentifier: String? { + blueprint?.string } public var buildableName: String @@ -35,24 +35,24 @@ extension XCScheme { // MARK: - Init public init(referencedContainer: String, - blueprint: PBXObject, + blueprint: PBXObject?, buildableName: String, blueprintName: String, buildableIdentifier: String = "primary") { self.referencedContainer = referencedContainer - self.blueprint = .reference(blueprint.reference) + self.blueprint = blueprint.map { Blueprint.reference($0.reference) } self.buildableName = buildableName self.buildableIdentifier = buildableIdentifier self.blueprintName = blueprintName } public init(referencedContainer: String, - blueprintIdentifier: String, + blueprintIdentifier: String?, buildableName: String, blueprintName: String, buildableIdentifier: String = "primary") { self.referencedContainer = referencedContainer - self.blueprint = .string(blueprintIdentifier) + self.blueprint = blueprintIdentifier.map(Blueprint.string) self.buildableName = buildableName self.buildableIdentifier = buildableIdentifier self.blueprintName = blueprintName @@ -64,9 +64,6 @@ extension XCScheme { guard let buildableIdentifier = element.attributes["BuildableIdentifier"] else { throw XCSchemeError.missing(property: "BuildableIdentifier") } - guard let blueprintIdentifier = element.attributes["BlueprintIdentifier"] else { - throw XCSchemeError.missing(property: "BlueprintIdentifier") - } guard let buildableName = element.attributes["BuildableName"] else { throw XCSchemeError.missing(property: "BuildableName") } @@ -77,22 +74,26 @@ extension XCScheme { throw XCSchemeError.missing(property: "ReferencedContainer") } self.buildableIdentifier = buildableIdentifier - blueprint = .string(blueprintIdentifier) + let blueprintIdentifier = element.attributes["BlueprintIdentifier"] + self.blueprint = blueprintIdentifier.map(Blueprint.string) self.buildableName = buildableName self.blueprintName = blueprintName self.referencedContainer = referencedContainer } func xmlElement() -> AEXMLElement { - AEXMLElement(name: "BuildableReference", - value: nil, - attributes: [ - "BuildableIdentifier": buildableIdentifier, - "BlueprintIdentifier": blueprint.string, - "BuildableName": buildableName, - "BlueprintName": blueprintName, - "ReferencedContainer": referencedContainer, - ]) + var attributes: [String: String] = [ + "BuildableIdentifier": buildableIdentifier, + "BuildableName": buildableName, + "BlueprintName": blueprintName, + "ReferencedContainer": referencedContainer, + ] + if let blueprintIdentifier = blueprint?.string { + attributes["BlueprintIdentifier"] = blueprintIdentifier + } + return AEXMLElement(name: "BuildableReference", + value: nil, + attributes: attributes) } // MARK: - Equatable diff --git a/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift b/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift index 3cea6f5d3..8a6325a1a 100644 --- a/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift +++ b/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift @@ -245,6 +245,19 @@ final class XCSchemeIntegrationTests: XCTestCase { XCTAssertNotEqual(runnableA1, remoteRunnableA1) } + func test_schemeWithoutBlueprintIdentifier_canBeCreated() { + let subject = try? XCScheme(path: noBlueprintIDPath) + XCTAssertNotNil(subject) + } + + func test_schemeWithoutBlueprintIdentifier_serializesWithoutBlueprintIdentifier() throws { + let subject = try XCScheme(path: noBlueprintIDPath) + let buildable = try XCTUnwrap(subject.buildAction?.buildActionEntries.first?.buildableReference) + let buildableXML = buildable.xmlElement() + XCTAssertNotNil(buildableXML.attributes["BlueprintName"]) + XCTAssertNil(buildableXML.attributes["BlueprintIdentifier"]) + } + func test_buildAction_runPostActionsOnFailure() throws { // Given / When let subject = try XCScheme(path: runPostActionsOnFailureSchemePath) @@ -545,6 +558,11 @@ final class XCSchemeIntegrationTests: XCTestCase { fixturesPath() + "Schemes/MinimalInformation.xcscheme" } + /// Path to a scheme with a buildable reference that contains no blueprint identifier + private var noBlueprintIDPath: Path { + fixturesPath() + "Schemes/NoBlueprintID.xcscheme" + } + private var watchAppSchemePath: Path { fixturesPath() + "iOS/AppWithExtensions/AppWithExtensions.xcodeproj/xcshareddata/xcschemes/WatchApp.xcscheme" }