- SwiftPM command plugin
- Xcode 14+
- No dependencies
- MIT
A scheme for every product,
in one command.
Scheme Generator reads the products of your Package.swift and writes a shared Xcode .xcscheme for each one, right where your workspace looks for them. Add a module, run the plugin, and its scheme is there. Remove one, and its scheme goes away.
$ swift package --allow-writing-to-package-directory \
scheme-generator
Found 42 products.
Schemes that will be removed:
LegacyNetworking
Schemes that will be created:
OnboardingFeature
SettingsFeature
Finished
Why
Modular apps have many products.
Xcode only shows the schemes you made.
Split an app into a package of feature modules, as with The Composable Architecture, and each module deserves its own scheme: build it alone, run its tests, preview it fast. Xcode's autocreated schemes are per user and get out of step; shared schemes written by hand drift the moment someone adds or renames a product. Scheme Generator makes the schemes a function of Package.swift.
Read
It loads schemeGenerator.json and the list of products SwiftPM reports for your package.
Plan
It compares them with the .xcscheme files already in schemesDirectory: new products get a scheme, obsolete schemes are removed, excluded ones are left alone.
Write
It writes each scheme from a template that builds, tests, profiles and archives that product, and remembers the product list so an unchanged package is a no-op.
Features
Small, predictable, out of your way.
Every product, one scheme each
Libraries and executables alike get a shared scheme with build, test, launch, profile, analyze and archive actions, named after the product.
Cleans up after itself
With removeNotGeneratedSchemes, a scheme whose product left Package.swift is deleted. excludedSchemes protects the hand-made ones.
A no-op when nothing changed
It keeps a hash of the product list and stops early when it is unchanged, so it is cheap to run on every build or on CI. overwriteAlreadyGeneratedSchemes forces a refresh.
Xcode or terminal
Right-click your package in Xcode's navigator, or run swift package scheme-generator from a script or a CI job. Messages appear in Xcode's Report navigator.
Sandboxed and dependency-free
A plain SwiftPM command plugin with no package dependencies. It asks for permission before writing, and writes only to the folder you configure.
Fast for large packages
Planning and rendering 1,000 schemes takes under 2 ms; the disk is the only cost you will notice. Measured with package-benchmark.
Configuration
One JSON file at the root of your package.
Name it schemeGenerator.json, or pass --confFile other.json once: the plugin remembers the name. If it is missing, the plugin writes a default one for you to fill in.
{
"schemesDirectory": "Project/project.xcworkspace/xcshareddata/xcschemes",
"excludedSchemes": ["Target1Tests", "Target2Tests"],
"removeNotGeneratedSchemes": true,
"overwriteAlreadyGeneratedSchemes": false,
"verbose": true
}
| Key | Meaning |
|---|---|
schemesDirectory | Where schemes are written. Required. Point it into a workspace's xcshareddata/xcschemes to share them. |
removeNotGeneratedSchemes | Delete schemes whose product is no longer in Package.swift. |
overwriteAlreadyGeneratedSchemes | Rewrite schemes that already exist. |
excludedSchemes | Names of existing scheme files the plugin must never remove. |
verbose | Print the configuration and every scheme it creates or removes. |
Install
Add the package, run the command.
dependencies: [
.package(url: "https://github.com/mackoj/SchemeGeneratorPlugin.git", from: "0.5.8"),
]
swift package --allow-writing-to-package-directory scheme-generator
- Add the dependency to the package whose products need schemes. No target needs to use it.
- Create
schemeGenerator.jsonnext toPackage.swift. - In Xcode, right-click the package and choose Scheme Generator, then Allow Command to Change Files. In a terminal or on CI, pass
--allow-writing-to-package-directory. - If the schemes go into a workspace, restart Xcode to see them all.
Requires Xcode 14 or later (swift-tools-version 5.7) on macOS 12 or later.