Repository: beeware/briefcase

Issue:
Add ability to refresh support package
The `briefcase update` command updates the user's code in a project, with options to also update dependencies (`-d`), and resources (`-r`). However, there is no ability to update the support package. This need doesn't arise often, but for completeness, it would be desirable to have this option.

**Describe the solution you'd like**

A new option `-s`/`--update-support` that updates the support package in an existing app.

**Describe alternatives you've considered**

The current workaround is to rebuild the app if you need to update the support package. This works, but is a sledgehammer approach.

**Additional context**

The general behavior will be very close to the behavior of the `-d` update dependencies option, so that implementation can be used as a point of comparison.

The code installing the support package will need to delete the existing support folder prior to unpacking the support package. This will need to check if the project *has* a support package - if the template doesn't define a `support_path`, then `update -s` will be a no-op.


Discussion:

Patch:
diff --git a/changes/856.misc.rst b/changes/856.misc.rst
new file mode 100644
index 00000000..ad90a4d3
--- /dev/null
+++ b/changes/856.misc.rst
@@ -0,0 +1,1 @@
+Briefcase can now update the support package on an existing app.
diff --git a/docs/reference/commands/build.rst b/docs/reference/commands/build.rst
index cd59bf2d..22a38e80 100644
--- a/docs/reference/commands/build.rst
+++ b/docs/reference/commands/build.rst
@@ -66,7 +66,18 @@ Update application requirements before building. Equivalent to running:
 ``--update-resources``
 ----------------------
 
-Update application resources (e.g., icons and splash screens) before building. Equivalent to running:
+Update application resources (e.g., icons and splash screens) before building.
+Equivalent to running:
+
+.. code-block:: console
+
+    $ briefcase update --update-resources
+    $ briefcase build
+
+``--update-support``
+----------------------
+
+Update application support package before building. Equivalent to running:
 
 .. code-block:: console
 
diff --git a/docs/reference/commands/run.rst b/docs/reference/commands/run.rst
index a8b70dc9..f4b58f9b 100644
--- a/docs/reference/commands/run.rst
+++ b/docs/reference/commands/run.rst
@@ -95,6 +95,17 @@ Update application requirements before running. Equivalent to running:
 Update application resources (e.g., icons and splash screens) before running.
 Equivalent to running:
 
+.. code-block:: console
+
+    $ briefcase update --update-resources
+    $ briefcase build
+    $ briefcase run
+
+``--update-support``
+----------------------
+
+Update application support package before running. Equivalent to running:
+
 .. code-block:: console
 
     $ briefcase update --update-resources
diff --git a/docs/reference/commands/update.rst b/docs/reference/commands/update.rst
index 82007546..cd0d4c30 100644
--- a/docs/reference/commands/update.rst
+++ b/docs/reference/commands/update.rst
@@ -45,3 +45,8 @@ Update application requirements.
 ----------------------
 
 Update application resources (e.g., icons and splash screens).
+
+``--update-support``
+----------------------
+
+Update application support package.
diff --git a/docs/reference/platforms/linux/appimage.rst b/docs/reference/platforms/linux/appimage.rst
index 2f364880..a1a9e1a2 100644
--- a/docs/reference/platforms/linux/appimage.rst
+++ b/docs/reference/platforms/linux/appimage.rst
@@ -173,6 +173,21 @@ perform container setup operations as ``root``, switch the container's user to
     USER brutus
     """
 
+Platform quirks
+===============
+
+Use caution with ``--update-support``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Care should be taken when using the ``--update-support`` option to the
+``update``, ``build`` or ``run`` commands. Support packages in Linux AppImages
+are overlaid with app content, so it isn't possible to remove all old support
+files before installing new ones.
+
+Briefcase will unpack the new support package without cleaning up existing
+support package content. This *should* work; however, ensure a reproducible
+release artefacts, it is advisable to perform a clean app build before release.
+
 Runtime issues with AppImages
 =============================
 
diff --git a/docs/reference/platforms/windows/app.rst b/docs/reference/platforms/windows/app.rst
index 22e743f1..e60fe979 100644
--- a/docs/reference/platforms/windows/app.rst
+++ b/docs/reference/platforms/windows/app.rst
@@ -83,3 +83,18 @@ pre, post and dev version indicators), padding with zeros if necessary:
 However, if you need to override this default value, you can define
 ``version_triple`` in your app settings. If provided, this value will be used
 in the MSI configuration file instead of the auto-generated value.
+
+Platform quirks
+===============
+
+Use caution with ``--update-support``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Care should be taken when using the ``--update-support`` option to the
+``update``, ``build`` or ``run`` commands. Support packages in Windows apps are
+overlaid with app content, so it isn't possible to remove all old support files
+before installing new ones.
+
+Briefcase will unpack the new support package without cleaning up existing
+support package content. This *should* work; however, ensure a reproducible
+release artefacts, it is advisable to perform a clean app build before release.
diff --git a/docs/reference/platforms/windows/visualstudio.rst b/docs/reference/platforms/windows/visualstudio.rst
index 9909fac3..875b1c2e 100644
--- a/docs/reference/platforms/windows/visualstudio.rst
+++ b/docs/reference/platforms/windows/visualstudio.rst
@@ -107,3 +107,18 @@ pre, post and dev version indicators), padding with zeros if necessary:
 However, if you need to override this default value, you can define
 ``version_triple`` in your app settings. If provided, this value will be used
 in the MSI configuration file instead of the auto-generated value.
+
+Platform quirks
+===============
+
+Use caution with ``--update-support``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Care should be taken when using the ``--update-support`` option to the
+``update``, ``build`` or ``run`` commands. Support packages in Windows apps are
+overlaid with app content, so it isn't possible to remove all old support files
+before installing new ones.
+
+Briefcase will unpack the new support package without cleaning up existing
+support package content. This *should* work; however, ensure a reproducible
+release artefacts, it is advisable to perform a clean app build before release.
diff --git a/src/briefcase/commands/base.py b/src/briefcase/commands/base.py
index b434bc21..08b37d66 100644
--- a/src/briefcase/commands/base.py
+++ b/src/briefcase/commands/base.py
@@ -673,6 +673,12 @@ a custom location for Briefcase's tools.
             help=f"Update requirements for the app{context_label}",
         )
 
+        parser.add_argument(
+            "--update-support",
+            action="store_true",
+            help=f"Update support package for the app{context_label}",
+        )
+
         parser.add_argument(
             "--update-resources",
             action="store_true",
diff --git a/src/briefcase/commands/build.py b/src/briefcase/commands/build.py
index 41e1d88e..6c5b85f0 100644
--- a/src/briefcase/commands/build.py
+++ b/src/briefcase/commands/build.py
@@ -27,6 +27,7 @@ class BuildCommand(BaseCommand):
         update: bool,
         update_requirements: bool,
         update_resources: bool,
+        update_support: bool,
         no_update: bool,
         test_mode: bool,
         **options,
@@ -41,6 +42,7 @@ class BuildCommand(BaseCommand):
             updated before building?
         :param update_resources: Should the application resources be updated
             before building?
+        :param update_support: Should the application support be updated?
         :param no_update: Should automated updates be disabled?
         :param test_mode: Is the app being build in test mode?
         """
