diff --git a/charmcraft/commands/store/__init__.py b/charmcraft/commands/store/__init__.py
index 9102dcc..bb4e784 100644
--- a/charmcraft/commands/store/__init__.py
+++ b/charmcraft/commands/store/__init__.py
@@ -1650,12 +1650,27 @@ class ListResourcesCommand(BaseCommand):
 
     def fill_parser(self, parser):
         """Add own parameters to the general parser."""
+        self.include_format_option(parser)
         parser.add_argument("charm_name", metavar="charm-name", help="The name of the charm")
 
     def run(self, parsed_args):
         """Run the command."""
         store = Store(self.config.charmhub)
         result = store.list_resources(parsed_args.charm_name)
+
+        if parsed_args.format:
+            info = [
+                {
+                    "charm_revision": item.revision,
+                    "name": item.name,
+                    "type": item.resource_type,
+                    "optional": item.optional,
+                }
+                for item in result
+            ]
+            emit.message(self.format_content(parsed_args.format, info))
+            return
+
         if not result:
             emit.message(f"No resources associated to {parsed_args.charm_name}.")
             return
@@ -1701,6 +1716,7 @@ class UploadResourceCommand(BaseCommand):
 
     def fill_parser(self, parser):
         """Add own parameters to the general parser."""
+        self.include_format_option(parser)
         parser.add_argument(
             "charm_name",
             metavar="charm-name",
@@ -1751,24 +1767,22 @@ class UploadResourceCommand(BaseCommand):
 
             # check if the specific image is already in Canonical's registry
             already_uploaded = ih.check_in_registry(image_digest)
+            # XXX Facundo 2022-06-13: converting the following four messages to progress ones
+            # so they don't interfere with the programmatic output; we need to add the
+            # permanent=True flag once is available from Craft CLI
             if already_uploaded:
-                emit.message("Using OCI image from Canonical's registry.", intermediate=True)
+                emit.progress("Using OCI image from Canonical's registry.")
             else:
                 # upload it from local registry
-                emit.message(
-                    "Remote image not found, uploading from local registry.", intermediate=True
-                )
+                emit.progress("Remote image not found, uploading from local registry.")
                 image_digest = ih.upload_from_local(image_digest)
                 if image_digest is None:
-                    emit.message(
+                    emit.progress(
                         f"Image with digest {parsed_args.image} is not available in "
                         "the Canonical's registry nor locally.",
-                        intermediate=True,
                     )
                     return
-                emit.message(
-                    f"Image uploaded, new remote digest: {image_digest}.", intermediate=True
-                )
+                emit.progress(f"Image uploaded, new remote digest: {image_digest}.")
 
             # all is green, get the blob to upload to Charmhub
             content = store.get_oci_image_blob(
@@ -1793,15 +1807,27 @@ class UploadResourceCommand(BaseCommand):
             resource_filepath.unlink()
 
         if result.ok:
-            emit.message(
-                f"Revision {result.revision} created of "
-                f"resource {parsed_args.resource_name!r} for charm {parsed_args.charm_name!r}.",
-            )
+            if parsed_args.format:
+                info = {"revision": result.revision}
+                emit.message(self.format_content(parsed_args.format, info))
+            else:
+                emit.message(
+                    f"Revision {result.revision} created of resource "
+                    f"{parsed_args.resource_name!r} for charm {parsed_args.charm_name!r}.",
+                )
             retcode = 0
         else:
-            emit.message(f"Upload failed with status {result.status!r}:")
-            for error in result.errors:
-                emit.message(f"- {error.code}: {error.message}")
+            if parsed_args.format:
+                info = {
+                    "errors": [
+                        {"code": error.code, "message": error.message} for error in result.errors
+                    ]
+                }
+                emit.message(self.format_content(parsed_args.format, info))
+            else:
+                emit.message(f"Upload failed with status {result.status!r}:")
+                for error in result.errors:
+                    emit.message(f"- {error.code}: {error.message}")
             retcode = 1
         return retcode
 
@@ -1827,6 +1853,7 @@ class ListResourceRevisionsCommand(BaseCommand):
 
     def fill_parser(self, parser):
         """Add own parameters to the general parser."""
+        self.include_format_option(parser)
         parser.add_argument(
             "charm_name",
             metavar="charm-name",
@@ -1838,6 +1865,19 @@ class ListResourceRevisionsCommand(BaseCommand):
         """Run the command."""
         store = Store(self.config.charmhub)
         result = store.list_resource_revisions(parsed_args.charm_name, parsed_args.resource_name)
+
+        if parsed_args.format:
+            info = [
+                {
+                    "revision": item.revision,
+                    "created at": format_timestamp(item.created_at),
+                    "size": item.size,
+                }
+                for item in result
+            ]
+            emit.message(self.format_content(parsed_args.format, info))
+            return
+
         if not result:
             emit.message("No revisions found.")
             return

diff --git a/tests/commands/test_store_commands.py b/tests/commands/test_store_commands.py
index 3a9e8cb..f44db47 100644
--- a/tests/commands/test_store_commands.py
+++ b/tests/commands/test_store_commands.py
@@ -4180,60 +4180,112 @@ def test_listlib_properly_sorted(emitter, store_mock, config, formatted):
 # -- tests for list resources command
 
 
-def test_resources_simple(emitter, store_mock, config):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_resources_simple(emitter, store_mock, config, formatted):
     """Happy path of one result from the Store."""
     store_response = [
         Resource(name="testresource", optional=True, revision=1, resource_type="file"),
     ]
     store_mock.list_resources.return_value = store_response
 
-    args = Namespace(charm_name="testcharm")
+    args = Namespace(charm_name="testcharm", format=formatted)
     ListResourcesCommand(config).run(args)
 
     assert store_mock.mock_calls == [
         call.list_resources("testcharm"),
     ]
-    expected = [
-        "Charm Rev    Resource      Type    Optional",
-        "1            testresource  file    True",
-    ]
-    emitter.assert_messages(expected)
+    if formatted:
+        expected = [
+            {
+                "charm_revision": 1,
+                "name": "testresource",
+                "type": "file",
+                "optional": True,
+            }
+        ]
+        emitter.assert_json_output(expected)
+    else:
+        expected = [
+            "Charm Rev    Resource      Type    Optional",
+            "1            testresource  file    True",
+        ]
+        emitter.assert_messages(expected)
 
 
-def test_resources_empty(emitter, store_mock, config):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_resources_empty(emitter, store_mock, config, formatted):
     """No results from the store."""
     store_response = []
     store_mock.list_resources.return_value = store_response
 
-    args = Namespace(charm_name="testcharm")
+    args = Namespace(charm_name="testcharm", format=formatted)
     ListResourcesCommand(config).run(args)
 
-    emitter.assert_message("No resources associated to testcharm.")
+    if formatted:
+        emitter.assert_json_output([])
+    else:
+        emitter.assert_message("No resources associated to testcharm.")
 
 
-def test_resources_ordered_and_grouped(emitter, store_mock, config):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_resources_ordered_and_grouped(emitter, store_mock, config, formatted):
     """Results are presented ordered by name in the table."""
     store_response = [
         Resource(name="bbb-resource", optional=True, revision=2, resource_type="file"),
         Resource(name="ccc-resource", optional=True, revision=1, resource_type="file"),
-        Resource(name="bbb-resource", optional=True, revision=3, resource_type="file"),
-        Resource(name="aaa-resource", optional=True, revision=2, resource_type="file"),
+        Resource(name="bbb-resource", optional=False, revision=3, resource_type="file"),
+        Resource(name="aaa-resource", optional=True, revision=2, resource_type="oci-image"),
         Resource(name="bbb-resource", optional=True, revision=5, resource_type="file"),
     ]
     store_mock.list_resources.return_value = store_response
 
-    args = Namespace(charm_name="testcharm")
+    args = Namespace(charm_name="testcharm", format=formatted)
     ListResourcesCommand(config).run(args)
 
-    expected = [
-        "Charm Rev    Resource      Type    Optional",
-        "5            bbb-resource  file    True",
-        "3            bbb-resource  file    True",
-        "2            aaa-resource  file    True",
-        "             bbb-resource  file    True",
-        "1            ccc-resource  file    True",
-    ]
-    emitter.assert_messages(expected)
+    if formatted:
+        expected = [
+            {
+                "charm_revision": 2,
+                "name": "bbb-resource",
+                "type": "file",
+                "optional": True,
+            },
+            {
+                "charm_revision": 1,
+                "name": "ccc-resource",
+                "type": "file",
+                "optional": True,
+            },
+            {
+                "charm_revision": 3,
+                "name": "bbb-resource",
+                "type": "file",
+                "optional": False,
+            },
+            {
+                "charm_revision": 2,
+                "name": "aaa-resource",
+                "type": "oci-image",
+                "optional": True,
+            },
+            {
+                "charm_revision": 5,
+                "name": "bbb-resource",
+                "type": "file",
+                "optional": True,
+            },
+        ]
+        emitter.assert_json_output(expected)
+    else:
+        expected = [
+            "Charm Rev    Resource      Type       Optional",
+            "5            bbb-resource  file       True",
+            "3            bbb-resource  file       False",
+            "2            aaa-resource  oci-image  True",
+            "             bbb-resource  file       True",
+            "1            ccc-resource  file       True",
+        ]
+        emitter.assert_messages(expected)
 
 
 # -- tests for upload resources command
@@ -4302,7 +4354,8 @@ def test_uploadresource_options_bad_combinations(config, sysargs, tmp_path, monk
         cmd.parsed_args_post_verification(parser, parsed_args)
 
 
-def test_uploadresource_filepath_call_ok(emitter, store_mock, config, tmp_path):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_uploadresource_filepath_call_ok(emitter, store_mock, config, tmp_path, formatted):
     """Simple upload, success result."""
     store_response = Uploaded(ok=True, status=200, revision=7, errors=[])
     store_mock.upload_resource.return_value = store_response
@@ -4314,6 +4367,7 @@ def test_uploadresource_filepath_call_ok(emitter, store_mock, config, tmp_path):
         resource_name="myresource",
         filepath=test_resource,
         image=None,
+        format=formatted,
     )
     retcode = UploadResourceCommand(config).run(args)
     assert retcode == 0
@@ -4321,17 +4375,24 @@ def test_uploadresource_filepath_call_ok(emitter, store_mock, config, tmp_path):
     assert store_mock.mock_calls == [
         call.upload_resource("mycharm", "myresource", "file", test_resource)
     ]
-    emitter.assert_interactions(
-        [
-            call("progress", f"Uploading resource directly from file {str(test_resource)!r}."),
-            call("message", "Revision 7 created of resource 'myresource' for charm 'mycharm'."),
-        ]
-    )
+    if formatted:
+        expected = {"revision": 7}
+        emitter.assert_json_output(expected)
+    else:
+        emitter.assert_interactions(
+            [
+                call("progress", f"Uploading resource directly from file {str(test_resource)!r}."),
+                call(
+                    "message", "Revision 7 created of resource 'myresource' for charm 'mycharm'."
+                ),
+            ]
+        )
     assert test_resource.exists()  # provided by the user, don't touch it
 
 
 @pytest.mark.skipif(sys.platform == "win32", reason="Windows not [yet] supported")
-def test_uploadresource_image_call_already_uploaded(emitter, store_mock, config):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_uploadresource_image_call_already_uploaded(emitter, store_mock, config, formatted):
     """Upload an oci-image resource, the image itself already being in the registry."""
     # fake credentials for the charm/resource, and the final json content
     store_mock.get_oci_registry_credentials.return_value = RegistryCredentials(
@@ -4368,6 +4429,7 @@ def test_uploadresource_image_call_already_uploaded(emitter, store_mock, config)
         resource_name="myresource",
         filepath=None,
         image=original_image_digest,
+        format=formatted,
     )
     with patch("charmcraft.commands.store.ImageHandler", autospec=True) as im_class_mock:
         with patch("charmcraft.commands.store.OCIRegistry", autospec=True) as reg_class_mock:
@@ -4402,17 +4464,23 @@ def test_uploadresource_image_call_already_uploaded(emitter, store_mock, config)
         call.upload_resource("mycharm", "myresource", "oci-image", uploaded_resource_filepath),
     ]
 
-    emitter.assert_interactions(
-        [
-            call(
-                "progress",
-                "Uploading resource from image "
-                "charm/charm-id/test-image-name @ test-digest-given-by-user.",
-            ),
-            call("message", "Using OCI image from Canonical's registry.", intermediate=True),
-            call("message", "Revision 7 created of resource 'myresource' for charm 'mycharm'."),
-        ]
-    )
+    if formatted:
+        expected = {"revision": 7}
+        emitter.assert_json_output(expected)
+    else:
+        emitter.assert_interactions(
+            [
+                call(
+                    "progress",
+                    "Uploading resource from image "
+                    "charm/charm-id/test-image-name @ test-digest-given-by-user.",
+                ),
+                call("progress", "Using OCI image from Canonical's registry."),
+                call(
+                    "message", "Revision 7 created of resource 'myresource' for charm 'mycharm'."
+                ),
+            ]
+        )
 
 
 @pytest.mark.skipif(sys.platform == "win32", reason="Windows not [yet] supported")
@@ -4437,6 +4505,7 @@ def test_uploadresource_image_call_upload_from_local(emitter, store_mock, config
         resource_name="myresource",
         filepath=None,
         image=original_image_digest,
+        format=False,
     )
     with patch("charmcraft.commands.store.ImageHandler", autospec=True) as im_class_mock:
         with patch("charmcraft.commands.store.OCIRegistry", autospec=True) as reg_class_mock:
@@ -4471,14 +4540,12 @@ def test_uploadresource_image_call_upload_from_local(emitter, store_mock, config
                 "charm/charm-id/test-image-name @ test-digest-given-by-user.",
             ),
             call(
-                "message",
+                "progress",
                 "Remote image not found, uploading from local registry.",
-                intermediate=True,
             ),
             call(
-                "message",
+                "progress",
                 "Image uploaded, new remote digest: new-digest-after-upload.",
-                intermediate=True,
             ),
             call("message", "Revision 7 created of resource 'myresource' for charm 'mycharm'."),
         ]
@@ -4501,6 +4568,7 @@ def test_uploadresource_image_call_missing_everywhere(emitter, store_mock, confi
         resource_name="myresource",
         filepath=None,
         image=original_image_digest,
+        format=False,
     )
     with patch("charmcraft.commands.store.ImageHandler", autospec=True) as im_class_mock:
         with patch("charmcraft.commands.store.OCIRegistry", autospec=True) as reg_class_mock:
@@ -4532,21 +4600,20 @@ def test_uploadresource_image_call_missing_everywhere(emitter, store_mock, confi
                 "image charm/charm-id/test-image-name @ test-digest-given-by-user.",
             ),
             call(
-                "message",
+                "progress",
                 "Remote image not found, uploading from local registry.",
-                intermediate=True,
             ),
             call(
-                "message",
+                "progress",
                 "Image with digest test-digest-given-by-user is not available in "
                 "the Canonical's registry nor locally.",
-                intermediate=True,
             ),
         ]
     )
 
 
