diff --git a/CHANGELOG.md b/CHANGELOG.md index c62677ff..257cd75c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Next Version +### Fixed + +- Fixed `supportedDestinations` validation when it contains watchOS for multiplatform apps. #1470 @tatsuky + ## 2.40.1 ### Fixed diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index fd821a6e..430e54e4 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -500,7 +500,7 @@ targets: destinationFilters: [iOS] ``` -Note that the definition of supported destinations can be applied to every type of bundle making everything more easy to manage (app targets, unit tests, UI tests etc). +Note that the definition of supported destinations can be applied to almost every type of bundle making everything more easy to manage (app targets, unit tests, UI tests etc). App targets currently do not support the watchOS destination. Create a separate target using `platform` for watchOS apps. See Apple's [Configuring a multiplatform app](https://developer.apple.com/documentation/xcode/configuring-a-multiplatform-app-target) for details. ### Sources diff --git a/Sources/ProjectSpec/SpecValidation.swift b/Sources/ProjectSpec/SpecValidation.swift index 9bf43e1a..a34fb3d4 100644 --- a/Sources/ProjectSpec/SpecValidation.swift +++ b/Sources/ProjectSpec/SpecValidation.swift @@ -185,6 +185,12 @@ extension Project { errors.append(.unexpectedTargetPlatformForSupportedDestinations(target: target.name, platform: target.platform)) } + if let supportedDestinations = target.supportedDestinations, + target.type.isApp, + supportedDestinations.contains(.watchOS) { + errors.append(.containsWatchOSDestinationForMultiplatformApp(target: target.name)) + } + if target.supportedDestinations?.contains(.macOS) == true, target.supportedDestinations?.contains(.macCatalyst) == true { diff --git a/Sources/ProjectSpec/SpecValidationError.swift b/Sources/ProjectSpec/SpecValidationError.swift index 1840a9bd..6e93de0e 100644 --- a/Sources/ProjectSpec/SpecValidationError.swift +++ b/Sources/ProjectSpec/SpecValidationError.swift @@ -19,6 +19,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidTargetSchemeTest(target: String, testTarget: String) case invalidTargetPlatformForSupportedDestinations(target: String) case unexpectedTargetPlatformForSupportedDestinations(target: String, platform: Platform) + case containsWatchOSDestinationForMultiplatformApp(target: String) case multipleMacPlatformsInSupportedDestinations(target: String) case missingTargetPlatformInSupportedDestinations(target: String, platform: Platform) case invalidSchemeTarget(scheme: String, target: String, action: String) @@ -66,6 +67,8 @@ public struct SpecValidationError: Error, CustomStringConvertible { return "Target \(target.quoted) has multiple definitions of mac platforms in supported destinations" case let .missingTargetPlatformInSupportedDestinations(target, platform): return "Target \(target.quoted) has platform \(platform.rawValue.quoted) that is missing in supported destinations" + case let .containsWatchOSDestinationForMultiplatformApp(target): + return "Multiplatform app \(target.quoted) cannot contain watchOS in \"supportedDestinations\". Create a separate target using \"platform\" for watchOS apps" case let .invalidConfigFile(configFile, config): return "Invalid config file \(configFile.quoted) for config \(config.quoted)" case let .invalidSchemeTarget(scheme, target, action): diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index 5f1f4854..b6d5f017 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -203,6 +203,32 @@ class ProjectSpecTests: XCTestCase { try expectValidationError(project, .unexpectedTargetPlatformForSupportedDestinations(target: "target1", platform: .watchOS)) } + $0.it("watchOS in multiplatform app's supported destinations") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .application, + platform: .auto, + supportedDestinations: [.watchOS] + ) + ] + try expectValidationError(project, .containsWatchOSDestinationForMultiplatformApp(target: "target1")) + } + + $0.it("watchOS in non-app's supported destinations") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .framework, + platform: .auto, + supportedDestinations: [.watchOS] + ) + ] + try expectNoValidationError(project, .containsWatchOSDestinationForMultiplatformApp(target: "target1")) + } + $0.it("multiple definitions of mac platform in supported destinations") { var project = baseProject project.targets = [ diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 44046460..f34d487c 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -485,8 +485,8 @@ class ProjectGeneratorTests: XCTestCase { try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" } - $0.it("supportedDestinations merges settings - iOS, watchOS") { - let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.iOS, .watchOS]) + $0.it("supportedDestinations merges settings - iOS, watchOS (framework)") { + let target = Target(name: "Target", type: .framework, platform: .auto, supportedDestinations: [.iOS, .watchOS]) let project = Project(name: "", targets: [target]) let pbxProject = try project.generatePbxProj() @@ -499,8 +499,8 @@ class ProjectGeneratorTests: XCTestCase { try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true } - $0.it("supportedDestinations merges settings - visionOS, watchOS") { - let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.visionOS, .watchOS]) + $0.it("supportedDestinations merges settings - visionOS, watchOS (framework)") { + let target = Target(name: "Target", type: .framework, platform: .auto, supportedDestinations: [.visionOS, .watchOS]) let project = Project(name: "", targets: [target]) let pbxProject = try project.generatePbxProj()