@@ -50,6 +52,7 @@ class BuildCommand(BaseCommand):
             update  # An explicit update has been requested
             or update_requirements  # An explicit update of requirements has been requested
             or update_resources  # An explicit update of resources has been requested
+            or update_support  # An explicit update of app support has been requested
             or (
                 test_mode and not no_update
             )  # Test mode, but updates have not been disabled
@@ -58,6 +61,7 @@ class BuildCommand(BaseCommand):
                 app,
                 update_requirements=update_requirements,
                 update_resources=update_resources,
+                update_support=update_support,
                 test_mode=test_mode,
                 **options,
             )
@@ -81,6 +85,7 @@ class BuildCommand(BaseCommand):
         update: bool = False,
         update_requirements: bool = False,
         update_resources: bool = False,
+        update_support: bool = False,
         no_update: bool = False,
         test_mode: bool = False,
         **options,
@@ -100,6 +105,10 @@ class BuildCommand(BaseCommand):
                 raise BriefcaseCommandError(
                     "Cannot specify both --update-resources and --no-update"
                 )
+            if update_support:
+                raise BriefcaseCommandError(
+                    "Cannot specify both --update-support and --no-update"
+                )
 
         # Confirm host compatibility, that all required tools are available,
         # and that the app configuration is finalized.
@@ -111,6 +120,7 @@ class BuildCommand(BaseCommand):
                 update=update,
                 update_requirements=update_requirements,
                 update_resources=update_resources,
+                update_support=update_support,
                 no_update=no_update,
                 test_mode=test_mode,
                 **options,
@@ -123,6 +133,7 @@ class BuildCommand(BaseCommand):
                     update=update,
                     update_requirements=update_requirements,
                     update_resources=update_resources,
+                    update_support=update_support,
                     no_update=no_update,
                     test_mode=test_mode,
                     **full_options(state, options),
diff --git a/src/briefcase/commands/create.py b/src/briefcase/commands/create.py
index 53aea529..ceb9d38d 100644
--- a/src/briefcase/commands/create.py
+++ b/src/briefcase/commands/create.py
@@ -293,6 +293,31 @@ class CreateCommand(BaseCommand):
         except (shutil.ReadError, EOFError) as e:
             raise InvalidSupportPackage(support_file_path) from e
 
+    def _cleanup_app_support_package(self, support_path):
+        """The internal implementation of the app support cleanup method.
+
+        Guaranteed to only be invoked if the backend uses a support package,
+        and the support path exists.
+
+        :param support_path: The support path to clean up.
+        """
+        with self.input.wait_bar("Removing existing support package..."):
+            self.tools.shutil.rmtree(support_path)
+
+    def cleanup_app_support_package(self, app: BaseConfig):
+        """Clean up an existing application support package.
+
+        :param app: The config object for the app
+        """
+        try:
+            support_path = self.support_path(app)
+        except KeyError:
+            # No cleanup required.
+            pass
+        else:
+            if support_path.exists():
+                self._cleanup_app_support_package(support_path)
+
     def install_app_support_package(self, app: BaseConfig):
         """Install the application support package.
 
diff --git a/src/briefcase/commands/package.py b/src/briefcase/commands/package.py
index 2f904dfb..cf83e0dd 100644
--- a/src/briefcase/commands/package.py
+++ b/src/briefcase/commands/package.py
@@ -70,6 +70,7 @@ class PackageCommand(BaseCommand):
                 app,
                 update_resources=True,
                 update_requirements=True,
+                update_support=True,
                 **options,
             )
             state = self.build_command(app, **full_options(state, options))
diff --git a/src/briefcase/commands/run.py b/src/briefcase/commands/run.py
index 07310c6a..93bb77d1 100644
--- a/src/briefcase/commands/run.py
+++ b/src/briefcase/commands/run.py
@@ -246,6 +246,7 @@ class RunCommand(RunAppMixin, BaseCommand):
         update: bool = False,
         update_requirements: bool = False,
         update_resources: bool = False,
+        update_support: bool = False,
         no_update: bool = False,
         test_mode: bool = False,
         passthrough: Optional[List[str]] = None,
@@ -279,6 +280,7 @@ class RunCommand(RunAppMixin, BaseCommand):
             or update  # An explicit update has been requested
             or update_requirements  # An explicit update of requirements has been requested
             or update_resources  # An explicit update of resources has been requested
+            or update_support  # An explicit update of support files has been requested
             or (not binary_file.exists())  # Binary doesn't exist yet
             or (
                 test_mode and not no_update
@@ -289,6 +291,7 @@ class RunCommand(RunAppMixin, BaseCommand):
                 update=update,
                 update_requirements=update_requirements,
                 update_resources=update_resources,
+                update_support=update_support,
                 no_update=no_update,
                 test_mode=test_mode,
                 **options,
diff --git a/src/briefcase/commands/update.py b/src/briefcase/commands/update.py
index c8c2da6d..965b062c 100644
--- a/src/briefcase/commands/update.py
+++ b/src/briefcase/commands/update.py
@@ -22,6 +22,7 @@ class UpdateCommand(CreateCommand):
         app: BaseConfig,
         update_requirements: bool,
         update_resources: bool,
+        update_support: bool,
         test_mode: bool,
         **options,
     ):
@@ -30,6 +31,7 @@ class UpdateCommand(CreateCommand):
         :param app: The config object for the app
         :param update_requirements: Should requirements be updated?
         :param update_resources: Should extra resources be updated?
+        :param update_support: Should app support be updated?
         :param test_mode: Should the app be updated in test mode?
         """
 