-def test_uploadresource_call_error(emitter, store_mock, config, tmp_path):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_uploadresource_call_error(emitter, store_mock, config, tmp_path, formatted):
     """Simple upload but with a response indicating an error."""
     errors = [
         Error(message="text 1", code="missing-stuff"),
@@ -4557,54 +4624,81 @@ def test_uploadresource_call_error(emitter, store_mock, config, tmp_path):
 
     test_resource = tmp_path / "mystuff.bin"
     test_resource.write_text("sample stuff")
-    args = Namespace(charm_name="mycharm", resource_name="myresource", filepath=test_resource)
+    args = Namespace(
+        charm_name="mycharm", resource_name="myresource", filepath=test_resource, format=formatted
+    )
     retcode = UploadResourceCommand(config).run(args)
     assert retcode == 1
 
-    emitter.assert_messages(
-        [
-            "Upload failed with status 400:",
-            "- missing-stuff: text 1",
-            "- broken: other long error text",
-        ]
-    )
+    if formatted:
+        expected = {
+            "errors": [
+                {"code": "missing-stuff", "message": "text 1"},
+                {"code": "broken", "message": "other long error text"},
+            ]
+        }
+        emitter.assert_json_output(expected)
+    else:
+        emitter.assert_messages(
+            [
+                "Upload failed with status 400:",
+                "- missing-stuff: text 1",
+                "- broken: other long error text",
+            ]
+        )
 
 
 # -- tests for list resource revisions command
 
 
-def test_resourcerevisions_simple(emitter, store_mock, config):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_resourcerevisions_simple(emitter, store_mock, config, formatted):
     """Happy path of one result from the Store."""
     store_response = [
         ResourceRevision(revision=1, size=50, created_at=datetime.datetime(2020, 7, 3, 2, 30, 40)),
     ]
     store_mock.list_resource_revisions.return_value = store_response
 
-    args = Namespace(charm_name="testcharm", resource_name="testresource")
+    args = Namespace(charm_name="testcharm", resource_name="testresource", format=formatted)
     ListResourceRevisionsCommand(config).run(args)
 
     assert store_mock.mock_calls == [
         call.list_resource_revisions("testcharm", "testresource"),
     ]
-    expected = [
-        "Revision    Created at              Size",
-        "1           2020-07-03T02:30:40Z     50B",
-    ]
-    emitter.assert_messages(expected)
+    if formatted:
+        expected = [
+            {
+                "revision": 1,
+                "created at": "2020-07-03T02:30:40Z",
+                "size": 50,
+            },
+        ]
+        emitter.assert_json_output(expected)
+    else:
+        expected = [
+            "Revision    Created at              Size",
+            "1           2020-07-03T02:30:40Z     50B",
+        ]
+        emitter.assert_messages(expected)
 
 
-def test_resourcerevisions_empty(emitter, store_mock, config):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_resourcerevisions_empty(emitter, store_mock, config, formatted):
     """No results from the store."""
     store_response = []
     store_mock.list_resource_revisions.return_value = store_response
 
-    args = Namespace(charm_name="testcharm", resource_name="testresource")
+    args = Namespace(charm_name="testcharm", resource_name="testresource", format=formatted)
     ListResourceRevisionsCommand(config).run(args)
 
-    emitter.assert_message("No revisions found.")
+    if formatted:
+        emitter.assert_json_output([])
+    else:
+        emitter.assert_message("No revisions found.")
 
 
-def test_resourcerevisions_ordered_by_revision(emitter, store_mock, config):
+@pytest.mark.parametrize("formatted", [None, JSON_FORMAT])
+def test_resourcerevisions_ordered_by_revision(emitter, store_mock, config, formatted):
     """Results are presented ordered by revision in the table."""
     # three Revisions with all values weirdly similar, the only difference is revision, so
     # we really assert later that it was used for ordering
@@ -4617,14 +4711,39 @@ def test_resourcerevisions_ordered_by_revision(emitter, store_mock, config):
     ]
     store_mock.list_resource_revisions.return_value = store_response
 
