cloudsmith-cli 1.27.0__tar.gz → 1.28.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cloudsmith_cli-1.27.0/cloudsmith_cli.egg-info → cloudsmith_cli-1.28.0}/PKG-INFO +4 -3
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/credential_helper/__init__.py +6 -4
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/credential_helper/docker.py +8 -1
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/credential_helper/terraform.py +4 -2
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/domains.py +1 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/entitlements.py +9 -8
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/list_.py +1 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/main.py +11 -1
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/mcp.py +7 -5
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/metadata.py +1 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/registry.py +2 -0
- cloudsmith_cli-1.28.0/cloudsmith_cli/cli/commands/update.py +170 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/config.py +13 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/utils.py +8 -3
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/webserver.py +12 -7
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/download.py +2 -1
- cloudsmith_cli-1.28.0/cloudsmith_cli/core/installation.py +156 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/keyring.py +45 -6
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/mcp/server.py +108 -15
- cloudsmith_cli-1.28.0/cloudsmith_cli/core/self_update.py +429 -0
- cloudsmith_cli-1.28.0/cloudsmith_cli/core/update_check.py +474 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/utils.py +15 -0
- cloudsmith_cli-1.28.0/cloudsmith_cli/data/VERSION +1 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/data/config.ini +3 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0/cloudsmith_cli.egg-info}/PKG-INFO +4 -3
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli.egg-info/SOURCES.txt +4 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli.egg-info/requires.txt +3 -2
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/pyproject.toml +15 -12
- cloudsmith_cli-1.27.0/cloudsmith_cli/data/VERSION +0 -1
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/LICENSE +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/MANIFEST.in +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/README.md +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/__main__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/command.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/auth.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/check.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/copy.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/credential_helper/cargo.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/credential_helper/generic.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/credential_helper/manage.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/credential_helper/pnpm.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/delete.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/dependencies.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/docs.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/download.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/help_.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/login.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/logout.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/metrics/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/metrics/command.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/metrics/entitlements.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/metrics/packages.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/move.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/policy/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/policy/command.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/policy/deny.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/policy/license.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/policy/vulnerability.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/push.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/quarantine.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/quota/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/quota/command.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/quota/history.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/quota/quota.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/repos.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/resync.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/status.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/tags.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/tokens.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/upstream.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/vulnerabilities.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/commands/whoami.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/decorators.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/dsc_parser.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/exceptions.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/metadata_common.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/saml.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/table.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/types.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/cli/validators.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/conftest.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/distros.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/entitlements.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/exceptions.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/files.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/init.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/metadata.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/metrics.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/orgs.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/packages.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/quota.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/rates.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/repos.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/status.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/upstreams.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/user.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/version.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/api/vulnerabilities.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/cache_utils.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/config.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/chain.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/models.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/cache.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/aws.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/azure_devops.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/base.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/bitbucket_pipelines.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/circleci.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/generic.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/github_actions.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/detectors/gitlab_ci.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/oidc/exchange.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/provider.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/providers/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/providers/cli_flag.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/providers/credentials_file.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/providers/env_var.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/providers/keyring_provider.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/credentials/providers/oidc_provider.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/macos_keychain.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/mcp/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/mcp/data.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/pagination.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/ratelimits.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/rest.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/session.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/sso.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/core/version.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/backends.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/cargo/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/cargo/installer.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/cargo/runtime.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/common.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/custom_domains.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/default_domains.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/docker/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/docker/installer.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/docker/runtime.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/generic.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/launchers.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/pnpm/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/pnpm/installer.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/pnpm/rc.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/pnpm/runtime.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/terraform/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/terraform/installer.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/terraform/runtime.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/credential_helpers/terraform/terraformrc.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/data/credentials.ini +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/templates/__init__.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/templates/auth_error.html +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/templates/auth_success.html +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/templates/auth_two_factor.html +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli/wrapper.py +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli.egg-info/dependency_links.txt +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli.egg-info/entry_points.txt +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/cloudsmith_cli.egg-info/top_level.txt +0 -0
- {cloudsmith_cli-1.27.0 → cloudsmith_cli-1.28.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloudsmith-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.28.0
|
|
4
4
|
Summary: Cloudsmith Command-Line Interface (CLI)
|
|
5
5
|
Author-email: Cloudsmith Ltd <support@cloudsmith.io>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -23,6 +23,7 @@ Classifier: Topic :: Utilities
|
|
|
23
23
|
Requires-Python: >=3.10.0
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
|
+
Requires-Dist: certifi>=2024.7.4
|
|
26
27
|
Requires-Dist: click!=8.3.0,>=8.2
|
|
27
28
|
Requires-Dist: click-configfile>=0.2.3
|
|
28
29
|
Requires-Dist: click-didyoumean>=0.0.3
|
|
@@ -33,10 +34,10 @@ Requires-Dist: keyring>=25.4.1
|
|
|
33
34
|
Requires-Dist: keyrings-alt>=5.0.2
|
|
34
35
|
Requires-Dist: keyrings-cryptfile>=1.3.9
|
|
35
36
|
Requires-Dist: cryptography>=50.0.0
|
|
36
|
-
Requires-Dist: mcp==
|
|
37
|
+
Requires-Dist: mcp==2.2.0
|
|
37
38
|
Requires-Dist: pydantic-settings>=2.14.2
|
|
38
39
|
Requires-Dist: PyJWT[crypto]>=2.13.0
|
|
39
|
-
Requires-Dist: python-toon==0.1.
|
|
40
|
+
Requires-Dist: python-toon==0.1.3
|
|
40
41
|
Requires-Dist: requests>=2.18.4
|
|
41
42
|
Requires-Dist: requests_toolbelt>=1.0.0
|
|
42
43
|
Requires-Dist: rich>=13.0.0
|
|
@@ -27,18 +27,20 @@ def credential_helper():
|
|
|
27
27
|
manager automatically, or run the runtime command directly for debugging.
|
|
28
28
|
|
|
29
29
|
Examples:
|
|
30
|
+
|
|
31
|
+
\b
|
|
30
32
|
# Install Docker credential helper
|
|
31
33
|
$ cloudsmith credential-helper install docker
|
|
32
|
-
|
|
34
|
+
\b
|
|
33
35
|
# Install pnpm credential helper
|
|
34
36
|
$ cloudsmith credential-helper install pnpm
|
|
35
|
-
|
|
37
|
+
\b
|
|
36
38
|
# Install cargo credential helper
|
|
37
39
|
$ cloudsmith credential-helper install cargo
|
|
38
|
-
|
|
40
|
+
\b
|
|
39
41
|
# Test Docker credential helper directly
|
|
40
42
|
$ echo "docker.cloudsmith.io" | cloudsmith credential-helper docker
|
|
41
|
-
|
|
43
|
+
\b
|
|
42
44
|
# Test pnpm credential helper directly
|
|
43
45
|
$ cloudsmith credential-helper pnpm npm.cloudsmith.io
|
|
44
46
|
"""
|
|
@@ -33,23 +33,30 @@ def docker(opts, operation):
|
|
|
33
33
|
``workspace`` in ``config.ini``; legacy aliases are also accepted - and a
|
|
34
34
|
valid API key/token).
|
|
35
35
|
|
|
36
|
+
\b
|
|
36
37
|
Input (stdin):
|
|
37
38
|
Server URL as plain text (e.g. "docker.cloudsmith.io")
|
|
38
39
|
|
|
40
|
+
\b
|
|
39
41
|
Output (stdout):
|
|
40
42
|
JSON: {"Username": "token", "Secret": "<cloudsmith-token>"}
|
|
41
43
|
|
|
44
|
+
\b
|
|
42
45
|
Exit codes:
|
|
43
46
|
0: Success
|
|
44
47
|
1: Error (no credentials available, not a Cloudsmith registry, etc.)
|
|
45
48
|
|
|
49
|
+
\b
|
|
46
50
|
Examples:
|
|
51
|
+
|
|
52
|
+
\b
|
|
47
53
|
# Manual testing
|
|
48
54
|
$ echo "docker.cloudsmith.io" | cloudsmith credential-helper docker
|
|
49
|
-
|
|
55
|
+
\b
|
|
50
56
|
# Called by Docker via launcher
|
|
51
57
|
$ echo "docker.cloudsmith.io" | docker-credential-cloudsmith get
|
|
52
58
|
|
|
59
|
+
\b
|
|
53
60
|
Environment variables:
|
|
54
61
|
CLOUDSMITH_API_KEY: API key for authentication (optional)
|
|
55
62
|
CLOUDSMITH_WORKSPACE: Workspace slug (CLOUDSMITH_ORG is also accepted)
|
|
@@ -92,13 +92,15 @@ def terraform(opts, repo, params):
|
|
|
92
92
|
|
|
93
93
|
\b
|
|
94
94
|
Examples:
|
|
95
|
+
|
|
96
|
+
\b
|
|
95
97
|
# Direct usage
|
|
96
98
|
$ cloudsmith credential-helper terraform --repo my-repo terraform.cloudsmith.io
|
|
97
99
|
{"token": "..."}
|
|
98
|
-
|
|
100
|
+
\b
|
|
99
101
|
# Terraform's calling convention (verb + hostname)
|
|
100
102
|
$ cloudsmith credential-helper terraform --repo my-repo get terraform.cloudsmith.io
|
|
101
|
-
|
|
103
|
+
\b
|
|
102
104
|
# Select an org and profile explicitly (no env vars needed)
|
|
103
105
|
$ cloudsmith credential-helper terraform --org=acme -P ci get terraform.cloudsmith.io
|
|
104
106
|
|
|
@@ -162,6 +162,7 @@ def list_domains( # pylint: disable=too-many-arguments
|
|
|
162
162
|
paginated endpoint, so there is no benefit to hiding entries by default.
|
|
163
163
|
Passing --page or --page-size switches to paged output.
|
|
164
164
|
|
|
165
|
+
\b
|
|
165
166
|
Output (stdout):
|
|
166
167
|
JSON: {"version": 1, "domains": [{"host": ..., "format": ...,
|
|
167
168
|
"type": ..., "domain_type": ..., "workspace": ..., "repository": ...,
|
|
@@ -775,14 +775,15 @@ def restrict(
|
|
|
775
775
|
|
|
776
776
|
Full CLI example:
|
|
777
777
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
--limit-bandwidth
|
|
781
|
-
--limit-
|
|
782
|
-
--limit-num-
|
|
783
|
-
--limit-
|
|
784
|
-
--limit-
|
|
785
|
-
--limit-
|
|
778
|
+
\b
|
|
779
|
+
$ cloudsmith entitlements restrict cloudsmith/testing-private/9xGSdAxlIqIV \\
|
|
780
|
+
--limit-bandwidth=1 \\
|
|
781
|
+
--limit-bandwidth-unit=gigabyte \\
|
|
782
|
+
--limit-num-clients=10 \\
|
|
783
|
+
--limit-num-downloads=1000 \\
|
|
784
|
+
--limit-package-query="package-darwin-amd64 OR package-windows-amd64 OR package-linux-amd64" \\
|
|
785
|
+
--limit-path-query=tag:latest \\
|
|
786
|
+
--limit-date-range-from=2020-01-01T00:00:00Z \\
|
|
786
787
|
--limit-date-range-to=2077-01-01T00:00:00Z
|
|
787
788
|
"""
|
|
788
789
|
owner, repo, identifier = owner_repo_identifier
|
|
@@ -195,6 +195,7 @@ def packages(ctx, opts, owner_repo, page, page_size, query, sort, page_all):
|
|
|
195
195
|
|
|
196
196
|
--query 'name:^foo$ filename:.zip$ architecture:~x86'
|
|
197
197
|
|
|
198
|
+
\b
|
|
198
199
|
You can sort the results using --sort with these fields:
|
|
199
200
|
- date/-date: Sort by creation date
|
|
200
201
|
- downloads/-downloads: Sort by download count
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
4
|
|
|
5
|
+
from ...core import update_check
|
|
5
6
|
from ...core.api.version import get_version as get_api_version
|
|
6
7
|
from ...core.utils import get_github_website, get_help_website
|
|
7
8
|
from ...core.version import get_version as get_cli_version
|
|
@@ -56,13 +57,22 @@ For issues/contributing: {get_github_website()}
|
|
|
56
57
|
is_flag=True,
|
|
57
58
|
is_eager=True,
|
|
58
59
|
)
|
|
60
|
+
@click.option(
|
|
61
|
+
"--no-check-update",
|
|
62
|
+
is_flag=True,
|
|
63
|
+
default=False,
|
|
64
|
+
envvar="CLOUDSMITH_NO_UPDATE_CHECK",
|
|
65
|
+
help="Disable the once-a-day check for a newer version of the CLI.",
|
|
66
|
+
)
|
|
59
67
|
@decorators.common_cli_config_options
|
|
60
68
|
@decorators.common_cli_output_options
|
|
61
69
|
@click.pass_context
|
|
62
|
-
def main(ctx, opts, version):
|
|
70
|
+
def main(ctx, opts, version, no_check_update):
|
|
63
71
|
"""Handle entrypoint to CLI."""
|
|
64
72
|
# pylint: disable=unused-argument
|
|
65
73
|
|
|
74
|
+
update_check.arm(ctx, opts, no_check_update)
|
|
75
|
+
|
|
66
76
|
if version:
|
|
67
77
|
print_version(opts)
|
|
68
78
|
elif ctx.invoked_subcommand is None:
|
|
@@ -200,6 +200,7 @@ def configure(ctx, opts, client, is_global): # pylint: disable=unused-argument
|
|
|
200
200
|
"""
|
|
201
201
|
Configure the Cloudsmith MCP server for supported clients.
|
|
202
202
|
|
|
203
|
+
\b
|
|
203
204
|
This command automatically adds the Cloudsmith MCP server configuration
|
|
204
205
|
to the specified client's configuration file. Supported clients are:
|
|
205
206
|
- Claude Desktop
|
|
@@ -211,11 +212,12 @@ def configure(ctx, opts, client, is_global): # pylint: disable=unused-argument
|
|
|
211
212
|
For Claude Code, --global edits ~/.claude.json (user scope) and
|
|
212
213
|
--local writes ./.mcp.json (project scope, intended to be committed).
|
|
213
214
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
cloudsmith mcp configure --client claude
|
|
217
|
-
cloudsmith mcp configure --client
|
|
218
|
-
cloudsmith mcp configure --client
|
|
215
|
+
\b
|
|
216
|
+
Examples:
|
|
217
|
+
cloudsmith mcp configure --client claude
|
|
218
|
+
cloudsmith mcp configure --client claude-code
|
|
219
|
+
cloudsmith mcp configure --client cursor --local
|
|
220
|
+
cloudsmith mcp configure --client gemini-cli
|
|
219
221
|
cloudsmith mcp configure # Auto-detect and configure all
|
|
220
222
|
"""
|
|
221
223
|
|
|
@@ -37,6 +37,7 @@ LAZY_COMMANDS = {
|
|
|
37
37
|
"status": f"{_PACKAGE}.status",
|
|
38
38
|
"tags": f"{_PACKAGE}.tags",
|
|
39
39
|
"tokens": f"{_PACKAGE}.tokens",
|
|
40
|
+
"update": f"{_PACKAGE}.update",
|
|
40
41
|
"upstream": f"{_PACKAGE}.upstream",
|
|
41
42
|
"vulnerabilities": f"{_PACKAGE}.vulnerabilities",
|
|
42
43
|
"whoami": f"{_PACKAGE}.whoami",
|
|
@@ -56,4 +57,5 @@ LAZY_ALIASES = {
|
|
|
56
57
|
"quarantine": ["block"],
|
|
57
58
|
"repositories": ["repos"],
|
|
58
59
|
"tags": ["tag"],
|
|
60
|
+
"update": ["upgrade"],
|
|
59
61
|
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Copyright 2026 Cloudsmith Ltd
|
|
2
|
+
"""CLI/Commands - Update the CLI to the latest released version."""
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from ...core import installation, self_update, update_check
|
|
7
|
+
from ...core.session import create_requests_session
|
|
8
|
+
from ...core.version import get_version, parse_version
|
|
9
|
+
from .. import decorators, utils
|
|
10
|
+
from ..utils import maybe_spinner
|
|
11
|
+
from .main import main
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _fetch_manifest(opts, session, target):
|
|
15
|
+
import requests
|
|
16
|
+
|
|
17
|
+
# A non-standalone channel on a platform without a recognised standalone
|
|
18
|
+
# target has ``target is None``; the manifest is still fetched only to read
|
|
19
|
+
# the latest *version* (the channel prints its own upgrade command), so fall
|
|
20
|
+
# back to a known target rather than building a ``manifest-None`` URL. The
|
|
21
|
+
# standalone path guards ``target is None`` before reaching here.
|
|
22
|
+
target = target or update_check.VERSION_PROBE_TARGET
|
|
23
|
+
try:
|
|
24
|
+
with maybe_spinner(opts):
|
|
25
|
+
return update_check.fetch_latest_manifest(session, target=target)
|
|
26
|
+
except (requests.RequestException, ValueError) as exc:
|
|
27
|
+
raise click.ClickException(f"Failed to fetch the latest version: {exc}")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _is_up_to_date(latest, current):
|
|
31
|
+
try:
|
|
32
|
+
return parse_version(latest) <= parse_version(current)
|
|
33
|
+
except ValueError as exc:
|
|
34
|
+
raise click.ClickException(f"Cannot compare versions: {exc}")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _confirm_self_update(opts, current, latest, assume_yes):
|
|
38
|
+
"""Return True to proceed with the self-update.
|
|
39
|
+
|
|
40
|
+
Auto-confirms when ``--yes`` is given, when output is machine-readable, or
|
|
41
|
+
when stderr is not a terminal (so scripted/piped invocations do not hang on
|
|
42
|
+
a prompt).
|
|
43
|
+
"""
|
|
44
|
+
if assume_yes or utils.should_use_stderr(opts) or not update_check.stderr_is_tty():
|
|
45
|
+
return True
|
|
46
|
+
return click.confirm(
|
|
47
|
+
f"Update the Cloudsmith CLI from {current} to {latest}?", default=True
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _run_self_update(opts, session, manifest, data):
|
|
52
|
+
import requests
|
|
53
|
+
|
|
54
|
+
use_stderr = utils.should_use_stderr(opts)
|
|
55
|
+
click.echo(
|
|
56
|
+
f"Downloading and installing version {manifest['version']} ... ",
|
|
57
|
+
nl=False,
|
|
58
|
+
err=use_stderr,
|
|
59
|
+
)
|
|
60
|
+
try:
|
|
61
|
+
with maybe_spinner(opts):
|
|
62
|
+
self_update.perform_self_update(manifest, session=session)
|
|
63
|
+
except (self_update.SelfUpdateError, requests.RequestException, OSError) as exc:
|
|
64
|
+
click.secho("ERROR", fg="red", err=use_stderr)
|
|
65
|
+
raise click.ClickException(str(exc))
|
|
66
|
+
click.secho("OK", fg="green", err=use_stderr)
|
|
67
|
+
data["upgraded"] = True
|
|
68
|
+
if utils.maybe_print_as_json(opts, data):
|
|
69
|
+
return
|
|
70
|
+
click.echo(f"The Cloudsmith CLI is now at version {manifest['version']}.")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _print_manual_update(opts, current, latest, manifest, data):
|
|
74
|
+
"""Report a manual-update path when self-update cannot run (Windows).
|
|
75
|
+
|
|
76
|
+
The command already holds the host manifest, so it shows the exact archive
|
|
77
|
+
URL and checksum rather than a vague pointer; it exits 0 so scripts do not
|
|
78
|
+
treat "update available, self-update unsupported" as a failure.
|
|
79
|
+
"""
|
|
80
|
+
changelog = installation.changelog_url(latest)
|
|
81
|
+
data["outcome"] = "manual"
|
|
82
|
+
data["download_url"] = manifest.get("url")
|
|
83
|
+
data["sha256"] = manifest.get("sha256")
|
|
84
|
+
data["archive"] = manifest.get("archive")
|
|
85
|
+
data["changelog_url"] = changelog
|
|
86
|
+
if utils.maybe_print_as_json(opts, data):
|
|
87
|
+
return
|
|
88
|
+
click.echo(
|
|
89
|
+
f"A new version of the Cloudsmith CLI is available: {current} \u2192 {latest}"
|
|
90
|
+
)
|
|
91
|
+
click.echo(f"See what's changed: {changelog}")
|
|
92
|
+
click.echo("Self-update is not supported for the standalone binary on Windows.")
|
|
93
|
+
click.echo(
|
|
94
|
+
"Download and extract this archive, then replace your install directory:"
|
|
95
|
+
)
|
|
96
|
+
click.echo(f" URL: {manifest['url']}")
|
|
97
|
+
click.echo(f" SHA256: {manifest['sha256']}")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@main.command(aliases=["upgrade"])
|
|
101
|
+
@click.option(
|
|
102
|
+
"-y",
|
|
103
|
+
"--yes",
|
|
104
|
+
"assume_yes",
|
|
105
|
+
is_flag=True,
|
|
106
|
+
default=False,
|
|
107
|
+
help="Do not prompt for confirmation before installing an update.",
|
|
108
|
+
)
|
|
109
|
+
@decorators.common_cli_config_options
|
|
110
|
+
@decorators.common_cli_output_options
|
|
111
|
+
@click.pass_context
|
|
112
|
+
def update(ctx, opts, assume_yes):
|
|
113
|
+
"""Update the Cloudsmith CLI to the latest released version.
|
|
114
|
+
|
|
115
|
+
The check runs on every invocation, independent of the once-a-day
|
|
116
|
+
background version check. A standalone binary downloads and installs the
|
|
117
|
+
latest release in place; every other install channel is told the correct
|
|
118
|
+
upgrade command for that channel.
|
|
119
|
+
"""
|
|
120
|
+
# pylint: disable=unused-argument
|
|
121
|
+
current = get_version()
|
|
122
|
+
channel = installation.detect_channel()
|
|
123
|
+
target = installation.detect_target()
|
|
124
|
+
if channel == installation.CHANNEL_STANDALONE and target is None:
|
|
125
|
+
raise click.ClickException(
|
|
126
|
+
"Cannot detect a supported platform for the standalone binary."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
session = create_requests_session(user_agent=opts.api_user_agent)
|
|
130
|
+
manifest = _fetch_manifest(opts, session, target)
|
|
131
|
+
latest = manifest["version"]
|
|
132
|
+
|
|
133
|
+
# Stamp both timestamps regardless of the outcome: the user has just run an
|
|
134
|
+
# explicit check, so the background notice's daily re-nag is disarmed.
|
|
135
|
+
update_check.record_checked_and_notified(latest)
|
|
136
|
+
|
|
137
|
+
data = {"current_version": current, "latest_version": latest, "channel": channel}
|
|
138
|
+
|
|
139
|
+
if _is_up_to_date(latest, current):
|
|
140
|
+
data["up_to_date"] = True
|
|
141
|
+
if not utils.maybe_print_as_json(opts, data):
|
|
142
|
+
click.echo(f"The Cloudsmith CLI is up to date (version {current}).")
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
instruction = installation.upgrade_instruction(channel)
|
|
146
|
+
if instruction is not None:
|
|
147
|
+
changelog = installation.changelog_url(latest)
|
|
148
|
+
data["upgrade_command"] = instruction
|
|
149
|
+
data["changelog_url"] = changelog
|
|
150
|
+
if utils.maybe_print_as_json(opts, data):
|
|
151
|
+
return
|
|
152
|
+
click.echo(
|
|
153
|
+
f"A new version of the Cloudsmith CLI is available: {current} \u2192 {latest}"
|
|
154
|
+
)
|
|
155
|
+
click.echo(f"See what's changed: {changelog}")
|
|
156
|
+
click.echo(f"The CLI was installed via {channel}. To update, run:")
|
|
157
|
+
click.echo(f" {instruction}")
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
if not installation.self_update_supported():
|
|
161
|
+
_print_manual_update(opts, current, latest, manifest, data)
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
if not _confirm_self_update(opts, current, latest, assume_yes):
|
|
165
|
+
data["upgraded"] = False
|
|
166
|
+
if not utils.maybe_print_as_json(opts, data):
|
|
167
|
+
click.echo("Update cancelled.")
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
_run_self_update(opts, session, manifest, data)
|
|
@@ -75,6 +75,7 @@ class ConfigSchema:
|
|
|
75
75
|
oidc_detector_order = ConfigParam(name="oidc_detector_order", type=str)
|
|
76
76
|
oidc_disabled_detectors = ConfigParam(name="oidc_disabled_detectors", type=str)
|
|
77
77
|
metadata_failure_mode = ConfigParam(name="metadata_failure_mode", type=str)
|
|
78
|
+
check_for_update = ConfigParam(name="check_for_update", type=bool, default=True)
|
|
78
79
|
|
|
79
80
|
@matches_section("profile:*")
|
|
80
81
|
class Profile(Default):
|
|
@@ -602,6 +603,18 @@ class Options: # pylint: disable=too-many-public-methods
|
|
|
602
603
|
)
|
|
603
604
|
self._set_option("metadata_failure_mode", normalised)
|
|
604
605
|
|
|
606
|
+
@property
|
|
607
|
+
def check_for_update(self):
|
|
608
|
+
"""Get value for the once-a-day update check toggle."""
|
|
609
|
+
return self._get_option("check_for_update", default=True)
|
|
610
|
+
|
|
611
|
+
@check_for_update.setter
|
|
612
|
+
def check_for_update(self, value):
|
|
613
|
+
"""Set value for the once-a-day update check toggle."""
|
|
614
|
+
if value is None:
|
|
615
|
+
return
|
|
616
|
+
self._set_option("check_for_update", bool(value))
|
|
617
|
+
|
|
605
618
|
@property
|
|
606
619
|
def output(self):
|
|
607
620
|
"""Get value for output format."""
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import platform
|
|
5
|
+
import sys
|
|
5
6
|
from contextlib import contextmanager
|
|
6
7
|
from datetime import date, datetime
|
|
7
8
|
|
|
@@ -75,7 +76,7 @@ def rich_print_table(headers, rows, title=None, show_lines=False):
|
|
|
75
76
|
from rich.console import Console
|
|
76
77
|
from rich.table import Table
|
|
77
78
|
|
|
78
|
-
console = Console()
|
|
79
|
+
console = Console(width=(None if sys.stdout.isatty() else 1000))
|
|
79
80
|
table = Table(title=title, show_lines=show_lines)
|
|
80
81
|
|
|
81
82
|
for header in headers:
|
|
@@ -231,8 +232,12 @@ def confirm_operation(prompt, prefix=None, assume_yes=False, err=False):
|
|
|
231
232
|
@contextmanager
|
|
232
233
|
def maybe_spinner(opts):
|
|
233
234
|
"""Only activate the spinner if not in debug mode or using json output."""
|
|
234
|
-
if
|
|
235
|
-
|
|
235
|
+
if (
|
|
236
|
+
getattr(opts, "debug", False)
|
|
237
|
+
or should_use_stderr(opts)
|
|
238
|
+
or get_output_format(opts) in ("json", "pretty_json")
|
|
239
|
+
):
|
|
240
|
+
# No spinner (debug logs / machine output must not be clobbered)
|
|
236
241
|
yield
|
|
237
242
|
else:
|
|
238
243
|
with spinner() as spin:
|
|
@@ -240,13 +240,18 @@ class AuthenticationWebRequestHandler(BaseHTTPRequestHandler):
|
|
|
240
240
|
if self.server_instance:
|
|
241
241
|
self.server_instance.sso_access_token = access_token
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
243
|
+
from keyring.errors import KeyringError
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
if not store_sso_tokens(
|
|
247
|
+
self.api_host, access_token, refresh_token, profile=self.profile
|
|
248
|
+
):
|
|
249
|
+
click.echo(
|
|
250
|
+
"SSO tokens not stored (CLOUDSMITH_NO_KEYRING is set)",
|
|
251
|
+
err=True,
|
|
252
|
+
)
|
|
253
|
+
except KeyringError as exc:
|
|
254
|
+
click.echo(f"SSO tokens not stored: {exc}", err=True)
|
|
250
255
|
|
|
251
256
|
if self.refresh_api_on_success and self.server_instance:
|
|
252
257
|
self.server_instance.refresh_api_config_after_auth()
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import fnmatch
|
|
4
4
|
import hashlib
|
|
5
5
|
import os
|
|
6
|
+
import sys
|
|
6
7
|
|
|
7
8
|
import click
|
|
8
9
|
import requests
|
|
@@ -309,7 +310,7 @@ def _display_multiple_packages(packages: list[dict]) -> None:
|
|
|
309
310
|
_format_date(pkg.get("uploaded_at", "")),
|
|
310
311
|
)
|
|
311
312
|
|
|
312
|
-
Console().print(table)
|
|
313
|
+
Console(width=(None if sys.stdout.isatty() else 1000)).print(table)
|
|
313
314
|
click.echo()
|
|
314
315
|
|
|
315
316
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Copyright 2026 Cloudsmith Ltd
|
|
2
|
+
"""Detect how the CLI was installed and how to upgrade it."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import platform
|
|
6
|
+
import sys
|
|
7
|
+
from importlib import metadata
|
|
8
|
+
|
|
9
|
+
CHANNEL_STANDALONE = "standalone"
|
|
10
|
+
CHANNEL_HOMEBREW = "homebrew"
|
|
11
|
+
CHANNEL_DOCKER = "docker"
|
|
12
|
+
CHANNEL_AQUA = "aqua"
|
|
13
|
+
CHANNEL_PIP = "pip"
|
|
14
|
+
CHANNEL_PIPX = "pipx"
|
|
15
|
+
CHANNEL_UV_TOOL = "uv-tool"
|
|
16
|
+
CHANNEL_UV_PIP = "uv-pip"
|
|
17
|
+
CHANNEL_UNKNOWN = "unknown"
|
|
18
|
+
|
|
19
|
+
_DISTRIBUTION_NAME = "cloudsmith-cli"
|
|
20
|
+
|
|
21
|
+
#: Where a user downloads a fresh standalone build when self-update cannot run.
|
|
22
|
+
RELEASES_LATEST_URL = "https://github.com/cloudsmith-io/cloudsmith-cli/releases/latest"
|
|
23
|
+
|
|
24
|
+
#: Base for a version's GitHub release page. Each release is tagged ``v<version>``
|
|
25
|
+
#: and its page renders that version's changelog, so it answers "what do I gain
|
|
26
|
+
#: by upgrading?" for the exact version being offered.
|
|
27
|
+
_RELEASE_TAG_URL_TEMPLATE = (
|
|
28
|
+
"https://github.com/cloudsmith-io/cloudsmith-cli/releases/tag/v{version}"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def changelog_url(version=None):
|
|
33
|
+
"""Return the changelog URL for ``version`` (its release page), or the list.
|
|
34
|
+
|
|
35
|
+
With a version, points at that version's release page (tagged
|
|
36
|
+
``v<version>``), which shows exactly what changed. Without one, points at
|
|
37
|
+
the releases listing.
|
|
38
|
+
"""
|
|
39
|
+
if not version:
|
|
40
|
+
return RELEASES_LATEST_URL
|
|
41
|
+
return _RELEASE_TAG_URL_TEMPLATE.format(version=str(version).lstrip("v"))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_UPGRADE_INSTRUCTIONS = {
|
|
45
|
+
CHANNEL_PIP: "pip install --upgrade cloudsmith-cli",
|
|
46
|
+
CHANNEL_PIPX: "pipx upgrade cloudsmith-cli",
|
|
47
|
+
CHANNEL_UV_TOOL: "uv tool upgrade cloudsmith-cli",
|
|
48
|
+
CHANNEL_UV_PIP: "uv pip install --upgrade cloudsmith-cli",
|
|
49
|
+
CHANNEL_HOMEBREW: "brew update && brew upgrade cloudsmith-cli",
|
|
50
|
+
CHANNEL_DOCKER: "docker pull cloudsmith/cloudsmith-cli:latest",
|
|
51
|
+
CHANNEL_AQUA: (
|
|
52
|
+
"update the cloudsmith-io/cloudsmith-cli version in your aqua "
|
|
53
|
+
"configuration, then run `aqua install`"
|
|
54
|
+
),
|
|
55
|
+
CHANNEL_UNKNOWN: "pip install --upgrade cloudsmith-cli",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _running_in_container():
|
|
60
|
+
if os.path.exists("/.dockerenv") or os.path.exists("/run/.containerenv"):
|
|
61
|
+
return True
|
|
62
|
+
return bool(
|
|
63
|
+
os.environ.get("container") or os.environ.get("KUBERNETES_SERVICE_HOST")
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _distribution_location():
|
|
68
|
+
"""Return the installed distribution's directory, or None."""
|
|
69
|
+
try:
|
|
70
|
+
distribution = metadata.distribution(_DISTRIBUTION_NAME)
|
|
71
|
+
except metadata.PackageNotFoundError:
|
|
72
|
+
return None
|
|
73
|
+
return str(distribution.locate_file(""))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _distribution_installer():
|
|
77
|
+
"""Return the INSTALLER record of the installed distribution, or None."""
|
|
78
|
+
try:
|
|
79
|
+
distribution = metadata.distribution(_DISTRIBUTION_NAME)
|
|
80
|
+
except metadata.PackageNotFoundError:
|
|
81
|
+
return None
|
|
82
|
+
installer = distribution.read_text("INSTALLER")
|
|
83
|
+
return installer.strip() if installer else None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _detect_frozen_channel(executable_path):
|
|
87
|
+
normalized = os.path.realpath(executable_path).replace("\\", "/")
|
|
88
|
+
if "aquaproj-aqua" in normalized:
|
|
89
|
+
return CHANNEL_AQUA
|
|
90
|
+
if "/Cellar/" in normalized or "/linuxbrew/" in normalized:
|
|
91
|
+
return CHANNEL_HOMEBREW
|
|
92
|
+
if normalized.startswith("/opt/cloudsmith") and _running_in_container():
|
|
93
|
+
return CHANNEL_DOCKER
|
|
94
|
+
return CHANNEL_STANDALONE
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _detect_package_channel():
|
|
98
|
+
location = _distribution_location()
|
|
99
|
+
if location is None:
|
|
100
|
+
return CHANNEL_UNKNOWN
|
|
101
|
+
normalized = location.replace("\\", "/")
|
|
102
|
+
if "/pipx/" in normalized:
|
|
103
|
+
return CHANNEL_PIPX
|
|
104
|
+
if "/uv/tools/" in normalized:
|
|
105
|
+
return CHANNEL_UV_TOOL
|
|
106
|
+
installer = _distribution_installer()
|
|
107
|
+
if installer == "uv":
|
|
108
|
+
return CHANNEL_UV_PIP
|
|
109
|
+
if installer == "pip":
|
|
110
|
+
return CHANNEL_PIP
|
|
111
|
+
return CHANNEL_UNKNOWN
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def detect_channel(frozen=None, executable_path=None):
|
|
115
|
+
"""Detect the install channel of the running CLI."""
|
|
116
|
+
frozen = getattr(sys, "frozen", False) if frozen is None else frozen
|
|
117
|
+
if frozen:
|
|
118
|
+
return _detect_frozen_channel(executable_path or sys.executable)
|
|
119
|
+
return _detect_package_channel()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def detect_target():
|
|
123
|
+
"""Detect the standalone build target for this platform, or None."""
|
|
124
|
+
system = platform.system()
|
|
125
|
+
machine = platform.machine().lower()
|
|
126
|
+
arch = {"amd64": "x86_64", "x86_64": "x86_64"}.get(machine)
|
|
127
|
+
arm = machine in ("arm64", "aarch64")
|
|
128
|
+
if system == "Darwin":
|
|
129
|
+
return "macos-arm64" if arm else ("macos-x86_64" if arch else None)
|
|
130
|
+
if system == "Windows":
|
|
131
|
+
return "windows-x86_64" if arch else None
|
|
132
|
+
if system == "Linux":
|
|
133
|
+
if arm:
|
|
134
|
+
arch = "aarch64"
|
|
135
|
+
if arch is None:
|
|
136
|
+
return None
|
|
137
|
+
libc = "gnu" if platform.libc_ver()[0] == "glibc" else "musl"
|
|
138
|
+
return f"linux-{arch}-{libc}"
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def upgrade_instruction(channel):
|
|
143
|
+
"""Return the upgrade command for a channel, or None for self-update."""
|
|
144
|
+
if channel == CHANNEL_STANDALONE:
|
|
145
|
+
return None
|
|
146
|
+
return _UPGRADE_INSTRUCTIONS[channel]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def self_update_supported():
|
|
150
|
+
"""Whether the standalone binary can replace itself in place.
|
|
151
|
+
|
|
152
|
+
False on Windows: the running ``.exe`` is locked, so an in-place swap is
|
|
153
|
+
not possible (a deferred-swap helper is a future follow-up). Callers fall
|
|
154
|
+
back to manual-download instructions.
|
|
155
|
+
"""
|
|
156
|
+
return os.name != "nt"
|