Skip to content

[FIX] common: keep one broken plugin from taking odev down with it - #184

Open
sea-odoo wants to merge 1 commit into
betafrom
fix/plugin-load-isolation-beta
Open

[FIX] common: keep one broken plugin from taking odev down with it#184
sea-odoo wants to merge 1 commit into
betafrom
fix/plugin-load-isolation-beta

Conversation

@sea-odoo

@sea-odoo sea-odoo commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Description

A plugin whose commands cannot be imported took the whole registration with it. Every plugin was loaded inside one try block, so a single unparsable file left odev with none of the plugin commands — whichever plugin the developer happened to be working in:

$ odev shell
ERROR  Error while loading plugins commands: invalid syntax (mixins.py, line 28)
$ odev scaffold        # a command from an unrelated, healthy plugin
ERROR  Command 'scaffold' not found

The recovery path then made it worse. It pulled every plugin over that one error — development branches included — with Stash around the pull, and a conflicting git stash pop left conflict markers in the working tree while keeping the stash entry. Which is exactly how a checkout ends up with the unparsable python files that started this, on the next run.

  • Odev._register_plugin_commands takes the plugins to register and returns the ones that failed, each with the error that stopped it, rather than raising on the first. Each plugin is loaded on its own, reported by name, and the rest carry on.
  • The retry covers only the plugins that failed, and only when the pull actually brought something back: an import that failed for its own reasons (a genuine syntax error the developer is mid-way through writing) just repeats the same error otherwise. A plugin still broken after the update says where its repository is and how to disable it.
  • Odev._pull_plugin leaves a plugin alone unless it is on a branch odev owns — the default branch, main, master or beta. A detached head, a branch with no remote counterpart, or a development branch belongs to whoever is working in it; pulling it would at best fail and at worst rebase work in progress. It pulls the ref the remote knows the branch as rather than the local name, and reports a failed pull instead of raising through it. Resolving the default branch goes through the GitHub API, which the recovery path cannot depend on, so that lookup falls back to the conventional names.
  • Stash.__exit__ restores the working tree when the pop conflicts instead of leaving the markers in place, and says the changes are still in the stash — where the conflicts can actually be resolved by hand.

Tests

tests/tests/common/test_odev.py gains a plugin_fixture helper and four cases: a broken plugin not preventing a healthy one from registering its commands, a development branch being skipped rather than pulled, a failing pull being reported rather than raised, and the retry being skipped when nothing was pulled. The two existing registration tests are updated to the new return-based contract. Full suite passes: 361 passed, 3 subtests passed.

Linked Issues

  • None.

Compliance

  • I have read the contribution guide
  • I made sure the documentation is up-to-date both in doctrings and the docs directory
  • I have added or modified unit tests where necessary
  • I have added new libraries to the requirements.txt file, if any
  • I have incremented the version number according the versioning guide
  • The PR contains my changes only and no other external commit

Assisted by Claude Opus 5

A plugin whose commands cannot be imported took the whole registration with it: every
plugin was loaded inside one try block, so a single unparsable file left odev with none
of the plugin commands at all, whichever plugin the developer was actually working in.
Worse, the recovery pulled every plugin over that error - development branches included -
and a conflicting stash pop then left conflict markers in the working tree, which is how
a checkout ends up with the unparsable files that started this.

- odev: load each plugin's commands on its own, report the ones that fail by name and
  carry on with the rest; retry only the plugins that failed, and only when the pull
  actually brought something back, an import that failed for its own reasons repeating
  the same error otherwise.
- odev: leave a plugin alone unless it is on a branch odev owns - the default branch,
  `main`, `master` or `beta`. A detached head, a branch with no remote counterpart or a
  development branch belongs to whoever is working in it, and pulling it would at best
  fail and at worst rebase work in progress. Pull the ref the remote knows the branch as
  rather than the local name, and report a pull that fails instead of raising through it.
- git: restore the working tree when a stash pop conflicts, rather than leaving the
  conflict markers in place, and say that the changes are still in the stash - where the
  conflicts can be resolved by hand.

Assisted by Claude Opus 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant