diff --git a/Example/Config/RemoteDependencies.json b/Example/Config/RemoteDependencies.json index 29e64aa..bba5446 100644 --- a/Example/Config/RemoteDependencies.json +++ b/Example/Config/RemoteDependencies.json @@ -9,6 +9,16 @@ "name": "RemoteDependencyB", "url": "https://github.com/DependencyB", "version": "2.0.0" + }, + { + "name": "RemoteDependencyC", + "url": "https://github.com/DependencyC", + "revision": "abcde1235kjh" + }, + { + "name": "RemoteDependencyD", + "url": "https://github.com/DependencyC", + "branch": "master" } ] } diff --git a/Example/Packages/Example/Example.json b/Example/Packages/Example/Example.json index fd7ef09..8b6d23f 100755 --- a/Example/Packages/Example/Example.json +++ b/Example/Packages/Example/Example.json @@ -25,6 +25,9 @@ }, { "name": "RemoteDependencyB" + }, + { + "name": "RemoteDependencyC" } ], "targets": [ diff --git a/Example/Packages/Example/Package.swift b/Example/Packages/Example/Package.swift index 4cf7754..a6f61ee 100644 --- a/Example/Packages/Example/Package.swift +++ b/Example/Packages/Example/Package.swift @@ -30,6 +30,10 @@ let package = Package( url: "https://github.com/DependencyB", exact: "2.0.0" ), + .package( + url: "https://github.com/DependencyC", + revision: "abcde1235kjh" + ), ], targets: [ .target( diff --git a/README.md b/README.md index 6a4e946..292caed 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,21 @@ The command `generate-package` requires the following arguments: "name": "ViewInspector", "url": "https://github.com/nalexn/ViewInspector", "version": "0.9.2" + }, + { + "name": "ViewInspector", + "url": "https://github.com/nalexn/ViewInspector", + "version": "0.9.2" + }, + { + "name": "SnapshotTesting", + "url": "https://github.com/pointfreeco/swift-snapshot-testing", + "branch": "master" + }, + { + "name": "Fastlane", + "url": "https://github.com/fastlane/fastlane.git", + "revision": "2c4f29fe161c5998e30000f96d23384fd0eebe90" } ] } @@ -60,6 +75,12 @@ Packages should be contained in respective folders inside a packages folder and "name": "ViewInspector", "version": "1.2.3" }, + { + "name": "Fastlane" + }, + { + "name": "SnapshotTesting" + }, ], "targets": [ { @@ -68,6 +89,9 @@ Packages should be contained in respective folders inside a packages folder and "dependencies": [ { "name": "Alamofire" + }, + { + "name": "Fastlane" } ], "sourcesPath": "Framework/Sources", @@ -83,6 +107,9 @@ Packages should be contained in respective folders inside a packages folder and }, { "name": "ViewInspector" + }, + { + "name": "SnapshotTesting" } ], "sourcesPath": "Tests/Sources", @@ -92,7 +119,7 @@ Packages should be contained in respective folders inside a packages folder and } ``` -> Note that `PackageGenerator` will automatically retrieve `url` & `version` values for `remoteDependencies` from the `RemoteDependencies.json` file. If you need to override those values, you can set them in the package spec. +> Note that `PackageGenerator` will automatically retrieve `url` & ( `version` || `branch` || `revision` ) values for `remoteDependencies` from the `RemoteDependencies.json` file. If you need to override those values, you can set them in the package spec. We provide a default Stencil template that `PackageGenerator` can work with. diff --git a/Sources/Core/SpecGenerator.swift b/Sources/Core/SpecGenerator.swift index c447be0..ee1f21d 100644 --- a/Sources/Core/SpecGenerator.swift +++ b/Sources/Core/SpecGenerator.swift @@ -45,7 +45,9 @@ final class SpecGenerator { guard let dependency = dependencies.first(where: { $0.name == remoteDependency.name }) else { return nil } return RemoteDependency(name: dependency.name, url: remoteDependency.url ?? dependency.url, - version: remoteDependency.version ?? dependency.version) + version: remoteDependency.version ?? dependency.version, + revision: remoteDependency.revision ?? dependency.revision, + branch: remoteDependency.branch ?? dependency.branch) } return Spec(name: partialSpec.name, diff --git a/Sources/Models/Dependencies.swift b/Sources/Models/Dependencies.swift index a3b0c17..0473750 100644 --- a/Sources/Models/Dependencies.swift +++ b/Sources/Models/Dependencies.swift @@ -9,5 +9,19 @@ struct Dependencies: Decodable { struct Dependency: Decodable { let name: String let url: String - let version: String + let version: String? + let revision: String? + let branch: String? + + init(name: String, url: String, version: String?, revision: String?, branch: String?) { + guard version != nil || revision != nil || branch != nil else { + fatalError("You need to provide at least one of the following: version, revision or branch") + } + + self.name = name + self.url = url + self.version = version + self.revision = revision + self.branch = branch + } } diff --git a/Sources/Models/Spec.swift b/Sources/Models/Spec.swift index e48a6d4..63529d2 100644 --- a/Sources/Models/Spec.swift +++ b/Sources/Models/Spec.swift @@ -83,11 +83,15 @@ struct RemoteDependency: Decodable { let name: String let url: String? let version: String? - + let revision: String? + let branch: String? + enum CodingKeys: CodingKey { case name case url case version + case revision + case branch } init(from decoder: Decoder) throws { @@ -95,12 +99,20 @@ struct RemoteDependency: Decodable { self.name = try container.decode(String.self, forKey: .name) self.url = try container.decodeIfPresent(String.self, forKey: .url) self.version = try container.decodeIfPresent(String.self, forKey: .version) + self.revision = try container.decodeIfPresent(String.self, forKey: .revision) + self.branch = try container.decodeIfPresent(String.self, forKey: .branch) } - init(name: String, url: String, version: String) { + init(name: String, url: String, version: String?, revision: String?, branch: String?) { + guard version != nil || revision != nil || branch != nil else { + fatalError("You need to provide at least one of the following: version, revision or branch") + } + self.name = name self.url = url self.version = version + self.revision = revision + self.branch = branch } } diff --git a/Templates/Package.stencil b/Templates/Package.stencil index ddb37bf..07fe179 100644 --- a/Templates/Package.stencil +++ b/Templates/Package.stencil @@ -95,7 +95,13 @@ let package = Package( {% for remote_dependency in remote_dependencies %} .package( url: "{{ remote_dependency.url }}", + {% if remote_dependency.version %} exact: "{{ remote_dependency.version }}" + {% elif remote_dependency.revision %} + revision: "{{ remote_dependency.revision }}" + {% elif remote_dependency.branch %} + branch: "{{ remote_dependency.branch }}" + {% endif %} ), {% endfor %} ], diff --git a/Tests/PackageGeneratorTests.swift b/Tests/PackageGeneratorTests.swift index 15df8cf..62efdf9 100644 --- a/Tests/PackageGeneratorTests.swift +++ b/Tests/PackageGeneratorTests.swift @@ -6,6 +6,8 @@ import XCTest final class PackageGeneratorTests: XCTestCase { enum PackageType: String { + case revisionProduct = "RevisionProduct" + case branchProduct = "BranchProduct" case singleProduct = "SingleProduct" case multipleProducts = "MultipleProducts" case customPlatforms = "CustomPlatforms" @@ -14,23 +16,31 @@ final class PackageGeneratorTests: XCTestCase { case executableProduct = "ExecutableProduct" case plugins = "PluginProduct" } - + let resourcesFolder = URL(fileURLWithPath: #file) .deletingLastPathComponent() .appendingPathComponent("Resources") - + lazy var packagesFolderUrl = resourcesFolder.appendingPathComponent("Packages") lazy var dependenciesUrl = resourcesFolder.appendingPathComponent("TestRemoteDependencies.json") lazy var templatePath = resourcesFolder.appendingPathComponent("Package.stencil") - + func test_SingleProduct() throws { try assertPackage(for: .singleProduct) } - + + func test_RevisionProduct() throws { + try assertPackage(for: .revisionProduct) + } + + func test_BranchProduct() throws { + try assertPackage(for: .branchProduct) + } + func test_MultipleProducts() throws { try assertPackage(for: .multipleProducts) } - + func test_customPlatforms() throws { try assertPackage(for: .customPlatforms) } @@ -50,20 +60,20 @@ final class PackageGeneratorTests: XCTestCase { func test_pluginProduct() throws { try assertPackage(for: .plugins) } - + private func assertPackage(for packageType: PackageType) throws { let packageSpecUrl = resourcesFolder .appendingPathComponent("Packages") .appendingPathComponent(packageType.rawValue) .appendingPathComponent(packageType.rawValue) .appendingPathExtension("json") - + let packageUrl = resourcesFolder .appendingPathComponent("Packages") .appendingPathComponent(packageType.rawValue) .appendingPathComponent("\(packageType.rawValue)Package") .appendingPathExtension("swift") - + let specGenerator = SpecGenerator(dependenciesUrl: dependenciesUrl, packagesFolder: packagesFolderUrl) let spec = try specGenerator.makeSpec(for: packageType.rawValue, specUrl: packageSpecUrl) let templater = Templater(templatePath: templatePath.absoluteString) diff --git a/Tests/Resources/Package.stencil b/Tests/Resources/Package.stencil index ddb37bf..07fe179 100644 --- a/Tests/Resources/Package.stencil +++ b/Tests/Resources/Package.stencil @@ -95,7 +95,13 @@ let package = Package( {% for remote_dependency in remote_dependencies %} .package( url: "{{ remote_dependency.url }}", + {% if remote_dependency.version %} exact: "{{ remote_dependency.version }}" + {% elif remote_dependency.revision %} + revision: "{{ remote_dependency.revision }}" + {% elif remote_dependency.branch %} + branch: "{{ remote_dependency.branch }}" + {% endif %} ), {% endfor %} ], diff --git a/Tests/Resources/Packages/BranchProduct/BranchProduct.json b/Tests/Resources/Packages/BranchProduct/BranchProduct.json new file mode 100755 index 0000000..22f5e56 --- /dev/null +++ b/Tests/Resources/Packages/BranchProduct/BranchProduct.json @@ -0,0 +1,66 @@ +{ + "name": "BranchProduct", + "products": [ + { + "name": "BranchProduct", + "productType": "library", + "targets": [ + "TargetA" + ] + } + ], + "localDependencies": [ + { + "name": "LocalDependencyA", + "path": "../LocalDependencies" + } + ], + "remoteDependencies": [ + { + "name": "RemoteDependencyA" + }, + { + "name": "RemoteDependencyB" + }, + { + "name": "RemoteDependencyD" + } + ], + "targets": [ + { + "name": "TargetA", + "targetType": "target", + "dependencies": [ + { + "name": "LocalDependencyA" + }, + { + "name": "RemoteDependencyA" + }, + { + "name": "RemoteDependencyB" + }, + { + "name": "RemoteDependencyD" + } + ], + "sourcesPath": "Framework/Sources", + "resourcesPath": "Resources" + }, + { + "name": "TargetATests", + "targetType": "testTarget", + "dependencies": [ + { + "name": "TargetA", + "isTarget": true + }, + { + "name": "RemoteDependencyB" + } + ], + "sourcesPath": "Tests/Sources", + "resourcesPath": "Resources" + } + ] +} \ No newline at end of file diff --git a/Tests/Resources/Packages/BranchProduct/BranchProductPackage.swift b/Tests/Resources/Packages/BranchProduct/BranchProductPackage.swift new file mode 100644 index 0000000..32d5683 --- /dev/null +++ b/Tests/Resources/Packages/BranchProduct/BranchProductPackage.swift @@ -0,0 +1,65 @@ +// swift-tools-version: 5.7 + +// This file was automatically generated by PackageGenerator and untracked +// PLEASE DO NOT EDIT MANUALLY + +import PackageDescription + +let package = Package( + name: "BranchProduct", + defaultLocalization: "en", + platforms: [.iOS(.v15)], + products: [ + .library( + name: "BranchProduct", + targets: ["TargetA"] + ), + ], + dependencies: [ + .package( + path: "../LocalDependencies" + ), + .package( + url: "https://github.com/DependencyA", + exact: "1.0.0" + ), + .package( + url: "https://github.com/DependencyB", + exact: "2.0.0" + ), + .package( + url: "https://github.com/DependencyD", + branch: "master" + ), + ], + targets: [ + .target( + name: "TargetA", + dependencies: [ + .product(name: "LocalDependencyA", package: "LocalDependencyA"), + .product(name: "RemoteDependencyA", package: "RemoteDependencyA"), + .product(name: "RemoteDependencyB", package: "RemoteDependencyB"), + .product(name: "RemoteDependencyD", package: "RemoteDependencyD"), + ], + path: "Framework/Sources", + resources: [ + .process("Resources") + ], + plugins: [ + ] + ), + .testTarget( + name: "TargetATests", + dependencies: [ + .byName(name: "TargetA"), + .product(name: "RemoteDependencyB", package: "RemoteDependencyB"), + ], + path: "Tests/Sources", + resources: [ + .process("Resources") + ], + plugins: [ + ] + ), + ] +) \ No newline at end of file diff --git a/Tests/Resources/Packages/RevisionProduct/RevisionProduct.json b/Tests/Resources/Packages/RevisionProduct/RevisionProduct.json new file mode 100755 index 0000000..d433e9c --- /dev/null +++ b/Tests/Resources/Packages/RevisionProduct/RevisionProduct.json @@ -0,0 +1,66 @@ +{ + "name": "RevisionProduct", + "products": [ + { + "name": "RevisionProduct", + "productType": "library", + "targets": [ + "TargetA" + ] + } + ], + "localDependencies": [ + { + "name": "LocalDependencyA", + "path": "../LocalDependencies" + } + ], + "remoteDependencies": [ + { + "name": "RemoteDependencyA" + }, + { + "name": "RemoteDependencyB" + }, + { + "name": "RemoteDependencyC" + } + ], + "targets": [ + { + "name": "TargetA", + "targetType": "target", + "dependencies": [ + { + "name": "LocalDependencyA" + }, + { + "name": "RemoteDependencyA" + }, + { + "name": "RemoteDependencyB" + }, + { + "name": "RemoteDependencyC" + } + ], + "sourcesPath": "Framework/Sources", + "resourcesPath": "Resources" + }, + { + "name": "TargetATests", + "targetType": "testTarget", + "dependencies": [ + { + "name": "TargetA", + "isTarget": true + }, + { + "name": "RemoteDependencyB" + } + ], + "sourcesPath": "Tests/Sources", + "resourcesPath": "Resources" + } + ] +} \ No newline at end of file diff --git a/Tests/Resources/Packages/RevisionProduct/RevisionProductPackage.swift b/Tests/Resources/Packages/RevisionProduct/RevisionProductPackage.swift new file mode 100644 index 0000000..667e477 --- /dev/null +++ b/Tests/Resources/Packages/RevisionProduct/RevisionProductPackage.swift @@ -0,0 +1,65 @@ +// swift-tools-version: 5.7 + +// This file was automatically generated by PackageGenerator and untracked +// PLEASE DO NOT EDIT MANUALLY + +import PackageDescription + +let package = Package( + name: "RevisionProduct", + defaultLocalization: "en", + platforms: [.iOS(.v15)], + products: [ + .library( + name: "RevisionProduct", + targets: ["TargetA"] + ), + ], + dependencies: [ + .package( + path: "../LocalDependencies" + ), + .package( + url: "https://github.com/DependencyA", + exact: "1.0.0" + ), + .package( + url: "https://github.com/DependencyB", + exact: "2.0.0" + ), + .package( + url: "https://github.com/DependencyC", + revision: "abcde1235kjh" + ), + ], + targets: [ + .target( + name: "TargetA", + dependencies: [ + .product(name: "LocalDependencyA", package: "LocalDependencyA"), + .product(name: "RemoteDependencyA", package: "RemoteDependencyA"), + .product(name: "RemoteDependencyB", package: "RemoteDependencyB"), + .product(name: "RemoteDependencyC", package: "RemoteDependencyC"), + ], + path: "Framework/Sources", + resources: [ + .process("Resources") + ], + plugins: [ + ] + ), + .testTarget( + name: "TargetATests", + dependencies: [ + .byName(name: "TargetA"), + .product(name: "RemoteDependencyB", package: "RemoteDependencyB"), + ], + path: "Tests/Sources", + resources: [ + .process("Resources") + ], + plugins: [ + ] + ), + ] +) \ No newline at end of file diff --git a/Tests/Resources/TestRemoteDependencies.json b/Tests/Resources/TestRemoteDependencies.json index 29e64aa..ca2fe81 100644 --- a/Tests/Resources/TestRemoteDependencies.json +++ b/Tests/Resources/TestRemoteDependencies.json @@ -9,6 +9,16 @@ "name": "RemoteDependencyB", "url": "https://github.com/DependencyB", "version": "2.0.0" + }, + { + "name": "RemoteDependencyC", + "url": "https://github.com/DependencyC", + "revision": "abcde1235kjh" + }, + { + "name": "RemoteDependencyD", + "url": "https://github.com/DependencyD", + "branch": "master" } ] }