Skip to content

Commit e86009b

Browse files
committed
Add isort submodules migration step
Mirror the API template's `skip_glob = ["submodules/*"]` setting in the migration script so existing API repositories pick it up too. The automatic isort migration workflow runs `isort .`, so API repos need the same exclusion to avoid descending into external git submodules under `submodules/`. The step is a no-op for non-API projects and when the option already excludes `submodules/`. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
1 parent 22be0ee commit e86009b

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

cookiecutter/migrate.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ def main() -> None:
7575
print("Setting up the isort migration workflow...")
7676
migrate_isort_workflow_setup()
7777
print("=" * 72)
78+
print("Excluding submodules from isort for API projects...")
79+
migrate_isort_skip_glob_submodules()
80+
print("=" * 72)
7881
print()
7982

8083
if _manual_steps:
@@ -1393,6 +1396,103 @@ def read_cookiecutter_str_var(name: str) -> str | None:
13931396
return value
13941397

13951398

1399+
def migrate_isort_skip_glob_submodules() -> None:
1400+
"""Exclude the ``submodules/`` directory from isort for API projects.
1401+
1402+
API repositories may embed external git submodules under ``submodules/``
1403+
that don't follow our import sorting rules. Without an explicit exclusion,
1404+
the automatic isort migration workflow descends into them when running
1405+
``isort .``. The template now sets ``skip_glob = ["submodules/*"]`` under
1406+
``[tool.isort]`` for API projects; this step mirrors that change in
1407+
existing repositories.
1408+
1409+
The function is a no-op for non-API projects, when ``pyproject.toml``
1410+
does not exist, or when the option already excludes ``submodules/``.
1411+
"""
1412+
project_type = read_cookiecutter_str_var("type")
1413+
if project_type != "api":
1414+
print(
1415+
" Skipped: not an API project "
1416+
f"(type={project_type!r}); only API repositories ship a "
1417+
"submodules/ directory."
1418+
)
1419+
return
1420+
1421+
pyproject = Path("pyproject.toml")
1422+
if not pyproject.exists():
1423+
manual_step(
1424+
f"{pyproject} not found; please add "
1425+
'`skip_glob = ["submodules/*"]` under `[tool.isort]` manually.'
1426+
)
1427+
return
1428+
1429+
try:
1430+
content = pyproject.read_text(encoding="utf-8")
1431+
except OSError as exc:
1432+
manual_step(
1433+
f"Failed to read {pyproject}: {exc}. Please add "
1434+
'`skip_glob = ["submodules/*"]` under `[tool.isort]` manually.'
1435+
)
1436+
return
1437+
1438+
isort_section_match = re.search(
1439+
r"(?ms)^\[tool\.isort\]\n.*?(?=^\[|\Z)",
1440+
content,
1441+
)
1442+
if isort_section_match is None:
1443+
manual_step(
1444+
f"{pyproject} does not contain a [tool.isort] section; please add "
1445+
'`skip_glob = ["submodules/*"]` manually.'
1446+
)
1447+
return
1448+
1449+
isort_section = isort_section_match.group(0)
1450+
if '"submodules/*"' in isort_section or "'submodules/*'" in isort_section:
1451+
print(f" Skipped {pyproject}: already skips submodules/ in isort")
1452+
return
1453+
1454+
if re.search(r"^skip_glob\s*=", isort_section, flags=re.MULTILINE):
1455+
manual_step(
1456+
f"{pyproject} already contains a [tool.isort] skip_glob option; "
1457+
'please add `"submodules/*"` to it manually.'
1458+
)
1459+
return
1460+
1461+
new_line = (
1462+
"# Submodules may contain external code that doesn't follow our import "
1463+
'sorting rules.\nskip_glob = ["submodules/*"]\n'
1464+
)
1465+
1466+
# Anchor on the canonical [tool.isort] section as shipped by the template.
1467+
# Heavily customized layouts fall back to a manual step.
1468+
anchor_re = re.compile(
1469+
r"\[tool\.isort\]\n"
1470+
r'profile = "black"\n'
1471+
r"line_length = 88\n"
1472+
r"src_paths = \[[^\n]*\]\n",
1473+
)
1474+
match = anchor_re.search(content)
1475+
if match is None:
1476+
manual_step(
1477+
f"{pyproject} does not match the expected [tool.isort] layout; "
1478+
'please add `skip_glob = ["submodules/*"]` under `[tool.isort]` '
1479+
"manually."
1480+
)
1481+
return
1482+
1483+
anchor = match.group(0)
1484+
new_content = content.replace(anchor, anchor + new_line, 1)
1485+
1486+
try:
1487+
replace_file_atomically(pyproject, new_content)
1488+
print(f" Updated {pyproject}: added isort skip_glob for submodules/")
1489+
except OSError as exc:
1490+
manual_step(
1491+
f"Failed to update {pyproject}: {exc}. Please add "
1492+
'`skip_glob = ["submodules/*"]` under `[tool.isort]` manually.'
1493+
)
1494+
1495+
13961496
def migrate_black_extend_exclude_submodules() -> None:
13971497
"""Exclude the ``submodules/`` directory from black for API projects.
13981498

0 commit comments

Comments
 (0)