@@ -53,6 +55,11 @@ class UpdateCommand(CreateCommand):
             self.logger.info("Updating application resources...", prefix=app.app_name)
             self.install_app_resources(app=app)
 
+        if update_support:
+            self.logger.info("Updating application support...", prefix=app.app_name)
+            self.cleanup_app_support_package(app=app)
+            self.install_app_support_package(app=app)
+
         self.logger.info("Removing unneeded app content...", prefix=app.app_name)
         self.cleanup_app_content(app=app)
 
@@ -63,6 +70,7 @@ class UpdateCommand(CreateCommand):
         app: Optional[BaseConfig] = None,
         update_requirements: bool = False,
         update_resources: bool = False,
+        update_support: bool = False,
         test_mode: bool = False,
         **options,
     ):
@@ -75,6 +83,7 @@ class UpdateCommand(CreateCommand):
                 app,
                 update_requirements=update_requirements,
                 update_resources=update_resources,
+                update_support=update_support,
                 test_mode=test_mode,
                 **options,
             )
@@ -85,6 +94,7 @@ class UpdateCommand(CreateCommand):
                     app,
                     update_requirements=update_requirements,
                     update_resources=update_resources,
+                    update_support=update_support,
                     test_mode=test_mode,
                     **full_options(state, options),
                 )
diff --git a/src/briefcase/platforms/linux/appimage.py b/src/briefcase/platforms/linux/appimage.py
index 6f69c382..e1809e12 100644
--- a/src/briefcase/platforms/linux/appimage.py
+++ b/src/briefcase/platforms/linux/appimage.py
@@ -169,6 +169,29 @@ class LinuxAppImageCreateCommand(
 
         return context
 
+    def _cleanup_app_support_package(self, support_path):
+        # On Windows, the support path is co-mingled with app content.
+        # This means updating the support package is imperfect.
+        # Warn the user that there could be problems.
+        self.logger.warning(
+            """
+*************************************************************************
+** WARNING: Support package update may be imperfect                    **
+*************************************************************************
+
+    Support packages in Linux AppImages are overlaid with app content,
+    so it isn't possible to remove all old support files before
+    installing new ones.
+
+    Briefcase will unpack the new support package without cleaning up
+    existing support package content. This *should* work; however,
+    ensure a reproducible release artefacts, it is advisable to
+    perform a clean app build before release.
+
+*************************************************************************
+"""
+        )
+
 
 class LinuxAppImageUpdateCommand(LinuxAppImageCreateCommand, UpdateCommand):
     description = "Update an existing Linux AppImage."
diff --git a/src/briefcase/platforms/windows/__init__.py b/src/briefcase/platforms/windows/__init__.py
index da5bc8cc..a9707579 100644
--- a/src/briefcase/platforms/windows/__init__.py
+++ b/src/briefcase/platforms/windows/__init__.py
@@ -80,6 +80,29 @@ class WindowsCreateCommand(CreateCommand):
             "install_scope": install_scope,
         }
 
