• 
      

    Add support for always-enabled extensions.

    Review Request #15106 — Created June 7, 2026 and updated

    Information

    Djblets
    release-6.x

    Reviewers

    The extension manager can now be given a list of extensions that must
    always be enabled. These act like enabled-by-default extensions, except
    that they cannot be disabled through disable_extension() or the UI,
    and will be considered enabled every time the extension manager loads.

    This and the enabled-by-default extensions can both be set in
    settings, or can now be set as attributes on the extension manager,
    giving implementations a central, non-settings-based place to customize
    this.

    Any always-enabled extension will still show up in the extension
    manager, but it won't have a button for disabling the extension.
    Similarly, the API will return an error when attempting to disable it,
    if invoked through other means.

    Unit tests passed.

    Marked some extensions as always-enabled. Verified that they were
    enabled on load/refresh, even when I forced a disable through other
    means.

    Verified that they could not be disabled via the UI. No button
    appeared and API requests attempting to disable were met with an
    error response.

    Summary ID
    Add support for always-enabled extensions.
    The extension manager can now be given a list of extensions that must always be enabled. These act like enabled-by-default extensions, except that they cannot be disabled through `disable_extension()` or the UI, and will be considered enabled every time the extension manager loads. This and the enabled-by-default extensions can both be set in `settings`, or can now be set as attributes on the extension manager, giving implementations a central, non-settings-based place to customize this. Any always-enabled extension will still show up in the extension manager, but it won't have a button for disabling the extension. Similarly, the API will return an error when attempting to disable it, if invoked through other means.
    828a5b487bca0e9ae1740f12952f16e5ec6c8f02

    Description From Last Updated

    Missing a ) after EXTENSIONS_ENABLED_BY_DEFAULT

    david david

    And added an attribute for enabled by default extensions, which used to only exist as a setting.

    maubin maubin

    This should say settings.EXTENSIONS_ALWAYS_ENABLED.

    maubin maubin

    This is meant to say always_enabled_extension_ids for the :py:attr:.

    maubin maubin

    This should say settings.EXTENSIONS_ENABLED_BY_DEFAULT. Also we should mention that this will always include the IDs in always_enabled_extension_ids (see my comment …

    maubin maubin

    We should probably fetch get_dependent_extensions(extension_id) first and verify that all of the dependent extensions can be disabled before we allow …

    david david

    This should say settings.EXTENSIONS_ENABLED_BY_DEFAULT

    david david

    I think we should always include the always-enabled extension IDs in this list, regardless of if enabled_dy_default is UNSET or …

    maubin maubin

    Typo: testing -> Testing

    david david

    Typo: testing -> Testing

    david david

    Typo: testing -> Testing

    david david

    Typo: testing -> Testing

    david david

    Typo: testing -> Testing

    david david
    Checks run (2 succeeded)
    flake8 passed.
    JSHint passed.
    maubin
    1. 
        
    2. djblets/extensions/manager.py (Diff revision 1)
       
       
      Show all issues

      And added an attribute for enabled by default extensions, which used to only exist as a setting.

    3. djblets/extensions/manager.py (Diff revision 1)
       
       
      Show all issues

      This should say settings.EXTENSIONS_ALWAYS_ENABLED.

    4. djblets/extensions/manager.py (Diff revision 1)
       
       
      Show all issues

      This is meant to say always_enabled_extension_ids for the :py:attr:.

    5. djblets/extensions/manager.py (Diff revision 1)
       
       
      Show all issues

      This should say settings.EXTENSIONS_ENABLED_BY_DEFAULT. Also we should mention that this will always include the IDs in always_enabled_extension_ids (see my comment below).

    6. djblets/extensions/manager.py (Diff revision 1)
       
       
       
       
       
       
       
       
       
       
      Show all issues

      I think we should always include the always-enabled extension IDs in this list, regardless of if enabled_dy_default is UNSET or not. Otherwise its confusing wether the always-enabled extensions are expected to be in this list or not.

    7. 
        
    david
    1. 
        
    2. djblets/extensions/manager.py (Diff revision 1)
       
       
       
      Show all issues

      Missing a ) after EXTENSIONS_ENABLED_BY_DEFAULT

    3. djblets/extensions/manager.py (Diff revision 1)
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      We should probably fetch get_dependent_extensions(extension_id) first and verify that all of the dependent extensions can be disabled before we allow the dependency to be disabled.

    4. djblets/extensions/manager.py (Diff revision 1)
       
       
      Show all issues

      This should say settings.EXTENSIONS_ENABLED_BY_DEFAULT

    5. Show all issues

      Typo: testing -> Testing

    6. Show all issues

      Typo: testing -> Testing

    7. Show all issues

      Typo: testing -> Testing

    8. Show all issues

      Typo: testing -> Testing

    9. Show all issues

      Typo: testing -> Testing

    10.