Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spec validation for scheme test targets and tweak docs #775

Merged
merged 3 commits into from
Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Next Version

#### Fixed
- Validate scheme test action and test coverage target references before generating. [#775](https://github.com/yonaskolb/XcodeGen/pull/775) @liamnichols

## 2.13.0

#### Added
Expand Down
4 changes: 2 additions & 2 deletions Docs/ProjectSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,8 +714,8 @@ Schemes allows for more control than the convenience [Target Scheme](#target-sch

```yaml
targets:
myTarget: all
myTarget2: [test, run]
MyTarget: all
FooLib/FooTarget: [test, run]
parallelizeBuild: true
buildImplicitDependencies: true
```
Expand Down
33 changes: 21 additions & 12 deletions Sources/ProjectSpec/SpecValidation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,24 +194,21 @@ extension Project {
}

for scheme in schemes {
for buildTarget in scheme.build.targets {
switch buildTarget.target.location {
case .local:
if getProjectTarget(buildTarget.target.name) == nil {
errors.append(.invalidSchemeTarget(scheme: scheme.name, target: buildTarget.target.name))
}
case .project(let project):
if getProjectReference(project) == nil {
errors.append(.invalidProjectReference(scheme: scheme.name, reference: project))
}
}
}
errors.append(
contentsOf: scheme.build.targets.compactMap({ validationError(for: $0.target, in: scheme, action: "build") })
)
if let action = scheme.run, let config = action.config, getConfig(config) == nil {
errors.append(.invalidSchemeConfig(scheme: scheme.name, config: config))
}
if let action = scheme.test, let config = action.config, getConfig(config) == nil {
errors.append(.invalidSchemeConfig(scheme: scheme.name, config: config))
}
errors.append(
contentsOf: scheme.test?.targets.compactMap({ validationError(for: $0.targetReference, in: scheme, action: "test") }) ?? []
)
errors.append(
contentsOf: scheme.test?.coverageTargets.compactMap({ validationError(for: $0, in: scheme, action: "test") }) ?? []
)
if let action = scheme.profile, let config = action.config, getConfig(config) == nil {
errors.append(.invalidSchemeConfig(scheme: scheme.name, config: config))
}
Expand All @@ -233,4 +230,16 @@ extension Project {
throw SpecValidationError.ValidationError.invalidXcodeGenVersion(minimumVersion: minimumXcodeGenVersion, version: xcodeGenVersion)
}
}

/// Returns a descriptive error if the given target reference was invalid otherwise `nil`.
private func validationError(for targetReference: TargetReference, in scheme: Scheme, action: String) -> SpecValidationError.ValidationError? {
switch targetReference.location {
case .local where getProjectTarget(targetReference.name) == nil:
return .invalidSchemeTarget(scheme: scheme.name, target: targetReference.name, action: action)
case .project(let project) where getProjectReference(project) == nil:
return .invalidProjectReference(scheme: scheme.name, reference: project)
case .local, .project:
return nil
}
}
}
6 changes: 3 additions & 3 deletions Sources/ProjectSpec/SpecValidationError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public struct SpecValidationError: Error, CustomStringConvertible {
case invalidTargetConfigFile(target: String, configFile: String, config: String)
case invalidTargetSchemeConfigVariant(target: String, configVariant: String, configType: ConfigType)
case invalidTargetSchemeTest(target: String, testTarget: String)
case invalidSchemeTarget(scheme: String, target: String)
case invalidSchemeTarget(scheme: String, target: String, action: String)
case invalidSchemeConfig(scheme: String, config: String)
case invalidSwiftPackage(name: String, target: String)
case invalidLocalPackage(String)
Expand Down Expand Up @@ -50,8 +50,8 @@ public struct SpecValidationError: Error, CustomStringConvertible {
return "Target \(target.quoted) scheme has invalid test \(test.quoted)"
case let .invalidConfigFile(configFile, config):
return "Invalid config file \(configFile.quoted) for config \(config.quoted)"
case let .invalidSchemeTarget(scheme, target):
return "Scheme \(scheme.quoted) has invalid build target \(target.quoted)"
case let .invalidSchemeTarget(scheme, target, action):
return "Scheme \(scheme.quoted) has invalid \(action) target \(target.quoted)"
case let .invalidSchemeConfig(scheme, config):
return "Scheme \(scheme.quoted) has invalid build configuration \(config.quoted)"
case let .invalidBuildSettingConfig(config):
Expand Down
5 changes: 4 additions & 1 deletion Tests/ProjectSpecTests/ProjectSpecTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,15 @@ class ProjectSpecTests: XCTestCase {
name: "scheme1",
build: .init(targets: [.init(target: "invalidTarget")]),
run: .init(config: "debugInvalid"),
test: .init(config: "testInvalid", coverageTargets: ["SubProject/Yams"], targets: [.init(targetReference: "invalidTarget")]),
archive: .init(config: "releaseInvalid")
)]

try expectValidationError(project, .invalidSchemeTarget(scheme: "scheme1", target: "invalidTarget"))
try expectValidationError(project, .invalidSchemeTarget(scheme: "scheme1", target: "invalidTarget", action: "build"))
try expectValidationError(project, .invalidSchemeConfig(scheme: "scheme1", config: "debugInvalid"))
try expectValidationError(project, .invalidSchemeConfig(scheme: "scheme1", config: "releaseInvalid"))
try expectValidationError(project, .invalidSchemeTarget(scheme: "scheme1", target: "invalidTarget", action: "test"))
try expectValidationError(project, .invalidProjectReference(scheme: "scheme1", reference: "SubProject"))
}

$0.it("fails with invalid project reference in scheme") {
Expand Down