+    def _cleanup_app_support_package(self, support_path):
+        # On Windows, the support path is co-mingled with app content.
+        # This means updating the support package is imperfect.
+        # Warn the user that there could be problems.
+        self.logger.warning(
+            """
+*************************************************************************
+** WARNING: Support package update may be imperfect                    **
+*************************************************************************
+
+    Support packages in Windows apps are overlaid with app content,
+    so it isn't possible to remove all old support files before
+    installing new ones.
+
+    Briefcase will unpack the new support package without cleaning up
+    existing support package content. This *should* work; however,
+    ensure a reproducible release artefacts, it is advisable to
+    perform a clean app build before release.
+
+*************************************************************************
+"""
+        )
+
 
 class WindowsRunCommand(RunCommand):
     def run_app(


Test patch:
diff --git a/tests/commands/build/conftest.py b/tests/commands/build/conftest.py
index e7b4e1fa..d1fcd667 100644
--- a/tests/commands/build/conftest.py
+++ b/tests/commands/build/conftest.py
@@ -51,6 +51,7 @@ class DummyBuildCommand(BuildCommand):
         kwargs.pop("update", None)
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         kwargs.pop("no_update", None)
         kwargs.pop("test_mode", None)
         return full_options({"build_state": app.app_name}, kwargs)
@@ -69,6 +70,7 @@ class DummyBuildCommand(BuildCommand):
         # Remove arguments consumed by the underlying call to update_app()
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         kwargs.pop("test_mode", None)
         return full_options({"update_state": app.app_name}, kwargs)
 
diff --git a/tests/commands/build/test_call.py b/tests/commands/build/test_call.py
index ee7b4836..8cb92333 100644
--- a/tests/commands/build/test_call.py
+++ b/tests/commands/build/test_call.py
@@ -171,6 +171,7 @@ def test_update_app(build_command, first_app, second_app):
                 "test_mode": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -186,6 +187,7 @@ def test_update_app(build_command, first_app, second_app):
                 "test_mode": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -229,6 +231,7 @@ def test_update_app_requirements(build_command, first_app, second_app):
                 "test_mode": False,
                 "update_requirements": True,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -244,6 +247,7 @@ def test_update_app_requirements(build_command, first_app, second_app):
                 "test_mode": False,
                 "update_requirements": True,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -287,6 +291,7 @@ def test_update_app_resources(build_command, first_app, second_app):
                 "test_mode": False,
                 "update_requirements": False,
                 "update_resources": True,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -302,6 +307,7 @@ def test_update_app_resources(build_command, first_app, second_app):
                 "test_mode": False,
                 "update_requirements": False,
                 "update_resources": True,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -352,6 +358,7 @@ def test_update_non_existent(build_command, first_app_config, second_app):
                 "test_mode": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -400,6 +407,7 @@ def test_update_unbuilt(build_command, first_app_unbuilt, second_app):
                 "test_mode": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -415,6 +423,7 @@ def test_update_unbuilt(build_command, first_app_unbuilt, second_app):
                 "test_mode": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -458,6 +467,7 @@ def test_build_test(build_command, first_app, second_app):
                 "test_mode": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -473,6 +483,7 @@ def test_build_test(build_command, first_app, second_app):
                 "test_mode": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -556,6 +567,7 @@ def test_build_test_update_dependencies(build_command, first_app, second_app):
                 "test_mode": True,
                 "update_requirements": True,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -571,6 +583,7 @@ def test_build_test_update_dependencies(build_command, first_app, second_app):
                 "test_mode": True,
                 "update_requirements": True,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -615,6 +628,7 @@ def test_build_test_update_resources(build_command, first_app, second_app):
                 "test_mode": True,
                 "update_requirements": False,
                 "update_resources": True,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -630,6 +644,7 @@ def test_build_test_update_resources(build_command, first_app, second_app):
                 "test_mode": True,
                 "update_requirements": False,
                 "update_resources": True,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -701,6 +716,26 @@ def test_build_invalid_update_resources(build_command, first_app, second_app):
         build_command(**options)
 
 
+def test_build_invalid_update_support(build_command, first_app, second_app):
+    """If the user requests a build with update-support and no-update, an error is
+    raised."""
+    # Add two apps
+    build_command.apps = {
+        "first": first_app,
+        "second": second_app,
+    }
+
+    # Configure command line options
+    options = build_command.parse_options(["--update-support", "--no-update"])
+
+    # Run the build command
+    with pytest.raises(
+        BriefcaseCommandError,
+        match=r"Cannot specify both --update-support and --no-update",
+    ):
+        build_command(**options)
+
+
 def test_test_app_non_existent(build_command, first_app_config, second_app):
     """Requesting a test build of a non-existent app causes a create."""
     # Add two apps; use the "config only" version of the first app.
@@ -739,6 +774,7 @@ def test_test_app_non_existent(build_command, first_app_config, second_app):
                 "test_mode": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
@@ -788,6 +824,7 @@ def test_test_app_unbuilt(build_command, first_app_unbuilt, second_app):
                 "test_mode": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for first app
@@ -807,6 +844,7 @@ def test_test_app_unbuilt(build_command, first_app_unbuilt, second_app):
                 "test_mode": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
             },
         ),
         # App tools are verified for second app
diff --git a/tests/commands/create/conftest.py b/tests/commands/create/conftest.py
index 1ae0033f..fe99dba6 100644
--- a/tests/commands/create/conftest.py
+++ b/tests/commands/create/conftest.py
@@ -183,11 +183,10 @@ def myapp():
 @pytest.fixture
 def bundle_path(myapp, tmp_path):
     # Return the bundle path for the app; however, as a side effect,
-    # ensure that the app, app_packages and support target directories
+    # ensure that the app, and app_packages target directories
     # exist, and the briefcase index file has been created.
     bundle_path = tmp_path / "base_path" / "build" / myapp.app_name / "tester" / "dummy"
     (bundle_path / "path" / "to" / "app").mkdir(parents=True, exist_ok=True)
-    (bundle_path / "path" / "to" / "support").mkdir(parents=True, exist_ok=True)
 
     return bundle_path
 
diff --git a/tests/commands/create/test_cleanup_app_support_package.py b/tests/commands/create/test_cleanup_app_support_package.py
new file mode 100644
index 00000000..9db10494
--- /dev/null
+++ b/tests/commands/create/test_cleanup_app_support_package.py
@@ -0,0 +1,52 @@
+import shutil
+from unittest import mock
+
+from ...utils import create_file
+
+
+def test_no_support_path(create_command, myapp, no_support_path_index):
+    """If support_path is not listed in briefcase.toml, no cleanup will be performed."""
+    create_command.tools.download.file = mock.MagicMock()
+    create_command.cleanup_app_support_package(myapp)
+    create_command.tools.download.file.assert_not_called()
+
+
+def test_support_path_does_not_exist(
+    create_command,
+    myapp,
+    app_requirements_path_index,
+):
+    """If support_path is defined, but the folder doesn't exist, no cleanup is
+    needed."""
+    create_command.tools.shutil = mock.MagicMock(spec_set=shutil)
+
+    create_command.cleanup_app_support_package(myapp)
+
+    # No cleanup was performed.
+    create_command.tools.shutil.assert_not_called()
+
+
+def test_cleanup_support_package(
+    create_command,
+    myapp,
+    support_path,
+    app_requirements_path_index,
+):
+    """If a support package already exists, it can be cleaned up."""
+
+    # Mock an existing support file
+    create_file(support_path / "old" / "trash.txt", "Old support file")
+
+    # Mock shutil so we can confirm that rmtree is called,
+    # but we still want the side effect of calling it
+    create_command.tools.shutil = mock.MagicMock(spec_set=shutil)
+    create_command.tools.shutil.rmtree.side_effect = shutil.rmtree
+
+    # Re-install the support package
+    create_command.cleanup_app_support_package(myapp)
+
+    # The old support package was deleted
+    create_command.tools.shutil.rmtree.assert_called_with(support_path)
+
+    # Confirm that the old support files have been removed
+    assert not support_path.exists()
diff --git a/tests/commands/create/test_install_app_support_package.py b/tests/commands/create/test_install_app_support_package.py
index 723ac6cb..4b286ae9 100644
--- a/tests/commands/create/test_install_app_support_package.py
+++ b/tests/commands/create/test_install_app_support_package.py
@@ -28,7 +28,6 @@ def test_install_app_support_package(
     app_requirements_path_index,
 ):
     """A support package can be downloaded and unpacked where it is needed."""
