cloudsmith-cli 1.20.0__py3-none-any.whl
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/__init__.py +10 -0
- cloudsmith_cli/__main__.py +8 -0
- cloudsmith_cli/cli/__init__.py +1 -0
- cloudsmith_cli/cli/command.py +160 -0
- cloudsmith_cli/cli/commands/__init__.py +33 -0
- cloudsmith_cli/cli/commands/auth.py +173 -0
- cloudsmith_cli/cli/commands/check.py +129 -0
- cloudsmith_cli/cli/commands/copy.py +98 -0
- cloudsmith_cli/cli/commands/credential_helper/__init__.py +39 -0
- cloudsmith_cli/cli/commands/credential_helper/docker.py +66 -0
- cloudsmith_cli/cli/commands/credential_helper/manage.py +299 -0
- cloudsmith_cli/cli/commands/delete.py +67 -0
- cloudsmith_cli/cli/commands/dependencies.py +108 -0
- cloudsmith_cli/cli/commands/docs.py +16 -0
- cloudsmith_cli/cli/commands/download.py +620 -0
- cloudsmith_cli/cli/commands/entitlements.py +819 -0
- cloudsmith_cli/cli/commands/help_.py +12 -0
- cloudsmith_cli/cli/commands/list_.py +317 -0
- cloudsmith_cli/cli/commands/login.py +99 -0
- cloudsmith_cli/cli/commands/logout.py +151 -0
- cloudsmith_cli/cli/commands/main.py +73 -0
- cloudsmith_cli/cli/commands/mcp.py +523 -0
- cloudsmith_cli/cli/commands/metadata.py +503 -0
- cloudsmith_cli/cli/commands/metrics/__init__.py +2 -0
- cloudsmith_cli/cli/commands/metrics/command.py +20 -0
- cloudsmith_cli/cli/commands/metrics/entitlements.py +148 -0
- cloudsmith_cli/cli/commands/metrics/packages.py +134 -0
- cloudsmith_cli/cli/commands/move.py +111 -0
- cloudsmith_cli/cli/commands/policy/__init__.py +3 -0
- cloudsmith_cli/cli/commands/policy/command.py +20 -0
- cloudsmith_cli/cli/commands/policy/deny.py +248 -0
- cloudsmith_cli/cli/commands/policy/license.py +335 -0
- cloudsmith_cli/cli/commands/policy/vulnerability.py +322 -0
- cloudsmith_cli/cli/commands/push.py +1323 -0
- cloudsmith_cli/cli/commands/quarantine.py +148 -0
- cloudsmith_cli/cli/commands/quota/__init__.py +2 -0
- cloudsmith_cli/cli/commands/quota/command.py +20 -0
- cloudsmith_cli/cli/commands/quota/history.py +122 -0
- cloudsmith_cli/cli/commands/quota/quota.py +107 -0
- cloudsmith_cli/cli/commands/repos.py +330 -0
- cloudsmith_cli/cli/commands/resync.py +90 -0
- cloudsmith_cli/cli/commands/status.py +92 -0
- cloudsmith_cli/cli/commands/tags.py +375 -0
- cloudsmith_cli/cli/commands/tokens.py +318 -0
- cloudsmith_cli/cli/commands/upstream.py +479 -0
- cloudsmith_cli/cli/commands/vulnerabilities.py +141 -0
- cloudsmith_cli/cli/commands/whoami.py +188 -0
- cloudsmith_cli/cli/config.py +635 -0
- cloudsmith_cli/cli/decorators.py +624 -0
- cloudsmith_cli/cli/exceptions.py +215 -0
- cloudsmith_cli/cli/metadata_common.py +146 -0
- cloudsmith_cli/cli/saml.py +109 -0
- cloudsmith_cli/cli/table.py +59 -0
- cloudsmith_cli/cli/types.py +14 -0
- cloudsmith_cli/cli/utils.py +267 -0
- cloudsmith_cli/cli/validators.py +378 -0
- cloudsmith_cli/cli/webserver.py +263 -0
- cloudsmith_cli/core/__init__.py +1 -0
- cloudsmith_cli/core/api/__init__.py +1 -0
- cloudsmith_cli/core/api/distros.py +31 -0
- cloudsmith_cli/core/api/entitlements.py +130 -0
- cloudsmith_cli/core/api/exceptions.py +57 -0
- cloudsmith_cli/core/api/files.py +131 -0
- cloudsmith_cli/core/api/init.py +109 -0
- cloudsmith_cli/core/api/metadata.py +217 -0
- cloudsmith_cli/core/api/metrics.py +78 -0
- cloudsmith_cli/core/api/orgs.py +201 -0
- cloudsmith_cli/core/api/packages.py +309 -0
- cloudsmith_cli/core/api/quota.py +64 -0
- cloudsmith_cli/core/api/rates.py +28 -0
- cloudsmith_cli/core/api/repos.py +81 -0
- cloudsmith_cli/core/api/status.py +27 -0
- cloudsmith_cli/core/api/upstreams.py +72 -0
- cloudsmith_cli/core/api/user.py +109 -0
- cloudsmith_cli/core/api/version.py +15 -0
- cloudsmith_cli/core/api/vulnerabilities.py +230 -0
- cloudsmith_cli/core/cache_utils.py +160 -0
- cloudsmith_cli/core/config.py +140 -0
- cloudsmith_cli/core/credentials/__init__.py +0 -0
- cloudsmith_cli/core/credentials/chain.py +69 -0
- cloudsmith_cli/core/credentials/models.py +44 -0
- cloudsmith_cli/core/credentials/oidc/__init__.py +6 -0
- cloudsmith_cli/core/credentials/oidc/cache.py +220 -0
- cloudsmith_cli/core/credentials/oidc/detectors/__init__.py +122 -0
- cloudsmith_cli/core/credentials/oidc/detectors/aws.py +85 -0
- cloudsmith_cli/core/credentials/oidc/detectors/azure_devops.py +70 -0
- cloudsmith_cli/core/credentials/oidc/detectors/base.py +26 -0
- cloudsmith_cli/core/credentials/oidc/detectors/bitbucket_pipelines.py +35 -0
- cloudsmith_cli/core/credentials/oidc/detectors/circleci.py +40 -0
- cloudsmith_cli/core/credentials/oidc/detectors/generic.py +42 -0
- cloudsmith_cli/core/credentials/oidc/detectors/github_actions.py +64 -0
- cloudsmith_cli/core/credentials/oidc/detectors/gitlab_ci.py +49 -0
- cloudsmith_cli/core/credentials/oidc/exchange.py +87 -0
- cloudsmith_cli/core/credentials/provider.py +17 -0
- cloudsmith_cli/core/credentials/providers/__init__.py +15 -0
- cloudsmith_cli/core/credentials/providers/cli_flag.py +24 -0
- cloudsmith_cli/core/credentials/providers/credentials_file.py +24 -0
- cloudsmith_cli/core/credentials/providers/env_var.py +24 -0
- cloudsmith_cli/core/credentials/providers/keyring_provider.py +59 -0
- cloudsmith_cli/core/credentials/providers/oidc_provider.py +115 -0
- cloudsmith_cli/core/download.py +594 -0
- cloudsmith_cli/core/keyring.py +171 -0
- cloudsmith_cli/core/mcp/__init__.py +0 -0
- cloudsmith_cli/core/mcp/data.py +17 -0
- cloudsmith_cli/core/mcp/server.py +786 -0
- cloudsmith_cli/core/pagination.py +131 -0
- cloudsmith_cli/core/ratelimits.py +88 -0
- cloudsmith_cli/core/rest.py +255 -0
- cloudsmith_cli/core/utils.py +95 -0
- cloudsmith_cli/core/version.py +20 -0
- cloudsmith_cli/credential_helpers/__init__.py +7 -0
- cloudsmith_cli/credential_helpers/backends.py +41 -0
- cloudsmith_cli/credential_helpers/common.py +111 -0
- cloudsmith_cli/credential_helpers/custom_domains.py +281 -0
- cloudsmith_cli/credential_helpers/docker/__init__.py +4 -0
- cloudsmith_cli/credential_helpers/docker/installer.py +349 -0
- cloudsmith_cli/credential_helpers/docker/runtime.py +117 -0
- cloudsmith_cli/credential_helpers/launchers.py +175 -0
- cloudsmith_cli/data/VERSION +1 -0
- cloudsmith_cli/data/config.ini +23 -0
- cloudsmith_cli/data/credentials.ini +14 -0
- cloudsmith_cli/templates/__init__.py +3 -0
- cloudsmith_cli/templates/auth_error.html +45 -0
- cloudsmith_cli/templates/auth_success.html +37 -0
- cloudsmith_cli-1.20.0.dist-info/METADATA +610 -0
- cloudsmith_cli-1.20.0.dist-info/RECORD +130 -0
- cloudsmith_cli-1.20.0.dist-info/WHEEL +5 -0
- cloudsmith_cli-1.20.0.dist-info/entry_points.txt +2 -0
- cloudsmith_cli-1.20.0.dist-info/licenses/LICENSE +201 -0
- cloudsmith_cli-1.20.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Copyright 2026 Cloudsmith Ltd
|
|
2
|
+
"""
|
|
3
|
+
Docker credential helper command.
|
|
4
|
+
|
|
5
|
+
Implements the Docker credential helper protocol for Cloudsmith registries.
|
|
6
|
+
|
|
7
|
+
See: https://github.com/docker/docker-credential-helpers
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
import click
|
|
13
|
+
|
|
14
|
+
from ....credential_helpers.docker import execute
|
|
15
|
+
from ...decorators import common_api_auth_options, resolve_credentials
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.command()
|
|
19
|
+
@click.argument("operation", required=False, default="get")
|
|
20
|
+
@common_api_auth_options
|
|
21
|
+
@resolve_credentials
|
|
22
|
+
def docker(opts, operation):
|
|
23
|
+
"""
|
|
24
|
+
Docker credential helper for Cloudsmith registries.
|
|
25
|
+
|
|
26
|
+
Reads a Docker registry server URL from stdin and returns credentials in
|
|
27
|
+
JSON format. Implements the full Docker credential helper protocol
|
|
28
|
+
(get/store/erase/list).
|
|
29
|
+
|
|
30
|
+
Provides credentials for all Cloudsmith Docker registries: ``*.cloudsmith.io``,
|
|
31
|
+
``*.cloudsmith.com``, and any custom domains configured for the organisation
|
|
32
|
+
(requires CLOUDSMITH_ORG and a valid API key/token).
|
|
33
|
+
|
|
34
|
+
Input (stdin):
|
|
35
|
+
Server URL as plain text (e.g. "docker.cloudsmith.io")
|
|
36
|
+
|
|
37
|
+
Output (stdout):
|
|
38
|
+
JSON: {"Username": "token", "Secret": "<cloudsmith-token>"}
|
|
39
|
+
|
|
40
|
+
Exit codes:
|
|
41
|
+
0: Success
|
|
42
|
+
1: Error (no credentials available, not a Cloudsmith registry, etc.)
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
# Manual testing
|
|
46
|
+
$ echo "docker.cloudsmith.io" | cloudsmith credential-helper docker
|
|
47
|
+
|
|
48
|
+
# Called by Docker via launcher
|
|
49
|
+
$ echo "docker.cloudsmith.io" | docker-credential-cloudsmith get
|
|
50
|
+
|
|
51
|
+
Environment variables:
|
|
52
|
+
CLOUDSMITH_API_KEY: API key for authentication (optional)
|
|
53
|
+
CLOUDSMITH_ORG: Organisation slug (required for custom domain support)
|
|
54
|
+
"""
|
|
55
|
+
exit_code, stdout, stderr = execute(
|
|
56
|
+
operation,
|
|
57
|
+
sys.stdin,
|
|
58
|
+
credential=opts.credential,
|
|
59
|
+
api_host=opts.api_host,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if stdout is not None:
|
|
63
|
+
click.echo(stdout)
|
|
64
|
+
if stderr is not None:
|
|
65
|
+
click.echo(stderr, err=True)
|
|
66
|
+
sys.exit(exit_code)
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# Copyright 2026 Cloudsmith Ltd
|
|
2
|
+
"""Install/uninstall/list commands for credential helpers.
|
|
3
|
+
|
|
4
|
+
Provides ``credential-helper install``, ``credential-helper uninstall``, and
|
|
5
|
+
``credential-helper list`` to manage the on-PATH launcher binary and the
|
|
6
|
+
``config.json`` entries for each supported credential helper.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
import click
|
|
15
|
+
|
|
16
|
+
from ....credential_helpers.docker.installer import DockerInstaller
|
|
17
|
+
from ... import utils
|
|
18
|
+
from ...decorators import (
|
|
19
|
+
common_api_auth_options,
|
|
20
|
+
common_cli_config_options,
|
|
21
|
+
common_cli_output_options,
|
|
22
|
+
resolve_credentials,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
# Helper registry — extend here when new helpers are added
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
_INSTALLERS: dict[str, type] = {
|
|
30
|
+
"docker": DockerInstaller,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _get_installer(name: str):
|
|
35
|
+
"""Return an instantiated installer for *name*, or exit with a clear error.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
name:
|
|
40
|
+
The helper name as supplied by the user (e.g. ``"docker"``).
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
DockerInstaller
|
|
45
|
+
An instance of the appropriate installer class.
|
|
46
|
+
|
|
47
|
+
Raises
|
|
48
|
+
------
|
|
49
|
+
SystemExit
|
|
50
|
+
If *name* is not in :data:`_INSTALLERS`.
|
|
51
|
+
"""
|
|
52
|
+
cls = _INSTALLERS.get(name)
|
|
53
|
+
if cls is None:
|
|
54
|
+
available = ", ".join(sorted(_INSTALLERS))
|
|
55
|
+
click.echo(
|
|
56
|
+
f"Error: unknown helper {name!r}. Available helpers: {available}",
|
|
57
|
+
err=True,
|
|
58
|
+
)
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
return cls()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# ---------------------------------------------------------------------------
|
|
64
|
+
# install
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@click.command("install")
|
|
69
|
+
@click.argument("helper")
|
|
70
|
+
@click.option(
|
|
71
|
+
"--bin-dir", default=None, help="Directory to install the launcher binary."
|
|
72
|
+
)
|
|
73
|
+
@click.option(
|
|
74
|
+
"--domain",
|
|
75
|
+
"domains",
|
|
76
|
+
multiple=True,
|
|
77
|
+
help="Additional registry hostname to configure (repeatable).",
|
|
78
|
+
)
|
|
79
|
+
@click.option(
|
|
80
|
+
"--dry-run",
|
|
81
|
+
is_flag=True,
|
|
82
|
+
default=False,
|
|
83
|
+
help="Show what would be done without making any changes.",
|
|
84
|
+
)
|
|
85
|
+
@click.option(
|
|
86
|
+
"--no-discover",
|
|
87
|
+
is_flag=True,
|
|
88
|
+
default=False,
|
|
89
|
+
help="Disable automatic discovery of custom Docker domains.",
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"--refresh",
|
|
93
|
+
is_flag=True,
|
|
94
|
+
default=False,
|
|
95
|
+
help="Bypass the custom-domain cache and fetch fresh data from the API.",
|
|
96
|
+
)
|
|
97
|
+
@click.option(
|
|
98
|
+
"--org",
|
|
99
|
+
default=None,
|
|
100
|
+
help="Cloudsmith organisation slug for custom-domain discovery.",
|
|
101
|
+
)
|
|
102
|
+
@common_cli_config_options
|
|
103
|
+
@common_cli_output_options
|
|
104
|
+
@common_api_auth_options
|
|
105
|
+
@resolve_credentials
|
|
106
|
+
@click.pass_context
|
|
107
|
+
def install_cmd(
|
|
108
|
+
ctx,
|
|
109
|
+
opts,
|
|
110
|
+
helper: str,
|
|
111
|
+
bin_dir: str | None,
|
|
112
|
+
domains: tuple[str, ...],
|
|
113
|
+
dry_run: bool,
|
|
114
|
+
no_discover: bool,
|
|
115
|
+
refresh: bool,
|
|
116
|
+
org: str | None,
|
|
117
|
+
) -> None:
|
|
118
|
+
"""Install a credential helper launcher and configure the package manager.
|
|
119
|
+
|
|
120
|
+
HELPER is the name of the credential helper to install (e.g. ``docker``).
|
|
121
|
+
|
|
122
|
+
Examples:
|
|
123
|
+
|
|
124
|
+
\b
|
|
125
|
+
# Install Docker credential helper
|
|
126
|
+
$ cloudsmith credential-helper install docker
|
|
127
|
+
|
|
128
|
+
\b
|
|
129
|
+
# Install with a custom domain
|
|
130
|
+
$ cloudsmith credential-helper install docker --domain my.registry.example.com
|
|
131
|
+
|
|
132
|
+
\b
|
|
133
|
+
# Preview without making changes
|
|
134
|
+
$ cloudsmith credential-helper install docker --dry-run
|
|
135
|
+
|
|
136
|
+
\b
|
|
137
|
+
# Disable automatic custom-domain discovery
|
|
138
|
+
$ cloudsmith credential-helper install docker --no-discover
|
|
139
|
+
"""
|
|
140
|
+
installer = _get_installer(helper)
|
|
141
|
+
org = org or os.environ.get("CLOUDSMITH_ORG", "").strip() or None
|
|
142
|
+
api_key = opts.credential.api_key if opts.credential else None
|
|
143
|
+
auth_type = (
|
|
144
|
+
getattr(opts.credential, "auth_type", "api_key")
|
|
145
|
+
if opts.credential
|
|
146
|
+
else "api_key"
|
|
147
|
+
)
|
|
148
|
+
try:
|
|
149
|
+
actions = installer.install(
|
|
150
|
+
bin_dir=bin_dir,
|
|
151
|
+
domains=domains,
|
|
152
|
+
dry_run=dry_run,
|
|
153
|
+
discover=not no_discover,
|
|
154
|
+
refresh=refresh,
|
|
155
|
+
org=org,
|
|
156
|
+
api_key=api_key,
|
|
157
|
+
auth_type=auth_type,
|
|
158
|
+
api_host=opts.api_host,
|
|
159
|
+
)
|
|
160
|
+
except OSError as exc:
|
|
161
|
+
raise click.ClickException(
|
|
162
|
+
f"Failed to install {helper!r} credential helper: {exc}"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
use_stderr = utils.should_use_stderr(opts)
|
|
166
|
+
warnings = [a for a in actions if a.startswith("WARNING")]
|
|
167
|
+
normal = [a for a in actions if not a.startswith("WARNING")]
|
|
168
|
+
data = {
|
|
169
|
+
"helper": helper,
|
|
170
|
+
"dry_run": dry_run,
|
|
171
|
+
"actions": normal,
|
|
172
|
+
"warnings": warnings,
|
|
173
|
+
}
|
|
174
|
+
if utils.maybe_print_as_json(opts, data):
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
if dry_run:
|
|
178
|
+
click.echo("Dry run — no changes will be made:", err=use_stderr)
|
|
179
|
+
for action in normal:
|
|
180
|
+
click.echo(f" {action}" if dry_run else action, err=use_stderr)
|
|
181
|
+
for warning in warnings:
|
|
182
|
+
click.secho(f" {warning}" if dry_run else warning, err=True, fg="yellow")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# ---------------------------------------------------------------------------
|
|
186
|
+
# uninstall
|
|
187
|
+
# ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@click.command("uninstall")
|
|
191
|
+
@click.argument("helper")
|
|
192
|
+
@click.option(
|
|
193
|
+
"--bin-dir", default=None, help="Directory where the launcher binary was installed."
|
|
194
|
+
)
|
|
195
|
+
@click.option(
|
|
196
|
+
"--dry-run",
|
|
197
|
+
is_flag=True,
|
|
198
|
+
default=False,
|
|
199
|
+
help="Show what would be done without making any changes.",
|
|
200
|
+
)
|
|
201
|
+
@common_cli_config_options
|
|
202
|
+
@common_cli_output_options
|
|
203
|
+
@click.pass_context
|
|
204
|
+
def uninstall_cmd(ctx, opts, helper: str, bin_dir: str | None, dry_run: bool) -> None:
|
|
205
|
+
"""Uninstall a credential helper launcher and remove its config entries.
|
|
206
|
+
|
|
207
|
+
HELPER is the name of the credential helper to uninstall (e.g. ``docker``).
|
|
208
|
+
|
|
209
|
+
Examples:
|
|
210
|
+
|
|
211
|
+
\b
|
|
212
|
+
# Uninstall Docker credential helper
|
|
213
|
+
$ cloudsmith credential-helper uninstall docker
|
|
214
|
+
|
|
215
|
+
\b
|
|
216
|
+
# Preview without making changes
|
|
217
|
+
$ cloudsmith credential-helper uninstall docker --dry-run
|
|
218
|
+
"""
|
|
219
|
+
installer = _get_installer(helper)
|
|
220
|
+
try:
|
|
221
|
+
actions = installer.uninstall(bin_dir=bin_dir, dry_run=dry_run)
|
|
222
|
+
except OSError as exc:
|
|
223
|
+
raise click.ClickException(
|
|
224
|
+
f"Failed to uninstall {helper!r} credential helper: {exc}"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
use_stderr = utils.should_use_stderr(opts)
|
|
228
|
+
warnings = [a for a in actions if a.startswith("WARNING")]
|
|
229
|
+
normal = [a for a in actions if not a.startswith("WARNING")]
|
|
230
|
+
data = {
|
|
231
|
+
"helper": helper,
|
|
232
|
+
"dry_run": dry_run,
|
|
233
|
+
"actions": normal,
|
|
234
|
+
"warnings": warnings,
|
|
235
|
+
}
|
|
236
|
+
if utils.maybe_print_as_json(opts, data):
|
|
237
|
+
return
|
|
238
|
+
|
|
239
|
+
if dry_run:
|
|
240
|
+
click.echo("Dry run — no changes will be made:", err=use_stderr)
|
|
241
|
+
for action in normal:
|
|
242
|
+
click.echo(f" {action}" if dry_run else action, err=use_stderr)
|
|
243
|
+
for warning in warnings:
|
|
244
|
+
click.secho(f" {warning}" if dry_run else warning, err=True, fg="yellow")
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# ---------------------------------------------------------------------------
|
|
248
|
+
# list
|
|
249
|
+
# ---------------------------------------------------------------------------
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@click.command("list")
|
|
253
|
+
@common_cli_config_options
|
|
254
|
+
@common_cli_output_options
|
|
255
|
+
@click.pass_context
|
|
256
|
+
def list_cmd(ctx, opts) -> None:
|
|
257
|
+
"""List available credential helpers and their installation status.
|
|
258
|
+
|
|
259
|
+
Shows which helpers are available, whether their launcher binary is
|
|
260
|
+
present on PATH, and which registry hosts they are configured for.
|
|
261
|
+
|
|
262
|
+
Example:
|
|
263
|
+
|
|
264
|
+
\b
|
|
265
|
+
$ cloudsmith credential-helper list
|
|
266
|
+
"""
|
|
267
|
+
use_stderr = utils.should_use_stderr(opts)
|
|
268
|
+
|
|
269
|
+
data = []
|
|
270
|
+
for name, cls in sorted(_INSTALLERS.items()):
|
|
271
|
+
installer = cls()
|
|
272
|
+
st = installer.status()
|
|
273
|
+
data.append(
|
|
274
|
+
{
|
|
275
|
+
"helper": name,
|
|
276
|
+
"summary": installer.summary,
|
|
277
|
+
"launcher": st.get("launcher"),
|
|
278
|
+
"hosts": st.get("hosts", []),
|
|
279
|
+
}
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
if utils.maybe_print_as_json(opts, data):
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
for entry in data:
|
|
286
|
+
name = entry["helper"]
|
|
287
|
+
launcher = entry["launcher"]
|
|
288
|
+
hosts = entry["hosts"]
|
|
289
|
+
summary = entry["summary"]
|
|
290
|
+
|
|
291
|
+
click.echo(f"{name} ({summary})", err=use_stderr)
|
|
292
|
+
if launcher:
|
|
293
|
+
click.echo(f" launcher : {launcher}", err=use_stderr)
|
|
294
|
+
else:
|
|
295
|
+
click.echo(" launcher : not installed", err=use_stderr)
|
|
296
|
+
if hosts:
|
|
297
|
+
click.echo(f" hosts : {', '.join(hosts)}", err=use_stderr)
|
|
298
|
+
else:
|
|
299
|
+
click.echo(" hosts : none configured", err=use_stderr)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""CLI/Commands - Delete packages."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from ...core.api.packages import delete_package
|
|
6
|
+
from .. import decorators, utils, validators
|
|
7
|
+
from ..exceptions import handle_api_exceptions
|
|
8
|
+
from ..utils import maybe_spinner
|
|
9
|
+
from .main import main
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@main.command(aliases=["rm"])
|
|
13
|
+
@decorators.common_cli_config_options
|
|
14
|
+
@decorators.common_cli_output_options
|
|
15
|
+
@decorators.common_api_auth_options
|
|
16
|
+
@decorators.initialise_api
|
|
17
|
+
@click.argument(
|
|
18
|
+
"owner_repo_package",
|
|
19
|
+
metavar="OWNER/REPO/PACKAGE",
|
|
20
|
+
callback=validators.validate_owner_repo_package,
|
|
21
|
+
)
|
|
22
|
+
@click.option(
|
|
23
|
+
"-y",
|
|
24
|
+
"--yes",
|
|
25
|
+
default=False,
|
|
26
|
+
is_flag=True,
|
|
27
|
+
help="Assume yes as default answer to questions (this is dangerous!)",
|
|
28
|
+
)
|
|
29
|
+
@click.pass_context
|
|
30
|
+
def delete(ctx, opts, owner_repo_package, yes):
|
|
31
|
+
"""
|
|
32
|
+
Delete a package from a repository.
|
|
33
|
+
|
|
34
|
+
- OWNER/REPO/PACKAGE: Specify the OWNER namespace (i.e. user or org), the
|
|
35
|
+
REPO name where the package is stored, and the PACKAGE name (slug) of the
|
|
36
|
+
package itself. All separated by a slash.
|
|
37
|
+
|
|
38
|
+
Example: 'your-org/awesome-repo/better-pkg'.
|
|
39
|
+
"""
|
|
40
|
+
owner, repo, slug = owner_repo_package
|
|
41
|
+
|
|
42
|
+
delete_args = {
|
|
43
|
+
"owner": click.style(owner, bold=True),
|
|
44
|
+
"repo": click.style(repo, bold=True),
|
|
45
|
+
"package": click.style(slug, bold=True),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
use_stderr = utils.should_use_stderr(opts)
|
|
49
|
+
|
|
50
|
+
prompt = "delete the %(package)s from %(owner)s/%(repo)s" % delete_args
|
|
51
|
+
if not utils.confirm_operation(prompt, assume_yes=yes, err=use_stderr):
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
click.echo(
|
|
55
|
+
"Deleting %(package)s from %(owner)s/%(repo)s ... " % delete_args,
|
|
56
|
+
nl=False,
|
|
57
|
+
err=use_stderr,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
context_msg = "Failed to delete the package!"
|
|
61
|
+
with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
|
|
62
|
+
with maybe_spinner(opts):
|
|
63
|
+
delete_package(owner=owner, repo=repo, identifier=slug)
|
|
64
|
+
|
|
65
|
+
click.secho("OK", fg="green", err=use_stderr)
|
|
66
|
+
|
|
67
|
+
utils.maybe_print_status_json(opts, {"slug": slug, "status": "OK"})
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""CLI/Commands - Dependencies."""
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from ...core.api.packages import get_package_dependencies
|
|
8
|
+
from .. import decorators, utils, validators
|
|
9
|
+
from ..exceptions import handle_api_exceptions
|
|
10
|
+
from ..utils import maybe_spinner
|
|
11
|
+
from .main import main
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def list_dependencies_options(f):
|
|
15
|
+
"""Options for list dependencies subcommand."""
|
|
16
|
+
|
|
17
|
+
@decorators.common_cli_config_options
|
|
18
|
+
@decorators.common_cli_output_options
|
|
19
|
+
@decorators.common_api_auth_options
|
|
20
|
+
@decorators.initialise_api
|
|
21
|
+
@click.argument(
|
|
22
|
+
"owner_repo_package",
|
|
23
|
+
metavar="OWNER/REPO/PACKAGE",
|
|
24
|
+
callback=validators.validate_owner_repo_package,
|
|
25
|
+
)
|
|
26
|
+
@click.pass_context
|
|
27
|
+
@functools.wraps(f)
|
|
28
|
+
def wrapper(ctx, *args, **kwargs):
|
|
29
|
+
# pylint: disable=missing-docstring
|
|
30
|
+
return ctx.invoke(f, *args, **kwargs)
|
|
31
|
+
|
|
32
|
+
return wrapper
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def list_dependencies(ctx, opts, owner_repo_package):
|
|
36
|
+
"""
|
|
37
|
+
List direct (non-transitive) dependencies for a package.
|
|
38
|
+
|
|
39
|
+
NOTE: These are not guaranteed to be complete, and only represent the *direct* /
|
|
40
|
+
*non-transitive* dependencies of a package. If packages consistently show
|
|
41
|
+
no dependencies then it is possible that dependency extraction isn't support
|
|
42
|
+
for the package format yet.
|
|
43
|
+
|
|
44
|
+
- OWNER/REPO/PACKAGE: Specify the OWNER namespace (i.e. user or org), the
|
|
45
|
+
REPO name where the package is stored, and the PACKAGE name (identifier/slug) of the
|
|
46
|
+
package itself. All separated by a slash.
|
|
47
|
+
|
|
48
|
+
Example: 'your-org/awesome-repo/better-pkg'.
|
|
49
|
+
"""
|
|
50
|
+
owner, repo, identifier = owner_repo_package
|
|
51
|
+
|
|
52
|
+
# Use stderr for messages if the output is something else (e.g. # JSON)
|
|
53
|
+
use_stderr = utils.should_use_stderr(opts)
|
|
54
|
+
|
|
55
|
+
click.echo(
|
|
56
|
+
"Getting direct (non-transitive) dependencies of %(package)s in "
|
|
57
|
+
"%(owner)s/%(repo)s ... "
|
|
58
|
+
% {
|
|
59
|
+
"owner": click.style(owner, bold=True),
|
|
60
|
+
"repo": click.style(repo, bold=True),
|
|
61
|
+
"package": click.style(identifier, bold=True),
|
|
62
|
+
},
|
|
63
|
+
nl=False,
|
|
64
|
+
err=use_stderr,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
context_msg = "Failed to get dependencies of package!"
|
|
68
|
+
with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
|
|
69
|
+
with maybe_spinner(opts):
|
|
70
|
+
deps, page_info = get_package_dependencies(
|
|
71
|
+
owner=owner, repo=repo, identifier=identifier
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
click.secho("OK", fg="green", err=use_stderr)
|
|
75
|
+
|
|
76
|
+
if utils.maybe_print_as_json(opts, deps, page_info):
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
headers = ["Type", "Name", "Operator", "Version"]
|
|
80
|
+
rows = []
|
|
81
|
+
for dep in deps:
|
|
82
|
+
rows.append(
|
|
83
|
+
[
|
|
84
|
+
click.style(dep["dep_type"], fg="cyan"),
|
|
85
|
+
click.style(dep["name"], fg="yellow"),
|
|
86
|
+
click.style(dep["operator"], fg="magenta"),
|
|
87
|
+
click.style(dep["version"] or "", fg="green"),
|
|
88
|
+
]
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if deps:
|
|
92
|
+
click.echo()
|
|
93
|
+
utils.pretty_print_table(headers, rows)
|
|
94
|
+
|
|
95
|
+
click.echo()
|
|
96
|
+
num_results = len(deps)
|
|
97
|
+
list_suffix = "direct dependenc%s" % ("ies" if num_results != 1 else "y")
|
|
98
|
+
utils.pretty_print_list_info(
|
|
99
|
+
num_results=num_results, page_info=page_info, suffix=list_suffix
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@main.command(name="dependencies", aliases=["deps"])
|
|
104
|
+
@list_dependencies_options
|
|
105
|
+
@functools.wraps(list_dependencies)
|
|
106
|
+
@click.pass_context
|
|
107
|
+
def dependencies_(*args, **kwargs):
|
|
108
|
+
return list_dependencies(*args, **kwargs)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""CLI/Commands - Launch the help website."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from ...core.utils import get_help_website
|
|
6
|
+
from .. import decorators
|
|
7
|
+
from .main import main
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@main.command()
|
|
11
|
+
@decorators.common_cli_config_options
|
|
12
|
+
@click.pass_context
|
|
13
|
+
def docs(ctx, opts):
|
|
14
|
+
"""Launch the help website in your browser."""
|
|
15
|
+
# pylint: disable=unused-argument
|
|
16
|
+
click.launch(get_help_website())
|