-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add syntax to swiftlint_version to allow for specifying minimum and maximum versions #5694
Open
alex-taffe
wants to merge
2
commits into
realm:main
Choose a base branch
from
alex-taffe:minimum-version
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
// swiftlint:disable file_length | ||
// Everything in this file makes sense to be in this file | ||
|
||
import Foundation | ||
import SourceKittenFramework | ||
|
||
|
@@ -124,7 +127,7 @@ public struct Configuration { | |
|
||
/// Creates a `Configuration` by specifying its properties directly, | ||
/// except that rules are still to be synthesized from rulesMode, ruleList & allRulesWrapped | ||
/// and a check against the pinnedVersion is performed if given. | ||
/// and a check against the version in use is performed if a constraint is configured. | ||
/// | ||
/// - parameter rulesMode: The `RulesMode` for this configuration. | ||
/// - parameter allRulesWrapped: The rules with their own configurations already applied. | ||
|
@@ -139,7 +142,7 @@ public struct Configuration { | |
/// lint as having failed. | ||
/// - parameter reporter: The identifier for the `Reporter` to use to report style violations. | ||
/// - parameter cachePath: The location of the persisted cache to use with this configuration. | ||
/// - parameter pinnedVersion: The SwiftLint version defined in this configuration. | ||
/// - parameter versionConstraint: The SwiftLint version constraint defined in this configuration. | ||
/// - parameter allowZeroLintableFiles: Allow SwiftLint to exit successfully when passed ignored or unlintable | ||
/// files. | ||
/// - parameter strict: Treat warnings as errors. | ||
|
@@ -157,19 +160,15 @@ public struct Configuration { | |
warningThreshold: Int? = nil, | ||
reporter: String? = nil, | ||
cachePath: String? = nil, | ||
pinnedVersion: String? = nil, | ||
versionConstraint: String? = nil, | ||
allowZeroLintableFiles: Bool = false, | ||
strict: Bool = false, | ||
baseline: String? = nil, | ||
writeBaseline: String? = nil, | ||
checkForUpdates: Bool = false | ||
) { | ||
if let pinnedVersion, pinnedVersion != Version.current.value { | ||
queuedPrintError( | ||
"warning: Currently running SwiftLint \(Version.current.value) but " + | ||
"configuration specified version \(pinnedVersion)." | ||
) | ||
exit(2) | ||
if let versionConstraint { | ||
Self.compareVersion(to: versionConstraint) | ||
} | ||
|
||
self.init( | ||
|
@@ -286,6 +285,96 @@ public struct Configuration { | |
$0.bridge().absolutePathRepresentation(rootDirectory: previousBasePath).path(relativeTo: newBasePath) | ||
} | ||
} | ||
|
||
/// Compares a supplied version to the version SwiftLint is currently running with. If the version does not match, | ||
/// or the version syntax is invalid, the method will abort execution with an error. The syntax for valid version | ||
/// strings is as follows: | ||
/// | ||
/// * `0.54.0` | ||
/// * `>0.54.0` | ||
/// * `>=0.54.0` | ||
/// * `<0.54.0` | ||
/// * `<=0.54.0` | ||
/// | ||
/// - Parameter configurationVersion: The configuration version to compare against. | ||
static func checkVersion(against versionConstraint: String) { // swiftlint:disable:this function_body_length | ||
func showInvalidVersionStringError() -> Never { | ||
let invalidVersionString = """ | ||
error: swiftlint_version syntax invalid. | ||
Please specify a version as follows: | ||
0.54.0 | ||
>0.54.0 | ||
>=0.54.0 | ||
<0.54.0 | ||
<=0.54.0 | ||
""" | ||
|
||
queuedFatalError(invalidVersionString) | ||
} | ||
|
||
func compareVersionString(_ versionString: String) { | ||
var versionString = versionString | ||
let comparator: (Version, Version) -> Bool | ||
let errorDifferentiatorString: String | ||
|
||
if versionString.starts(with: ">=") { | ||
SimplyDanny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
comparator = (>=) | ||
versionString = String(versionString.dropFirst(2)) | ||
errorDifferentiatorString = "at least" | ||
} else if versionString.starts(with: ">") { | ||
comparator = (>) | ||
versionString = String(versionString.dropFirst(1)) | ||
errorDifferentiatorString = "greater than" | ||
} else if versionString.starts(with: "<=") { | ||
comparator = (<=) | ||
versionString = String(versionString.dropFirst(2)) | ||
errorDifferentiatorString = "at most" | ||
} else if versionString.starts(with: "<") { | ||
comparator = (<) | ||
versionString = String(versionString.dropFirst(1)) | ||
errorDifferentiatorString = "less than" | ||
} else { | ||
comparator = (==) | ||
errorDifferentiatorString = "exactly" | ||
} | ||
|
||
// make sure the remaining string is just a version string of numeral.numeral.numeral | ||
versionString = versionString.trimmingCharacters(in: .whitespacesAndNewlines) | ||
guard versionString.range(of: #"^\d+\.\d+\.\d+$"#, options: .regularExpression) != nil else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feels like the |
||
showInvalidVersionStringError() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be more specific for the error case of an invalid version number format. |
||
} | ||
|
||
let configVersion = Version(value: versionString) | ||
|
||
if !comparator(Version.current, configVersion) { | ||
queuedPrintError( | ||
""" | ||
warning: Currently running SwiftLint \(Version.current.value) but \ | ||
configuration specified \(errorDifferentiatorString) \(versionString). | ||
""" | ||
) | ||
exit(2) | ||
} | ||
} | ||
|
||
let splitVersion = versionConstraint | ||
.trimmingCharacters(in: .whitespacesAndNewlines) | ||
.components(separatedBy: .whitespaces) | ||
|
||
if splitVersion.count == 2 { | ||
// Assume the user put a space in between the operator and the version | ||
let `operator` = splitVersion[0] | ||
let version = splitVersion[1] | ||
compareVersionString(`operator` + version) | ||
} else if splitVersion.count == 1 { | ||
// Assume we're going for a discrete version or gt/gte/lt/lte scenario | ||
let versionString = splitVersion[0] | ||
compareVersionString(versionString) | ||
} else { | ||
// The user typed in too much | ||
showInvalidVersionStringError() | ||
} | ||
} | ||
} | ||
|
||
// MARK: - Hashable | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if "version constraint" should be a struct that implements the comparison logic. At least this struct can be tested then.