diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 488176b260..d2f80772b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: python-version: "3.14" - name: Run ruff check - run: uvx ruff check src tests + run: uvx ruff@0.15.0 check src tests pytest: runs-on: ${{ matrix.os }} diff --git a/src/specify_cli/bundler/services/installer.py b/src/specify_cli/bundler/services/installer.py index 7c5abf84db..58e220638d 100644 --- a/src/specify_cli/bundler/services/installer.py +++ b/src/specify_cli/bundler/services/installer.py @@ -50,7 +50,10 @@ class InstallResult: @property def changed(self) -> bool: - return bool(self.installed or self.refreshed) + # `uninstalled` is a mutating outcome too: a `bundle update` whose new + # manifest drops components (removing them via the refresh path) with no + # new install/refresh must still report changed=True, not a no-op. + return bool(self.installed or self.refreshed or self.uninstalled) def install_bundle( diff --git a/tests/integration/test_bundler_install_flow.py b/tests/integration/test_bundler_install_flow.py index 655094168d..0966008a74 100644 --- a/tests/integration/test_bundler_install_flow.py +++ b/tests/integration/test_bundler_install_flow.py @@ -491,3 +491,16 @@ def test_update_keeps_component_still_needed_by_sibling_bundle(tmp_path: Path): assert ("extensions", "ext-b") not in { (c.kind, c.id) for c in rec.contributed_components } + + +def test_install_result_changed_reports_uninstalled(): + # A `bundle update` that only DROPS components (new manifest reduces + # provides) populates uninstalled with nothing installed/refreshed; that is + # still a mutating change, so `changed` must be True — not a false no-op. + from specify_cli.bundler.services.installer import InstallResult + from specify_cli.bundler.models.manifest import ComponentRef + + result = InstallResult(bundle_id="x") + assert result.changed is False # empty == no change + result.uninstalled.append(ComponentRef(kind="presets", id="p1")) + assert result.changed is True