-
     # Mock download.file to return a support package
     create_command.tools.download.file = mock.MagicMock(
         side_effect=mock_tgz_download(
diff --git a/tests/commands/package/conftest.py b/tests/commands/package/conftest.py
index 1b751daa..07524ed9 100644
--- a/tests/commands/package/conftest.py
+++ b/tests/commands/package/conftest.py
@@ -95,6 +95,7 @@ class DummyPackageCommand(PackageCommand):
         kwargs.pop("update", None)
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         kwargs.pop("test_mode", None)
         return full_options({"update_state": app.app_name}, kwargs)
 
@@ -104,6 +105,7 @@ class DummyPackageCommand(PackageCommand):
         kwargs.pop("update", None)
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         kwargs.pop("test_mode", None)
         return full_options({"build_state": app.app_name}, kwargs)
 
diff --git a/tests/commands/package/test_call.py b/tests/commands/package/test_call.py
index 075d9c73..812c4297 100644
--- a/tests/commands/package/test_call.py
+++ b/tests/commands/package/test_call.py
@@ -597,6 +597,7 @@ def test_update_package_one_app(package_command, first_app, tmp_path):
                 "sign_app": True,
                 "update_requirements": True,
                 "update_resources": True,
+                "update_support": True,
             },
         ),
         (
@@ -665,6 +666,7 @@ def test_update_package_two_app(package_command, first_app, second_app, tmp_path
                 "sign_app": True,
                 "update_requirements": True,
                 "update_resources": True,
+                "update_support": True,
             },
         ),
         (
@@ -701,6 +703,7 @@ def test_update_package_two_app(package_command, first_app, second_app, tmp_path
                 "sign_app": True,
                 "update_requirements": True,
                 "update_resources": True,
+                "update_support": True,
                 # state of previous calls have been preserved.
                 "update_state": "first",
                 "build_state": "first",
diff --git a/tests/commands/publish/conftest.py b/tests/commands/publish/conftest.py
index e13675f1..ae97cbd3 100644
--- a/tests/commands/publish/conftest.py
+++ b/tests/commands/publish/conftest.py
@@ -72,6 +72,7 @@ class DummyPublishCommand(PublishCommand):
         kwargs.pop("test_mode", None)
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         return full_options({"update_state": app.app_name}, kwargs)
 
     def build_command(self, app, **kwargs):
diff --git a/tests/commands/run/conftest.py b/tests/commands/run/conftest.py
index 2bb808c9..5e754e84 100644
--- a/tests/commands/run/conftest.py
+++ b/tests/commands/run/conftest.py
@@ -51,6 +51,7 @@ class DummyRunCommand(RunCommand):
         kwargs.pop("update", None)
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         kwargs.pop("no_update", None)
         kwargs.pop("test_mode", None)
         kwargs.pop("passthrough", None)
@@ -70,6 +71,7 @@ class DummyRunCommand(RunCommand):
         # Remove arguments consumed by the underlying call to update_app()
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         kwargs.pop("test_mode", None)
         return full_options({"update_state": app.app_name}, kwargs)
 
@@ -79,6 +81,7 @@ class DummyRunCommand(RunCommand):
         kwargs.pop("update", None)
         kwargs.pop("update_requirements", None)
         kwargs.pop("update_resources", None)
+        kwargs.pop("update_support", None)
         kwargs.pop("no_update", None)
         kwargs.pop("test_mode", None)
         return full_options({"build_state": app.app_name}, kwargs)
diff --git a/tests/commands/run/test_call.py b/tests/commands/run/test_call.py
index 4ea34d81..70bb7618 100644
--- a/tests/commands/run/test_call.py
+++ b/tests/commands/run/test_call.py
@@ -187,6 +187,7 @@ def test_create_app_before_start(run_command, first_app_config):
                 "update": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -231,6 +232,7 @@ def test_build_app_before_start(run_command, first_app_unbuilt):
                 "update": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -275,6 +277,7 @@ def test_update_app(run_command, first_app):
                 "update": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -319,6 +322,7 @@ def test_update_app_requirements(run_command, first_app):
                 "update": False,
                 "update_requirements": True,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -363,6 +367,7 @@ def test_update_app_resources(run_command, first_app):
                 "update": False,
                 "update_requirements": False,
                 "update_resources": True,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -408,6 +413,7 @@ def test_update_unbuilt_app(run_command, first_app_unbuilt):
                 "update": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -453,6 +459,7 @@ def test_update_non_existent(run_command, first_app_config):
                 "update": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -497,6 +504,7 @@ def test_test_mode_existing_app(run_command, first_app):
                 "update": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -541,6 +549,7 @@ def test_test_mode_existing_app_with_passthrough(run_command, first_app):
                 "update": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -622,6 +631,7 @@ def test_test_mode_existing_app_update_requirements(run_command, first_app):
                 "update": False,
                 "update_requirements": True,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -666,6 +676,7 @@ def test_test_mode_existing_app_update_resources(run_command, first_app):
                 "update": False,
                 "update_requirements": False,
                 "update_resources": True,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -710,6 +721,7 @@ def test_test_mode_update_existing_app(run_command, first_app):
                 "update": True,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
@@ -754,6 +766,7 @@ def test_test_mode_non_existent(run_command, first_app_config):
                 "update": False,
                 "update_requirements": False,
                 "update_resources": False,
+                "update_support": False,
                 "no_update": False,
             },
         ),
diff --git a/tests/commands/update/conftest.py b/tests/commands/update/conftest.py
index 275a30b5..6290b7bb 100644
--- a/tests/commands/update/conftest.py
+++ b/tests/commands/update/conftest.py
@@ -58,6 +58,13 @@ class DummyUpdateCommand(UpdateCommand):
         self.actions.append(("resources", app.app_name))
         create_file(self.bundle_path(app) / "resources", "app resources")
 
+    def cleanup_app_support_package(self, app):
+        self.actions.append(("cleanup-support", app.app_name))
+
+    def install_app_support_package(self, app):
+        self.actions.append(("support", app.app_name))
+        create_file(self.bundle_path(app) / "support" / "content.txt", "app support")
+
     def cleanup_app_content(self, app):
         self.actions.append(("cleanup", app.app_name))
 
diff --git a/tests/commands/update/test_call.py b/tests/commands/update/test_call.py
index 21332f5a..4cc27559 100644
--- a/tests/commands/update/test_call.py
+++ b/tests/commands/update/test_call.py
@@ -124,3 +124,34 @@ def test_update_with_resources(update_command, first_app, second_app):
         ("resources", "second"),
         ("cleanup", "second"),
     ]
+
+
+def test_update_with_support(update_command, first_app, second_app):
+    """The update command can be called, requesting an app support update."""
+    # Configure no command line options
+    options = update_command.parse_options(["--update-support"])
+
+    update_command(**options)
+
+    # The right sequence of things will be done
+    assert update_command.actions == [
+        # Host OS is verified
+        ("verify-host",),
+        # Tools are verified
+        ("verify-tools",),
+        # App configs have been finalized
+        ("finalize-app-config", "first"),
+        ("finalize-app-config", "second"),
+        # Update the first app
+        ("verify-app-tools", "first"),
+        ("code", "first", False),
+        ("cleanup-support", "first"),
+        ("support", "first"),
+        ("cleanup", "first"),
+        # Update the second app
+        ("verify-app-tools", "second"),
+        ("code", "second", False),
+        ("cleanup-support", "second"),
+        ("support", "second"),
+        ("cleanup", "second"),
+    ]
diff --git a/tests/commands/update/test_update_app.py b/tests/commands/update/test_update_app.py
index f96c377a..fb55a417 100644
--- a/tests/commands/update/test_update_app.py
+++ b/tests/commands/update/test_update_app.py
@@ -4,6 +4,7 @@ def test_update_app(update_command, first_app, tmp_path):
         update_command.apps["first"],
         update_requirements=False,
         update_resources=False,
+        update_support=False,
         test_mode=False,
     )
 
@@ -38,6 +39,7 @@ def test_update_non_existing_app(update_command, tmp_path):
         update_command.apps["first"],
         update_requirements=False,
         update_resources=False,
+        update_support=False,
         test_mode=False,
     )
 
@@ -59,6 +61,7 @@ def test_update_app_with_requirements(update_command, first_app, tmp_path):
         update_command.apps["first"],
         update_requirements=True,
         update_resources=False,
+        update_support=False,
         test_mode=False,
     )
 
@@ -93,6 +96,7 @@ def test_update_app_with_resources(update_command, first_app, tmp_path):
         update_command.apps["first"],
         update_requirements=False,
         update_resources=True,
+        update_support=False,
         test_mode=False,
     )
 
@@ -121,6 +125,45 @@ def test_update_app_with_resources(update_command, first_app, tmp_path):
     ).exists()
 
 
+def test_update_app_with_support_package(update_command, first_app, tmp_path):
+    """If the user requests an app support package update, they are updated."""
+    update_command.update_app(
+        update_command.apps["first"],
+        update_requirements=False,
+        update_resources=False,
+        update_support=True,
+        test_mode=False,
+    )
+
+    # The right sequence of things will be done
+    assert update_command.actions == [
+        ("verify-app-tools", "first"),
+        ("code", "first", False),
+        ("cleanup-support", "first"),
+        ("support", "first"),
+        ("cleanup", "first"),
+    ]
+
+    # App content and support have been updated
+    assert (
+        tmp_path / "base_path" / "build" / "first" / "tester" / "dummy" / "code.py"
+    ).exists()
+    assert (
+        tmp_path / "base_path" / "build" / "first" / "tester" / "dummy" / "support"
+    ).exists()
+    # requirements and resources haven't been updated
+    assert not (
+        tmp_path / "base_path" / "build" / "first" / "tester" / "dummy" / "resources"
+    ).exists()
+    assert not (
+        tmp_path / "base_path" / "build" / "first" / "tester" / "dummy" / "requirements"
+    ).exists()
+    # ... and the app still exists
+    assert (
+        tmp_path / "base_path" / "build" / "first" / "tester" / "dummy" / "first.bundle"
+    ).exists()
+
+
 def test_update_app_test_mode(update_command, first_app, tmp_path):
     """Update app in test mode."""
     # Pass in the defaults for the update flags
@@ -129,6 +172,7 @@ def test_update_app_test_mode(update_command, first_app, tmp_path):
         test_mode=True,
         update_requirements=False,
         update_resources=False,
+        update_support=False,
     )
 
     # The right sequence of things will be done
@@ -163,6 +207,7 @@ def test_update_app_test_mode_requirements(update_command, first_app, tmp_path):
         test_mode=True,
         update_requirements=True,
         update_resources=False,
+        update_support=False,
     )
 
     # The right sequence of things will be done
