mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:48 +00:00
Add --required-version
(#1376)
This commit is contained in:
parent
19121219fb
commit
8b72f55a09
15 changed files with 183 additions and 17 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -1902,6 +1902,7 @@ dependencies = [
|
||||||
"rustpython-common",
|
"rustpython-common",
|
||||||
"rustpython-parser",
|
"rustpython-parser",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
|
@ -2122,9 +2123,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.14"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
|
|
|
@ -50,6 +50,7 @@ rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/
|
||||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" }
|
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" }
|
||||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" }
|
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "1b6cb170e925a43d605b3fed9f6b878e63e47744" }
|
||||||
schemars = { version = "0.8.11" }
|
schemars = { version = "0.8.11" }
|
||||||
|
semver = { version = "1.0.16" }
|
||||||
serde = { version = "1.0.147", features = ["derive"] }
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.87" }
|
serde_json = { version = "1.0.87" }
|
||||||
shellexpand = { version = "3.0.0" }
|
shellexpand = { version = "3.0.0" }
|
||||||
|
|
19
README.md
19
README.md
|
@ -1965,6 +1965,25 @@ when considering any matching files.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### [`required-version`](#required-version)
|
||||||
|
|
||||||
|
Require a specific version of Ruff to be running (useful for unifying
|
||||||
|
results across many environments, e.g., with a `pyproject.toml`
|
||||||
|
file).
|
||||||
|
|
||||||
|
**Default value**: `None`
|
||||||
|
|
||||||
|
**Type**: `String`
|
||||||
|
|
||||||
|
**Example usage**:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tool.ruff]
|
||||||
|
required-version = "0.0.193"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
#### [`respect-gitignore`](#respect-gitignore)
|
#### [`respect-gitignore`](#respect-gitignore)
|
||||||
|
|
||||||
Whether to automatically exclude files that are ignored by `.ignore`,
|
Whether to automatically exclude files that are ignored by `.ignore`,
|
||||||
|
|
|
@ -303,6 +303,7 @@ mod tests {
|
||||||
ignore_init_module_imports: None,
|
ignore_init_module_imports: None,
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
select: Some(vec![
|
select: Some(vec![
|
||||||
CheckCodePrefix::E,
|
CheckCodePrefix::E,
|
||||||
|
@ -359,6 +360,7 @@ mod tests {
|
||||||
ignore_init_module_imports: None,
|
ignore_init_module_imports: None,
|
||||||
line_length: Some(100),
|
line_length: Some(100),
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
select: Some(vec![
|
select: Some(vec![
|
||||||
CheckCodePrefix::E,
|
CheckCodePrefix::E,
|
||||||
|
@ -415,6 +417,7 @@ mod tests {
|
||||||
ignore_init_module_imports: None,
|
ignore_init_module_imports: None,
|
||||||
line_length: Some(100),
|
line_length: Some(100),
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
select: Some(vec![
|
select: Some(vec![
|
||||||
CheckCodePrefix::E,
|
CheckCodePrefix::E,
|
||||||
|
@ -471,6 +474,7 @@ mod tests {
|
||||||
ignore_init_module_imports: None,
|
ignore_init_module_imports: None,
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
select: Some(vec![
|
select: Some(vec![
|
||||||
CheckCodePrefix::E,
|
CheckCodePrefix::E,
|
||||||
|
@ -527,6 +531,7 @@ mod tests {
|
||||||
ignore_init_module_imports: None,
|
ignore_init_module_imports: None,
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
select: Some(vec![
|
select: Some(vec![
|
||||||
CheckCodePrefix::E,
|
CheckCodePrefix::E,
|
||||||
|
@ -591,6 +596,7 @@ mod tests {
|
||||||
ignore_init_module_imports: None,
|
ignore_init_module_imports: None,
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
select: Some(vec![
|
select: Some(vec![
|
||||||
CheckCodePrefix::D100,
|
CheckCodePrefix::D100,
|
||||||
|
@ -683,6 +689,7 @@ mod tests {
|
||||||
ignore_init_module_imports: None,
|
ignore_init_module_imports: None,
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
select: Some(vec![
|
select: Some(vec![
|
||||||
CheckCodePrefix::E,
|
CheckCodePrefix::E,
|
||||||
|
|
|
@ -34,7 +34,11 @@ bindings = "bin"
|
||||||
strip = true
|
strip = true
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
|
#required-version = "0.0.192"
|
||||||
|
|
||||||
[tool.ruff.isort]
|
[tool.ruff.isort]
|
||||||
force-wrap-aliases = true
|
force-wrap-aliases = true
|
||||||
combine-as-imports = true
|
combine-as-imports = true
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
required-version = "22.12.1"
|
||||||
|
|
|
@ -288,6 +288,17 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"required-version": {
|
||||||
|
"description": "Require a specific version of Ruff to be running (useful for unifying results across many environments, e.g., with a `pyproject.toml` file).",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Version"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"respect-gitignore": {
|
"respect-gitignore": {
|
||||||
"description": "Whether to automatically exclude files that are ignored by `.ignore`, `.gitignore`, `.git/info/exclude`, and global `gitignore` files. Enabled by default.",
|
"description": "Whether to automatically exclude files that are ignored by `.ignore`, `.gitignore`, `.git/info/exclude`, and global `gitignore` files. Enabled by default.",
|
||||||
"type": [
|
"type": [
|
||||||
|
@ -1196,6 +1207,9 @@
|
||||||
"parents",
|
"parents",
|
||||||
"all"
|
"all"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"Version": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -38,14 +38,8 @@ pub fn run(
|
||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
debug!("Identified files to lint in: {:?}", duration);
|
debug!("Identified files to lint in: {:?}", duration);
|
||||||
|
|
||||||
// Discover the package root for each Python file.
|
// Validate the `Settings` and return any errors.
|
||||||
let package_roots = packages::detect_package_roots(
|
resolver.validate(pyproject_strategy)?;
|
||||||
&paths
|
|
||||||
.iter()
|
|
||||||
.flatten()
|
|
||||||
.map(ignore::DirEntry::path)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initialize the cache.
|
// Initialize the cache.
|
||||||
if matches!(cache, flags::Cache::Enabled) {
|
if matches!(cache, flags::Cache::Enabled) {
|
||||||
|
@ -71,6 +65,15 @@ pub fn run(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Discover the package root for each Python file.
|
||||||
|
let package_roots = packages::detect_package_roots(
|
||||||
|
&paths
|
||||||
|
.iter()
|
||||||
|
.flatten()
|
||||||
|
.map(ignore::DirEntry::path)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut diagnostics: Diagnostics = par_iter(&paths)
|
let mut diagnostics: Diagnostics = par_iter(&paths)
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
|
@ -176,6 +179,9 @@ pub fn add_noqa(
|
||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
debug!("Identified files to lint in: {:?}", duration);
|
debug!("Identified files to lint in: {:?}", duration);
|
||||||
|
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
resolver.validate(pyproject_strategy)?;
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let modifications: usize = par_iter(&paths)
|
let modifications: usize = par_iter(&paths)
|
||||||
.flatten()
|
.flatten()
|
||||||
|
@ -212,6 +218,9 @@ pub fn autoformat(
|
||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
debug!("Identified files to lint in: {:?}", duration);
|
debug!("Identified files to lint in: {:?}", duration);
|
||||||
|
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
resolver.validate(pyproject_strategy)?;
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let modifications = par_iter(&paths)
|
let modifications = par_iter(&paths)
|
||||||
.flatten()
|
.flatten()
|
||||||
|
@ -245,6 +254,9 @@ pub fn show_settings(
|
||||||
let (paths, resolver) =
|
let (paths, resolver) =
|
||||||
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
|
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
|
||||||
|
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
resolver.validate(pyproject_strategy)?;
|
||||||
|
|
||||||
// Print the list of files.
|
// Print the list of files.
|
||||||
let Some(entry) = paths
|
let Some(entry) = paths
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -268,9 +280,12 @@ pub fn show_files(
|
||||||
overrides: &Overrides,
|
overrides: &Overrides,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Collect all files in the hierarchy.
|
// Collect all files in the hierarchy.
|
||||||
let (paths, _resolver) =
|
let (paths, resolver) =
|
||||||
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
|
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
|
||||||
|
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
resolver.validate(pyproject_strategy)?;
|
||||||
|
|
||||||
// Print the list of files.
|
// Print the list of files.
|
||||||
for entry in paths
|
for entry in paths
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -59,6 +59,9 @@ pub(crate) fn check_path(
|
||||||
autofix: flags::Autofix,
|
autofix: flags::Autofix,
|
||||||
noqa: flags::Noqa,
|
noqa: flags::Noqa,
|
||||||
) -> Result<Vec<Check>> {
|
) -> Result<Vec<Check>> {
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
settings.validate()?;
|
||||||
|
|
||||||
// Aggregate all checks.
|
// Aggregate all checks.
|
||||||
let mut checks: Vec<Check> = vec![];
|
let mut checks: Vec<Check> = vec![];
|
||||||
|
|
||||||
|
@ -175,6 +178,9 @@ pub fn lint_path(
|
||||||
cache: flags::Cache,
|
cache: flags::Cache,
|
||||||
autofix: fixer::Mode,
|
autofix: fixer::Mode,
|
||||||
) -> Result<Diagnostics> {
|
) -> Result<Diagnostics> {
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
settings.validate()?;
|
||||||
|
|
||||||
let metadata = path.metadata()?;
|
let metadata = path.metadata()?;
|
||||||
|
|
||||||
// Check the cache.
|
// Check the cache.
|
||||||
|
@ -202,6 +208,9 @@ pub fn lint_path(
|
||||||
|
|
||||||
/// Add any missing `#noqa` pragmas to the source code at the given `Path`.
|
/// Add any missing `#noqa` pragmas to the source code at the given `Path`.
|
||||||
pub fn add_noqa_to_path(path: &Path, settings: &Settings) -> Result<usize> {
|
pub fn add_noqa_to_path(path: &Path, settings: &Settings) -> Result<usize> {
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
settings.validate()?;
|
||||||
|
|
||||||
// Read the file from disk.
|
// Read the file from disk.
|
||||||
let contents = fs::read_file(path)?;
|
let contents = fs::read_file(path)?;
|
||||||
|
|
||||||
|
@ -241,7 +250,10 @@ pub fn add_noqa_to_path(path: &Path, settings: &Settings) -> Result<usize> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply autoformatting to the source code at the given `Path`.
|
/// Apply autoformatting to the source code at the given `Path`.
|
||||||
pub fn autoformat_path(path: &Path, _settings: &Settings) -> Result<()> {
|
pub fn autoformat_path(path: &Path, settings: &Settings) -> Result<()> {
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
settings.validate()?;
|
||||||
|
|
||||||
// Read the file from disk.
|
// Read the file from disk.
|
||||||
let contents = fs::read_file(path)?;
|
let contents = fs::read_file(path)?;
|
||||||
|
|
||||||
|
@ -266,6 +278,9 @@ pub fn lint_stdin(
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
autofix: fixer::Mode,
|
autofix: fixer::Mode,
|
||||||
) -> Result<Diagnostics> {
|
) -> Result<Diagnostics> {
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
settings.validate()?;
|
||||||
|
|
||||||
// Read the file from disk.
|
// Read the file from disk.
|
||||||
let contents = stdin.to_string();
|
let contents = stdin.to_string();
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,12 @@ fn inner_main() -> Result<ExitCode> {
|
||||||
cli.stdin_filename.as_deref(),
|
cli.stdin_filename.as_deref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Validate the `Settings` and return any errors.
|
||||||
|
match &pyproject_strategy {
|
||||||
|
PyprojectDiscovery::Fixed(settings) => settings.validate()?,
|
||||||
|
PyprojectDiscovery::Hierarchical(settings) => settings.validate()?,
|
||||||
|
};
|
||||||
|
|
||||||
// Extract options that are included in `Settings`, but only apply at the top
|
// Extract options that are included in `Settings`, but only apply at the top
|
||||||
// level.
|
// level.
|
||||||
let file_strategy = FileDiscovery {
|
let file_strategy = FileDiscovery {
|
||||||
|
|
|
@ -91,6 +91,26 @@ impl Resolver {
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Settings> {
|
pub fn iter(&self) -> impl Iterator<Item = &Settings> {
|
||||||
self.settings.values()
|
self.settings.values()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Validate all resolved `Settings` in this `Resolver`.
|
||||||
|
pub fn validate(&self, strategy: &PyprojectDiscovery) -> Result<()> {
|
||||||
|
// TODO(charlie): This risks false positives (but not false negatives), since
|
||||||
|
// some of the `Settings` in the path may ultimately be unused (or, e.g., they
|
||||||
|
// could have their `required_version` overridden by other `Settings` in
|
||||||
|
// the path). It'd be preferable to validate once we've determined the
|
||||||
|
// `Settings` for each path, but that's more expensive.
|
||||||
|
match &strategy {
|
||||||
|
PyprojectDiscovery::Fixed(settings) => {
|
||||||
|
settings.validate()?;
|
||||||
|
}
|
||||||
|
PyprojectDiscovery::Hierarchical(default) => {
|
||||||
|
for settings in std::iter::once(default).chain(self.iter()) {
|
||||||
|
settings.validate()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively resolve a `Configuration` from a `pyproject.toml` file at the
|
/// Recursively resolve a `Configuration` from a `pyproject.toml` file at the
|
||||||
|
|
|
@ -16,7 +16,9 @@ use crate::checks_gen::CheckCodePrefix;
|
||||||
use crate::cli::{collect_per_file_ignores, Overrides};
|
use crate::cli::{collect_per_file_ignores, Overrides};
|
||||||
use crate::settings::options::Options;
|
use crate::settings::options::Options;
|
||||||
use crate::settings::pyproject::load_options;
|
use crate::settings::pyproject::load_options;
|
||||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion, SerializationFormat};
|
use crate::settings::types::{
|
||||||
|
FilePattern, PerFileIgnore, PythonVersion, SerializationFormat, Version,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_import_conventions, flake8_quotes,
|
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_import_conventions, flake8_quotes,
|
||||||
flake8_tidy_imports, flake8_unused_arguments, fs, isort, mccabe, pep8_naming, pyupgrade,
|
flake8_tidy_imports, flake8_unused_arguments, fs, isort, mccabe, pep8_naming, pyupgrade,
|
||||||
|
@ -41,6 +43,7 @@ pub struct Configuration {
|
||||||
pub ignore_init_module_imports: Option<bool>,
|
pub ignore_init_module_imports: Option<bool>,
|
||||||
pub line_length: Option<usize>,
|
pub line_length: Option<usize>,
|
||||||
pub per_file_ignores: Option<Vec<PerFileIgnore>>,
|
pub per_file_ignores: Option<Vec<PerFileIgnore>>,
|
||||||
|
pub required_version: Option<Version>,
|
||||||
pub respect_gitignore: Option<bool>,
|
pub respect_gitignore: Option<bool>,
|
||||||
pub select: Option<Vec<CheckCodePrefix>>,
|
pub select: Option<Vec<CheckCodePrefix>>,
|
||||||
pub show_source: Option<bool>,
|
pub show_source: Option<bool>,
|
||||||
|
@ -124,6 +127,7 @@ impl Configuration {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}),
|
}),
|
||||||
|
required_version: options.required_version,
|
||||||
respect_gitignore: options.respect_gitignore,
|
respect_gitignore: options.respect_gitignore,
|
||||||
select: options.select,
|
select: options.select,
|
||||||
show_source: options.show_source,
|
show_source: options.show_source,
|
||||||
|
@ -162,7 +166,6 @@ impl Configuration {
|
||||||
allowed_confusables: self.allowed_confusables.or(config.allowed_confusables),
|
allowed_confusables: self.allowed_confusables.or(config.allowed_confusables),
|
||||||
dummy_variable_rgx: self.dummy_variable_rgx.or(config.dummy_variable_rgx),
|
dummy_variable_rgx: self.dummy_variable_rgx.or(config.dummy_variable_rgx),
|
||||||
exclude: self.exclude.or(config.exclude),
|
exclude: self.exclude.or(config.exclude),
|
||||||
respect_gitignore: self.respect_gitignore.or(config.respect_gitignore),
|
|
||||||
extend: self.extend.or(config.extend),
|
extend: self.extend.or(config.extend),
|
||||||
extend_exclude: config
|
extend_exclude: config
|
||||||
.extend_exclude
|
.extend_exclude
|
||||||
|
@ -191,6 +194,8 @@ impl Configuration {
|
||||||
.or(config.ignore_init_module_imports),
|
.or(config.ignore_init_module_imports),
|
||||||
line_length: self.line_length.or(config.line_length),
|
line_length: self.line_length.or(config.line_length),
|
||||||
per_file_ignores: self.per_file_ignores.or(config.per_file_ignores),
|
per_file_ignores: self.per_file_ignores.or(config.per_file_ignores),
|
||||||
|
required_version: self.required_version.or(config.required_version),
|
||||||
|
respect_gitignore: self.respect_gitignore.or(config.respect_gitignore),
|
||||||
select: self.select.or(config.select),
|
select: self.select.or(config.select),
|
||||||
show_source: self.show_source.or(config.show_source),
|
show_source: self.show_source.or(config.show_source),
|
||||||
src: self.src.or(config.src),
|
src: self.src.or(config.src),
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use globset::{Glob, GlobMatcher, GlobSet};
|
use globset::{Glob, GlobMatcher, GlobSet};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
@ -17,7 +17,9 @@ use crate::cache::cache_dir;
|
||||||
use crate::checks::CheckCode;
|
use crate::checks::CheckCode;
|
||||||
use crate::checks_gen::{CheckCodePrefix, SuffixLength, CATEGORIES};
|
use crate::checks_gen::{CheckCodePrefix, SuffixLength, CATEGORIES};
|
||||||
use crate::settings::configuration::Configuration;
|
use crate::settings::configuration::Configuration;
|
||||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion, SerializationFormat};
|
use crate::settings::types::{
|
||||||
|
FilePattern, PerFileIgnore, PythonVersion, SerializationFormat, Version,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_import_conventions, flake8_quotes,
|
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_import_conventions, flake8_quotes,
|
||||||
flake8_tidy_imports, flake8_unused_arguments, isort, mccabe, pep8_naming, pyupgrade,
|
flake8_tidy_imports, flake8_unused_arguments, isort, mccabe, pep8_naming, pyupgrade,
|
||||||
|
@ -30,6 +32,8 @@ pub mod options_base;
|
||||||
pub mod pyproject;
|
pub mod pyproject;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(clippy::struct_excessive_bools)]
|
#[allow(clippy::struct_excessive_bools)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
|
@ -47,6 +51,7 @@ pub struct Settings {
|
||||||
pub ignore_init_module_imports: bool,
|
pub ignore_init_module_imports: bool,
|
||||||
pub line_length: usize,
|
pub line_length: usize,
|
||||||
pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, FxHashSet<CheckCode>)>,
|
pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, FxHashSet<CheckCode>)>,
|
||||||
|
pub required_version: Option<Version>,
|
||||||
pub respect_gitignore: bool,
|
pub respect_gitignore: bool,
|
||||||
pub show_source: bool,
|
pub show_source: bool,
|
||||||
pub src: Vec<PathBuf>,
|
pub src: Vec<PathBuf>,
|
||||||
|
@ -139,6 +144,7 @@ impl Settings {
|
||||||
config.per_file_ignores.unwrap_or_default(),
|
config.per_file_ignores.unwrap_or_default(),
|
||||||
)?,
|
)?,
|
||||||
respect_gitignore: config.respect_gitignore.unwrap_or(true),
|
respect_gitignore: config.respect_gitignore.unwrap_or(true),
|
||||||
|
required_version: config.required_version,
|
||||||
src: config
|
src: config
|
||||||
.src
|
.src
|
||||||
.unwrap_or_else(|| vec![project_root.to_path_buf()]),
|
.unwrap_or_else(|| vec![project_root.to_path_buf()]),
|
||||||
|
@ -211,6 +217,7 @@ impl Settings {
|
||||||
ignore_init_module_imports: false,
|
ignore_init_module_imports: false,
|
||||||
line_length: 88,
|
line_length: 88,
|
||||||
per_file_ignores: vec![],
|
per_file_ignores: vec![],
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: true,
|
respect_gitignore: true,
|
||||||
show_source: false,
|
show_source: false,
|
||||||
src: vec![path_dedot::CWD.clone()],
|
src: vec![path_dedot::CWD.clone()],
|
||||||
|
@ -246,6 +253,7 @@ impl Settings {
|
||||||
ignore_init_module_imports: false,
|
ignore_init_module_imports: false,
|
||||||
line_length: 88,
|
line_length: 88,
|
||||||
per_file_ignores: vec![],
|
per_file_ignores: vec![],
|
||||||
|
required_version: None,
|
||||||
respect_gitignore: true,
|
respect_gitignore: true,
|
||||||
show_source: false,
|
show_source: false,
|
||||||
src: vec![path_dedot::CWD.clone()],
|
src: vec![path_dedot::CWD.clone()],
|
||||||
|
@ -264,6 +272,19 @@ impl Settings {
|
||||||
pyupgrade: pyupgrade::settings::Settings::default(),
|
pyupgrade: pyupgrade::settings::Settings::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn validate(&self) -> Result<()> {
|
||||||
|
if let Some(required_version) = &self.required_version {
|
||||||
|
if &**required_version != CARGO_PKG_VERSION {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Required version `{}` does not match the running version `{}`",
|
||||||
|
&**required_version,
|
||||||
|
CARGO_PKG_VERSION
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Settings {
|
impl Hash for Settings {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::checks_gen::CheckCodePrefix;
|
use crate::checks_gen::CheckCodePrefix;
|
||||||
use crate::settings::types::{PythonVersion, SerializationFormat};
|
use crate::settings::types::{PythonVersion, SerializationFormat, Version};
|
||||||
use crate::{
|
use crate::{
|
||||||
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_import_conventions, flake8_quotes,
|
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_import_conventions, flake8_quotes,
|
||||||
flake8_tidy_imports, flake8_unused_arguments, isort, mccabe, pep8_naming, pyupgrade,
|
flake8_tidy_imports, flake8_unused_arguments, isort, mccabe, pep8_naming, pyupgrade,
|
||||||
|
@ -216,6 +216,17 @@ pub struct Options {
|
||||||
/// The line length to use when enforcing long-lines violations (like
|
/// The line length to use when enforcing long-lines violations (like
|
||||||
/// `E501`).
|
/// `E501`).
|
||||||
pub line_length: Option<usize>,
|
pub line_length: Option<usize>,
|
||||||
|
#[option(
|
||||||
|
default = "None",
|
||||||
|
value_type = "String",
|
||||||
|
example = r#"
|
||||||
|
required-version = "0.0.193"
|
||||||
|
"#
|
||||||
|
)]
|
||||||
|
/// Require a specific version of Ruff to be running (useful for unifying
|
||||||
|
/// results across many environments, e.g., with a `pyproject.toml`
|
||||||
|
/// file).
|
||||||
|
pub required_version: Option<Version>,
|
||||||
#[option(
|
#[option(
|
||||||
default = "true",
|
default = "true",
|
||||||
value_type = "bool",
|
value_type = "bool",
|
||||||
|
|
|
@ -137,6 +137,7 @@ mod tests {
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
|
required_version: None,
|
||||||
select: None,
|
select: None,
|
||||||
show_source: None,
|
show_source: None,
|
||||||
src: None,
|
src: None,
|
||||||
|
@ -187,6 +188,7 @@ line-length = 79
|
||||||
line_length: Some(79),
|
line_length: Some(79),
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
|
required_version: None,
|
||||||
select: None,
|
select: None,
|
||||||
show_source: None,
|
show_source: None,
|
||||||
src: None,
|
src: None,
|
||||||
|
@ -237,6 +239,7 @@ exclude = ["foo.py"]
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
|
required_version: None,
|
||||||
select: None,
|
select: None,
|
||||||
show_source: None,
|
show_source: None,
|
||||||
src: None,
|
src: None,
|
||||||
|
@ -287,6 +290,7 @@ select = ["E501"]
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
|
required_version: None,
|
||||||
select: Some(vec![CheckCodePrefix::E501]),
|
select: Some(vec![CheckCodePrefix::E501]),
|
||||||
show_source: None,
|
show_source: None,
|
||||||
src: None,
|
src: None,
|
||||||
|
@ -338,6 +342,7 @@ ignore = ["E501"]
|
||||||
line_length: None,
|
line_length: None,
|
||||||
per_file_ignores: None,
|
per_file_ignores: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
|
required_version: None,
|
||||||
select: None,
|
select: None,
|
||||||
show_source: None,
|
show_source: None,
|
||||||
src: None,
|
src: None,
|
||||||
|
@ -433,6 +438,7 @@ other-attribute = 1
|
||||||
)])),
|
)])),
|
||||||
dummy_variable_rgx: None,
|
dummy_variable_rgx: None,
|
||||||
respect_gitignore: None,
|
respect_gitignore: None,
|
||||||
|
required_version: None,
|
||||||
src: None,
|
src: None,
|
||||||
target_version: None,
|
target_version: None,
|
||||||
show_source: None,
|
show_source: None,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
@ -165,3 +166,23 @@ impl Default for SerializationFormat {
|
||||||
Self::Text
|
Self::Text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(try_from = "String")]
|
||||||
|
pub struct Version(String);
|
||||||
|
|
||||||
|
impl TryFrom<String> for Version {
|
||||||
|
type Error = semver::Error;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
semver::Version::parse(&value).map(|_| Self(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Version {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue