|
1 | | -# spmgraph |
| 1 | +# spmgraph - SwiftPM dependency graph management |
| 2 | + |
| 3 | +A CLI tool that **unlocks Swift dependency graphs**, giving you extra information and capabilities. |
| 4 | +With it you can visualize your dependency graph, run selective testing, and enforce architectural rules for optimal modular setups. |
| 5 | + |
| 6 | +## How to use |
| 7 | + |
| 8 | +`spmgraph` is run for a local `Package.swift` and takes the user configuration from a `SPMGraphConfig.swift` file. |
| 9 | + |
| 10 | +### Edit |
| 11 | +Create and edit your spmgraph config |
| 12 | + |
| 13 | +- run `spmgraph edit <'Package.swift' path> <options>` |
| 14 | +- it creates an initial `SPMGraphConfig.swift` on the same path as your `Package.swift` |
| 15 | +- spmgraph opens up a temporary Swift Package where you configure spmgraph in Swift and build to check that everything is correct |
| 16 | + |
| 17 | +### Visualize |
| 18 | +Generate an image with a visual representation of your dependency. **Open the map!** |
| 19 | + |
| 20 | +run `spmgraph visualize <'Package.swift' path> help` for more |
| 21 | + |
| 22 | +### Tests |
| 23 | +**Selective testing** based on git changes or a given list of changed files. |
| 24 | +The output is a comma separate list of test targets that can be fed into `xcodebuild`'s `-only-testing:TEST-IDENTIFIER` or [fastlane scan](https://docs.fastlane.tools/actions/scan/#scan)'s `only_testing` |
| 25 | + |
| 26 | +run `spmgraph tests <'Package.swift' path> help` for more |
| 27 | + |
| 28 | +### Lint |
| 29 | +Verify if the dependency graph follow the defined team and industry best practices. |
| 30 | + |
| 31 | +For example, enforce that |
| 32 | +- feature modules don't depend on each other |
| 33 | +- Linked dependencies are imported (used) at least once |
| 34 | +- Base modules don't depend on feature modules |
| 35 | +- the dependency graph isn't too deep |
| 36 | + |
| 37 | +All possible using Swift. Below an example of creating your own lint rule by traversing the dependency graph: |
| 38 | +```swift |
| 39 | +extension SPMGraphConfig.Lint.Rule { |
| 40 | + static let unregisteredLiveModules = Self( |
| 41 | + id: "unregisteredLiveModules", |
| 42 | + name: "Unregistered Live modules", |
| 43 | + abstract: "Live modules need to be added to the app target / feature module as dependencies.", |
| 44 | + validate: { package, excludedSuffixes in |
| 45 | + let liveModules = package |
| 46 | + .modules |
| 47 | + .compactMap { module -> Module? in |
| 48 | + guard !module.containsOneOf(suffixes: excludedSuffixes), module.isLiveModule else { |
| 49 | + return nil |
| 50 | + } |
| 51 | + return module |
| 52 | + } |
| 53 | + |
| 54 | + guard |
| 55 | + let featureModule = package |
| 56 | + .modules |
| 57 | + .first(where: { $0.name == "GetYourGuideFeature" }), |
| 58 | + case let featureModuleDependencies = featureModule |
| 59 | + .dependencies |
| 60 | + .compactMap(\.module) |
| 61 | + else { |
| 62 | + return [LintError.missingFeatureModule] |
| 63 | + } |
| 64 | + |
| 65 | + return liveModules.compactMap { liveModule in |
| 66 | + if !featureModuleDependencies.contains(liveModule) { |
| 67 | + return LintError.unregisteredLiveModules( |
| 68 | + moduleName: liveModule.name, |
| 69 | + appModule: featureModule.name |
| 70 | + ) |
| 71 | + } |
| 72 | + |
| 73 | + return nil |
| 74 | + } |
| 75 | + } |
| 76 | + ) |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +run `spmgraph lint <'Package.swift' path> help` for more |
| 81 | + |
| 82 | +## Requirements |
| 83 | +- [graphviz](https://github.com/graphp/graphviz) (available via `brew install graphviz`) |
| 84 | +- Xcode 16+ and the Swift 6.0+ toolchain |
| 85 | + |
| 86 | +## Installation |
| 87 | + |
| 88 | +### [Mint](https://github.com/yonaskolb/mint) |
| 89 | + |
| 90 | +``` |
| 91 | +mint install getyourguide/spmgraph |
| 92 | +``` |
| 93 | +* For optimal build times make sure `~/.mint/bin/spmgraph` is cached on your CI runner. |
| 94 | + |
| 95 | +## Acknowledgments |
| 96 | +- Inspired by the work that the [Tuist](https://tuist.dev/) team does for the Apple developers community and their focus on leveraging the dependency graph to provide amazing features for engineers. Also, source of inspiration for our shell abstraction layer. |
| 97 | + |
| 98 | +## Open roadmap |
| 99 | +- [ ] Cover the core logic of Lint, Map and Visualize libs with tests |
| 100 | +- [ ] Support macros (to become a GitHub issue) |
| 101 | + |
| 102 | +Ideas |
| 103 | +- [ ] Lint - see if it can be improved to cover auto-exported dependencies. For example usages of `import Dependencies` justify linking `DependenciesExtras` as a dependency. |
| 104 | +- [ ] Add fix it suggestion to lint errors |
0 commit comments