@@ -198,6 +243,7 @@ def test_update_app_test_mode_resources(update_command, first_app, tmp_path):
         test_mode=True,
         update_requirements=False,
         update_resources=True,
+        update_support=False,
     )
 
     # The right sequence of things will be done
diff --git a/tests/platforms/android/gradle/test_run.py b/tests/platforms/android/gradle/test_run.py
index d95c1272..61614348 100644
--- a/tests/platforms/android/gradle/test_run.py
+++ b/tests/platforms/android/gradle/test_run.py
@@ -86,6 +86,7 @@ def test_device_option(run_command):
         "update": False,
         "update_requirements": False,
         "update_resources": False,
+        "update_support": False,
         "no_update": False,
         "test_mode": False,
         "passthrough": [],
@@ -106,6 +107,7 @@ def test_extra_emulator_args_option(run_command):
         "update": False,
         "update_requirements": False,
         "update_resources": False,
+        "update_support": False,
         "no_update": False,
         "test_mode": False,
         "passthrough": [],
@@ -124,6 +126,7 @@ def test_shutdown_on_exit_option(run_command):
         "update": False,
         "update_requirements": False,
         "update_resources": False,
+        "update_support": False,
         "no_update": False,
         "test_mode": False,
         "passthrough": [],
diff --git a/tests/platforms/iOS/xcode/test_run.py b/tests/platforms/iOS/xcode/test_run.py
index 4ae412cc..0a7975b6 100644
--- a/tests/platforms/iOS/xcode/test_run.py
+++ b/tests/platforms/iOS/xcode/test_run.py
@@ -46,6 +46,7 @@ def test_device_option(run_command):
         "update": False,
         "update_requirements": False,
         "update_resources": False,
+        "update_support": False,
         "no_update": False,
         "test_mode": False,
         "passthrough": [],
diff --git a/tests/platforms/linux/appimage/test_build.py b/tests/platforms/linux/appimage/test_build.py
index 0b3d503a..8944d5c3 100644
--- a/tests/platforms/linux/appimage/test_build.py
+++ b/tests/platforms/linux/appimage/test_build.py
@@ -1,9 +1,11 @@
 import os
+import shutil
 import subprocess
 import sys
 from unittest import mock
 
 import pytest
+import tomli_w
 
 from briefcase.console import Console, Log
 from briefcase.exceptions import (
@@ -15,6 +17,8 @@ from briefcase.integrations.docker import DockerAppContext
 from briefcase.integrations.linuxdeploy import LinuxDeploy
 from briefcase.platforms.linux.appimage import LinuxAppImageBuildCommand
 
+from ....utils import create_file
+
 
 @pytest.fixture
 def first_app(first_app_config, tmp_path):
@@ -586,3 +590,103 @@ def test_build_appimage_with_plugins_in_docker(
         / "First_App-0.0.1-wonky.AppImage",
         0o755,
     )
+
+
+def test_build_appimage_with_support_package_update(
+    build_command,
+    first_app,
+    tmp_path,
+    sub_stream_kw,
+    capsys,
+):
+    """If a support package update is performed, the user is warned."""
+    # To trigger the app package update logic, we need to invoke the full build
+    # command, and fake being on a verified Linux install with a generated
+    # app.
+    build_command.tools.host_os = "Linux"
+
+    # Mock shutil so we can check for folder deletion
+    build_command.tools.shutil = mock.MagicMock(spec_set=shutil)
+
+    # Mock downloads so we don't hit the network
+    build_command.tools.download = mock.MagicMock()
+
+    # Hard code a support revision so that the download support package is fixed,
+    # and no linuxdeploy plugins.
+    first_app.support_revision = "3.37.42+12345"
+    first_app.linuxdeploy_plugins = []
+
+    # Fake the existence of some source files.
+    create_file(
+        tmp_path / "base_path" / "src" / "first_app" / "app.py",
+        "print('an app')",
+    )
+
+    # Mock the generated app template
+    (build_command.bundle_path(first_app) / "src").mkdir(parents=True)
+
+    # Populate a briefcase.toml that mirrors a real Windows app
+    with (build_command.bundle_path(first_app) / "briefcase.toml").open("wb") as f:
+        index = {
+            "paths": {
+                "app_path": "First App.AppDir/usr/app",
+                "app_package_path": "First App.AppDir/usr/app_packages",
+                "support_path": "First App.AppDir/usr",
+            }
+        }
+        tomli_w.dump(index, f)
+
+    # Build the app with a support package update
+    build_command(first_app, update_support=True)
+
+    # linuxdeploy was invoked
+    app_dir = (
+        tmp_path
+        / "base_path"
+        / "build"
+        / "first-app"
+        / "linux"
+        / "appimage"
+        / "First App.AppDir"
+    )
+    build_command._subprocess.Popen.assert_called_with(
+        [
+            os.fsdecode(
+                tmp_path / "briefcase" / "tools" / "linuxdeploy-wonky.AppImage"
+            ),
+            "--appdir",
+            os.fsdecode(app_dir),
+            "--desktop-file",
+            os.fsdecode(app_dir / "com.example.first-app.desktop"),
+            "--output",
+            "appimage",
+            "--deploy-deps-only",
+            os.fsdecode(app_dir / "usr" / "app" / "support"),
+            "--deploy-deps-only",
+            os.fsdecode(app_dir / "usr" / "app_packages" / "firstlib"),
+            "--deploy-deps-only",
+            os.fsdecode(app_dir / "usr" / "app_packages" / "secondlib"),
+        ],
+        env={
+            "PATH": "/usr/local/bin:/usr/bin:/path/to/somewhere",
+            "VERSION": "0.0.1",
+            "DISABLE_COPYRIGHT_FILES_DEPLOYMENT": "1",
+            "APPIMAGE_EXTRACT_AND_RUN": "1",
+            "ARCH": "wonky",
+        },
+        cwd=os.fsdecode(
+            tmp_path / "base_path" / "build" / "first-app" / "linux" / "appimage"
+        ),
+        **sub_stream_kw,
+    )
+    # Binary is marked executable
+    build_command.tools.os.chmod.assert_called_with(
+        tmp_path
+        / "base_path"
+        / "build"
+        / "first-app"
+        / "linux"
+        / "appimage"
+        / "First_App-0.0.1-wonky.AppImage",
+        0o755,
+    )
diff --git a/tests/platforms/web/static/test_run.py b/tests/platforms/web/static/test_run.py
index d2da9b06..04e54f1d 100644
--- a/tests/platforms/web/static/test_run.py
+++ b/tests/platforms/web/static/test_run.py
@@ -35,6 +35,7 @@ def test_default_options(run_command):
         "update": False,
         "update_requirements": False,
         "update_resources": False,
+        "update_support": False,
         "no_update": False,
         "test_mode": False,
         "passthrough": [],
@@ -55,6 +56,7 @@ def test_options(run_command):
         "update": False,
         "update_requirements": False,
         "update_resources": False,
+        "update_support": False,
         "no_update": False,
         "test_mode": False,
         "passthrough": [],
diff --git a/tests/platforms/windows/app/test_build.py b/tests/platforms/windows/app/test_build.py
index 3d21c223..d84788bc 100644
--- a/tests/platforms/windows/app/test_build.py
+++ b/tests/platforms/windows/app/test_build.py
@@ -1,9 +1,11 @@
 import re
+import shutil
 import subprocess
 from pathlib import Path
 from unittest import mock
 
 import pytest
+import tomli_w
 
 import briefcase.platforms.windows.app
 from briefcase.console import Console, Log
@@ -13,6 +15,8 @@ from briefcase.integrations.subprocess import Subprocess
 from briefcase.integrations.windows_sdk import WindowsSDK
 from briefcase.platforms.windows.app import WindowsAppBuildCommand
 
+from ....utils import create_file
+
 
 @pytest.fixture
 def build_command(tmp_path):
@@ -23,6 +27,8 @@ def build_command(tmp_path):
         data_path=tmp_path / "briefcase",
     )
     command.tools.subprocess = mock.MagicMock(spec_set=Subprocess)
