Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
[Hokila](https://github.com/Hokila)
[#6897](https://github.com/realm/SwiftLint/issues/6897)

* Fix `excluded` configuration being ignored when file paths matching a non-wildcard
exclusion pattern are passed as arguments.
[Tomotaka Takahashi](https://github.com/tomotakatakahashi)
[#6795](https://github.com/realm/SwiftLint/issues/6795)

## 0.65.1: Fresh Folded Fixtures

### Breaking
Expand Down
4 changes: 1 addition & 3 deletions Source/SwiftLintFramework/Configuration+CommandLine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,9 @@ extension Configuration {

return files.parallelFilterGroup { file in
let fileConfiguration = configuration(for: file)
let fileConfigurationRootPath = fileConfiguration.rootDirectory

// Files whose configuration specifies they should be excluded will be skipped
let shouldSkip = fileConfiguration.excludedPaths.contains { excludedRelativePath in
let excludedPath = fileConfigurationRootPath.appending(path: excludedRelativePath.relativePath)
let shouldSkip = fileConfiguration.excludedPaths.contains { excludedPath in
let filePathComponents = file.path?.pathComponents ?? []
let excludedPathComponents = excludedPath.pathComponents
return filePathComponents.starts(with: excludedPathComponents)
Expand Down
106 changes: 103 additions & 3 deletions Tests/IntegrationTests/ConfigPathResolutionTests.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Foundation
import SourceKittenFramework
import SwiftLintFramework
import TestHelpers
import Testing

@testable import SwiftLintCore
@testable import SwiftLintFramework

@Suite(.rulesRegistered)
struct ConfigPathResolutionTests {
Expand All @@ -26,11 +26,34 @@ struct ConfigPathResolutionTests {
excludeByPrefix: false
)

// swiftlint:disable:next force_try
return files.map { $0.path!.path.replacing(try! Regex(".+/\(scenario)/"), with: "") }.sorted()
return relativePaths(of: files, in: scenario)
}
}

/// Returns the paths of the files that are actually linted when the given paths are passed as command line
/// arguments, relative to the fixture directory.
private func visitedLintableFilePaths(in scenario: String, paths: [String]) async throws -> [String] {
let scenarioPath = fixturePath(scenario)
return try await CurrentWorkingDirectory.$url.withValue(scenarioPath) {
let config = Configuration(configurationFiles: [])
let files = try await config.visitLintableFiles(
// Lint files in the current working directory if no paths were specified, just like the command does.
options: .lint(paths: paths.isEmpty ? [URL.cwd] : paths.map { $0.url() }),
storage: RuleStorage(),
visitorBlock: { _ in
// Only the set of visited files matters, not the violations found in them.
}
)

return relativePaths(of: files, in: scenario)
}
}

private func relativePaths(of files: [SwiftLintFile], in scenario: String) -> [String] {
// swiftlint:disable:next force_try
files.map { $0.path!.path.replacing(try! Regex(".+/\(scenario)/"), with: "") }.sorted()
}

@Test
func parentChildSameDirectory() {
#expect(
Expand Down Expand Up @@ -75,6 +98,23 @@ struct ConfigPathResolutionTests {
)
}

@Test
func nestedConfigurationBasicWithCommandLine() async throws {
// `swiftlint --quiet --no-cache ModuleA/File.swift ModuleA/Generated/File.swift ModuleB/File.swift`
#expect(
try await visitedLintableFilePaths(
in: "_4_nested_basic",
paths: ["ModuleA/File.swift", "ModuleA/Generated/File.swift", "ModuleB/File.swift"]
) == ["ModuleA/File.swift", "ModuleB/File.swift"]
)

// `swiftlint --quiet --no-cache`
#expect(
try await visitedLintableFilePaths(in: "_4_nested_basic", paths: [])
== ["ModuleA/File.swift", "ModuleB/File.swift"]
)
}

@Test
func wildcardPatternCount() {
#expect(
Expand All @@ -86,6 +126,28 @@ struct ConfigPathResolutionTests {
)
}

@Test
func wildCardPatternCountWithCommandLine() async throws {
// `swiftlint --quiet --no-cache Sources/Models/User.swift Sources/Models/User.generated.swift`
let visitedWithPaths = try await visitedLintableFilePaths(
in: "_5_wildcard_patterns",
paths: ["project/Sources/Models/User.swift", "project/Sources/Models/User.generated.swift"]
)
withKnownIssue("Wildcard patterns do not work as expected.") {
#expect(
visitedWithPaths == ["project/Sources/Models/User.swift"]
)
}

// `swiftlint --quiet --no-cache`
let visitedWithoutPaths = try await visitedLintableFilePaths(in: "_5_wildcard_patterns", paths: [])
withKnownIssue("Wildcard patterns do not work as expected.") {
#expect(
visitedWithoutPaths == ["project/Sources/Models/User.swift"]
)
}
}

@Test
func lintChildFolder() {
#expect(
Expand Down Expand Up @@ -229,3 +291,41 @@ struct ConfigPathResolutionTests {
}
#endif
}

private extension LintOrAnalyzeOptions {
/// Options equivalent to running `swiftlint lint --quiet --no-cache <paths>`.
static func lint(paths: [URL]) -> Self {
Self(
mode: .lint,
paths: paths,
useSTDIN: false,
configurationFiles: [],
strict: false,
lenient: false,
forceExclude: false,
useExcludingByPrefix: false,
useScriptInputFiles: false,
useScriptInputFileLists: false,
benchmark: false,
reporter: nil,
baseline: nil,
writeBaseline: nil,
workingDirectory: nil,
// Avoid verbose stderr.
quiet: true,
output: nil,
progress: false,
cachePath: nil,
// `visitedLintableFilePaths` does not pass `LinterCache`.
ignoreCache: true,
enableAllRules: false,
onlyRule: [],
autocorrect: false,
format: false,
disableSourceKit: false,
compilerLogPath: nil,
compileCommands: nil,
checkForUpdates: false
)
}
}
Loading