`conflicting_migration_leaves` fires when `dependencies` is built by a function

Abierto
#247 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
Medio día
Aptitud para principiantes
74/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
django, python
Área
cli, databases

Línea de trabajo

Start with _extract_dependency_pairs() and _parse_migration_file() in cli/orm_lens/migrations_parser.py, then the leaf rule in analyze_migration_risks(), to see how a non-literal dependencies value is currently treated as empty. Add the tests in cli/tests/test_migration_conflicts.py, beginning with the repro, which should yield no conflicting_migration_leaves finding. Done means that test passes, the existing two-branches-on-the-same-parent test still fires, and pytest, ruff and mypy pass.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug good first issue python

Source: weblate — weblate/trans/migrations/0084_consolidate_inherited_settings.py

What happens

Some migrations compute their dependencies, usually to depend on an optional app only when it's installed:

def get_dependencies():
    dependencies = [("trans", "0083_...")]
    if "weblate.billing" in settings.INSTALLED_APPS:
        dependencies.append(("billing", "0011_workspace"))
    return dependencies


class Migration(migrations.Migration):
    dependencies = get_dependencies()

_extract_dependency_pairs() only reads a literal list, so this migration gets []. Its parent (0083) now has no child, and migration-risk reports a critical conflict between 0083_... and the real leaf 0122_.... Exit code 1 on a perfectly linear history.

The comment above the rule already says the right thing: "a false 'your migrations conflict' is worse than a missed one". We just don't know when we're guessing.

Found on weblate: trans gets two critical findings (0083_alter_contributoragreement_unique_together_and_more vs 0122_backupauthorclaim_...).

Repro

trans/migrations/

# 0001_initial.py — creates Project, dependencies = []

# 0002_backfill.py
from django.conf import settings
from django.db import migrations


def get_dependencies():
    dependencies = [("trans", "0001_initial")]
    if "billing" in settings.INSTALLED_APPS:
        dependencies.append(("billing", "0001_initial"))
    return dependencies


class Migration(migrations.Migration):
    dependencies = get_dependencies()
    operations = [migrations.RunPython(migrations.RunPython.noop)]

# 0003_noop.py
class Migration(migrations.Migration):
    dependencies = [("trans", "0002_backfill")]
    operations = []
$ orm-lens migration-risk
trans/migrations/0001_initial.py:1  [critical/high]  (migration graph) trans.None
  rule:      conflicting_migration_leaves
  risk:      App 'trans' has 2 leaf migrations (0001_initial, 0003_noop). ...
$ echo $?
1

Expected: no finding.

Where

cli/orm_lens/migrations_parser.py

  • line 125, _extract_dependency_pairs() returns [] for anything that isn't a list/tuple;
  • line 145, _parse_migration_file() can't tell "no dependencies" from "couldn't read them";
  • around line 1310–1385, the leaf rule in analyze_migration_risks() (line 1254).
Suggested fix

In _parse_migration_file(), set a flag such as "dependencies_unknown": True when the dependencies = ... value is not a list/tuple literal. In the leaf rule, skip the app (stay silent) if any of its migrations has that flag. Same spirit as the effective_label fallback a few lines above.

Optional, only if it stays small: resolve dependencies = some_func() when some_func is a module-level function whose first statement is dependencies = [ ...literal... ]. Not needed to close the issue.

How to test
  • cli/tests/test_migration_conflicts.py: the repro gives no conflicting_migration_leaves.
  • The existing "two branches on the same parent" test still fires.
  • cd cli && python -m pytest -q, ruff and mypy pass.

Difficulty: good first issue.

Lenguaje dominante
Python
Estrellas
84
Forks
13
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de FROWNINGdev/django-orm-lens

Todos los issues de FROWNINGdev/django-orm-lens

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.