Added support for scheme management (#1142)

* wip

* Added scheme management metadata properties to TargetScheme

* wip

* Added Scheme.Management for metadata

* use sharedDefault

* move generateSchemeManagement to SchemeGenerator

* revert

* update changelog

* update docs

* update test case

* remove

* remove unused file

* revert

* changed on fixtures project

* Updated ProjectSpec docs index

* User Scheme.Management also for TargetSchemes, use XCUserData

* Changelog

* Switch XcodeProj back tuist/XcodeProj - 8.9.0

* Reindent TOC Docs/ProjectSpec.md

* Revert swift tools version

---------

Co-authored-by: Tieme van Veen <tiemevanveen@hotmail.com>
This commit is contained in:
Wendy Liga
2023-02-24 05:49:57 +07:00
committed by GitHub
parent 80e317206b
commit 43e40a9efc
24 changed files with 610 additions and 61 deletions
-2
View File
@@ -2,9 +2,7 @@
.swiftpm
/.build
/Packages
xcuserdata
*.xccheckout
*.xcuserstate
XcodeGen.xcodeproj
xcodegen.zip
.vscode/launch.json
+1
View File
@@ -6,6 +6,7 @@
- Renamed build phase `Embed App Extensions` to `Embed Foundation Extensions` to fix Xcode 14 warning #1310 @casperriboe
- Added support for `swiftcrossimport` folders. #1317 @Iron-Ham
- Added support for [Scheme Management](Docs/ProjectSpec.md##scheme-management) #1142 @wendyliga, @teameh
### Fixed
+37 -16
View File
@@ -4,27 +4,42 @@
- [General](#general)
- [Project](#project)
- [Include](#include)
- [Options](#options)
- [Configs](#configs)
- [Setting Groups](#setting-groups)
- [Include](#include)
- [Options](#options)
- [GroupOrdering](#groupordering)
- [FileType](#filetype)
- [Configs](#configs)
- [Setting Groups](#setting-groups)
- [Settings](#settings)
- [Target](#target)
- [Product Type](#product-type)
- [Platform](#platform)
- [Sources](#sources)
- [Config Files](#config-files)
- [Settings](#settings)
- [Build Script](#build-script)
- [Build Rule](#build-rule)
- [Dependency](#dependency)
- [Target Scheme](#target-scheme)
- [Legacy Target](#legacy-target)
- [Product Type](#product-type)
- [Platform](#platform)
- [Sources](#sources)
- [Dependency](#dependency)
- [Config Files](#config-files)
- [Plist](#plist)
- [Build Script](#build-script)
- [Build Rule](#build-rule)
- [Target Scheme](#target-scheme)
- [Legacy Target](#legacy-target)
- [Aggregate Target](#aggregate-target)
- [Target Template](#target-template)
- [Scheme](#scheme)
- [Build](#build)
- [Common Build Action options](#common-build-action-options)
- [Execution Action](#execution-action)
- [Run Action](#run-action)
- [Test Action](#test-action)
- [Archive Action](#archive-action)
- [Simulate Location](#simulate-location)
- [Scheme Management](#scheme-management)
- [Environment Variable](#environment-variable)
- [Test Plan](#test-plan)
- [Scheme Template](#scheme-template)
- [Remote Package](#remote-package)
- [Local Package](#local-package)
- [Swift Package](#swift-package)
- [Project Reference](#project-reference)
## General
@@ -649,7 +664,7 @@ targets:
runOncePerArchitecture: false
```
### Target Scheme
### Target Scheme
This is a convenience used to automatically generate schemes for a target based on different configs or included tests. If you want more control check out the top level [Scheme](#scheme).
@@ -667,6 +682,7 @@ This is a convenience used to automatically generate schemes for a target based
- [ ] **testPlans**: **[[Test Plan](#test-plan)]** - List of test plan locations that will be referenced in the scheme.
- [ ] **preActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *before* the build action
- [ ] **postActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *after* the build action
- [ ] **management**: **[Scheme Management](#scheme-management)** - Management options for the scheme
- [ ] **storeKitConfiguration**: **String** - specify storekit configuration to use during run. See [Options](#options).
For example, the spec below would create 3 schemes called:
@@ -708,7 +724,7 @@ targets:
sources: Tests
```
### Legacy Target
### Legacy Target
By providing a legacy target, you are opting in to the "Legacy Target" mode. This is the "External Build Tool" from the Xcode GUI. This is useful for scripts that you want to run as dependencies of other targets, but you want to make sure that it only runs once even if it is specified as a dependency from multiple other targets.
@@ -762,6 +778,7 @@ Schemes allows for more control than the convenience [Target Scheme](#target-sch
- [ ] ***profile***: The profile action
- [ ] ***analyze***: The analyze action
- [ ] ***archive***: The archive action
- [ ] ***management***: management metadata
### Build
@@ -896,6 +913,10 @@ targets:
Note that the path the gpx file will be prefixed according to the `schemePathPrefix` option in order to support both `.xcodeproj` and `.xcworkspace` setups. See [Options](#options).
### Scheme Management
- [ ] **shared**: **Bool** - indicates whether the scheme is shared
- [ ] **orderHint**: **Int** - used by Xcode to sort the schemes
- [ ] **isShown**: **Bool** - indicates whether the sheme is shown in the scheme list
### Environment Variable
+2 -2
View File
@@ -78,8 +78,8 @@
"repositoryURL": "https://github.com/tuist/XcodeProj.git",
"state": {
"branch": null,
"revision": "b6de1bfe021b861c94e7c83821b595083f74b997",
"version": "8.8.0"
"revision": "fae27b48bc14ff3fd9b02902e48c4665ce5a0793",
"version": "8.9.0"
}
},
{
+2 -1
View File
@@ -16,11 +16,12 @@ let package = Package(
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.2.0"),
.package(url: "https://github.com/kylef/Spectre.git", from: "0.9.2"),
.package(url: "https://github.com/onevcat/Rainbow.git", from: "3.0.0"),
.package(url: "https://github.com/tuist/XcodeProj.git", from: "8.8.0"),
.package(url: "https://github.com/tuist/XcodeProj.git", from: "8.9.0"),
.package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.3"),
.package(url: "https://github.com/mxcl/Version", from: "2.0.0"),
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .exact("0.2.0")),
],
targets: [
.target(name: "XcodeGen", dependencies: [
"XcodeGenCLI",
+57 -1
View File
@@ -14,6 +14,7 @@ public struct Scheme: Equatable {
public var analyze: Analyze?
public var test: Test?
public var profile: Profile?
public var management: Management?
public init(
name: String,
@@ -22,7 +23,8 @@ public struct Scheme: Equatable {
test: Test? = nil,
profile: Profile? = nil,
analyze: Analyze? = nil,
archive: Archive? = nil
archive: Archive? = nil,
management: Management? = nil
) {
self.name = name
self.build = build
@@ -31,6 +33,29 @@ public struct Scheme: Equatable {
self.profile = profile
self.analyze = analyze
self.archive = archive
self.management = management
}
public struct Management: Equatable {
public static let sharedDefault = true
public var shared: Bool
public var orderHint: Int?
public var isShown: Bool?
public init?(
shared: Bool = Scheme.Management.sharedDefault,
orderHint: Int? = nil,
isShown: Bool? = nil
) {
if shared == Scheme.Management.sharedDefault, orderHint == nil, isShown == nil {
return nil
}
self.shared = shared
self.orderHint = orderHint
self.isShown = isShown
}
}
public struct SimulateLocation: Equatable {
@@ -403,6 +428,35 @@ extension Scheme.SimulateLocation: JSONEncodable {
}
}
extension Scheme.Management: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
shared = jsonDictionary.json(atKeyPath: "shared") ?? Scheme.Management.sharedDefault
orderHint = jsonDictionary.json(atKeyPath: "orderHint")
isShown = jsonDictionary.json(atKeyPath: "isShown")
}
}
extension Scheme.Management: JSONEncodable {
public func toJSONValue() -> Any {
var dict: [String: Any?] = [:]
if shared != Scheme.Management.sharedDefault {
dict["shared"] = shared
}
if let isShown = isShown {
dict["isShown"] = isShown
}
if let orderHint = orderHint {
dict["orderHint"] = orderHint
}
return dict
}
}
extension Scheme.Run: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
@@ -718,6 +772,7 @@ extension Scheme: NamedJSONDictionaryConvertible {
analyze = jsonDictionary.json(atKeyPath: "analyze")
profile = jsonDictionary.json(atKeyPath: "profile")
archive = jsonDictionary.json(atKeyPath: "archive")
management = jsonDictionary.json(atKeyPath: "management")
}
}
@@ -730,6 +785,7 @@ extension Scheme: JSONEncodable {
"analyze": analyze?.toJSONValue(),
"profile": profile?.toJSONValue(),
"archive": archive?.toJSONValue(),
"management": management?.toJSONValue(),
] as [String: Any?]
}
}
+10 -1
View File
@@ -22,6 +22,7 @@ public struct TargetScheme: Equatable {
public var environmentVariables: [XCScheme.EnvironmentVariable]
public var preActions: [Scheme.ExecutionAction]
public var postActions: [Scheme.ExecutionAction]
public var management: Scheme.Management?
public var testPlans: [TestPlan]
public init(
@@ -39,7 +40,8 @@ public struct TargetScheme: Equatable {
commandLineArguments: [String: Bool] = [:],
environmentVariables: [XCScheme.EnvironmentVariable] = [],
preActions: [Scheme.ExecutionAction] = [],
postActions: [Scheme.ExecutionAction] = []
postActions: [Scheme.ExecutionAction] = [],
management: Scheme.Management? = nil
) {
self.testTargets = testTargets
self.testPlans = testPlans
@@ -56,6 +58,8 @@ public struct TargetScheme: Equatable {
self.environmentVariables = environmentVariables
self.preActions = preActions
self.postActions = postActions
self.postActions = postActions
self.management = management
}
}
@@ -105,6 +109,7 @@ extension TargetScheme: JSONObjectConvertible {
environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary)
preActions = jsonDictionary.json(atKeyPath: "preActions") ?? []
postActions = jsonDictionary.json(atKeyPath: "postActions") ?? []
management = jsonDictionary.json(atKeyPath: "management")
}
}
@@ -149,6 +154,10 @@ extension TargetScheme: JSONEncodable {
dict["region"] = region
}
if let management = management {
dict["management"] = management.toJSONValue()
}
return dict
}
}
@@ -102,7 +102,13 @@ class GenerateCommand: ProjectCommand {
let xcodeProject: XcodeProj
do {
let projectGenerator = ProjectGenerator(project: project)
xcodeProject = try projectGenerator.generateXcodeProject(in: projectDirectory)
guard let userName = ProcessInfo.processInfo.environment["LOGNAME"] else {
throw GenerationError.missingUsername
}
xcodeProject = try projectGenerator.generateXcodeProject(in: projectDirectory, userName: userName)
} catch {
throw GenerationError.generationError(error)
}
@@ -111,6 +117,7 @@ class GenerateCommand: ProjectCommand {
info("⚙️ Writing project...")
do {
try fileWriter.writeXcodeProject(xcodeProject, to: projectPath)
success("Created project at \(projectPath)")
} catch {
throw GenerationError.writingError(error)
@@ -10,6 +10,7 @@ enum GenerationError: Error, CustomStringConvertible, ProcessError {
case cacheGenerationError(Error)
case validationError(SpecValidationError)
case generationError(Error)
case missingUsername
case writingError(Error)
var description: String {
@@ -24,6 +25,8 @@ enum GenerationError: Error, CustomStringConvertible, ProcessError {
return error.description
case let .generationError(error):
return String(describing: error)
case .missingUsername:
return "Couldn't find current username"
case let .writingError(error):
return String(describing: error)
}
+19 -7
View File
@@ -13,22 +13,34 @@ public class ProjectGenerator {
self.project = project
}
public func generateXcodeProject(in projectDirectory: Path? = nil) throws -> XcodeProj {
public func generateXcodeProject(in projectDirectory: Path? = nil, userName: String) throws -> XcodeProj {
// generate PBXProj
let pbxProjGenerator = PBXProjGenerator(project: project,
projectDirectory: projectDirectory)
let pbxProj = try pbxProjGenerator.generate()
// generate Schemes
let schemeGenerator = SchemeGenerator(project: project, pbxProj: pbxProj)
let schemes = try schemeGenerator.generateSchemes()
// generate Workspace
let workspace = try generateWorkspace()
let sharedData = XCSharedData(schemes: schemes)
return XcodeProj(workspace: workspace, pbxproj: pbxProj, sharedData: sharedData)
// generate Schemes
let schemeGenerator = SchemeGenerator(project: project, pbxProj: pbxProj)
let (sharedSchemes, userSchemes, schemeManagement) = try schemeGenerator.generateSchemes()
// generate shared data
let sharedData = XCSharedData(schemes: sharedSchemes)
// generate user data
let userData = userSchemes.isEmpty && schemeManagement == nil ? [] : [
XCUserData(userName: userName, schemes: userSchemes, schemeManagement: schemeManagement)
]
return XcodeProj(
workspace: workspace,
pbxproj: pbxProj,
sharedData: sharedData,
userData: userData
)
}
func generateWorkspace() throws -> XCWorkspace {
+47 -14
View File
@@ -40,12 +40,15 @@ public class SchemeGenerator {
return pbxproj
}
public func generateSchemes() throws -> [XCScheme] {
var xcschemes: [XCScheme] = []
public func generateSchemes() throws -> (
shared: [XCScheme],
user: [XCScheme],
management: XCSchemeManagement?
) {
var schemes: [(Scheme, ProjectTarget?)] = []
for scheme in project.schemes {
let xcscheme = try generateScheme(scheme)
xcschemes.append(xcscheme)
schemes.append((scheme, nil))
}
for target in project.projectTargets {
@@ -64,19 +67,18 @@ public class SchemeGenerator {
debugConfig: debugConfig.name,
releaseConfig: releaseConfig.name
)
let xcscheme = try generateScheme(scheme, for: target)
xcschemes.append(xcscheme)
schemes.append((scheme, target))
} else {
for configVariant in targetScheme.configVariants {
let schemeName = "\(target.name) \(configVariant)"
let debugConfig = project.configs
.first(including: configVariant, for: .debug)!
let releaseConfig = project.configs
.first(including: configVariant, for: .release)!
let scheme = Scheme(
name: schemeName,
target: target,
@@ -85,14 +87,44 @@ public class SchemeGenerator {
debugConfig: debugConfig.name,
releaseConfig: releaseConfig.name
)
let xcscheme = try generateScheme(scheme, for: target)
xcschemes.append(xcscheme)
schemes.append((scheme, target))
}
}
}
}
return xcschemes
var sharedSchemes: [XCScheme] = []
var userSchemes: [XCScheme] = []
var schemeManagements: [XCSchemeManagement.UserStateScheme] = []
for (scheme, projectTarget) in schemes {
let xcscheme = try generateScheme(scheme, for: projectTarget)
if scheme.management?.shared == false {
userSchemes.append(xcscheme)
} else {
sharedSchemes.append(xcscheme)
}
if let management = scheme.management {
schemeManagements.append(
XCSchemeManagement.UserStateScheme(
name: scheme.name + ".xcscheme",
shared: management.shared,
orderHint: management.orderHint,
isShown: management.isShown
)
)
}
}
return (
shared: sharedSchemes,
user: userSchemes,
management: schemeManagements.isEmpty
? nil
: XCSchemeManagement(schemeUserState: schemeManagements, suppressBuildableAutocreation: nil)
)
}
public func generateScheme(_ scheme: Scheme, for target: ProjectTarget? = nil) throws -> XCScheme {
@@ -358,7 +390,7 @@ public class SchemeGenerator {
.flatMap { $0.type.isExtension ? true : nil }
)
}
private func launchAutomaticallySubstyle(for target: ProjectTarget?) -> String? {
if target?.type.isExtension == true {
return "2"
@@ -461,7 +493,8 @@ extension Scheme {
),
archive: .init(
config: releaseConfig
)
),
management: targetScheme.management
)
}
+1 -1
View File
@@ -28,7 +28,7 @@ private func generateXcodeProject(specPath: Path, file: String = #file, line: In
let project = try Project(path: specPath)
let generator = ProjectGenerator(project: project)
let writer = FileWriter(project: project)
let xcodeProject = try generator.generateXcodeProject()
let xcodeProject = try generator.generateXcodeProject(userName: "someUser")
try writer.writeXcodeProject(xcodeProject)
try writer.writePlists()
}
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXFileReference section */
5FE827133AD803E389008F92 /* Shared_TargetScheme.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = Shared_TargetScheme.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
9194D98A5CC4C58074AED541 /* ExternalTarget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ExternalTarget.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@@ -22,6 +23,7 @@
isa = PBXGroup;
children = (
9194D98A5CC4C58074AED541 /* ExternalTarget.framework */,
5FE827133AD803E389008F92 /* Shared_TargetScheme.bundle */,
);
name = Products;
sourceTree = "<group>";
@@ -44,6 +46,20 @@
productReference = 9194D98A5CC4C58074AED541 /* ExternalTarget.framework */;
productType = "com.apple.product-type.framework";
};
7D5ECBED52C0D723572BDC7A /* Shared_TargetScheme */ = {
isa = PBXNativeTarget;
buildConfigurationList = FF87BC5AF9E43A6A84F165D0 /* Build configuration list for PBXNativeTarget "Shared_TargetScheme" */;
buildPhases = (
);
buildRules = (
);
dependencies = (
);
name = Shared_TargetScheme;
productName = Shared_TargetScheme;
productReference = 5FE827133AD803E389008F92 /* Shared_TargetScheme.bundle */;
productType = "com.apple.product-type.bundle";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -67,6 +83,7 @@
projectRoot = "";
targets = (
370BCE474732AA3FDEE3019C /* ExternalTarget */,
7D5ECBED52C0D723572BDC7A /* Shared_TargetScheme */,
);
};
/* End PBXProject section */
@@ -241,6 +258,30 @@
};
name = Debug;
};
EC8D269E955A03687C9CC471 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
EFFEE19ADA3596D4D0EDD264 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -262,6 +303,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
FF87BC5AF9E43A6A84F165D0 /* Build configuration list for PBXNativeTarget "Shared_TargetScheme" */ = {
isa = XCConfigurationList;
buildConfigurations = (
EC8D269E955A03687C9CC471 /* Debug */,
EFFEE19ADA3596D4D0EDD264 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};
rootObject = 8702E0566EC7EF0ABE948569 /* Project object */;
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
onlyGenerateCoverageForSpecifiedTargets = "NO">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
<CommandLineArguments>
</CommandLineArguments>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<CommandLineArguments>
</CommandLineArguments>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7D5ECBED52C0D723572BDC7A"
BuildableName = "Shared_TargetScheme.bundle"
BlueprintName = "Shared_TargetScheme"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
onlyGenerateCoverageForSpecifiedTargets = "NO">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7D5ECBED52C0D723572BDC7A"
BuildableName = "Shared_TargetScheme.bundle"
BlueprintName = "Shared_TargetScheme"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
<CommandLineArguments>
</CommandLineArguments>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7D5ECBED52C0D723572BDC7A"
BuildableName = "Shared_TargetScheme.bundle"
BlueprintName = "Shared_TargetScheme"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<CommandLineArguments>
</CommandLineArguments>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7D5ECBED52C0D723572BDC7A"
BuildableName = "Shared_TargetScheme.bundle"
BlueprintName = "Shared_TargetScheme"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
onlyGenerateCoverageForSpecifiedTargets = "NO">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "370BCE474732AA3FDEE3019C"
BuildableName = "ExternalTarget.framework"
BlueprintName = "ExternalTarget"
ReferencedContainer = "container:TestProject.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>ExternalTarget.xcscheme_^#shared#^_</key>
<dict>
<key>isShown</key>
<false/>
</dict>
<key>Shared_TargetScheme.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>User_ProjectScheme.xcscheme</key>
<dict>
<key>isShown</key>
<true/>
<key>orderHint</key>
<integer>1</integer>
</dict>
</dict>
</dict>
</plist>
@@ -1,5 +1,24 @@
name: TestProject
schemes:
User_ProjectScheme:
build:
targets:
ExternalTarget: all
management:
shared: false
orderHint: 1
isShown: true
targets:
ExternalTarget:
type: framework
platform: iOS
scheme:
management:
shared: true
isShown: false
Shared_TargetScheme:
type: bundle
platform: iOS
scheme:
management:
orderHint: 0
@@ -25,14 +25,14 @@ class GeneratedPerformanceTests: XCTestCase {
let project = try Project.testProject(basePath: basePath)
measure {
let generator = ProjectGenerator(project: project)
_ = try! generator.generateXcodeProject()
_ = try! generator.generateXcodeProject(userName: "someUser")
}
}
func testWriting() throws {
let project = try Project.testProject(basePath: basePath)
let generator = ProjectGenerator(project: project)
let xcodeProject = try generator.generateXcodeProject()
let xcodeProject = try generator.generateXcodeProject(userName: "someUser")
measure {
xcodeProject.pbxproj.invalidateUUIDs()
try! xcodeProject.write(path: project.defaultProjectPath)
@@ -65,14 +65,14 @@ class FixturePerformanceTests: XCTestCase {
let project = try Project(path: specPath)
measure {
let generator = ProjectGenerator(project: project)
_ = try! generator.generateXcodeProject()
_ = try! generator.generateXcodeProject(userName: "someUser")
}
}
func testFixtureWriting() throws {
let project = try Project(path: specPath)
let generator = ProjectGenerator(project: project)
let xcodeProject = try generator.generateXcodeProject()
let xcodeProject = try generator.generateXcodeProject(userName: "someUser")
measure {
xcodeProject.pbxproj.invalidateUUIDs()
try! xcodeProject.write(path: project.defaultProjectPath)
+2 -1
View File
@@ -30,7 +30,8 @@ extension Project {
XCScheme.EnvironmentVariable(variable: "ENV2", value: "HELLO", enabled: false),
],
preActions: [Scheme.ExecutionAction(name: "run", script: "script")],
postActions: [Scheme.ExecutionAction(name: "run", script: "script")]
postActions: [Scheme.ExecutionAction(name: "run", script: "script")],
management: Scheme.Management(shared: false, orderHint: 1, isShown: true)
)
for platform in Platform.allCases {
let appTarget = Target(
+27 -1
View File
@@ -796,6 +796,11 @@ class SpecLoadingTests: XCTestCase {
"script": "hello",
],
],
"management": [
"shared": false,
"isShown": true,
"orderHint": 10
],
]
let target = try Target(name: "test", jsonDictionary: targetDictionary)
@@ -813,7 +818,8 @@ class SpecLoadingTests: XCTestCase {
commandLineArguments: ["ENV1": true],
environmentVariables: [XCScheme.EnvironmentVariable(variable: "TEST_VAR", value: "TEST_VAL", enabled: true)],
preActions: [.init(name: "Do Thing", script: "dothing", settingsTarget: "test")],
postActions: [.init(name: "Run Script", script: "hello")]
postActions: [.init(name: "Run Script", script: "hello")],
management: Scheme.Management(shared: false, orderHint: 10, isShown: true)
)
try expect(target.scheme) == scheme
@@ -873,6 +879,10 @@ class SpecLoadingTests: XCTestCase {
]
]
],
"management": [
"isShown": false,
"orderHint": 4
],
]
let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary)
let expectedTargets: [Scheme.BuildTarget] = [
@@ -923,6 +933,9 @@ class SpecLoadingTests: XCTestCase {
]
)
try expect(scheme.test) == expectedTest
let expectedManagement = Scheme.Management(shared: true, orderHint: 4, isShown: false)
try expect(scheme.management) == expectedManagement
}
$0.it("parses alternate test schemes") {
@@ -946,6 +959,9 @@ class SpecLoadingTests: XCTestCase {
"disableMainThreadChecker": true,
"stopOnEveryMainThreadCheckerIssue": true,
],
"management": [
"isShown": false
],
]
let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary)
@@ -965,6 +981,9 @@ class SpecLoadingTests: XCTestCase {
]
)
try expect(scheme.test) == expectedTest
let expectedManagement = Scheme.Management(shared: true, orderHint: nil, isShown: false)
try expect(scheme.management) == expectedManagement
}
$0.it("parses schemes variables") {
@@ -1104,6 +1123,10 @@ class SpecLoadingTests: XCTestCase {
"disableMainThreadChecker": true,
"stopOnEveryMainThreadCheckerIssue": false,
],
"management": [
"shared": false,
"orderHint": 8
],
],
],
"schemes": [
@@ -1154,6 +1177,9 @@ class SpecLoadingTests: XCTestCase {
]
)
try expect(scheme.test) == expectedTest
let expectedManagement = Scheme.Management(shared: false, orderHint: 8, isShown: nil)
try expect(scheme.management) == expectedManagement
}
$0.it("parses copy files on install") {
@@ -15,7 +15,7 @@ extension Project {
try self.validate()
}
let generator = ProjectGenerator(project: self)
return try generator.generateXcodeProject()
return try generator.generateXcodeProject(userName: "someUser")
}
}
@@ -355,7 +355,7 @@ class ProjectGeneratorTests: XCTestCase {
let project = try! Project(path: fixturePath + "TestProject/AnotherProject/project.yml")
let generator = ProjectGenerator(project: project)
let writer = FileWriter(project: project)
let xcodeProject = try! generator.generateXcodeProject()
let xcodeProject = try! generator.generateXcodeProject(userName: "someUser")
try! writer.writeXcodeProject(xcodeProject)
try! writer.writePlists()
subproject = xcodeProject.pbxproj
@@ -1513,7 +1513,7 @@ class ProjectGeneratorTests: XCTestCase {
$0.it("generate groups") {
let project = Project(name: "test", targets: [frameworkWithSources])
let generator = ProjectGenerator(project: project)
let generatedProject = try generator.generateXcodeProject()
let generatedProject = try generator.generateXcodeProject(userName: "someUser")
let group = generatedProject.pbxproj.groups.first(where: { $0.nameOrPath == groupName })
try expect(group?.path) == "App_iOS"
}
@@ -1524,7 +1524,7 @@ class ProjectGeneratorTests: XCTestCase {
let destinationPath = fixturePath
let project = Project(name: "test", targets: [frameworkWithSources])
let generator = ProjectGenerator(project: project)
let generatedProject = try generator.generateXcodeProject(in: destinationPath)
let generatedProject = try generator.generateXcodeProject(in: destinationPath, userName: "someUser")
let group = generatedProject.pbxproj.groups.first(where: { $0.nameOrPath == groupName })
try expect(group?.path) == "TestProject/App_iOS"
}
@@ -1533,7 +1533,7 @@ class ProjectGeneratorTests: XCTestCase {
let destinationPath = fixturePath
let project = Project(name: "test", targets: [frameworkWithSources])
let generator = ProjectGenerator(project: project)
let generatedProject = try generator.generateXcodeProject(in: destinationPath)
let generatedProject = try generator.generateXcodeProject(in: destinationPath, userName: "someUser")
let plists = generatedProject.pbxproj.buildConfigurations.compactMap { $0.buildSettings["INFOPLIST_FILE"] as? String }
try expect(plists.count) == 2
for plist in plists {
@@ -119,7 +119,6 @@ class SchemeGeneratorTests: XCTestCase {
try expect(xcscheme.testAction?.testables[1].locationScenarioReference?.referenceType) == "1"
try expect(xcscheme.testAction?.testables[1].locationScenarioReference?.identifier) == "New York, NY, USA"
}
let frameworkTarget = Scheme.BuildTarget(target: .local(framework.name), buildTypes: [.archiving])
@@ -352,7 +351,7 @@ class SchemeGeneratorTests: XCTestCase {
let project = try! Project(path: fixturePath + "scheme_test/test_project.yml")
let generator = ProjectGenerator(project: project)
let writer = FileWriter(project: project)
let xcodeProject = try! generator.generateXcodeProject()
let xcodeProject = try! generator.generateXcodeProject(userName: "someUser")
try! writer.writeXcodeProject(xcodeProject)
try! writer.writePlists()
}
@@ -383,7 +382,7 @@ class SchemeGeneratorTests: XCTestCase {
let project = try! Project(path: fixturePath + "scheme_test/test_project.yml")
let generator = ProjectGenerator(project: project)
let writer = FileWriter(project: project)
let xcodeProject = try! generator.generateXcodeProject()
let xcodeProject = try! generator.generateXcodeProject(userName: "someUser")
try! writer.writeXcodeProject(xcodeProject)
try! writer.writePlists()
}
@@ -586,7 +585,7 @@ class SchemeGeneratorTests: XCTestCase {
XCTAssertEqual(xcscheme.lastUpgradeVersion, lastUpgradeValue)
}
func testDefaultLastUpgradeVersionWhenUserDidNotSpecify() throws {
var target = app
target.scheme = TargetScheme()
@@ -598,6 +597,20 @@ class SchemeGeneratorTests: XCTestCase {
XCTAssertEqual(xcscheme.lastUpgradeVersion, project.xcodeVersion)
}
func testGenerateSchemeManagementOnHiddenTargetScheme() throws {
var target = app
target.scheme = TargetScheme(management: Scheme.Management(isShown: false))
let project = Project(name: "test", targets: [target, framework])
let xcodeProject = try project.generateXcodeProject()
let xcSchemeManagement = try XCTUnwrap(xcodeProject.userData.first?.schemeManagement)
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].name, "MyApp.xcscheme")
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].shared, true)
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].isShown, false)
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].orderHint, nil)
}
// MARK: - Helpers
private func makeWatchScheme(appType: PBXProductType, extensionType: PBXProductType) throws -> XCScheme {