+    command.tools.shutil = mock.MagicMock(spec_set=shutil)
+    command.tools.download = mock.MagicMock()
     command.tools.rcedit = RCEdit(command.tools)
     return command
 
@@ -278,3 +284,87 @@ def test_build_app_failure(build_command, first_app_config, tmp_path):
         match=r"Unable to update details on stub app for first-app.",
     ):
         build_command.build_app(first_app_config)
+
+
+def test_build_app_with_support_package_update(
+    build_command,
+    first_app_config,
+    tmp_path,
+    windows_sdk,
+    capsys,
+):
+    """If a support package update is performed, the user is warned."""
+
+    # To trigger the app package update logic, we need to invoke the full build
+    # command, and fake being on a verified Windows install with a generated
+    # app.
+    build_command.tools.host_os = "Windows"
+    build_command.tools.windows_sdk = windows_sdk
+    build_command.bundle_path(first_app_config).mkdir(parents=True)
+
+    # Hard code a support revision so that the download support package is fixed
+    first_app_config.support_revision = "1"
+
+    # Fake the existence of some source files.
+    create_file(
+        tmp_path / "base_path" / "src" / "first_app" / "app.py",
+        "print('an app')",
+    )
+
+    # Mock the generated app template
+    (build_command.bundle_path(first_app_config) / "src").mkdir(parents=True)
+
+    # Populate a briefcase.toml that mirrors a real Windows app
+    with (build_command.bundle_path(first_app_config) / "briefcase.toml").open(
+        "wb"
+    ) as f:
+        index = {
+            "paths": {
+                "app_path": "src/app",
+                "app_package_path": "src/app_packages",
+                "support_path": "src",
+            }
+        }
+        tomli_w.dump(index, f)
+
+    # Build the app with a support package update
+    build_command(first_app_config, update_support=True)
+
+    # update the app binary resources
+    build_command.tools.subprocess.run.assert_called_once_with(
+        [
+            tmp_path / "briefcase" / "tools" / "rcedit-x64.exe",
+            Path("src/First App.exe"),
+            "--set-version-string",
+            "CompanyName",
+            "Megacorp",
+            "--set-version-string",
+            "FileDescription",
+            "First App",
+            "--set-version-string",
+            "FileVersion",
+            "0.0.1",
+            "--set-version-string",
+            "InternalName",
+            "first_app",
+            "--set-version-string",
+            "OriginalFilename",
+            "First App.exe",
+            "--set-version-string",
+            "ProductName",
+            "First App",
+            "--set-version-string",
+            "ProductVersion",
+            "0.0.1",
+            "--set-icon",
+            "icon.ico",
+        ],
+        check=True,
+        cwd=tmp_path / "base_path" / "build" / "first-app" / "windows" / "app",
+    )
+
+    # No attempt was made to clean up the support package.
+    build_command.tools.shutil.rmtree.assert_not_called()
+
+    # The user was warned that support package update may not work.
+    assert "WARNING: Support package update may be imperfect" in capsys.readouterr().out
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index da9a263a..e760f887 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -170,6 +170,7 @@ def test_dev_command(monkeypatch, logger, console, cmdline, expected_options):
         ("run -u", {"update": True}),
         ("run --update", {"update": True}),
         ("run --update-resources", {"update_resources": True}),
+        ("run --update-support", {"update_support": True}),
         ("run --no-update", {"no_update": True}),
     ],
 )
@@ -192,6 +193,7 @@ def test_run_command(monkeypatch, logger, console, cmdline, expected_options):
         "update": False,
         "update_requirements": False,
         "update_resources": False,
+        "update_support": False,
         "no_update": False,
         "test_mode": False,
         "passthrough": [],