From 402a79ba160f32db5d1c775ef61e41983990d1e6 Mon Sep 17 00:00:00 2001 From: Jimmy Arts Date: Thu, 24 Oct 2024 13:20:12 +0200 Subject: [PATCH] Add support for child configs (#1338) --- Package.resolved | 6 +++--- Sourcery/Configuration.swift | 17 ++++++++++++--- SourceryTests/ConfigurationSpec.swift | 30 ++++++++++++++++++++++++++- SourceryTests/Stub/Configs/parent.yml | 2 ++ guides/Usage.md | 10 +++++++++ 5 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 SourceryTests/Stub/Configs/parent.yml diff --git a/Package.resolved b/Package.resolved index 82a6d74b4..d30a23b5c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -165,10 +165,10 @@ { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", + "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "08a2f0a9a30e0f705f79c9cfaca1f68b71bdc775", - "version" : "510.0.0" + "revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82", + "version" : "510.0.3" } }, { diff --git a/Sourcery/Configuration.swift b/Sourcery/Configuration.swift index a8da66fc9..fcc35004d 100644 --- a/Sourcery/Configuration.swift +++ b/Sourcery/Configuration.swift @@ -183,7 +183,7 @@ public struct Package { }) semaphore.wait() - guard let manifest = try manifestResult?.get() else{ + guard let manifest = try manifestResult?.get() else { throw Configuration.Error.invalidSources(message: "Unable to load manifest") } self.root = path @@ -227,6 +227,8 @@ public enum Source { } else if let packages = (dict["package"] as? [[String: Any]]) ?? (dict["package"] as? [String: Any]).map({ [$0] }) { guard !packages.isEmpty else { throw Configuration.Error.invalidSources(message: "No packages provided.") } self = try .packages(packages.map({ try Package(dict: $0, relativePath: relativePath) })) + } else if dict["child"] != nil { + throw Configuration.Error.internalError(message: "'child' should have been parsed already.") } else { throw Configuration.Error.invalidSources(message: "'sources', 'project' or 'package' key are missing.") } @@ -315,6 +317,7 @@ public struct Configuration { case invalidOutput(message: String) case invalidCacheBasePath(message: String) case invalidPaths(message: String) + case internalError(message: String) public var description: String { switch self { @@ -332,6 +335,8 @@ public struct Configuration { return "Invalid cacheBasePath. \(message)" case .invalidPaths(let message): return "\(message)" + case .internalError(let message): + return "\(message)" } } } @@ -431,8 +436,14 @@ public enum Configurations { } if let configurations = dict["configurations"] as? [[String: Any]] { - return try configurations.map { dict in - try Configuration(dict: dict, relativePath: relativePath) + return try configurations.flatMap { dict in + if let child = dict["child"] as? String { + let childPath = Path(child, relativeTo: relativePath) + let childRelativePath = Path(components: childPath.components.dropLast()) + return try Configurations.make(path: childPath, relativePath: childRelativePath, env: env) + } else { + return try [Configuration(dict: dict, relativePath: relativePath)] + } } } else { return try [Configuration(dict: dict, relativePath: relativePath)] diff --git a/SourceryTests/ConfigurationSpec.swift b/SourceryTests/ConfigurationSpec.swift index 0d1b8e5ab..9d5fdd771 100644 --- a/SourceryTests/ConfigurationSpec.swift +++ b/SourceryTests/ConfigurationSpec.swift @@ -15,7 +15,8 @@ class ConfigurationSpec: QuickSpec { describe("Configuration") { let serverUrlArg = "serverUrl" let serverUrl: String = "www.example.com" - let env = ["SOURCE_PATH": "Sources", + let sourcePath = "Sources" + let env = ["SOURCE_PATH": sourcePath, serverUrlArg: serverUrl] context("given valid config file with env placeholders") { @@ -86,6 +87,33 @@ class ConfigurationSpec: QuickSpec { } } + context("given config file with child configurations") { + it("resolves each child configuration") { + do { + let configs = try Configurations.make( + path: Stubs.configs + "parent.yml", + relativePath: Stubs.configs, + env: env + ) + + expect(configs.count).to(equal(1)) + + guard case let Source.sources(paths) = configs[0].source, + let path = paths.include.first else { + fail("Config has no Source Paths") + return + } + + let configServerUrl = configs[0].args[serverUrlArg] as? String + + expect(configServerUrl).to(equal(serverUrl)) + expect(path).to(equal(Stubs.configs + sourcePath)) + } catch { + expect("\(error)").to(equal("Invalid config file format. Expected dictionary.")) + } + } + } + context("given invalid config file") { func configError(_ config: [String: Any]) -> String { diff --git a/SourceryTests/Stub/Configs/parent.yml b/SourceryTests/Stub/Configs/parent.yml new file mode 100644 index 000000000..8aeda652c --- /dev/null +++ b/SourceryTests/Stub/Configs/parent.yml @@ -0,0 +1,2 @@ +configurations: + - child: valid.yml diff --git a/guides/Usage.md b/guides/Usage.md index 68000f17a..2bb6aa921 100644 --- a/guides/Usage.md +++ b/guides/Usage.md @@ -78,6 +78,16 @@ configurations: This will be equivalent to running Sourcery separately for each of the configurations. In watch mode Sourcery will observe changes in the paths from all the configurations. +#### Child configurations + +You can specify a child configurations by using the `child` key: +```yaml +configurations: + - child: ./.child_config.yml + - child: Subdirectory/.another_child_config.yml +``` +Sources will be resolved relative to the child config paths. + #### Sources You can provide sources using paths to directories or specific files.