Fix code actions migration (#40303)

Closes #40270

Release Notes:

- Fixed an issue with the settings migration to flatten `code_actions`
format steps where comments would cause enabled code actions to be
omitted from the migrated settings. If you were effected, restoring the
settings file backup and allowing the migration to re-run will result in
a valid settings file
- Fixed an issue where automated settings and keymap file updates would
occasionally assume 4-space indentation
This commit is contained in:
Ben Kunkle
2025-10-16 09:13:34 -04:00
committed by GitHub
parent c37a2f885a
commit ea6853d35c
10 changed files with 786 additions and 538 deletions
+498 -375
View File
@@ -74,6 +74,7 @@ fn run_migrations(text: &str, migrations: &[MigrationType]) -> Result<Option<Str
let mut current_text = text.to_string();
let mut result: Option<String> = None;
let json_indent_size = settings::infer_json_indent_size(&current_text);
for migration in migrations.iter() {
let migrated_text = match migration {
MigrationType::TreeSitter(patterns, query) => migrate(&current_text, patterns, query)?,
@@ -92,7 +93,7 @@ fn run_migrations(text: &str, migrations: &[MigrationType]) -> Result<Option<Str
settings::update_value_in_json_text(
&mut current,
&mut vec![],
2,
json_indent_size,
&old_value,
&new_value,
&mut edits,
@@ -204,10 +205,7 @@ pub fn migrate_settings(text: &str) -> Result<Option<String>> {
migrations::m_2025_07_08::SETTINGS_PATTERNS,
&SETTINGS_QUERY_2025_07_08,
),
MigrationType::TreeSitter(
migrations::m_2025_10_01::SETTINGS_PATTERNS,
&SETTINGS_QUERY_2025_10_01,
),
MigrationType::Json(migrations::m_2025_10_01::flatten_code_actions_formatters),
MigrationType::Json(migrations::m_2025_10_02::remove_formatters_on_save),
MigrationType::TreeSitter(
migrations::m_2025_10_03::SETTINGS_PATTERNS,
@@ -328,10 +326,6 @@ define_query!(
SETTINGS_QUERY_2025_07_08,
migrations::m_2025_07_08::SETTINGS_PATTERNS
);
define_query!(
SETTINGS_QUERY_2025_10_01,
migrations::m_2025_10_01::SETTINGS_PATTERNS
);
define_query!(
SETTINGS_QUERY_2025_10_03,
migrations::m_2025_10_03::SETTINGS_PATTERNS
@@ -351,10 +345,11 @@ mod tests {
use super::*;
use unindent::Unindent as _;
#[track_caller]
fn assert_migrated_correctly(migrated: Option<String>, expected: Option<&str>) {
match (&migrated, &expected) {
(Some(migrated), Some(expected)) => {
pretty_assertions::assert_str_eq!(migrated, expected);
pretty_assertions::assert_str_eq!(expected, migrated);
}
_ => {
pretty_assertions::assert_eq!(migrated.as_deref(), expected);
@@ -372,6 +367,7 @@ mod tests {
assert_migrated_correctly(migrated, output);
}
#[track_caller]
fn assert_migrate_settings_with_migrations(
migrations: &[MigrationType],
input: &str,
@@ -1343,24 +1339,28 @@ mod tests {
fn test_flatten_code_action_formatters_basic_array() {
assert_migrate_settings(
&r#"{
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
}
]
}"#
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
}
]
}"#
.unindent(),
Some(
&r#"{
"formatter": [
{ "code_action": "included-1" },
{ "code_action": "included-2" }
]
}"#
"formatter": [
{
"code_action": "included-1"
},
{
"code_action": "included-2"
}
]
}"#
.unindent(),
),
);
@@ -1370,21 +1370,25 @@ mod tests {
fn test_flatten_code_action_formatters_basic_object() {
assert_migrate_settings(
&r#"{
"formatter": {
"code_actions": {
"included-1": true,
"excluded": false,
"included-2": true
}
}
}"#
"formatter": {
"code_actions": {
"included-1": true,
"excluded": false,
"included-2": true
}
}
}"#
.unindent(),
Some(
&r#"{
"formatter": [
{ "code_action": "included-1" },
{ "code_action": "included-2" }
]
"formatter": [
{
"code_action": "included-1"
},
{
"code_action": "included-2"
}
]
}"#
.unindent(),
),
@@ -1394,47 +1398,57 @@ mod tests {
#[test]
fn test_flatten_code_action_formatters_array_with_multiple_action_blocks() {
assert_migrate_settings(
r#"{
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}"#,
&r#"{
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}"#
.unindent(),
Some(
r#"{
"formatter": [
{ "code_action": "included-1" },
{ "code_action": "included-2" },
{
"language_server": "ruff"
},
{ "code_action": "included-3" },
{ "code_action": "included-4" },
]
}"#,
&r#"{
"formatter": [
{
"code_action": "included-1"
},
{
"code_action": "included-2"
},
{
"language_server": "ruff"
},
{
"code_action": "included-3"
},
{
"code_action": "included-4"
}
]
}"#
.unindent(),
),
);
}
@@ -1443,55 +1457,63 @@ mod tests {
fn test_flatten_code_action_formatters_array_with_multiple_action_blocks_in_languages() {
assert_migrate_settings(
&r#"{
"languages": {
"Rust": {
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}
"languages": {
"Rust": {
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
}"#
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}
}
}"#
.unindent(),
Some(
&r#"{
"languages": {
"Rust": {
"formatter": [
{ "code_action": "included-1" },
{ "code_action": "included-2" },
{
"language_server": "ruff"
},
{ "code_action": "included-3" },
{ "code_action": "included-4" },
]
}
}
}"#
"languages": {
"Rust": {
"formatter": [
{
"code_action": "included-1"
},
{
"code_action": "included-2"
},
{
"language_server": "ruff"
},
{
"code_action": "included-3"
},
{
"code_action": "included-4"
}
]
}
}
}"#
.unindent(),
),
);
@@ -1502,100 +1524,120 @@ mod tests {
{
assert_migrate_settings(
&r#"{
"formatter": {
"code_actions": {
"default-1": true,
"default-2": true,
"default-3": true,
"default-4": true,
}
},
"languages": {
"Rust": {
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
},
"Python": {
"formatter": [
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}
"formatter": {
"code_actions": {
"default-1": true,
"default-2": true,
"default-3": true,
"default-4": true,
}
},
"languages": {
"Rust": {
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
}"#
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
},
"Python": {
"formatter": [
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}
}
}"#
.unindent(),
Some(
&r#"{
"formatter": [
{ "code_action": "default-1" },
{ "code_action": "default-2" },
{ "code_action": "default-3" },
{ "code_action": "default-4" }
],
"languages": {
"Rust": {
"formatter": [
{ "code_action": "included-1" },
{ "code_action": "included-2" },
{
"language_server": "ruff"
},
{ "code_action": "included-3" },
{ "code_action": "included-4" },
]
},
"Python": {
"formatter": [
{
"language_server": "ruff"
},
{ "code_action": "included-3" },
{ "code_action": "included-4" },
]
}
}
}"#
"formatter": [
{
"code_action": "default-1"
},
{
"code_action": "default-2"
},
{
"code_action": "default-3"
},
{
"code_action": "default-4"
}
],
"languages": {
"Rust": {
"formatter": [
{
"code_action": "included-1"
},
{
"code_action": "included-2"
},
{
"language_server": "ruff"
},
{
"code_action": "included-3"
},
{
"code_action": "included-4"
}
]
},
"Python": {
"formatter": [
{
"language_server": "ruff"
},
{
"code_action": "included-3"
},
{
"code_action": "included-4"
}
]
}
}
}"#
.unindent(),
),
);
@@ -1604,153 +1646,185 @@ mod tests {
#[test]
fn test_flatten_code_action_formatters_array_with_format_on_save_and_multiple_languages() {
assert_migrate_settings_with_migrations(
&[MigrationType::TreeSitter(
migrations::m_2025_10_01::SETTINGS_PATTERNS,
&SETTINGS_QUERY_2025_10_01,
&[MigrationType::Json(
migrations::m_2025_10_01::flatten_code_actions_formatters,
)],
&r#"{
"formatter": {
"code_actions": {
"default-1": true,
"default-2": true,
"default-3": true,
"default-4": true,
}
},
"format_on_save": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
],
"languages": {
"Rust": {
"format_on_save": "prettier",
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
},
"Python": {
"format_on_save": {
"code_actions": {
"on-save-1": true,
"on-save-2": true,
}
},
"formatter": [
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}
"formatter": {
"code_actions": {
"default-1": true,
"default-2": true,
"default-3": true,
"default-4": true,
}
},
"format_on_save": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
],
"languages": {
"Rust": {
"format_on_save": "prettier",
"formatter": [
{
"code_actions": {
"included-1": true,
"included-2": true,
"excluded": false,
}
}"#
},
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
},
"Python": {
"format_on_save": {
"code_actions": {
"on-save-1": true,
"on-save-2": true,
}
},
"formatter": [
{
"language_server": "ruff"
},
{
"code_actions": {
"excluded": false,
"excluded-2": false,
}
}
// some comment
,
{
"code_actions": {
"excluded": false,
"included-3": true,
"included-4": true,
}
},
]
}
}
}"#
.unindent(),
Some(
&r#"{
"formatter": [
{ "code_action": "default-1" },
{ "code_action": "default-2" },
{ "code_action": "default-3" },
{ "code_action": "default-4" }
],
"format_on_save": [
{ "code_action": "included-1" },
{ "code_action": "included-2" },
{
"language_server": "ruff"
},
{ "code_action": "included-3" },
{ "code_action": "included-4" },
],
"languages": {
"Rust": {
"format_on_save": "prettier",
"formatter": [
{ "code_action": "included-1" },
{ "code_action": "included-2" },
{
"language_server": "ruff"
},
{ "code_action": "included-3" },
{ "code_action": "included-4" },
]
},
"Python": {
"format_on_save": [
{ "code_action": "on-save-1" },
{ "code_action": "on-save-2" }
],
"formatter": [
{
"language_server": "ruff"
},
{ "code_action": "included-3" },
{ "code_action": "included-4" },
]
}
}
}"#
&r#"
{
"formatter": [
{
"code_action": "default-1"
},
{
"code_action": "default-2"
},
{
"code_action": "default-3"
},
{
"code_action": "default-4"
}
],
"format_on_save": [
{
"code_action": "included-1"
},
{
"code_action": "included-2"
},
{
"language_server": "ruff"
},
{
"code_action": "included-3"
},
{
"code_action": "included-4"
}
],
"languages": {
"Rust": {
"format_on_save": "prettier",
"formatter": [
{
"code_action": "included-1"
},
{
"code_action": "included-2"
},
{
"language_server": "ruff"
},
{
"code_action": "included-3"
},
{
"code_action": "included-4"
}
]
},
"Python": {
"format_on_save": [
{
"code_action": "on-save-1"
},
{
"code_action": "on-save-2"
}
],
"formatter": [
{
"language_server": "ruff"
},
{
"code_action": "included-3"
},
{
"code_action": "included-4"
}
]
}
}
}"#
.unindent(),
),
);
@@ -1952,25 +2026,25 @@ mod tests {
migrations::m_2025_10_10::remove_code_actions_on_format,
)],
&r#"{
"code_actions_on_format": {
"a": true,
"b": false,
"c": true
}
}"#
"code_actions_on_format": {
"a": true,
"b": false,
"c": true
}
}"#
.unindent(),
Some(
&r#"{
"formatter": [
{
"code_action": "a"
},
{
"code_action": "c"
}
]
}
"#
"formatter": [
{
"code_action": "a"
},
{
"code_action": "c"
}
]
}
"#
.unindent(),
),
);
@@ -2163,12 +2237,12 @@ mod tests {
]
},
"Python": {
"formatter": [
{
"code_action": "source.organizeImports"
}
]
"formatter": [
{
"code_action": "source.organizeImports"
}
]
}
}
}"#
.unindent(),
@@ -2212,4 +2286,53 @@ mod tests {
),
);
}
#[test]
fn test_code_action_formatters_issue() {
assert_migrate_settings_with_migrations(
&[MigrationType::Json(
migrations::m_2025_10_01::flatten_code_actions_formatters,
)],
&r#"
{
"languages": {
"Python": {
"language_servers": ["ruff"],
"format_on_save": "on",
"formatter": [
{
"code_actions": {
// Fix all auto-fixable lint violations
"source.fixAll.ruff": true,
// Organize imports
"source.organizeImports.ruff": true
}
}
]
}
}
}"#
.unindent(),
Some(
&r#"
{
"languages": {
"Python": {
"language_servers": ["ruff"],
"format_on_save": "on",
"formatter": [
{
"code_action": "source.fixAll.ruff"
},
{
"code_action": "source.organizeImports.ruff"
}
]
}
}
}"#
.unindent(),
),
);
}
}