From 0190f277df9afe7cf7511141074b1b9499cedef8 Mon Sep 17 00:00:00 2001 From: Jimmy Arts Date: Thu, 30 May 2024 20:03:25 +0200 Subject: [PATCH] Add support for child configs --- Sourcery/Configuration.swift | 17 ++++++++++++++--- SourceryTests/ConfigurationSpec.swift | 27 +++++++++++++++++++++++++++ SourceryTests/Stub/Configs/parent.yml | 2 ++ guides/Usage.md | 10 ++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 SourceryTests/Stub/Configs/parent.yml 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..5b9b2283d 100644 --- a/SourceryTests/ConfigurationSpec.swift +++ b/SourceryTests/ConfigurationSpec.swift @@ -86,6 +86,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)) + } 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.