Ensuring target product names are consistent with Xcode (#323)
Resolves https://github.com/tuist/tuist/issues/254 - When creating new Xcode projects manually from the UI, the product names do not include the extension - Renaming existing `productName` references to `productNameWithExtension` Test Plan: - Ensure unit tests pass via `swift test` - Ensure acceptance tests pass via `bundle exec rake features`
This commit is contained in:
parent
a03a4e932b
commit
fcbbfb14ac
|
@ -16,6 +16,8 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
|
|||
|
||||
### Fixed
|
||||
|
||||
- Ensuring target product names are consistent with Xcode https://github.com/tuist/tuist/pull/323 by @kwridan
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Added
|
||||
|
|
|
@ -179,7 +179,7 @@ final class ConfigGenerator: ConfigGenerating {
|
|||
settings["TEST_TARGET_NAME"] = "\(app.target.name)"
|
||||
|
||||
if target.product == .unitTests {
|
||||
settings["TEST_HOST"] = "$(BUILT_PRODUCTS_DIR)/\(app.target.productName)/\(app.target.name)"
|
||||
settings["TEST_HOST"] = "$(BUILT_PRODUCTS_DIR)/\(app.target.productNameWithExtension)/\(app.target.name)"
|
||||
settings["BUNDLE_LOADER"] = "$(TEST_HOST)"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ class ProjectFileElements {
|
|||
|
||||
func targetProducts(target: Target) -> Set<String> {
|
||||
var products: Set<String> = Set()
|
||||
products.insert(target.productName)
|
||||
products.insert(target.productNameWithExtension)
|
||||
return products
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,7 @@ class ProjectFileElements {
|
|||
try dependencies.forEach { node in
|
||||
if let targetNode = node as? TargetNode {
|
||||
// Product name
|
||||
let productName = targetNode.target.productName
|
||||
let productName = targetNode.target.productNameWithExtension
|
||||
if self.products[productName] != nil { return }
|
||||
|
||||
/// The dependency belongs to the same project and its product
|
||||
|
|
|
@ -254,7 +254,7 @@ final class SchemesGenerator: SchemesGenerating {
|
|||
func targetBuildableReference(target: Target, pbxTarget: PBXNativeTarget, projectName: String) -> XCScheme.BuildableReference {
|
||||
return XCScheme.BuildableReference(referencedContainer: "container:\(projectName)",
|
||||
blueprint: pbxTarget,
|
||||
buildableName: target.productName,
|
||||
buildableName: target.productNameWithExtension,
|
||||
blueprintName: target.name,
|
||||
buildableIdentifier: "primary")
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ final class TargetGenerator: TargetGenerating {
|
|||
graph: Graphing,
|
||||
system: Systeming = System()) throws -> PBXNativeTarget {
|
||||
/// Products reference.
|
||||
let productFileReference = fileElements.products[target.productName]!
|
||||
let productFileReference = fileElements.products[target.productNameWithExtension]!
|
||||
|
||||
/// Target
|
||||
let pbxTarget = PBXNativeTarget(name: target.name,
|
||||
|
@ -63,7 +63,7 @@ final class TargetGenerator: TargetGenerating {
|
|||
buildRules: [],
|
||||
dependencies: [],
|
||||
productInstallPath: nil,
|
||||
productName: target.productName,
|
||||
productName: target.name,
|
||||
product: productFileReference,
|
||||
productType: target.product.xcodeValue)
|
||||
pbxproj.add(object: pbxTarget)
|
||||
|
|
|
@ -122,7 +122,7 @@ class Graph: Graphing {
|
|||
|
||||
return targetNode.targetDependencies
|
||||
.filter(isStaticLibrary)
|
||||
.map(\.target.productName)
|
||||
.map(\.target.productNameWithExtension)
|
||||
.map(DependencyReference.product)
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ class Graph: Graphing {
|
|||
|
||||
let staticLibraries = findAll(targetNode: targetNode, test: isStaticLibrary, skip: isFramework)
|
||||
.lazy
|
||||
.map(\.target.productName)
|
||||
.map(\.target.productNameWithExtension)
|
||||
.map(DependencyReference.product)
|
||||
|
||||
references.append(contentsOf: staticLibraries)
|
||||
|
@ -159,7 +159,7 @@ class Graph: Graphing {
|
|||
|
||||
let dynamicLibrariesAndFrameworks = targetNode.targetDependencies
|
||||
.filter(or(isFramework, isDynamicLibrary))
|
||||
.map(\.target.productName)
|
||||
.map(\.target.productNameWithExtension)
|
||||
.map(DependencyReference.product)
|
||||
|
||||
references.append(contentsOf: dynamicLibrariesAndFrameworks)
|
||||
|
@ -224,7 +224,7 @@ class Graph: Graphing {
|
|||
/// Other targets' frameworks.
|
||||
let otherTargetFrameworks = findAll(targetNode: targetNode, test: isFramework)
|
||||
.lazy
|
||||
.map(\.target.productName)
|
||||
.map(\.target.productNameWithExtension)
|
||||
.map(DependencyReference.product)
|
||||
|
||||
references.append(contentsOf: otherTargetFrameworks)
|
||||
|
|
|
@ -68,7 +68,7 @@ public class Target: Equatable {
|
|||
}
|
||||
|
||||
/// Returns the product name including the extension.
|
||||
var productName: String {
|
||||
var productNameWithExtension: String {
|
||||
switch product {
|
||||
case .staticLibrary, .dynamicLibrary:
|
||||
return "lib\(name).\(product.xcodeValue.fileExtension!)"
|
||||
|
|
|
@ -39,19 +39,19 @@ final class SchemeGeneratorTests: XCTestCase {
|
|||
|
||||
XCTAssertEqual(appEntry.buildFor, [.analyzing, .archiving, .profiling, .running, .testing])
|
||||
XCTAssertEqual(appEntry.buildableReference.referencedContainer, "container:project.xcodeproj")
|
||||
XCTAssertEqual(appEntry.buildableReference.buildableName, app.productName)
|
||||
XCTAssertEqual(appEntry.buildableReference.buildableName, app.productNameWithExtension)
|
||||
XCTAssertEqual(appEntry.buildableReference.blueprintName, app.name)
|
||||
XCTAssertEqual(appEntry.buildableReference.buildableIdentifier, "primary")
|
||||
|
||||
XCTAssertEqual(testsEntry.buildFor, [.testing])
|
||||
XCTAssertEqual(testsEntry.buildableReference.referencedContainer, "container:project.xcodeproj")
|
||||
XCTAssertEqual(testsEntry.buildableReference.buildableName, appTests.productName)
|
||||
XCTAssertEqual(testsEntry.buildableReference.buildableName, appTests.productNameWithExtension)
|
||||
XCTAssertEqual(testsEntry.buildableReference.blueprintName, appTests.name)
|
||||
XCTAssertEqual(testsEntry.buildableReference.buildableIdentifier, "primary")
|
||||
|
||||
XCTAssertEqual(uiTestsEntry.buildFor, [.testing])
|
||||
XCTAssertEqual(uiTestsEntry.buildableReference.referencedContainer, "container:project.xcodeproj")
|
||||
XCTAssertEqual(uiTestsEntry.buildableReference.buildableName, appUITests.productName)
|
||||
XCTAssertEqual(uiTestsEntry.buildableReference.buildableName, appUITests.productNameWithExtension)
|
||||
XCTAssertEqual(uiTestsEntry.buildableReference.blueprintName, appUITests.name)
|
||||
XCTAssertEqual(uiTestsEntry.buildableReference.buildableIdentifier, "primary")
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ final class SchemeGeneratorTests: XCTestCase {
|
|||
XCTAssertEqual(testable?.skipped, false)
|
||||
|
||||
XCTAssertEqual(testable?.buildableReference.referencedContainer, "container:project.xcodeproj")
|
||||
XCTAssertEqual(testable?.buildableReference.buildableName, appTests.productName)
|
||||
XCTAssertEqual(testable?.buildableReference.buildableName, appTests.productNameWithExtension)
|
||||
XCTAssertEqual(testable?.buildableReference.blueprintName, appTests.name)
|
||||
XCTAssertEqual(testable?.buildableReference.buildableIdentifier, "primary")
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ final class SchemeGeneratorTests: XCTestCase {
|
|||
XCTAssertNil(got?.macroExpansion)
|
||||
XCTAssertEqual(got?.buildableProductRunnable?.runnableDebuggingMode, "0")
|
||||
XCTAssertEqual(buildable?.referencedContainer, "container:project.xcodeproj")
|
||||
XCTAssertEqual(buildable?.buildableName, target.productName)
|
||||
XCTAssertEqual(buildable?.buildableName, target.productNameWithExtension)
|
||||
XCTAssertEqual(buildable?.blueprintName, target.name)
|
||||
XCTAssertEqual(buildable?.buildableIdentifier, "primary")
|
||||
|
||||
|
|
|
@ -5,46 +5,69 @@ import XCTest
|
|||
@testable import TuistGenerator
|
||||
|
||||
final class TargetGeneratorTests: XCTestCase {
|
||||
var path: AbsolutePath!
|
||||
var subject: TargetGenerator!
|
||||
var pbxproj: PBXProj!
|
||||
var pbxProject: PBXProject!
|
||||
var fileElements: ProjectFileElements!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
path = AbsolutePath("/test")
|
||||
pbxproj = PBXProj()
|
||||
pbxProject = createPbxProject(pbxproj: pbxproj)
|
||||
fileElements = ProjectFileElements([:], playgrounds: MockPlaygrounds())
|
||||
|
||||
subject = TargetGenerator()
|
||||
}
|
||||
|
||||
func test_generateTarget_productName() throws {
|
||||
// Given
|
||||
let target = Target.test(name: "MyFramework",
|
||||
product: .framework)
|
||||
let project = Project.test(path: path, targets: [target])
|
||||
let graph = Graph.test()
|
||||
let groups = ProjectGroups.generate(project: project,
|
||||
pbxproj: pbxproj,
|
||||
sourceRootPath: path,
|
||||
playgrounds: MockPlaygrounds())
|
||||
try fileElements.generateProjectFiles(project: project,
|
||||
graph: graph,
|
||||
groups: groups,
|
||||
pbxproj: pbxproj,
|
||||
sourceRootPath: path)
|
||||
|
||||
// When
|
||||
let generatedTarget = try subject.generateTarget(target: target,
|
||||
pbxproj: pbxproj,
|
||||
pbxProject: pbxProject,
|
||||
groups: groups,
|
||||
fileElements: fileElements,
|
||||
path: path,
|
||||
sourceRootPath: path,
|
||||
options: GenerationOptions(),
|
||||
graph: graph)
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(generatedTarget.productName, "MyFramework")
|
||||
XCTAssertEqual(generatedTarget.productNameWithExtension(), "MyFramework.framework")
|
||||
XCTAssertEqual(generatedTarget.productType, .framework)
|
||||
}
|
||||
|
||||
func test_generateTargetDependencies() throws {
|
||||
let pbxproj = PBXProj()
|
||||
let path = AbsolutePath("/test")
|
||||
// Given
|
||||
let targetA = Target.test(name: "TargetA")
|
||||
let targetB = Target.test(name: "TargetB")
|
||||
let nativeTargetA = PBXNativeTarget(name: "TargetA")
|
||||
let nativeTargetB = PBXNativeTarget(name: "TargetB")
|
||||
pbxproj.add(object: nativeTargetA)
|
||||
pbxproj.add(object: nativeTargetB)
|
||||
let configList = XCConfigurationList(buildConfigurations: [])
|
||||
pbxproj.add(object: configList)
|
||||
let mainGroup = PBXGroup()
|
||||
pbxproj.add(object: mainGroup)
|
||||
let project = Project.test(path: path,
|
||||
name: "Project",
|
||||
targets: [targetA, targetB])
|
||||
let pbxProject = PBXProject(name: "Project",
|
||||
buildConfigurationList: configList,
|
||||
compatibilityVersion: "0",
|
||||
mainGroup: mainGroup)
|
||||
pbxproj.add(object: pbxProject)
|
||||
let graphCache = GraphLoaderCache()
|
||||
let targetBNode = TargetNode(project: project,
|
||||
target: targetA,
|
||||
dependencies: [])
|
||||
let targetANode = TargetNode(project: project,
|
||||
target: targetA,
|
||||
dependencies: [targetBNode])
|
||||
let graph = Graph.test(cache: graphCache)
|
||||
graphCache.targetNodes[path] = [
|
||||
"TargetA": targetANode,
|
||||
"TargetB": targetBNode,
|
||||
]
|
||||
let nativeTargetA = createNativeTarget(for: targetA)
|
||||
let nativeTargetB = createNativeTarget(for: targetB)
|
||||
let graph = createGraph(project: .test(path: path),
|
||||
dependencies: [
|
||||
(target: targetA, dependencies: [targetB]),
|
||||
(target: targetB, dependencies: []),
|
||||
])
|
||||
|
||||
// When
|
||||
try subject.generateTargetDependencies(path: path,
|
||||
targets: [targetA, targetB],
|
||||
nativeTargets: [
|
||||
|
@ -52,6 +75,59 @@ final class TargetGeneratorTests: XCTestCase {
|
|||
"TargetB": nativeTargetB,
|
||||
],
|
||||
graph: graph)
|
||||
XCTAssertNotNil(nativeTargetA.dependencies.first)
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(nativeTargetA.dependencies.map(\.name), [
|
||||
"TargetB",
|
||||
])
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func createTargetNodes(project: Project,
|
||||
dependencies: [(target: Target, dependencies: [Target])]) -> [TargetNode] {
|
||||
let nodesCache = Dictionary(uniqueKeysWithValues: dependencies.map {
|
||||
($0.target.name, TargetNode(project: project,
|
||||
target: $0.target,
|
||||
dependencies: []))
|
||||
})
|
||||
|
||||
dependencies.forEach {
|
||||
let node = nodesCache[$0.target.name]!
|
||||
node.dependencies = $0.dependencies.map { nodesCache[$0.name]! }
|
||||
}
|
||||
|
||||
return dependencies.map { nodesCache[$0.target.name]! }
|
||||
}
|
||||
|
||||
private func createGraph(project: Project,
|
||||
dependencies: [(target: Target, dependencies: [Target])]) -> Graph {
|
||||
let targetNodes = createTargetNodes(project: project, dependencies: dependencies)
|
||||
|
||||
let cache = GraphLoaderCache()
|
||||
let graph = Graph.test(cache: cache)
|
||||
|
||||
targetNodes.forEach { cache.add(targetNode: $0) }
|
||||
|
||||
return graph
|
||||
}
|
||||
|
||||
private func createNativeTarget(for target: Target) -> PBXNativeTarget {
|
||||
let nativeTarget = PBXNativeTarget(name: target.name)
|
||||
pbxproj.add(object: nativeTarget)
|
||||
return nativeTarget
|
||||
}
|
||||
|
||||
private func createPbxProject(pbxproj: PBXProj) -> PBXProject {
|
||||
let configList = XCConfigurationList(buildConfigurations: [])
|
||||
pbxproj.add(object: configList)
|
||||
let mainGroup = PBXGroup()
|
||||
pbxproj.add(object: mainGroup)
|
||||
let pbxProject = PBXProject(name: "Project",
|
||||
buildConfigurationList: configList,
|
||||
compatibilityVersion: "0",
|
||||
mainGroup: mainGroup)
|
||||
pbxproj.add(object: pbxProject)
|
||||
return pbxProject
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,17 +19,17 @@ final class TargetTests: XCTestCase {
|
|||
|
||||
func test_productName_when_staticLibrary() {
|
||||
let target = Target.test(name: "Test", product: .staticLibrary)
|
||||
XCTAssertEqual(target.productName, "libTest.a")
|
||||
XCTAssertEqual(target.productNameWithExtension, "libTest.a")
|
||||
}
|
||||
|
||||
func test_productName_when_dynamicLibrary() {
|
||||
let target = Target.test(name: "Test", product: .dynamicLibrary)
|
||||
XCTAssertEqual(target.productName, "libTest.dylib")
|
||||
XCTAssertEqual(target.productNameWithExtension, "libTest.dylib")
|
||||
}
|
||||
|
||||
func test_productName_when_app() {
|
||||
let target = Target.test(name: "Test", product: .app)
|
||||
XCTAssertEqual(target.productName, "Test.app")
|
||||
XCTAssertEqual(target.productNameWithExtension, "Test.app")
|
||||
}
|
||||
|
||||
func test_sequence_testBundles() {
|
||||
|
|
Loading…
Reference in New Issue