-    args = Namespace(charm_name="testcharm", resource_name="testresource")
+    args = Namespace(charm_name="testcharm", resource_name="testresource", format=formatted)
     ListResourceRevisionsCommand(config).run(args)
 
-    expected = [
-        "Revision    Created at              Size",
-        "4           2020-07-03T20:30:40Z  856.0K",
-        "3           2020-07-03T20:30:40Z   32.9M",
-        "2           2020-07-03T20:30:40Z     50B",
-        "1           2020-07-03T20:30:40Z    4.9K",
-    ]
-    emitter.assert_messages(expected)
+    if formatted:
+        expected = [
+            {
+                "revision": 1,
+                "created at": "2020-07-03T20:30:40Z",
+                "size": 5000,
+            },
+            {
+                "revision": 3,
+                "created at": "2020-07-03T20:30:40Z",
+                "size": 34450520,
+            },
+            {
+                "revision": 4,
+                "created at": "2020-07-03T20:30:40Z",
+                "size": 876543,
+            },
+            {
+                "revision": 2,
+                "created at": "2020-07-03T20:30:40Z",
+                "size": 50,
+            },
+        ]
+        emitter.assert_json_output(expected)
+    else:
+        expected = [
+            "Revision    Created at              Size",
+            "4           2020-07-03T20:30:40Z  856.0K",
+            "3           2020-07-03T20:30:40Z   32.9M",
+            "2           2020-07-03T20:30:40Z     50B",
+            "1           2020-07-03T20:30:40Z    4.9K",
+        ]
+        emitter.assert_messages(expected)

