mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2024-08-17 00:30:29 +03:00
Compare commits
4 Commits
64c8a5802a
...
63f35564f0
Author | SHA1 | Date | |
---|---|---|---|
|
63f35564f0 | ||
|
f8842228c5 | ||
|
7eb5e9bd06 | ||
|
f0e1db79e0 |
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
## Next Version
|
## Next Version
|
||||||
|
|
||||||
|
- Removed `xcodegen dump --type graphviz` feature. @giginet
|
||||||
|
|
||||||
## 2.41.0
|
## 2.41.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
53
Docs/Recipes/ios-alternate-app-icons.md
Normal file
53
Docs/Recipes/ios-alternate-app-icons.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# (iOS) Alternate app icons
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Adds alternate app icons to include in the built product.
|
||||||
|
|
||||||
|
## File structure
|
||||||
|
|
||||||
|
```diff
|
||||||
|
.
|
||||||
|
├── MyApp
|
||||||
|
│ ├── AppDelegate.swift
|
||||||
|
│ ├── Assets.xcassets
|
||||||
|
│ │ ├── AppIcon.appiconset
|
||||||
|
│ │ │ ├── AppIcon.png
|
||||||
|
| | | └── Contents.json
|
||||||
|
+│ │ ├── AppIcon2.appiconset
|
||||||
|
+│ │ │ ├── AppIcon.png
|
||||||
|
+| | | └── Contents.json
|
||||||
|
+│ │ ├── AppIcon3.appiconset
|
||||||
|
+│ │ │ ├── AppIcon.png
|
||||||
|
+| | | └── Contents.json
|
||||||
|
│ │ └── Contents.json
|
||||||
|
│ ├── LaunchScreen.storyboard
|
||||||
|
│ └── RootViewController.swift
|
||||||
|
└── project.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## project.yml
|
||||||
|
|
||||||
|
```diff
|
||||||
|
name: MyApp
|
||||||
|
targets:
|
||||||
|
MyApp:
|
||||||
|
type: application
|
||||||
|
platform: iOS
|
||||||
|
deploymentTarget: 12.0
|
||||||
|
settings:
|
||||||
|
TARGETED_DEVICE_FAMILY: 1
|
||||||
|
MARKETING_VERSION: 1.0
|
||||||
|
CURRENT_PROJECT_VERSION: 1
|
||||||
|
DEVELOPMENT_TEAM: MYTEAMID
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: com.mycompany.myapp
|
||||||
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents: YES
|
||||||
|
INFOPLIST_KEY_UILaunchStoryboardName: LaunchScreen.storyboard
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations: UIInterfaceOrientationPortrait
|
||||||
|
+ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS: YES
|
||||||
|
+ ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES: AppIcon2 AppIcon3
|
||||||
|
sources:
|
||||||
|
- MyApp
|
||||||
|
```
|
72
Docs/Recipes/ios-environments.md
Normal file
72
Docs/Recipes/ios-environments.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# (iOS) Environments
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Best way to setup Development, Testing and Production environments.
|
||||||
|
|
||||||
|
## File structure
|
||||||
|
|
||||||
|
```diff
|
||||||
|
.
|
||||||
|
├── MyApp
|
||||||
|
│ ├── AppDelegate.swift
|
||||||
|
│ ├── Assets.xcassets
|
||||||
|
│ │ ├── AppIcon.appiconset
|
||||||
|
│ │ │ ├── AppIcon.png
|
||||||
|
| | | └── Contents.json
|
||||||
|
│ │ └── Contents.json
|
||||||
|
│ ├── LaunchScreen.storyboard
|
||||||
|
│ └── RootViewController.swift
|
||||||
|
└── project.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## project.yml
|
||||||
|
|
||||||
|
```diff
|
||||||
|
name: MyApp
|
||||||
|
+configs:
|
||||||
|
+ Dev Debug: debug
|
||||||
|
+ Test Debug: debug
|
||||||
|
+ Prod Debug: debug
|
||||||
|
+ Dev Release: release
|
||||||
|
+ Test Release: release
|
||||||
|
+ Prod Release: release
|
||||||
|
+settings:
|
||||||
|
+ configs:
|
||||||
|
+ Dev Debug:
|
||||||
|
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS: DEBUG DEV
|
||||||
|
+ Test Debug:
|
||||||
|
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS: DEBUG TEST
|
||||||
|
+ Prod Debug:
|
||||||
|
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS: DEBUG PROD
|
||||||
|
+ Dev Release:
|
||||||
|
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS: DEV
|
||||||
|
+ Test Release:
|
||||||
|
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS: TEST
|
||||||
|
+ Prod Release:
|
||||||
|
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS: PROD
|
||||||
|
targets:
|
||||||
|
MyApp:
|
||||||
|
type: application
|
||||||
|
platform: iOS
|
||||||
|
deploymentTarget: 12.0
|
||||||
|
settings:
|
||||||
|
TARGETED_DEVICE_FAMILY: 1
|
||||||
|
MARKETING_VERSION: 1.0
|
||||||
|
CURRENT_PROJECT_VERSION: 1
|
||||||
|
DEVELOPMENT_TEAM: MYTEAMID
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: com.mycompany.myapp
|
||||||
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents: YES
|
||||||
|
INFOPLIST_KEY_UILaunchStoryboardName: LaunchScreen.storyboard
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations: UIInterfaceOrientationPortrait
|
||||||
|
sources:
|
||||||
|
- MyApp
|
||||||
|
+ scheme:
|
||||||
|
+ configVariants:
|
||||||
|
+ - Dev
|
||||||
|
+ - Test
|
||||||
|
+ - Prod
|
||||||
|
```
|
||||||
|
|
90
Docs/Recipes/ios-playground.md
Normal file
90
Docs/Recipes/ios-playground.md
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# (iOS) Playground
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
An alternative to XCode Playground.
|
||||||
|
|
||||||
|
Example of Source.swift:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@main
|
||||||
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
|
) -> Bool {
|
||||||
|
var greeting = "Hello, playground"
|
||||||
|
print(greeting)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Another example with UI:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@main
|
||||||
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
var window: UIWindow?
|
||||||
|
|
||||||
|
func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
|
) -> Bool {
|
||||||
|
let window = UIWindow()
|
||||||
|
self.window = window
|
||||||
|
|
||||||
|
let rootViewController = RootViewController(nibName: nil, bundle: nil)
|
||||||
|
window.rootViewController = rootViewController
|
||||||
|
window.makeKeyAndVisible()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RootViewController: UIViewController {
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
// Do any additional setup after loading the view.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## File structure
|
||||||
|
|
||||||
|
```diff
|
||||||
|
.
|
||||||
|
├── Source.swift
|
||||||
|
└── project.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## project.yml
|
||||||
|
|
||||||
|
```diff
|
||||||
|
name: MyApp
|
||||||
|
targets:
|
||||||
|
MyApp:
|
||||||
|
type: application
|
||||||
|
platform: iOS
|
||||||
|
deploymentTarget: 12.0
|
||||||
|
settings:
|
||||||
|
TARGETED_DEVICE_FAMILY: 1
|
||||||
|
MARKETING_VERSION: 1.0
|
||||||
|
CURRENT_PROJECT_VERSION: 1
|
||||||
|
DEVELOPMENT_TEAM: MYTEAMID
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: com.mycompany.myapp
|
||||||
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents: YES
|
||||||
|
- INFOPLIST_KEY_UILaunchStoryboardName: LaunchScreen.storyboard
|
||||||
|
+ INFOPLIST_KEY_UILaunchScreen_Generation: YES
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations: UIInterfaceOrientationPortrait
|
||||||
|
sources:
|
||||||
|
- Source.swift
|
||||||
|
```
|
58
Docs/Recipes/ios-ui-testing-bundle.md
Normal file
58
Docs/Recipes/ios-ui-testing-bundle.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# (iOS) UI Testing Bundle
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Adds a user interface testing bundle that uses the XCTest framework.
|
||||||
|
|
||||||
|
## File structure
|
||||||
|
|
||||||
|
```diff
|
||||||
|
.
|
||||||
|
├── MyApp
|
||||||
|
│ ├── AppDelegate.swift
|
||||||
|
│ ├── Assets.xcassets
|
||||||
|
│ │ ├── AppIcon.appiconset
|
||||||
|
│ │ │ ├── AppIcon.png
|
||||||
|
| | | └── Contents.json
|
||||||
|
│ │ └── Contents.json
|
||||||
|
│ ├── LaunchScreen.storyboard
|
||||||
|
│ └── RootViewController.swift
|
||||||
|
+├── MyAppUITests
|
||||||
|
+│ └── SomeUITests.swift
|
||||||
|
└── project.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## project.yml
|
||||||
|
|
||||||
|
```diff
|
||||||
|
name: MyApp
|
||||||
|
targets:
|
||||||
|
MyApp:
|
||||||
|
type: application
|
||||||
|
platform: iOS
|
||||||
|
deploymentTarget: 12.0
|
||||||
|
settings:
|
||||||
|
TARGETED_DEVICE_FAMILY: 1
|
||||||
|
MARKETING_VERSION: 1.0
|
||||||
|
CURRENT_PROJECT_VERSION: 1
|
||||||
|
DEVELOPMENT_TEAM: MYTEAMID
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: com.mycompany.myapp
|
||||||
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents: YES
|
||||||
|
INFOPLIST_KEY_UILaunchStoryboardName: LaunchScreen.storyboard
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations: UIInterfaceOrientationPortrait
|
||||||
|
sources:
|
||||||
|
- MyApp
|
||||||
|
+ MyAppUITests:
|
||||||
|
+ type: bundle.ui-testing
|
||||||
|
+ platform: iOS
|
||||||
|
+ settings:
|
||||||
|
+ DEVELOPMENT_TEAM: MYTEAMID
|
||||||
|
+ PRODUCT_BUNDLE_IDENTIFIER: com.company.myappuitests
|
||||||
|
+ GENERATE_INFOPLIST_FILE: YES
|
||||||
|
+ sources:
|
||||||
|
+ - MyAppUITests
|
||||||
|
+ dependencies:
|
||||||
|
+ - target: MyApp
|
||||||
|
```
|
58
Docs/Recipes/ios-unit-testing-bundle.md
Normal file
58
Docs/Recipes/ios-unit-testing-bundle.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# (iOS) Unit Testing Bundle
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Adds a unit test bundle that uses the XCTest framework.
|
||||||
|
|
||||||
|
## File structure
|
||||||
|
|
||||||
|
```diff
|
||||||
|
.
|
||||||
|
├── MyApp
|
||||||
|
│ ├── AppDelegate.swift
|
||||||
|
│ ├── Assets.xcassets
|
||||||
|
│ │ ├── AppIcon.appiconset
|
||||||
|
│ │ │ ├── AppIcon.png
|
||||||
|
| | | └── Contents.json
|
||||||
|
│ │ └── Contents.json
|
||||||
|
│ ├── LaunchScreen.storyboard
|
||||||
|
│ └── RootViewController.swift
|
||||||
|
+├── MyAppTests
|
||||||
|
+│ └── SomeTests.swift
|
||||||
|
└── project.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## project.yml
|
||||||
|
|
||||||
|
```diff
|
||||||
|
name: MyApp
|
||||||
|
targets:
|
||||||
|
MyApp:
|
||||||
|
type: application
|
||||||
|
platform: iOS
|
||||||
|
deploymentTarget: 12.0
|
||||||
|
settings:
|
||||||
|
TARGETED_DEVICE_FAMILY: 1
|
||||||
|
MARKETING_VERSION: 1.0
|
||||||
|
CURRENT_PROJECT_VERSION: 1
|
||||||
|
DEVELOPMENT_TEAM: MYTEAMID
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: com.mycompany.myapp
|
||||||
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents: YES
|
||||||
|
INFOPLIST_KEY_UILaunchStoryboardName: LaunchScreen.storyboard
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations: UIInterfaceOrientationPortrait
|
||||||
|
sources:
|
||||||
|
- MyApp
|
||||||
|
+ MyAppTests:
|
||||||
|
+ type: bundle.unit-test
|
||||||
|
+ platform: iOS
|
||||||
|
+ settings:
|
||||||
|
+ DEVELOPMENT_TEAM: MYTEAMID
|
||||||
|
+ PRODUCT_BUNDLE_IDENTIFIER: com.company.myapptests
|
||||||
|
+ GENERATE_INFOPLIST_FILE: YES
|
||||||
|
+ sources:
|
||||||
|
+ - MyAppTests
|
||||||
|
+ dependencies:
|
||||||
|
+ - target: MyApp
|
||||||
|
```
|
@ -18,15 +18,6 @@
|
|||||||
"version" : "0.0.6"
|
"version" : "0.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"identity" : "graphviz",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/SwiftDocOrg/GraphViz.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "70bebcf4597b9ce33e19816d6bbd4ba9b7bdf038",
|
|
||||||
"version" : "0.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"identity" : "jsonutilities",
|
"identity" : "jsonutilities",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
@ -19,7 +19,6 @@ let package = Package(
|
|||||||
.package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.13.0"),
|
.package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.13.0"),
|
||||||
.package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.3"),
|
.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/mxcl/Version", from: "2.0.0"),
|
||||||
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", exact: "0.2.0"),
|
|
||||||
.package(url: "https://github.com/freddi-kit/ArtifactBundleGen", exact: "0.0.6")
|
.package(url: "https://github.com/freddi-kit/ArtifactBundleGen", exact: "0.0.6")
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
@ -41,7 +40,6 @@ let package = Package(
|
|||||||
"XcodeProj",
|
"XcodeProj",
|
||||||
"PathKit",
|
"PathKit",
|
||||||
"XcodeGenCore",
|
"XcodeGenCore",
|
||||||
"GraphViz",
|
|
||||||
], resources: [
|
], resources: [
|
||||||
.copy("SettingPresets")
|
.copy("SettingPresets")
|
||||||
]),
|
]),
|
||||||
|
22
README.md
22
README.md
@ -35,7 +35,6 @@ The project spec is a YAML or JSON file that defines your targets, configuration
|
|||||||
- ✅ Distribute your spec amongst multiple files for easy **sharing** and overriding
|
- ✅ Distribute your spec amongst multiple files for easy **sharing** and overriding
|
||||||
- ✅ Easily create **multi-platform** frameworks
|
- ✅ Easily create **multi-platform** frameworks
|
||||||
- ✅ Integrate **Carthage** frameworks without any work
|
- ✅ Integrate **Carthage** frameworks without any work
|
||||||
- ✅ Export **Dependency Diagrams** to view in [Graphviz](https://www.graphviz.org)
|
|
||||||
|
|
||||||
Given an example project spec:
|
Given an example project spec:
|
||||||
|
|
||||||
@ -138,27 +137,6 @@ Options:
|
|||||||
|
|
||||||
There are other commands as well such as `xcodegen dump` which lets one output the resolved spec in many different formats, or write it to a file. Use `xcodegen help` to see more detailed usage information.
|
There are other commands as well such as `xcodegen dump` which lets one output the resolved spec in many different formats, or write it to a file. Use `xcodegen help` to see more detailed usage information.
|
||||||
|
|
||||||
## Dependency Diagrams
|
|
||||||
<details>
|
|
||||||
<summary>Click to expand!</summary>
|
|
||||||
|
|
||||||
#### How to export dependency diagrams:
|
|
||||||
|
|
||||||
To stdout:
|
|
||||||
|
|
||||||
```
|
|
||||||
xcodegen dump --type graphviz
|
|
||||||
```
|
|
||||||
|
|
||||||
To a file:
|
|
||||||
|
|
||||||
```
|
|
||||||
xcodegen dump --type graphviz --file Graph.viz
|
|
||||||
```
|
|
||||||
|
|
||||||
During implementation, `graphviz` formatting was validated using [GraphvizOnline](https://dreampuf.github.io/GraphvizOnline/), [WebGraphviz](http://www.webgraphviz.com), and [Graphviz on MacOS](https://graphviz.org).
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Editing
|
## Editing
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/yonaskolb/XcodeGen.git
|
git clone https://github.com/yonaskolb/XcodeGen.git
|
||||||
|
@ -41,8 +41,6 @@ class DumpCommand: ProjectCommand {
|
|||||||
output = try Yams.dump(object: project.toJSONDictionary())
|
output = try Yams.dump(object: project.toJSONDictionary())
|
||||||
case .summary:
|
case .summary:
|
||||||
output = project.debugDescription
|
output = project.debugDescription
|
||||||
case .graphviz:
|
|
||||||
output = GraphVizGenerator().generateModuleGraphViz(targets: project.targets)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let file = file {
|
if let file = file {
|
||||||
@ -61,7 +59,6 @@ private enum DumpType: String, ConvertibleFromString, CaseIterable {
|
|||||||
case parsedJSON = "parsed-json"
|
case parsedJSON = "parsed-json"
|
||||||
case parsedYaml = "parsed-yaml"
|
case parsedYaml = "parsed-yaml"
|
||||||
case summary
|
case summary
|
||||||
case graphviz
|
|
||||||
|
|
||||||
static var defaultValue: DumpType { .yaml }
|
static var defaultValue: DumpType { .yaml }
|
||||||
}
|
}
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
import DOT
|
|
||||||
import Foundation
|
|
||||||
import GraphViz
|
|
||||||
import ProjectSpec
|
|
||||||
|
|
||||||
extension Dependency {
|
|
||||||
var graphVizName: String {
|
|
||||||
switch self.type {
|
|
||||||
case .bundle, .package, .sdk, .framework, .carthage:
|
|
||||||
return "[\(self.type)]\\n\(reference)"
|
|
||||||
case .target:
|
|
||||||
return reference
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Dependency.DependencyType: CustomStringConvertible {
|
|
||||||
public var description: String {
|
|
||||||
switch self {
|
|
||||||
case .bundle: return "bundle"
|
|
||||||
case .package: return "package"
|
|
||||||
case .framework: return "framework"
|
|
||||||
case .carthage: return "carthage"
|
|
||||||
case .sdk: return "sdk"
|
|
||||||
case .target: return "target"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Node {
|
|
||||||
init(target: Target) {
|
|
||||||
self.init(target.name)
|
|
||||||
self.shape = .box
|
|
||||||
}
|
|
||||||
|
|
||||||
init(dependency: Dependency) {
|
|
||||||
self.init(dependency.reference)
|
|
||||||
self.shape = .box
|
|
||||||
self.label = dependency.graphVizName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GraphVizGenerator {
|
|
||||||
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func generateModuleGraphViz(targets: [Target]) -> String {
|
|
||||||
return DOTEncoder().encode(generateGraph(targets: targets))
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateGraph(targets: [Target]) -> Graph {
|
|
||||||
var graph = Graph(directed: true)
|
|
||||||
targets.forEach { target in
|
|
||||||
target.dependencies.forEach { dependency in
|
|
||||||
let from = Node(target: target)
|
|
||||||
graph.append(from)
|
|
||||||
let to = Node(dependency: dependency)
|
|
||||||
graph.append(to)
|
|
||||||
var edge = Edge(from: from, to: to)
|
|
||||||
edge.style = .dashed
|
|
||||||
graph.append(edge)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return graph
|
|
||||||
}
|
|
||||||
}
|
|
@ -286,10 +286,12 @@ public class SchemeGenerator {
|
|||||||
let testPlans = scheme.test?.testPlans.enumerated().map { index, testPlan in
|
let testPlans = scheme.test?.testPlans.enumerated().map { index, testPlan in
|
||||||
XCScheme.TestPlanReference(reference: "container:\(testPlan.path)", default: defaultTestPlanIndex == index)
|
XCScheme.TestPlanReference(reference: "container:\(testPlan.path)", default: defaultTestPlanIndex == index)
|
||||||
} ?? []
|
} ?? []
|
||||||
|
let testBuildableEntries = buildActionEntries.filter({ $0.buildFor.contains(.testing) }) + testBuildTargetEntries
|
||||||
|
let testMacroExpansionBuildableRef = testBuildableEntries.map(\.buildableReference).contains(buildableReference) ? buildableReference : testBuildableEntries.first?.buildableReference
|
||||||
|
|
||||||
let testAction = XCScheme.TestAction(
|
let testAction = XCScheme.TestAction(
|
||||||
buildConfiguration: scheme.test?.config ?? defaultDebugConfig.name,
|
buildConfiguration: scheme.test?.config ?? defaultDebugConfig.name,
|
||||||
macroExpansion: buildableReference,
|
macroExpansion: testMacroExpansionBuildableRef,
|
||||||
testables: testables,
|
testables: testables,
|
||||||
testPlans: testPlans.isEmpty ? nil : testPlans,
|
testPlans: testPlans.isEmpty ? nil : testPlans,
|
||||||
preActions: scheme.test?.preActions.map(getExecutionAction) ?? [],
|
preActions: scheme.test?.preActions.map(getExecutionAction) ?? [],
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
import ProjectSpec
|
|
||||||
import Spectre
|
|
||||||
@testable import XcodeGenKit
|
|
||||||
import XCTest
|
|
||||||
|
|
||||||
private let app = Target(
|
|
||||||
name: "MyApp",
|
|
||||||
type: .application,
|
|
||||||
platform: .iOS,
|
|
||||||
settings: Settings(buildSettings: ["SETTING_1": "VALUE"]),
|
|
||||||
dependencies: [
|
|
||||||
Dependency(type: .target, reference: "MyInternalFramework"),
|
|
||||||
Dependency(type: .bundle, reference: "Resources"),
|
|
||||||
Dependency(type: .carthage(findFrameworks: true, linkType: .static), reference: "MyStaticFramework"),
|
|
||||||
Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "MyDynamicFramework"),
|
|
||||||
Dependency(type: .framework, reference: "MyExternalFramework"),
|
|
||||||
Dependency(type: .package(products: ["MyPackage"]), reference: "MyPackage"),
|
|
||||||
Dependency(type: .sdk(root: "MySDK"), reference: "MySDK"),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
private let framework = Target(
|
|
||||||
name: "MyFramework",
|
|
||||||
type: .framework,
|
|
||||||
platform: .iOS,
|
|
||||||
settings: Settings(buildSettings: ["SETTING_2": "VALUE"])
|
|
||||||
)
|
|
||||||
|
|
||||||
private let uiTest = Target(
|
|
||||||
name: "MyAppUITests",
|
|
||||||
type: .uiTestBundle,
|
|
||||||
platform: .iOS,
|
|
||||||
settings: Settings(buildSettings: ["SETTING_3": "VALUE"]),
|
|
||||||
dependencies: [Dependency(type: .target, reference: "MyApp")]
|
|
||||||
)
|
|
||||||
|
|
||||||
private let targets = [app, framework, uiTest]
|
|
||||||
|
|
||||||
class GraphVizGeneratorTests: XCTestCase {
|
|
||||||
|
|
||||||
func testGraphOutput() throws {
|
|
||||||
describe {
|
|
||||||
let graph = GraphVizGenerator().generateGraph(targets: targets)
|
|
||||||
$0.it("generates the expected number of nodes") {
|
|
||||||
try expect(graph.nodes.count) == 16
|
|
||||||
}
|
|
||||||
$0.it("generates box nodes") {
|
|
||||||
try expect(graph.nodes.filter { $0.shape == .box }.count) == 16
|
|
||||||
}
|
|
||||||
$0.it("generates the expected carthage nodes") {
|
|
||||||
try expect(graph.nodes.filter { $0.label?.contains("[carthage]") ?? false }.count) == 2
|
|
||||||
}
|
|
||||||
$0.it("generates the expected sdk nodes") {
|
|
||||||
try expect(graph.nodes.filter { $0.label?.contains("[sdk]") ?? false }.count) == 1
|
|
||||||
}
|
|
||||||
$0.it("generates the expected Framework nodes") {
|
|
||||||
try expect(graph.nodes.filter { $0.label?.contains("[framework]") ?? false }.count) == 1
|
|
||||||
}
|
|
||||||
$0.it("generates the expected package nodes") {
|
|
||||||
try expect(graph.nodes.filter { $0.label?.contains("[package]") ?? false }.count) == 1
|
|
||||||
}
|
|
||||||
$0.it("generates the expected bundle nodes") {
|
|
||||||
try expect(graph.nodes.filter { $0.label?.contains("[bundle]") ?? false }.count) == 1
|
|
||||||
}
|
|
||||||
$0.it("generates the expected edges") {
|
|
||||||
try expect(graph.edges.count) == 8
|
|
||||||
}
|
|
||||||
$0.it("generates dashed edges") {
|
|
||||||
try expect(graph.edges.filter { $0.style == .dashed }.count) == 8
|
|
||||||
}
|
|
||||||
$0.it("generates the expected output") {
|
|
||||||
let output = GraphVizGenerator().generateModuleGraphViz(targets: targets)
|
|
||||||
try expect(output) == """
|
|
||||||
digraph {
|
|
||||||
MyApp [shape=box]
|
|
||||||
MyInternalFramework [label=MyInternalFramework shape=box]
|
|
||||||
MyApp [shape=box]
|
|
||||||
Resources [label="[bundle]\\nResources" shape=box]
|
|
||||||
MyApp [shape=box]
|
|
||||||
MyStaticFramework [label="[carthage]\\nMyStaticFramework" shape=box]
|
|
||||||
MyApp [shape=box]
|
|
||||||
MyDynamicFramework [label="[carthage]\\nMyDynamicFramework" shape=box]
|
|
||||||
MyApp [shape=box]
|
|
||||||
MyExternalFramework [label="[framework]\\nMyExternalFramework" shape=box]
|
|
||||||
MyApp [shape=box]
|
|
||||||
MyPackage [label="[package]\\nMyPackage" shape=box]
|
|
||||||
MyApp [shape=box]
|
|
||||||
MySDK [label="[sdk]\\nMySDK" shape=box]
|
|
||||||
MyAppUITests [shape=box]
|
|
||||||
MyApp [label=MyApp shape=box]
|
|
||||||
MyApp -> MyInternalFramework [style=dashed]
|
|
||||||
MyApp -> Resources [style=dashed]
|
|
||||||
MyApp -> MyStaticFramework [style=dashed]
|
|
||||||
MyApp -> MyDynamicFramework [style=dashed]
|
|
||||||
MyApp -> MyExternalFramework [style=dashed]
|
|
||||||
MyApp -> MyPackage [style=dashed]
|
|
||||||
MyApp -> MySDK [style=dashed]
|
|
||||||
MyAppUITests -> MyApp [style=dashed]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -479,6 +479,46 @@ class SchemeGeneratorTests: XCTestCase {
|
|||||||
try expect(xcscheme.launchAction?.macroExpansion?.buildableName) == "MyApp.app"
|
try expect(xcscheme.launchAction?.macroExpansion?.buildableName) == "MyApp.app"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$0.it("generates scheme with macroExpansion from tests when the main target is not part of the scheme") {
|
||||||
|
let app = Target(
|
||||||
|
name: "MyApp",
|
||||||
|
type: .application,
|
||||||
|
platform: .iOS,
|
||||||
|
dependencies: []
|
||||||
|
)
|
||||||
|
|
||||||
|
let mockApp = Target(
|
||||||
|
name: "MockApp",
|
||||||
|
type: .application,
|
||||||
|
platform: .iOS,
|
||||||
|
dependencies: []
|
||||||
|
)
|
||||||
|
|
||||||
|
let testBundle = Target(
|
||||||
|
name: "TestBundle",
|
||||||
|
type: .unitTestBundle,
|
||||||
|
platform: .iOS
|
||||||
|
)
|
||||||
|
let appTarget = Scheme.BuildTarget(target: .local(app.name), buildTypes: [.running])
|
||||||
|
let mockAppTarget = Scheme.BuildTarget(target: .local(mockApp.name), buildTypes: [.testing])
|
||||||
|
let testBundleTarget = Scheme.BuildTarget(target: .local(testBundle.name), buildTypes: [.testing])
|
||||||
|
|
||||||
|
let scheme = Scheme(
|
||||||
|
name: "TestScheme",
|
||||||
|
build: Scheme.Build(targets: [appTarget, mockAppTarget, testBundleTarget]),
|
||||||
|
run: Scheme.Run(config: "Debug", macroExpansion: "MyApp")
|
||||||
|
)
|
||||||
|
let project = Project(
|
||||||
|
name: "test",
|
||||||
|
targets: [app, mockApp, testBundle],
|
||||||
|
schemes: [scheme]
|
||||||
|
)
|
||||||
|
let xcodeProject = try project.generateXcodeProject()
|
||||||
|
|
||||||
|
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
|
||||||
|
try expect(xcscheme.testAction?.macroExpansion?.buildableName) == "MockApp.app"
|
||||||
|
}
|
||||||
|
|
||||||
$0.it("generates scheme with test target of local swift package") {
|
$0.it("generates scheme with test target of local swift package") {
|
||||||
let targetScheme = TargetScheme(
|
let targetScheme = TargetScheme(
|
||||||
testTargets: [Scheme.Test.TestTarget(targetReference: TestableTargetReference(name: "XcodeGenKitTests", location: .package("XcodeGen")))])
|
testTargets: [Scheme.Test.TestTarget(targetReference: TestableTargetReference(name: "XcodeGenKitTests", location: .package("XcodeGen")))])
|
||||||
|
Loading…
Reference in New Issue
Block a user