diff --git a/CHANGELOG.md b/CHANGELOG.md index be786e3de4..11b1440056 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -693,7 +693,12 @@ or other error. [Martin Redington](https://github.com/mildm8nnered) [#6052](https://github.com/realm/SwiftLint/issues/6052) - + +* Fall back to default configuration when a nested `.swiftlint.yml` cannot be parsed + instead of aborting (e.g. duplicate YAML keys in a subdirectory). + [leno23](https://github.com/leno23) + [#6052](https://github.com/realm/SwiftLint/issues/6052) + * Keep the default severity levels when neither `warning` nor `error` values are configured. Ensure especially that the `error` level is not set to `nil` when the `warning` level isn't set either. diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 86e0190b34..3439ef82e4 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -122,6 +122,8 @@ public enum Issue: LocalizedError, Equatable { return "error: \(message)" case .genericWarning: return "warning: \(message)" + case .yamlParsing: + return "warning: \(message)" default: return Self.genericWarning(message).errorDescription } diff --git a/Source/SwiftLintFramework/Configuration/Configuration+Merging.swift b/Source/SwiftLintFramework/Configuration/Configuration+Merging.swift index 1546e3dbdf..85d15b5cd1 100644 --- a/Source/SwiftLintFramework/Configuration/Configuration+Merging.swift +++ b/Source/SwiftLintFramework/Configuration/Configuration+Merging.swift @@ -116,7 +116,8 @@ extension Configuration { // Ignore parent_config / child_config specifications of nested configs var childConfiguration = Configuration( configurationFiles: [configurationSearchPath], - ignoreParentAndChildConfigs: true + ignoreParentAndChildConfigs: true, + useDefaultConfigOnFailure: true ) childConfiguration.fileGraph = FileGraph(rootDirectory: directory) config = merged(withChild: childConfiguration, rootDirectory: rootDirectory) diff --git a/Tests/FileSystemAccessTests/ConfigurationTests+Mock.swift b/Tests/FileSystemAccessTests/ConfigurationTests+Mock.swift index e4a7fc5e15..3fb1016d7f 100644 --- a/Tests/FileSystemAccessTests/ConfigurationTests+Mock.swift +++ b/Tests/FileSystemAccessTests/ConfigurationTests+Mock.swift @@ -33,6 +33,7 @@ internal extension ConfigurationTests { static var remoteConfigLocalRef: String { level0.stringByAppendingPathComponent("RemoteConfig/LocalRef") } static var remoteConfigCycle: String { level0.stringByAppendingPathComponent("RemoteConfig/Cycle") } static var emptyFolder: String { level0.stringByAppendingPathComponent("EmptyFolder") } + static var duplicateYamlKeys: String { level0.stringByAppendingPathComponent("DuplicateYamlKeys") } static var exclusionTests: String { testResourcesPath.stringByAppendingPathComponent("ExclusionTests") } static var directory: String { exclusionTests.stringByAppendingPathComponent("directory") } @@ -65,6 +66,9 @@ internal extension ConfigurationTests { static var _2: String { Dir.level2.stringByAppendingPathComponent("Level2.swift") } static var _3: String { Dir.level3.stringByAppendingPathComponent("Level3.swift") } static var nestedSub: String { Dir.nestedSub.stringByAppendingPathComponent("Sub.swift") } + static var duplicateYamlKeysSub: String { + Dir.duplicateYamlKeys.stringByAppendingPathComponent("subdir/a.swift") + } } // MARK: Configurations diff --git a/Tests/FileSystemAccessTests/ConfigurationTests+MultipleConfigs.swift b/Tests/FileSystemAccessTests/ConfigurationTests+MultipleConfigs.swift index 937647187b..b308907bc3 100644 --- a/Tests/FileSystemAccessTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/FileSystemAccessTests/ConfigurationTests+MultipleConfigs.swift @@ -234,6 +234,18 @@ extension ConfigurationTests { ) } + func testNestedConfigurationWithInvalidYamlFallsBackToDefault() async throws { + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.duplicateYamlKeys)) + + let console = try await Issue.captureConsole { + let config = Configuration(configurationFiles: []) + _ = config.configuration(for: SwiftLintFile(path: Mock.Swift.duplicateYamlKeysSub)!) + } + + XCTAssertTrue(console.contains("Cannot parse YAML file")) + XCTAssertTrue(console.contains("Falling back to default configuration")) + } + func testNestedConfigurationForOnePathPassedIn() { // If a path to one or more configuration files is specified, nested configurations should be ignored let config = Configuration(configurationFiles: [Mock.Yml._0]) diff --git a/Tests/FileSystemAccessTests/Resources/ProjectMock/DuplicateYamlKeys/subdir/.swiftlint.yml b/Tests/FileSystemAccessTests/Resources/ProjectMock/DuplicateYamlKeys/subdir/.swiftlint.yml new file mode 100644 index 0000000000..852efc753f --- /dev/null +++ b/Tests/FileSystemAccessTests/Resources/ProjectMock/DuplicateYamlKeys/subdir/.swiftlint.yml @@ -0,0 +1,5 @@ +opt_in_rules: + - closure_body_length + +opt_in_rules: + - closure_body_length diff --git a/Tests/FileSystemAccessTests/Resources/ProjectMock/DuplicateYamlKeys/subdir/a.swift b/Tests/FileSystemAccessTests/Resources/ProjectMock/DuplicateYamlKeys/subdir/a.swift new file mode 100644 index 0000000000..c455ccf147 --- /dev/null +++ b/Tests/FileSystemAccessTests/Resources/ProjectMock/DuplicateYamlKeys/subdir/a.swift @@ -0,0 +1 @@ +// Test file for nested configuration with invalid YAML.