Move the auto-generation of schemes to a mapper (#1357)
* Add empty AutogeneratedSchemesGraphMapper * Don't generate the schemes at generation time * Implement AutogeneratedSchemesGraphMapper * Update CHANGELOG * Remove unnecessary method * Turn the graph mapper into a project mapper * Address some comments Co-authored-by: Pedro Piñera <pedro@ppinera.es>
This commit is contained in:
parent
c07df2be86
commit
5dc8b7ab92
|
@ -11,6 +11,7 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
|
|||
### Changed
|
||||
|
||||
- Upgrade XcodeProj to 7.11.0 [#1398](https://github.com/tuist/tuist/pull/1398) by [@pepibumur](https://github.com/pepibumur)
|
||||
- Move the auto-generation of schemes to a model mapper [#1357](https://github.com/tuist/tuist/pull/1357) by [@pepibumur](https://github.com/pepibumur)
|
||||
|
||||
## 1.9.0 - Speedy Gonzales
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ public protocol ProjectMapping {
|
|||
}
|
||||
|
||||
public class SequentialProjectMapper: ProjectMapping {
|
||||
private let mappers: [ProjectMapping]
|
||||
let mappers: [ProjectMapping]
|
||||
|
||||
public init(mappers: [ProjectMapping]) {
|
||||
self.mappers = mappers
|
||||
|
|
|
@ -11,7 +11,6 @@ public struct Project: Equatable, CustomStringConvertible {
|
|||
lhs.targets == rhs.targets &&
|
||||
lhs.packages == rhs.packages &&
|
||||
lhs.schemes == rhs.schemes &&
|
||||
lhs.autogenerateSchemes == rhs.autogenerateSchemes &&
|
||||
lhs.settings == rhs.settings &&
|
||||
lhs.filesGroup == rhs.filesGroup &&
|
||||
lhs.additionalFiles == rhs.additionalFiles
|
||||
|
@ -40,9 +39,6 @@ public struct Project: Equatable, CustomStringConvertible {
|
|||
/// Project schemes
|
||||
public var schemes: [Scheme]
|
||||
|
||||
/// Auto generate default schemes
|
||||
public var autogenerateSchemes: Bool
|
||||
|
||||
/// Project settings.
|
||||
public var settings: Settings
|
||||
|
||||
|
@ -67,15 +63,14 @@ public struct Project: Equatable, CustomStringConvertible {
|
|||
/// *(Those won't be included in any build phases)*
|
||||
public init(path: AbsolutePath,
|
||||
name: String,
|
||||
organizationName: String? = nil,
|
||||
fileName: String? = nil,
|
||||
organizationName: String?,
|
||||
fileName: String?,
|
||||
settings: Settings,
|
||||
filesGroup: ProjectGroup,
|
||||
targets: [Target] = [],
|
||||
packages: [Package] = [],
|
||||
schemes: [Scheme] = [],
|
||||
autogenerateSchemes: Bool = true,
|
||||
additionalFiles: [FileElement] = []) {
|
||||
targets: [Target],
|
||||
packages: [Package],
|
||||
schemes: [Scheme],
|
||||
additionalFiles: [FileElement]) {
|
||||
self.path = path
|
||||
self.name = name
|
||||
self.organizationName = organizationName
|
||||
|
@ -83,7 +78,6 @@ public struct Project: Equatable, CustomStringConvertible {
|
|||
self.targets = targets
|
||||
self.packages = packages
|
||||
self.schemes = schemes
|
||||
self.autogenerateSchemes = autogenerateSchemes
|
||||
self.settings = settings
|
||||
self.filesGroup = filesGroup
|
||||
self.additionalFiles = additionalFiles
|
||||
|
@ -144,7 +138,28 @@ public struct Project: Equatable, CustomStringConvertible {
|
|||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
autogenerateSchemes: autogenerateSchemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
|
||||
/// Returns a copy of the project with the given schemes set.
|
||||
/// - Parameter schemes: Schemes to be set to the copy.
|
||||
public func with(schemes: [Scheme]) -> Project {
|
||||
Project(path: path,
|
||||
name: name,
|
||||
organizationName: organizationName,
|
||||
fileName: fileName,
|
||||
settings: settings,
|
||||
filesGroup: filesGroup,
|
||||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
|
||||
/// Returns the name of the default configuration.
|
||||
public var defaultDebugBuildConfigurationName: String {
|
||||
let debugConfiguration = settings.defaultDebugBuildConfiguration()
|
||||
let buildConfiguration = debugConfiguration ?? settings.configurations.keys.first
|
||||
return buildConfiguration?.name ?? BuildConfiguration.debug.name
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ public extension Project {
|
|||
targets: [Target] = [Target.test()],
|
||||
packages: [Package] = [],
|
||||
schemes: [Scheme] = [],
|
||||
autogenerateSchemes: Bool = true,
|
||||
additionalFiles: [FileElement] = []) -> Project {
|
||||
Project(path: path,
|
||||
name: name,
|
||||
|
@ -23,29 +22,28 @@ public extension Project {
|
|||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
autogenerateSchemes: autogenerateSchemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
|
||||
static func empty(path: AbsolutePath = AbsolutePath("/test/"),
|
||||
name: String = "Project",
|
||||
organizationName: String? = nil,
|
||||
fileName: String? = nil,
|
||||
settings: Settings = .default,
|
||||
filesGroup: ProjectGroup = .group(name: "Project"),
|
||||
targets: [Target] = [],
|
||||
packages: [Package] = [],
|
||||
schemes: [Scheme] = [],
|
||||
autogenerateSchemes: Bool = true,
|
||||
additionalFiles: [FileElement] = []) -> Project {
|
||||
Project(path: path,
|
||||
name: name,
|
||||
organizationName: organizationName,
|
||||
fileName: fileName,
|
||||
settings: settings,
|
||||
filesGroup: filesGroup,
|
||||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
autogenerateSchemes: autogenerateSchemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,29 +55,12 @@ final class SchemesGenerator: SchemesGenerating {
|
|||
func generateProjectSchemes(project: Project,
|
||||
generatedProject: GeneratedProject,
|
||||
graph: Graph) throws -> [SchemeDescriptor] {
|
||||
let customSchemes: [SchemeDescriptor] = try project.schemes.map { scheme in
|
||||
try project.schemes.map { scheme in
|
||||
try generateScheme(scheme: scheme,
|
||||
path: project.path,
|
||||
graph: graph,
|
||||
generatedProjects: [project.path: generatedProject])
|
||||
}
|
||||
|
||||
guard project.autogenerateSchemes else {
|
||||
return customSchemes
|
||||
}
|
||||
|
||||
let buildConfiguration = defaultDebugBuildConfigurationName(in: project)
|
||||
let userDefinedSchemes = Set(project.schemes.map(\.name))
|
||||
let defaultSchemeTargets = project.targets.filter { !userDefinedSchemes.contains($0.name) }
|
||||
let defaultSchemes: [SchemeDescriptor] = try defaultSchemeTargets.map { target in
|
||||
let scheme = createDefaultScheme(target: target, project: project, buildConfiguration: buildConfiguration, graph: graph)
|
||||
return try generateScheme(scheme: scheme,
|
||||
path: project.path,
|
||||
graph: graph,
|
||||
generatedProjects: [project.path: generatedProject])
|
||||
}
|
||||
|
||||
return customSchemes + defaultSchemes
|
||||
}
|
||||
|
||||
/// Wipes shared and user schemes at a workspace or project path. This is needed
|
||||
|
@ -94,37 +77,6 @@ final class SchemesGenerator: SchemesGenerating {
|
|||
if fileHandler.exists(sharedPath) { try fileHandler.delete(sharedPath) }
|
||||
}
|
||||
|
||||
func createDefaultScheme(target: Target, project: Project, buildConfiguration: String, graph: Graph) -> Scheme {
|
||||
let targetReference = TargetReference(projectPath: project.path, name: target.name)
|
||||
|
||||
let testTargets: [TestableTarget]
|
||||
|
||||
if target.product.testsBundle {
|
||||
testTargets = [TestableTarget(target: targetReference)]
|
||||
} else {
|
||||
testTargets = graph.testTargetsDependingOn(path: project.path, name: target.name)
|
||||
.map { TargetReference(projectPath: $0.project.path, name: $0.target.name) }
|
||||
.map { TestableTarget(target: $0) }
|
||||
}
|
||||
|
||||
return Scheme(name: target.name,
|
||||
shared: true,
|
||||
buildAction: BuildAction(targets: [targetReference]),
|
||||
testAction: TestAction(targets: testTargets,
|
||||
arguments: nil,
|
||||
configurationName: buildConfiguration,
|
||||
coverage: false,
|
||||
codeCoverageTargets: [],
|
||||
preActions: [],
|
||||
postActions: [],
|
||||
diagnosticsOptions: Set()),
|
||||
runAction: RunAction(configurationName: buildConfiguration,
|
||||
executable: targetReference,
|
||||
filePath: nil,
|
||||
arguments: Arguments(environment: target.environment),
|
||||
diagnosticsOptions: Set()))
|
||||
}
|
||||
|
||||
/// Generate schemes for a project or workspace.
|
||||
///
|
||||
/// - Parameters:
|
||||
|
@ -325,7 +277,7 @@ final class SchemesGenerator: SchemesGenerating {
|
|||
pathRunnable = XCScheme.PathRunnable(filePath: filePath.pathString)
|
||||
} else {
|
||||
guard let targetNode = graph.target(path: target.projectPath, name: target.name) else { return nil }
|
||||
defaultBuildConfiguration = defaultDebugBuildConfigurationName(in: targetNode.project)
|
||||
defaultBuildConfiguration = targetNode.project.defaultDebugBuildConfigurationName
|
||||
guard let buildableReference = try createBuildableReference(targetReference: target,
|
||||
graph: graph,
|
||||
rootPath: rootPath,
|
||||
|
@ -426,7 +378,7 @@ final class SchemesGenerator: SchemesGenerating {
|
|||
guard let target = try defaultTargetReference(scheme: scheme),
|
||||
let targetNode = graph.target(path: target.projectPath, name: target.name) else { return nil }
|
||||
|
||||
let buildConfiguration = scheme.analyzeAction?.configurationName ?? defaultDebugBuildConfigurationName(in: targetNode.project)
|
||||
let buildConfiguration = scheme.analyzeAction?.configurationName ?? targetNode.project.defaultDebugBuildConfigurationName
|
||||
return XCScheme.AnalyzeAction(buildConfiguration: buildConfiguration)
|
||||
}
|
||||
|
||||
|
@ -611,13 +563,6 @@ final class SchemesGenerator: SchemesGenerating {
|
|||
}.sorted { $0.variable < $1.variable }
|
||||
}
|
||||
|
||||
private func defaultDebugBuildConfigurationName(in project: Project) -> String {
|
||||
let debugConfiguration = project.settings.defaultDebugBuildConfiguration()
|
||||
let buildConfiguration = debugConfiguration ?? project.settings.configurations.keys.first
|
||||
|
||||
return buildConfiguration?.name ?? BuildConfiguration.debug.name
|
||||
}
|
||||
|
||||
/// Returns the scheme buildable reference for a given target.
|
||||
///
|
||||
/// - Parameters:
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import Foundation
|
||||
import TuistCore
|
||||
|
||||
/// A project mapper that auto-generates schemes for each of the targets of the graph
|
||||
/// if the user hasn't already defined schemes for those.
|
||||
public class AutogeneratedSchemesProjectMapper: ProjectMapping {
|
||||
// MARK: - Init
|
||||
|
||||
public init() {}
|
||||
|
||||
// MARK: - GraphMapping
|
||||
|
||||
public func map(project: Project) throws -> (Project, [SideEffectDescriptor]) {
|
||||
let schemeNames = Set(project.schemes.map { $0.name })
|
||||
let schemes = project.schemes
|
||||
|
||||
let autogeneratedSchemes = project.targets.compactMap { (target: Target) -> Scheme? in
|
||||
let scheme = self.createDefaultScheme(target: target,
|
||||
project: project,
|
||||
buildConfiguration: project.defaultDebugBuildConfigurationName)
|
||||
// The user has already defined a scheme with that name.
|
||||
if schemeNames.contains(scheme.name) { return nil }
|
||||
return scheme
|
||||
}
|
||||
|
||||
return (project.with(schemes: schemes + autogeneratedSchemes), [])
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func createDefaultScheme(target: Target, project: Project, buildConfiguration: String) -> Scheme {
|
||||
let targetReference = TargetReference(projectPath: project.path, name: target.name)
|
||||
|
||||
let testTargets: [TestableTarget]
|
||||
|
||||
if target.product.testsBundle {
|
||||
testTargets = [TestableTarget(target: targetReference)]
|
||||
} else {
|
||||
// The test targets that are dependant on the given target.
|
||||
testTargets = project.targets
|
||||
.filter { $0.product.testsBundle && $0.dependencies.contains(.target(name: target.name)) }
|
||||
.sorted(by: { $0.name < $1.name })
|
||||
.map { TargetReference(projectPath: project.path, name: $0.name) }
|
||||
.map { TestableTarget(target: $0) }
|
||||
}
|
||||
|
||||
return Scheme(name: target.name,
|
||||
shared: true,
|
||||
buildAction: BuildAction(targets: [targetReference]),
|
||||
testAction: TestAction(targets: testTargets,
|
||||
arguments: nil,
|
||||
configurationName: buildConfiguration,
|
||||
coverage: false,
|
||||
codeCoverageTargets: [],
|
||||
preActions: [],
|
||||
postActions: [],
|
||||
diagnosticsOptions: Set()),
|
||||
runAction: RunAction(configurationName: buildConfiguration,
|
||||
executable: targetReference,
|
||||
filePath: nil,
|
||||
arguments: Arguments(environment: target.environment),
|
||||
diagnosticsOptions: Set()))
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import Foundation
|
|||
import TuistCache
|
||||
import TuistCloud
|
||||
import TuistCore
|
||||
import TuistGenerator
|
||||
|
||||
/// It defines an interface for providing the mappers to be used for a specific configuration.
|
||||
protocol GraphMapperProviding {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import Foundation
|
||||
import TuistCore
|
||||
import TuistGenerator
|
||||
|
||||
/// It defines an interface for providing the project mappers to be used for a specific configuration.
|
||||
protocol ProjectMapperProviding {
|
||||
/// Returns a list of mappers to be used for a specific configuration.
|
||||
/// - Parameter config: Project's configuration.
|
||||
func mapper(config: Config) -> ProjectMapping
|
||||
}
|
||||
|
||||
class ProjectMapperProvider: ProjectMapperProviding {
|
||||
func mapper(config: Config) -> ProjectMapping {
|
||||
var mappers: [ProjectMapping] = []
|
||||
|
||||
// Auto-generation of schemes
|
||||
if !config.generationOptions.contains(.disableAutogeneratedSchemes) {
|
||||
mappers.append(AutogeneratedSchemesProjectMapper())
|
||||
}
|
||||
|
||||
return SequentialProjectMapper(mappers: mappers)
|
||||
}
|
||||
}
|
|
@ -78,10 +78,14 @@ final class ProjectEditorMapper: ProjectEditorMapping {
|
|||
// Project
|
||||
let project = Project(path: sourceRootPath,
|
||||
name: "Manifests",
|
||||
organizationName: nil,
|
||||
fileName: nil,
|
||||
settings: projectSettings,
|
||||
filesGroup: .group(name: "Manifests"),
|
||||
targets: targets,
|
||||
schemes: [scheme])
|
||||
packages: [],
|
||||
schemes: [scheme],
|
||||
additionalFiles: [])
|
||||
|
||||
// Graph
|
||||
var dependencies: [TargetNode] = []
|
||||
|
|
|
@ -24,11 +24,12 @@ class ProjectGenerator: ProjectGenerating {
|
|||
private let modelLoader: GeneratorModelLoading
|
||||
private let graphLoader: GraphLoading
|
||||
private let sideEffectDescriptorExecutor: SideEffectDescriptorExecuting
|
||||
private let projectMapper: ProjectMapping
|
||||
private let graphMapperProvider: GraphMapperProviding
|
||||
private let projectMapperProvider: ProjectMapperProviding
|
||||
private let manifestLoader: ManifestLoading
|
||||
|
||||
init(graphMapperProvider: GraphMapperProviding = GraphMapperProvider(useCache: false),
|
||||
projectMapperProvider: ProjectMapperProviding = ProjectMapperProvider(),
|
||||
manifestLoaderFactory: ManifestLoaderFactory = ManifestLoaderFactory()) {
|
||||
let manifestLoader = manifestLoaderFactory.createManifestLoader()
|
||||
recursiveManifestLoader = RecursiveManifestLoader(manifestLoader: manifestLoader)
|
||||
|
@ -39,7 +40,7 @@ class ProjectGenerator: ProjectGenerating {
|
|||
sideEffectDescriptorExecutor = SideEffectDescriptorExecutor()
|
||||
self.modelLoader = modelLoader
|
||||
self.graphMapperProvider = graphMapperProvider
|
||||
projectMapper = SequentialProjectMapper(mappers: [])
|
||||
self.projectMapperProvider = projectMapperProvider
|
||||
self.manifestLoader = manifestLoader
|
||||
}
|
||||
|
||||
|
@ -154,10 +155,14 @@ class ProjectGenerator: ProjectGenerating {
|
|||
manifestLinter.lint(project: $0.value)
|
||||
}.printAndThrowIfNeeded()
|
||||
|
||||
// Load config
|
||||
let config = try graphLoader.loadConfig(path: path)
|
||||
|
||||
// Convert to models
|
||||
let models = try convert(manifests: manifests)
|
||||
|
||||
// Apply any registered model mappers
|
||||
let projectMapper = projectMapperProvider.mapper(config: config)
|
||||
let updatedModels = try models.map(projectMapper.map)
|
||||
let updatedProjects = updatedModels.map(\.0)
|
||||
let modelMapperSideEffects = updatedModels.flatMap { $0.1 }
|
||||
|
@ -168,7 +173,6 @@ class ProjectGenerator: ProjectGenerating {
|
|||
let (graph, project) = try cachedGraphLoader.loadProject(path: path)
|
||||
|
||||
// Apply graph mappers
|
||||
let config = try graphLoader.loadConfig(path: graph.entryPath)
|
||||
let (updatedGraph, graphMapperSideEffects) = try graphMapperProvider.mapper(config: config).map(graph: graph)
|
||||
|
||||
return (project, updatedGraph, modelMapperSideEffects + graphMapperSideEffects)
|
||||
|
@ -183,10 +187,14 @@ class ProjectGenerator: ProjectGenerating {
|
|||
manifestLinter.lint(project: $0.value)
|
||||
}.printAndThrowIfNeeded()
|
||||
|
||||
// Load config
|
||||
let config = try graphLoader.loadConfig(path: path)
|
||||
|
||||
// Convert to models
|
||||
let models = try convert(manifests: manifests)
|
||||
|
||||
// Apply model mappers
|
||||
let projectMapper = projectMapperProvider.mapper(config: config)
|
||||
let updatedModels = try models.projects.map(projectMapper.map)
|
||||
let updatedProjects = updatedModels.map(\.0)
|
||||
let modelMapperSideEffects = updatedModels.flatMap { $0.1 }
|
||||
|
@ -197,7 +205,6 @@ class ProjectGenerator: ProjectGenerating {
|
|||
let (graph, workspace) = try cachedGraphLoader.loadWorkspace(path: path)
|
||||
|
||||
// Apply graph mappers
|
||||
let config = try graphLoader.loadConfig(path: graph.entryPath)
|
||||
let (updatedGraph, graphMapperSideEffects) = try graphMapperProvider.mapper(config: config).map(graph: graph)
|
||||
|
||||
return (workspace, updatedGraph, modelMapperSideEffects + graphMapperSideEffects)
|
||||
|
|
|
@ -102,10 +102,6 @@ extension GeneratorModelLoader {
|
|||
enrichedModel = enrichedModel.replacing(organizationName: organizationName)
|
||||
}
|
||||
|
||||
if config.generationOptions.contains(.disableAutogeneratedSchemes) {
|
||||
enrichedModel = enrichedModel.replacing(autogenerateSchemes: false)
|
||||
}
|
||||
|
||||
return enrichedModel
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ extension TuistCore.Project {
|
|||
return Project(path: generatorPaths.manifestDirectory,
|
||||
name: name,
|
||||
organizationName: organizationName,
|
||||
fileName: nil,
|
||||
settings: settings ?? .default,
|
||||
filesGroup: .group(name: "Project"),
|
||||
targets: targets,
|
||||
|
@ -39,7 +40,6 @@ extension TuistCore.Project {
|
|||
targets: targets + [target],
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
autogenerateSchemes: autogenerateSchemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,6 @@ extension TuistCore.Project {
|
|||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
autogenerateSchemes: autogenerateSchemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
|
||||
|
@ -67,21 +66,6 @@ extension TuistCore.Project {
|
|||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
autogenerateSchemes: autogenerateSchemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
|
||||
func replacing(autogenerateSchemes: Bool) -> TuistCore.Project {
|
||||
Project(path: path,
|
||||
name: name,
|
||||
organizationName: organizationName,
|
||||
fileName: fileName,
|
||||
settings: settings,
|
||||
filesGroup: filesGroup,
|
||||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes,
|
||||
autogenerateSchemes: autogenerateSchemes,
|
||||
additionalFiles: additionalFiles)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@ public extension XCTestCase {
|
|||
|
||||
// MARK: - XCTAssertions
|
||||
|
||||
func XCTAssertEmpty<T: Collection>(_ collection: T, file: StaticString = #file, line: UInt = #line) {
|
||||
XCTAssertEqual(collection.count, 0, "Expected to be empty but it has \(collection.count) elements", file: file, line: line)
|
||||
}
|
||||
|
||||
// swiftlint:disable large_tuple
|
||||
func XCTAssertEqualPairs<T: Equatable>(_ subjects: [(T, T, Bool)], file: StaticString = #file, line: UInt = #line) {
|
||||
subjects.forEach {
|
||||
|
|
|
@ -48,4 +48,27 @@ final class ProjectTests: XCTestCase {
|
|||
XCTAssertEqual(project.fileName, "SomeProjectName")
|
||||
XCTAssertEqual(project.name, "SomeProjectName")
|
||||
}
|
||||
|
||||
func test_defaultDebugBuildConfigurationName_when_defaultDebugConfigExists() {
|
||||
// Given
|
||||
let project = Project.test(settings: Settings.test())
|
||||
|
||||
// When
|
||||
let got = project.defaultDebugBuildConfigurationName
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(got, "Debug")
|
||||
}
|
||||
|
||||
func test_defaultDebugBuildConfigurationName_when_defaultDebugConfigDoesntExist() {
|
||||
// Given
|
||||
let settings = Settings.test(base: [:], configurations: [.debug("Test"): Configuration.test()])
|
||||
let project = Project.test(settings: settings)
|
||||
|
||||
// When
|
||||
let got = project.defaultDebugBuildConfigurationName
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(got, "Test")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ final class ProjectGroupsTests: XCTestCase {
|
|||
sourceRootPath = AbsolutePath("/test/")
|
||||
project = Project(path: path,
|
||||
name: "Project",
|
||||
organizationName: nil,
|
||||
fileName: nil,
|
||||
settings: .default,
|
||||
filesGroup: .group(name: "Project"),
|
||||
targets: [
|
||||
|
@ -30,7 +32,8 @@ final class ProjectGroupsTests: XCTestCase {
|
|||
.test(),
|
||||
],
|
||||
packages: [],
|
||||
schemes: [])
|
||||
schemes: [],
|
||||
additionalFiles: [])
|
||||
pbxproj = PBXProj()
|
||||
}
|
||||
|
||||
|
|
|
@ -17,68 +17,6 @@ final class SchemesGeneratorTests: XCTestCase {
|
|||
subject = SchemesGenerator()
|
||||
}
|
||||
|
||||
// MARK: - Scheme Generation
|
||||
|
||||
func test_defaultGeneratedScheme_RegularTarget() throws {
|
||||
// Given
|
||||
let target = Target.test(name: "App", product: .app)
|
||||
let testTarget1 = Target.test(name: "AppTests1", product: .unitTests)
|
||||
let testTarget2 = Target.test(name: "AppTests2", product: .unitTests)
|
||||
let testTarget3 = Target.test(name: "AppTests3", product: .unitTests)
|
||||
let testTargets = [testTarget1, testTarget2, testTarget3]
|
||||
let project = Project.test(targets: [target] + testTargets)
|
||||
|
||||
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: []),
|
||||
(project: project, target: testTarget1, dependencies: [target]),
|
||||
(project: project, target: testTarget2, dependencies: [target]),
|
||||
(project: project, target: testTarget3, dependencies: [target])])
|
||||
|
||||
// When
|
||||
let got = subject.createDefaultScheme(target: target, project: project, buildConfiguration: "Debug", graph: graph)
|
||||
|
||||
// Then
|
||||
let result = try XCTUnwrap(got)
|
||||
XCTAssertEqual(result.name, target.name)
|
||||
XCTAssertTrue(result.shared)
|
||||
|
||||
let buildAction = try XCTUnwrap(result.buildAction)
|
||||
let targetReference = TargetReference(projectPath: project.path, name: target.name)
|
||||
XCTAssertEqual(buildAction.targets, [targetReference])
|
||||
|
||||
let testAction = try XCTUnwrap(result.testAction)
|
||||
let testableTargests = testTargets
|
||||
.map { TargetReference(projectPath: project.path, name: $0.name) }
|
||||
.map { TestableTarget(target: $0) }
|
||||
XCTAssertEqual(testAction.targets, testableTargests)
|
||||
}
|
||||
|
||||
func test_defaultGeneratedScheme_TestTarget() throws {
|
||||
// Given
|
||||
let target = Target.test(name: "App", product: .app)
|
||||
let testTarget = Target.test(name: "AppTests", product: .unitTests)
|
||||
let project = Project.test(targets: [target, testTarget])
|
||||
|
||||
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: []),
|
||||
(project: project, target: testTarget, dependencies: [target])])
|
||||
|
||||
// When
|
||||
let got = subject.createDefaultScheme(target: testTarget, project: project, buildConfiguration: "Debug", graph: graph)
|
||||
|
||||
// Then
|
||||
let result = try XCTUnwrap(got)
|
||||
XCTAssertEqual(result.name, testTarget.name)
|
||||
XCTAssertTrue(result.shared)
|
||||
|
||||
let buildAction = try XCTUnwrap(result.buildAction)
|
||||
let targetReference = TargetReference(projectPath: project.path, name: testTarget.name)
|
||||
XCTAssertEqual(buildAction.targets, [targetReference])
|
||||
|
||||
let testAction = try XCTUnwrap(result.testAction)
|
||||
let testTargetReference = TargetReference(projectPath: project.path, name: testTarget.name)
|
||||
let testableTarget = TestableTarget(target: testTargetReference)
|
||||
XCTAssertEqual(testAction.targets, [testableTarget])
|
||||
}
|
||||
|
||||
// MARK: - Build Action Tests
|
||||
|
||||
func test_schemeBuildAction_whenSingleProject() throws {
|
||||
|
@ -662,39 +600,6 @@ final class SchemesGeneratorTests: XCTestCase {
|
|||
XCTAssertEqual(result.revealArchiveInOrganizer, true)
|
||||
}
|
||||
|
||||
func test_schemeGenerationModes_default() throws {
|
||||
// Given
|
||||
let app = Target.test(name: "App", product: .app)
|
||||
let framework = Target.test(name: "Framework", product: .framework)
|
||||
let unitTests = Target.test(name: "AppTests", product: .unitTests)
|
||||
let uiTests = Target.test(name: "AppUITests", product: .uiTests)
|
||||
let project = Project.test(targets: [app, framework, unitTests, uiTests])
|
||||
|
||||
let graph = Graph.create(
|
||||
project: project,
|
||||
dependencies: [
|
||||
(target: app, dependencies: [framework]),
|
||||
(target: framework, dependencies: []),
|
||||
(target: unitTests, dependencies: [app]),
|
||||
(target: uiTests, dependencies: [app]),
|
||||
]
|
||||
)
|
||||
|
||||
// When
|
||||
let result = try subject.generateProjectSchemes(project: project,
|
||||
generatedProject: generatedProject(targets: project.targets),
|
||||
graph: graph)
|
||||
|
||||
// Then
|
||||
let schemes = result.map(\.xcScheme.name)
|
||||
XCTAssertEqual(schemes, [
|
||||
"App",
|
||||
"Framework",
|
||||
"AppTests",
|
||||
"AppUITests",
|
||||
])
|
||||
}
|
||||
|
||||
func test_schemeGenerationModes_customOnly() throws {
|
||||
// Given
|
||||
let app = Target.test(name: "App", product: .app)
|
||||
|
@ -702,7 +607,7 @@ final class SchemesGeneratorTests: XCTestCase {
|
|||
let unitTests = Target.test(name: "AppTests", product: .unitTests)
|
||||
let uiTests = Target.test(name: "AppUITests", product: .uiTests)
|
||||
let scheme = Scheme.test()
|
||||
let project = Project.test(targets: [app, framework, unitTests, uiTests], schemes: [scheme], autogenerateSchemes: false)
|
||||
let project = Project.test(targets: [app, framework, unitTests, uiTests], schemes: [scheme])
|
||||
|
||||
let graph = Graph.create(
|
||||
project: project,
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
import Foundation
|
||||
import TSCBasic
|
||||
import TuistCore
|
||||
import XCTest
|
||||
|
||||
@testable import TuistGenerator
|
||||
@testable import TuistSupport
|
||||
@testable import TuistSupportTesting
|
||||
|
||||
final class AutogeneratedSchemesProjectMapperTests: TuistUnitTestCase {
|
||||
var subject: AutogeneratedSchemesProjectMapper!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
subject = AutogeneratedSchemesProjectMapper()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
super.tearDown()
|
||||
subject = nil
|
||||
}
|
||||
|
||||
func test_map() throws {
|
||||
// Given
|
||||
let targetA = Target.test(name: "A")
|
||||
let targetB = Target.test(name: "B",
|
||||
product: .unitTests,
|
||||
dependencies: [.target(name: "A")])
|
||||
let project = Project.test(targets: [targetA, targetB])
|
||||
|
||||
// When
|
||||
let (got, sideEffects) = try subject.map(project: project)
|
||||
|
||||
// Then
|
||||
XCTAssertEmpty(sideEffects)
|
||||
XCTAssertEqual(got.schemes.count, 2)
|
||||
|
||||
// Then: A
|
||||
let aScheme = got.schemes.first!
|
||||
XCTAssertEqual(aScheme.name, targetA.name)
|
||||
let aBuildAction = try XCTUnwrap(aScheme.buildAction)
|
||||
XCTAssertEqual(aBuildAction.targets.count, 1)
|
||||
let aBuildTargetReference = try XCTUnwrap(aBuildAction.targets.first)
|
||||
XCTAssertEqual(aBuildTargetReference.projectPath, project.path)
|
||||
XCTAssertEqual(aBuildTargetReference.name, targetA.name)
|
||||
|
||||
// Then: A tests
|
||||
// Since B is a tests bundle with a dependency on A,
|
||||
// there should be a test action in A scheme to run the tests in B
|
||||
let aTestAction = try XCTUnwrap(aScheme.testAction)
|
||||
XCTAssertEqual(aTestAction.targets.count, 1)
|
||||
let aTestTargetReference = try XCTUnwrap(aTestAction.targets.first?.target)
|
||||
XCTAssertEqual(aTestTargetReference.projectPath, project.path)
|
||||
XCTAssertEqual(aTestTargetReference.name, targetB.name)
|
||||
|
||||
// Then: B
|
||||
let bScheme = got.schemes.last!
|
||||
XCTAssertEqual(bScheme.name, targetB.name)
|
||||
let bBuildAction = try XCTUnwrap(bScheme.buildAction)
|
||||
XCTAssertEqual(bBuildAction.targets.count, 1)
|
||||
let bBuildTargetReference = try XCTUnwrap(bBuildAction.targets.first)
|
||||
XCTAssertEqual(bBuildTargetReference.projectPath, project.path)
|
||||
XCTAssertEqual(bBuildTargetReference.name, targetB.name)
|
||||
let bTestAction = try XCTUnwrap(bScheme.testAction)
|
||||
XCTAssertEqual(bTestAction.targets.count, 1)
|
||||
let bTestTargetReference = try XCTUnwrap(bTestAction.targets.first?.target)
|
||||
XCTAssertEqual(bTestTargetReference.projectPath, project.path)
|
||||
XCTAssertEqual(bTestTargetReference.name, targetB.name)
|
||||
}
|
||||
|
||||
func test_map_doesnt_override_user_schemes() throws {
|
||||
// Given
|
||||
let targetA = Target.test(name: "A")
|
||||
let aScheme = Scheme.test(name: "A",
|
||||
shared: true,
|
||||
buildAction: nil,
|
||||
testAction: nil,
|
||||
runAction: nil,
|
||||
archiveAction: nil,
|
||||
profileAction: nil,
|
||||
analyzeAction: nil)
|
||||
let project = Project.test(targets: [targetA],
|
||||
schemes: [aScheme])
|
||||
|
||||
// When
|
||||
let (got, sideEffects) = try subject.map(project: project)
|
||||
|
||||
// Then
|
||||
XCTAssertEmpty(sideEffects)
|
||||
XCTAssertEqual(got.schemes.count, 1)
|
||||
|
||||
// Then: A
|
||||
let gotAScheme = got.schemes.first!
|
||||
XCTAssertNil(gotAScheme.buildAction)
|
||||
}
|
||||
}
|
|
@ -345,11 +345,14 @@ final class MultipleConfigurationsIntegrationTests: TuistUnitTestCase {
|
|||
private func createProject(path: AbsolutePath, settings: Settings, targets: [Target], packages: [Package] = [], schemes: [Scheme]) -> Project {
|
||||
Project(path: path,
|
||||
name: "App",
|
||||
organizationName: nil,
|
||||
fileName: nil,
|
||||
settings: settings,
|
||||
filesGroup: .group(name: "Project"),
|
||||
targets: targets,
|
||||
packages: packages,
|
||||
schemes: schemes)
|
||||
schemes: schemes,
|
||||
additionalFiles: [])
|
||||
}
|
||||
|
||||
private func createAppTarget(settings: Settings?) throws -> Target {
|
||||
|
|
|
@ -159,6 +159,8 @@ final class StableXcodeProjIntegrationTests: TuistTestCase {
|
|||
private func createProject(path: AbsolutePath, settings: Settings, targets: [Target], packages: [Package] = [], schemes: [Scheme]) -> Project {
|
||||
Project(path: path,
|
||||
name: "App",
|
||||
organizationName: nil,
|
||||
fileName: nil,
|
||||
settings: settings,
|
||||
filesGroup: .group(name: "Project"),
|
||||
targets: targets,
|
||||
|
|
|
@ -3,6 +3,7 @@ import TuistCache
|
|||
import TuistCloud
|
||||
import TuistCore
|
||||
import TuistCoreTesting
|
||||
import TuistGenerator
|
||||
import TuistSupport
|
||||
import XCTest
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import Foundation
|
||||
import TuistCache
|
||||
import TuistCloud
|
||||
import TuistCoreTesting
|
||||
import TuistGenerator
|
||||
import TuistSupport
|
||||
import XCTest
|
||||
|
||||
@testable import TuistCore
|
||||
@testable import TuistKit
|
||||
@testable import TuistSupportTesting
|
||||
|
||||
final class ProjectMapperProviderTests: TuistUnitTestCase {
|
||||
var subject: ProjectMapperProvider!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
subject = ProjectMapperProvider()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
subject = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func test_mapper_returns_a_sequential_mapper_with_the_autogenerated_schemes_project_mapper() throws {
|
||||
// Given
|
||||
subject = ProjectMapperProvider()
|
||||
|
||||
// When
|
||||
let got = subject.mapper(config: Config.test(cloud: .test(options: [])))
|
||||
|
||||
// Then
|
||||
let sequentialProjectMapper = try XCTUnwrap(got as? SequentialProjectMapper)
|
||||
XCTAssertEqual(sequentialProjectMapper.mappers.filter { $0 is AutogeneratedSchemesProjectMapper }.count, 1)
|
||||
}
|
||||
}
|
|
@ -268,30 +268,6 @@ class GeneratorModelLoaderTests: TuistUnitTestCase {
|
|||
XCTAssertEqual(model.organizationName, "tuist")
|
||||
}
|
||||
|
||||
func test_loadProject_withDisabledAutogeneratedSchemesFromConfig() throws {
|
||||
// Given
|
||||
let temporaryPath = try self.temporaryPath()
|
||||
try createFiles([
|
||||
"Config.swift",
|
||||
])
|
||||
|
||||
let manifests = [
|
||||
temporaryPath: ProjectManifest.test(),
|
||||
]
|
||||
let configs = [
|
||||
temporaryPath: ProjectDescription.TuistConfig.test(generationOptions: [.disableAutogeneratedSchemes]),
|
||||
]
|
||||
let manifestLoader = createManifestLoader(with: manifests, configs: configs)
|
||||
let subject = GeneratorModelLoader(manifestLoader: manifestLoader,
|
||||
manifestLinter: manifestLinter)
|
||||
|
||||
// When
|
||||
let model = try subject.loadProject(at: temporaryPath)
|
||||
|
||||
// Then
|
||||
XCTAssertFalse(model.autogenerateSchemes)
|
||||
}
|
||||
|
||||
func test_loadWorkspace() throws {
|
||||
// Given
|
||||
let temporaryPath = try self.temporaryPath()
|
||||
|
|
Loading…
Reference in New Issue