approach for using store commands programmatically 
Hello,

We are trying to create some release infrastructure to help us automate releasing charms to the store. Is anyone currently using store commands  programmatically? It seems we currently need to auth against the ubuntu one from the browser. Is there a way to do this without a human?

Thanks
tests/commands/test_store_commands.py::test_resources_simple[json] tests/commands/test_store_commands.py::test_resources_empty[json] tests/commands/test_store_commands.py::test_resources_ordered_and_grouped[json] tests/commands/test_store_commands.py::test_uploadresource_filepath_call_ok[json] tests/commands/test_store_commands.py::test_uploadresource_image_call_already_uploaded[None] tests/commands/test_store_commands.py::test_uploadresource_image_call_already_uploaded[json] tests/commands/test_store_commands.py::test_uploadresource_image_call_upload_from_local tests/commands/test_store_commands.py::test_uploadresource_image_call_missing_everywhere tests/commands/test_store_commands.py::test_uploadresource_call_error[json] tests/commands/test_store_commands.py::test_resourcerevisions_simple[json] tests/commands/test_store_commands.py::test_resourcerevisions_empty[json] tests/commands/test_store_commands.py::test_resourcerevisions_ordered_by_revision[json]
tests/commands/test_store_commands.py::test_get_name_from_metadata_ok tests/commands/test_store_commands.py::test_get_name_from_metadata_no_file tests/commands/test_store_commands.py::test_get_name_from_metadata_bad_content_garbage tests/commands/test_store_commands.py::test_get_name_from_metadata_bad_content_no_name tests/commands/test_store_commands.py::test_login_simple tests/commands/test_store_commands.py::test_login_exporting tests/commands/test_store_commands.py::test_login_restrictions_without_export[charm] tests/commands/test_store_commands.py::test_login_restrictions_without_export[bundle] tests/commands/test_store_commands.py::test_login_restrictions_without_export[permission] tests/commands/test_store_commands.py::test_login_restrictions_without_export[channel] tests/commands/test_store_commands.py::test_login_restrictions_without_export[ttl] tests/commands/test_store_commands.py::test_login_restricting_ttl tests/commands/test_store_commands.py::test_login_restricting_channels tests/commands/test_store_commands.py::test_login_restricting_permissions tests/commands/test_store_commands.py::test_login_restricting_permission_invalid tests/commands/test_store_commands.py::test_login_restricting_charms tests/commands/test_store_commands.py::test_login_restricting_bundles tests/commands/test_store_commands.py::test_login_restriction_mix tests/commands/test_store_commands.py::test_logout tests/commands/test_store_commands.py::test_logout_but_not_logged_in tests/commands/test_store_commands.py::test_whoami[None] tests/commands/test_store_commands.py::test_whoami[json] tests/commands/test_store_commands.py::test_whoami_but_not_logged_in[None] tests/commands/test_store_commands.py::test_whoami_but_not_logged_in[json] tests/commands/test_store_commands.py::test_whoami_with_channels[None] tests/commands/test_store_commands.py::test_whoami_with_channels[json] tests/commands/test_store_commands.py::test_whoami_with_charms[None] tests/commands/test_store_commands.py::test_whoami_with_charms[json] tests/commands/test_store_commands.py::test_whoami_with_bundles[None] tests/commands/test_store_commands.py::test_whoami_with_bundles[json] tests/commands/test_store_commands.py::test_whoami_comprehensive tests/commands/test_store_commands.py::test_register_charm_name tests/commands/test_store_commands.py::test_register_bundle_name tests/commands/test_store_commands.py::test_list_registered_empty[None] tests/commands/test_store_commands.py::test_list_registered_empty[json] tests/commands/test_store_commands.py::test_list_registered_one_private[None] tests/commands/test_store_commands.py::test_list_registered_one_private[json] tests/commands/test_store_commands.py::test_list_registered_one_public[None] tests/commands/test_store_commands.py::test_list_registered_one_public[json] tests/commands/test_store_commands.py::test_list_registered_several[None] tests/commands/test_store_commands.py::test_list_registered_several[json] tests/commands/test_store_commands.py::test_get_name_bad_zip tests/commands/test_store_commands.py::test_get_name_charm_ok tests/commands/test_store_commands.py::test_get_name_charm_bad_metadata[=] tests/commands/test_store_commands.py::test_get_name_charm_bad_metadata[foo: tests/commands/test_store_commands.py::test_get_name_bundle_ok tests/commands/test_store_commands.py::test_get_name_bundle_bad_data[=] tests/commands/test_store_commands.py::test_get_name_bundle_bad_data[foo: tests/commands/test_store_commands.py::test_get_name_nor_charm_nor_bundle tests/commands/test_store_commands.py::test_upload_parameters_filepath_type tests/commands/test_store_commands.py::test_upload_call_ok[None] tests/commands/test_store_commands.py::test_upload_call_ok[json] tests/commands/test_store_commands.py::test_upload_call_error[None] tests/commands/test_store_commands.py::test_upload_call_error[json] tests/commands/test_store_commands.py::test_upload_call_ok_including_release[None] tests/commands/test_store_commands.py::test_upload_call_ok_including_release[json] tests/commands/test_store_commands.py::test_upload_call_ok_including_release_multiple tests/commands/test_store_commands.py::test_upload_including_release_with_resources[None] tests/commands/test_store_commands.py::test_upload_including_release_with_resources[json] tests/commands/test_store_commands.py::test_upload_options_resource tests/commands/test_store_commands.py::test_upload_call_error_including_release tests/commands/test_store_commands.py::test_upload_charm_with_init_template_todo_token tests/commands/test_store_commands.py::test_upload_with_different_name_than_in_metadata tests/commands/test_store_commands.py::test_revisions_simple[None] tests/commands/test_store_commands.py::test_revisions_simple[json] tests/commands/test_store_commands.py::test_revisions_empty[None] tests/commands/test_store_commands.py::test_revisions_empty[json] tests/commands/test_store_commands.py::test_revisions_ordered_by_revision[None] tests/commands/test_store_commands.py::test_revisions_ordered_by_revision[json] tests/commands/test_store_commands.py::test_revisions_version_null[None] tests/commands/test_store_commands.py::test_revisions_version_null[json] tests/commands/test_store_commands.py::test_revisions_errors_simple[None] tests/commands/test_store_commands.py::test_revisions_errors_simple[json] tests/commands/test_store_commands.py::test_revisions_errors_multiple[None] tests/commands/test_store_commands.py::test_revisions_errors_multiple[json] tests/commands/test_store_commands.py::test_release_simple_ok tests/commands/test_store_commands.py::test_release_simple_multiple_channels tests/commands/test_store_commands.py::test_release_including_resources tests/commands/test_store_commands.py::test_release_options_resource tests/commands/test_store_commands.py::test_release_parameters_ok[sysargs0-expected_parsed0] tests/commands/test_store_commands.py::test_release_parameters_ok[sysargs1-expected_parsed1] tests/commands/test_store_commands.py::test_release_parameters_ok[sysargs2-expected_parsed2] tests/commands/test_store_commands.py::test_release_parameters_ok[sysargs3-expected_parsed3] tests/commands/test_store_commands.py::test_release_parameters_ok[sysargs4-expected_parsed4] tests/commands/test_store_commands.py::test_release_parameters_ok[sysargs5-expected_parsed5] tests/commands/test_store_commands.py::test_release_parameters_ok[sysargs6-expected_parsed6] tests/commands/test_store_commands.py::test_release_parameters_bad[sysargs0] tests/commands/test_store_commands.py::test_release_parameters_bad[sysargs1] tests/commands/test_store_commands.py::test_release_parameters_bad[sysargs2] tests/commands/test_store_commands.py::test_release_parameters_bad[sysargs3] tests/commands/test_store_commands.py::test_release_parameters_bad[sysargs4] tests/commands/test_store_commands.py::test_release_parameters_bad[sysargs5] tests/commands/test_store_commands.py::test_close_simple_ok tests/commands/test_store_commands.py::test_status_simple_ok[None] tests/commands/test_store_commands.py::test_status_simple_ok[json] tests/commands/test_store_commands.py::test_status_empty[None] tests/commands/test_store_commands.py::test_status_empty[json] tests/commands/test_store_commands.py::test_status_channels_not_released_with_fallback[None] tests/commands/test_store_commands.py::test_status_channels_not_released_with_fallback[json] tests/commands/test_store_commands.py::test_status_channels_not_released_without_fallback[None] tests/commands/test_store_commands.py::test_status_channels_not_released_without_fallback[json] tests/commands/test_store_commands.py::test_status_multiple_tracks[None] tests/commands/test_store_commands.py::test_status_multiple_tracks[json] tests/commands/test_store_commands.py::test_status_tracks_order tests/commands/test_store_commands.py::test_status_with_one_branch[None] tests/commands/test_store_commands.py::test_status_with_one_branch[json] tests/commands/test_store_commands.py::test_status_with_multiple_branches tests/commands/test_store_commands.py::test_status_with_resources[None] tests/commands/test_store_commands.py::test_status_with_resources[json] tests/commands/test_store_commands.py::test_status_with_resources_missing_after_closed_channel tests/commands/test_store_commands.py::test_status_with_resources_and_branches tests/commands/test_store_commands.py::test_status_multiplebases_single_track[None] tests/commands/test_store_commands.py::test_status_multiplebases_single_track[json] tests/commands/test_store_commands.py::test_status_multiplebases_multiple_tracks tests/commands/test_store_commands.py::test_status_multiplebases_everything_combined tests/commands/test_store_commands.py::test_status_with_base_in_none[None] tests/commands/test_store_commands.py::test_status_with_base_in_none[json] tests/commands/test_store_commands.py::test_status_unreleased_track tests/commands/test_store_commands.py::test_createlib_simple[None] tests/commands/test_store_commands.py::test_createlib_simple[json] tests/commands/test_store_commands.py::test_createlib_name_from_metadata_problem tests/commands/test_store_commands.py::test_createlib_name_contains_dash tests/commands/test_store_commands.py::test_createlib_invalid_name[foo.bar] tests/commands/test_store_commands.py::test_createlib_invalid_name[foo/bar] tests/commands/test_store_commands.py::test_createlib_invalid_name[Foo] tests/commands/test_store_commands.py::test_createlib_invalid_name[123foo] tests/commands/test_store_commands.py::test_createlib_invalid_name[_foo] tests/commands/test_store_commands.py::test_createlib_invalid_name[] tests/commands/test_store_commands.py::test_createlib_path_already_there tests/commands/test_store_commands.py::test_createlib_library_template_is_python tests/commands/test_store_commands.py::test_publishlib_simple[None] tests/commands/test_store_commands.py::test_publishlib_simple[json] tests/commands/test_store_commands.py::test_publishlib_contains_dash tests/commands/test_store_commands.py::test_publishlib_all[None] tests/commands/test_store_commands.py::test_publishlib_all[json] tests/commands/test_store_commands.py::test_publishlib_not_found tests/commands/test_store_commands.py::test_publishlib_not_from_current_charm tests/commands/test_store_commands.py::test_publishlib_name_from_metadata_problem tests/commands/test_store_commands.py::test_publishlib_store_is_advanced[None] tests/commands/test_store_commands.py::test_publishlib_store_is_advanced[json] tests/commands/test_store_commands.py::test_publishlib_store_is_exactly_behind_ok tests/commands/test_store_commands.py::test_publishlib_store_is_exactly_behind_same_hash[None] tests/commands/test_store_commands.py::test_publishlib_store_is_exactly_behind_same_hash[json] tests/commands/test_store_commands.py::test_publishlib_store_is_too_behind[None] tests/commands/test_store_commands.py::test_publishlib_store_is_too_behind[json] tests/commands/test_store_commands.py::test_publishlib_store_has_same_revision_same_hash[None] tests/commands/test_store_commands.py::test_publishlib_store_has_same_revision_same_hash[json] tests/commands/test_store_commands.py::test_publishlib_store_has_same_revision_other_hash[None] tests/commands/test_store_commands.py::test_publishlib_store_has_same_revision_other_hash[json] tests/commands/test_store_commands.py::test_getlibinfo_success_simple tests/commands/test_store_commands.py::test_getlibinfo_success_content tests/commands/test_store_commands.py::test_getlibinfo_bad_name[charms.testcharm.v3.testlib.py] tests/commands/test_store_commands.py::test_getlibinfo_bad_name[charms.testcharm.testlib] tests/commands/test_store_commands.py::test_getlibinfo_bad_name[testcharm.v2.testlib] tests/commands/test_store_commands.py::test_getlibinfo_bad_name[mycharms.testcharm.v2.testlib] tests/commands/test_store_commands.py::test_getlibinfo_not_importable_charm_name tests/commands/test_store_commands.py::test_getlibinfo_bad_path[charms/testcharm/v3/testlib] tests/commands/test_store_commands.py::test_getlibinfo_bad_path[charms/testcharm/v3/testlib.html] tests/commands/test_store_commands.py::test_getlibinfo_bad_path[charms/testcharm/v3/testlib.] tests/commands/test_store_commands.py::test_getlibinfo_bad_path[charms/testcharm/testlib.py] tests/commands/test_store_commands.py::test_getlibinfo_bad_path[testcharm/v2/testlib.py] tests/commands/test_store_commands.py::test_getlibinfo_bad_path[mycharms/testcharm/v2/testlib.py] tests/commands/test_store_commands.py::test_getlibinfo_bad_api[charms.testcharm.v-three.testlib] tests/commands/test_store_commands.py::test_getlibinfo_bad_api[charms.testcharm.v-3.testlib] tests/commands/test_store_commands.py::test_getlibinfo_bad_api[charms.testcharm.3.testlib] tests/commands/test_store_commands.py::test_getlibinfo_bad_api[charms.testcharm.vX.testlib] tests/commands/test_store_commands.py::test_getlibinfo_missing_library_from_name tests/commands/test_store_commands.py::test_getlibinfo_missing_library_from_path tests/commands/test_store_commands.py::test_getlibinfo_malformed_metadata_field tests/commands/test_store_commands.py::test_getlibinfo_missing_metadata_field tests/commands/test_store_commands.py::test_getlibinfo_api_not_int tests/commands/test_store_commands.py::test_getlibinfo_api_negative tests/commands/test_store_commands.py::test_getlibinfo_patch_not_int tests/commands/test_store_commands.py::test_getlibinfo_patch_negative tests/commands/test_store_commands.py::test_getlibinfo_api_patch_both_zero tests/commands/test_store_commands.py::test_getlibinfo_metadata_api_different_path_api tests/commands/test_store_commands.py::test_getlibinfo_libid_non_string tests/commands/test_store_commands.py::test_getlibinfo_libid_non_ascii tests/commands/test_store_commands.py::test_getlibinfo_libid_empty tests/commands/test_store_commands.py::test_fetchlib_simple_downloaded[None] tests/commands/test_store_commands.py::test_fetchlib_simple_downloaded[json] tests/commands/test_store_commands.py::test_fetchlib_simple_dash_in_name tests/commands/test_store_commands.py::test_fetchlib_simple_dash_in_name_on_disk tests/commands/test_store_commands.py::test_fetchlib_simple_updated tests/commands/test_store_commands.py::test_fetchlib_all[None] tests/commands/test_store_commands.py::test_fetchlib_all[json] tests/commands/test_store_commands.py::test_fetchlib_store_not_found[None] tests/commands/test_store_commands.py::test_fetchlib_store_not_found[json] tests/commands/test_store_commands.py::test_fetchlib_store_is_old[None] tests/commands/test_store_commands.py::test_fetchlib_store_is_old[json] tests/commands/test_store_commands.py::test_fetchlib_store_same_versions_same_hash[None] tests/commands/test_store_commands.py::test_fetchlib_store_same_versions_same_hash[json] tests/commands/test_store_commands.py::test_fetchlib_store_same_versions_different_hash[None] tests/commands/test_store_commands.py::test_fetchlib_store_same_versions_different_hash[json] tests/commands/test_store_commands.py::test_listlib_simple[None] tests/commands/test_store_commands.py::test_listlib_simple[json] tests/commands/test_store_commands.py::test_listlib_charm_from_metadata tests/commands/test_store_commands.py::test_listlib_name_from_metadata_problem tests/commands/test_store_commands.py::test_listlib_empty[None] tests/commands/test_store_commands.py::test_listlib_empty[json] tests/commands/test_store_commands.py::test_listlib_properly_sorted[None] tests/commands/test_store_commands.py::test_listlib_properly_sorted[json] tests/commands/test_store_commands.py::test_resources_simple[None] tests/commands/test_store_commands.py::test_resources_empty[None] tests/commands/test_store_commands.py::test_resources_ordered_and_grouped[None] tests/commands/test_store_commands.py::test_uploadresource_options_filepath_type tests/commands/test_store_commands.py::test_uploadresource_options_image_type tests/commands/test_store_commands.py::test_uploadresource_options_good_combinations[sysargs0] tests/commands/test_store_commands.py::test_uploadresource_options_good_combinations[sysargs1] tests/commands/test_store_commands.py::test_uploadresource_options_bad_combinations[sysargs0] tests/commands/test_store_commands.py::test_uploadresource_options_bad_combinations[sysargs1] tests/commands/test_store_commands.py::test_uploadresource_filepath_call_ok[None] tests/commands/test_store_commands.py::test_uploadresource_call_error[None] tests/commands/test_store_commands.py::test_resourcerevisions_simple[None] tests/commands/test_store_commands.py::test_resourcerevisions_empty[None] tests/commands/test_store_commands.py::test_resourcerevisions_ordered_by_revision[None]