Error if nursery rules are selected without preview (#9683)

Extends #9682 to error if the nursery selector is used or nursery rules
are selected without preview.

Part of #7992 — we will remove this in 0.3.0 instead so we can provide
nice errors in 0.2.0.
# Conflicts:
#	crates/ruff/tests/integration_test.rs
#	crates/ruff_workspace/src/configuration.rs
This commit is contained in:
Zanie 2024-02-01 08:55:55 -06:00 committed by Zanie Blue
parent 6aa643346f
commit a0f32dfa55
3 changed files with 46 additions and 93 deletions

View file

@ -857,45 +857,44 @@ fn nursery_all() {
#[test] #[test]
fn nursery_direct() { fn nursery_direct() {
// Should warn that the nursery rule is selected without preview flag but still // Should fail when a nursery rule is selected without the preview flag
// include the diagnostic // Before Ruff v0.2.0 this would warn
let mut cmd = RuffCheck::default() let mut cmd = RuffCheck::default()
.args(["--select", "RUF912", "--output-format=concise"]) .args(["--select", "RUF912", "--output-format=concise"])
.build(); .build();
assert_cmd_snapshot!(cmd, @r###" assert_cmd_snapshot!(cmd, @r###"
success: false success: false
exit_code: 1 exit_code: 2
----- stdout ----- ----- stdout -----
-:1:1: RUF912 Hey this is a nursery test rule.
Found 1 error.
----- stderr ----- ----- stderr -----
warning: Selection of nursery rule `RUF912` without the `--preview` flag is deprecated. ruff failed
Cause: Selection of unstable rule `RUF912` without the `--preview` flag is not allowed.
"###); "###);
} }
#[test] #[test]
fn nursery_group_selector() { fn nursery_group_selector() {
// Only nursery rules should be detected e.g. RUF912 // The NURSERY selector is removed but parses in the CLI for a nicer error message
// Before Ruff v0.2.0 this would warn
let mut cmd = RuffCheck::default() let mut cmd = RuffCheck::default()
.args(["--select", "NURSERY", "--output-format=concise"]) .args(["--select", "NURSERY", "--output-format=concise"])
.build(); .build();
assert_cmd_snapshot!(cmd, @r###" assert_cmd_snapshot!(cmd, @r###"
success: false success: false
exit_code: 1 exit_code: 2
----- stdout ----- ----- stdout -----
-:1:1: CPY001 Missing copyright notice at top of file
-:1:1: RUF912 Hey this is a nursery test rule.
Found 2 errors.
----- stderr ----- ----- stderr -----
warning: The `NURSERY` selector has been deprecated. Use the `--preview` flag instead. ruff failed
Cause: The `NURSERY` selector was removed. Use the `--preview` flag instead.
"###); "###);
} }
#[test] #[test]
fn nursery_group_selector_preview_enabled() { fn nursery_group_selector_preview_enabled() {
// A warning should be displayed due to deprecated selector usage // When preview mode is enabled, we shouldn't suggest using the `--preview` flag.
// Before Ruff v0.2.0 this would warn
let mut cmd = RuffCheck::default() let mut cmd = RuffCheck::default()
.args(["--select", "NURSERY", "--preview"]) .args(["--select", "NURSERY", "--preview"])
.build(); .build();
@ -906,7 +905,7 @@ fn nursery_group_selector_preview_enabled() {
----- stderr ----- ----- stderr -----
ruff failed ruff failed
Cause: The `NURSERY` selector is deprecated and cannot be used with preview mode enabled. Cause: The `NURSERY` selector was removed. Unstable rules should be selected individually or by their respective groups.
"###); "###);
} }

View file

@ -887,10 +887,12 @@ impl LintConfiguration {
for (kind, selector) in selection.selectors_by_kind() { for (kind, selector) in selection.selectors_by_kind() {
#[allow(deprecated)] #[allow(deprecated)]
if matches!(selector, RuleSelector::Nursery) { if matches!(selector, RuleSelector::Nursery) {
if preview.mode.is_enabled() { let suggestion = if preview.mode.is_disabled() {
return Err(anyhow!("The `NURSERY` selector is deprecated and cannot be used with preview mode enabled.")); " Use the `--preview` flag instead."
} } else {
warn_user_once!("The `NURSERY` selector has been deprecated. Use the `--preview` flag instead."); " Unstable rules should be selected individually or by their respective groups."
};
return Err(anyhow!("The `NURSERY` selector was removed.{suggestion}"));
}; };
// Only warn for the following selectors if used to enable rules // Only warn for the following selectors if used to enable rules
@ -928,9 +930,24 @@ impl LintConfiguration {
); );
} }
let deprecated_nursery_selectors = deprecated_nursery_selectors.iter().collect::<Vec<_>>();
match deprecated_nursery_selectors.as_slice() {
[] => (),
[selection] => {
let (prefix, code) = selection.prefix_and_code();
return Err(anyhow!("Selection of unstable rule `{prefix}{code}` without the `--preview` flag is not allowed."));
}
[..] => {
let mut message = "Selection of unstable rules without the `--preview` flag is not allowed. Enable preview or remove selection of:".to_string();
for selection in deprecated_nursery_selectors { for selection in deprecated_nursery_selectors {
let (prefix, code) = selection.prefix_and_code(); let (prefix, code) = selection.prefix_and_code();
warn_user!("Selection of nursery rule `{prefix}{code}` without the `--preview` flag is deprecated.",); message.push_str("\n\t- ");
message.push_str(prefix);
message.push_str(code);
}
message.push('\n');
return Err(anyhow!(message));
}
} }
for selection in ignored_preview_selectors { for selection in ignored_preview_selectors {
@ -1363,52 +1380,6 @@ mod tests {
use ruff_linter::RuleSelector; use ruff_linter::RuleSelector;
use std::str::FromStr; use std::str::FromStr;
const NURSERY_RULES: &[Rule] = &[
Rule::MissingCopyrightNotice,
Rule::IndentationWithInvalidMultiple,
Rule::NoIndentedBlock,
Rule::UnexpectedIndentation,
Rule::IndentationWithInvalidMultipleComment,
Rule::NoIndentedBlockComment,
Rule::UnexpectedIndentationComment,
Rule::OverIndented,
Rule::WhitespaceAfterOpenBracket,
Rule::WhitespaceBeforeCloseBracket,
Rule::WhitespaceBeforePunctuation,
Rule::WhitespaceBeforeParameters,
Rule::MultipleSpacesBeforeOperator,
Rule::MultipleSpacesAfterOperator,
Rule::TabBeforeOperator,
Rule::TabAfterOperator,
Rule::MissingWhitespaceAroundOperator,
Rule::MissingWhitespaceAroundArithmeticOperator,
Rule::MissingWhitespaceAroundBitwiseOrShiftOperator,
Rule::MissingWhitespaceAroundModuloOperator,
Rule::MissingWhitespace,
Rule::MultipleSpacesAfterComma,
Rule::TabAfterComma,
Rule::UnexpectedSpacesAroundKeywordParameterEquals,
Rule::MissingWhitespaceAroundParameterEquals,
Rule::TooFewSpacesBeforeInlineComment,
Rule::NoSpaceAfterInlineComment,
Rule::NoSpaceAfterBlockComment,
Rule::MultipleLeadingHashesForBlockComment,
Rule::MultipleSpacesAfterKeyword,
Rule::MultipleSpacesBeforeKeyword,
Rule::TabAfterKeyword,
Rule::TabBeforeKeyword,
Rule::MissingWhitespaceAfterKeyword,
Rule::CompareToEmptyString,
Rule::NoSelfUse,
Rule::EqWithoutHash,
Rule::BadDunderMethodName,
Rule::RepeatedAppend,
Rule::DeleteFullSlice,
Rule::CheckAndRemoveFromSet,
Rule::QuadraticListSummation,
Rule::NurseryTestRule,
];
const PREVIEW_RULES: &[Rule] = &[ const PREVIEW_RULES: &[Rule] = &[
Rule::AndOrTernary, Rule::AndOrTernary,
Rule::AssignmentInAssert, Rule::AssignmentInAssert,
@ -1811,9 +1782,8 @@ mod tests {
#[test] #[test]
fn nursery_select_code() -> Result<()> { fn nursery_select_code() -> Result<()> {
// Backwards compatible behavior allows selection of nursery rules with their exact code // We do not allow selection of nursery rules when preview is disabled
// when preview is disabled assert!(resolve_rules(
let actual = resolve_rules(
[RuleSelection { [RuleSelection {
select: Some(vec![Flake8Copyright::_001.into()]), select: Some(vec![Flake8Copyright::_001.into()]),
..RuleSelection::default() ..RuleSelection::default()
@ -1822,9 +1792,8 @@ mod tests {
mode: PreviewMode::Disabled, mode: PreviewMode::Disabled,
..PreviewOptions::default() ..PreviewOptions::default()
}), }),
)?; )
let expected = RuleSet::from_rule(Rule::MissingCopyrightNotice); .is_err());
assert_eq!(actual, expected);
let actual = resolve_rules( let actual = resolve_rules(
[RuleSelection { [RuleSelection {
@ -1843,10 +1812,9 @@ mod tests {
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
fn select_nursery() -> Result<()> { fn select_nursery() {
// Backwards compatible behavior allows selection of nursery rules with the nursery selector // We no longer allow use of the NURSERY selector and should error in both cases
// when preview is disabled assert!(resolve_rules(
let actual = resolve_rules(
[RuleSelection { [RuleSelection {
select: Some(vec![RuleSelector::Nursery]), select: Some(vec![RuleSelector::Nursery]),
..RuleSelection::default() ..RuleSelection::default()
@ -1855,11 +1823,8 @@ mod tests {
mode: PreviewMode::Disabled, mode: PreviewMode::Disabled,
..PreviewOptions::default() ..PreviewOptions::default()
}), }),
)?; )
let expected = RuleSet::from_rules(NURSERY_RULES); .is_err());
assert_eq!(actual, expected);
// When preview is enabled, use of NURSERY is banned
assert!(resolve_rules( assert!(resolve_rules(
[RuleSelection { [RuleSelection {
select: Some(vec![RuleSelector::Nursery]), select: Some(vec![RuleSelector::Nursery]),
@ -1871,8 +1836,6 @@ mod tests {
}), }),
) )
.is_err()); .is_err());
Ok(())
} }
#[test] #[test]

View file

@ -143,12 +143,3 @@ In our previous example, `--select` with `ALL` `HYP`, `HYP0`, or `HYP00` would n
rule will need to be selected with its exact code, e.g. `--select ALL,HYP001`. rule will need to be selected with its exact code, e.g. `--select ALL,HYP001`.
If preview mode is not enabled, this setting has no effect. If preview mode is not enabled, this setting has no effect.
## Legacy behavior
Before the preview mode was introduced, new rules were added in a "nursery" category that required selection of
rules with their exact codes — similar to if `explicit-preview-rules` is enabled.
The nursery category has been deprecated and all rules in the nursery are now considered to be in preview.
For backwards compatibility, nursery rules are selectable with their exact codes without enabling preview mode.
However, this behavior will display a warning and support will be removed in a future release.