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.
Files changed (130) hide show
  1. cloudsmith_cli/__init__.py +10 -0
  2. cloudsmith_cli/__main__.py +8 -0
  3. cloudsmith_cli/cli/__init__.py +1 -0
  4. cloudsmith_cli/cli/command.py +160 -0
  5. cloudsmith_cli/cli/commands/__init__.py +33 -0
  6. cloudsmith_cli/cli/commands/auth.py +173 -0
  7. cloudsmith_cli/cli/commands/check.py +129 -0
  8. cloudsmith_cli/cli/commands/copy.py +98 -0
  9. cloudsmith_cli/cli/commands/credential_helper/__init__.py +39 -0
  10. cloudsmith_cli/cli/commands/credential_helper/docker.py +66 -0
  11. cloudsmith_cli/cli/commands/credential_helper/manage.py +299 -0
  12. cloudsmith_cli/cli/commands/delete.py +67 -0
  13. cloudsmith_cli/cli/commands/dependencies.py +108 -0
  14. cloudsmith_cli/cli/commands/docs.py +16 -0
  15. cloudsmith_cli/cli/commands/download.py +620 -0
  16. cloudsmith_cli/cli/commands/entitlements.py +819 -0
  17. cloudsmith_cli/cli/commands/help_.py +12 -0
  18. cloudsmith_cli/cli/commands/list_.py +317 -0
  19. cloudsmith_cli/cli/commands/login.py +99 -0
  20. cloudsmith_cli/cli/commands/logout.py +151 -0
  21. cloudsmith_cli/cli/commands/main.py +73 -0
  22. cloudsmith_cli/cli/commands/mcp.py +523 -0
  23. cloudsmith_cli/cli/commands/metadata.py +503 -0
  24. cloudsmith_cli/cli/commands/metrics/__init__.py +2 -0
  25. cloudsmith_cli/cli/commands/metrics/command.py +20 -0
  26. cloudsmith_cli/cli/commands/metrics/entitlements.py +148 -0
  27. cloudsmith_cli/cli/commands/metrics/packages.py +134 -0
  28. cloudsmith_cli/cli/commands/move.py +111 -0
  29. cloudsmith_cli/cli/commands/policy/__init__.py +3 -0
  30. cloudsmith_cli/cli/commands/policy/command.py +20 -0
  31. cloudsmith_cli/cli/commands/policy/deny.py +248 -0
  32. cloudsmith_cli/cli/commands/policy/license.py +335 -0
  33. cloudsmith_cli/cli/commands/policy/vulnerability.py +322 -0
  34. cloudsmith_cli/cli/commands/push.py +1323 -0
  35. cloudsmith_cli/cli/commands/quarantine.py +148 -0
  36. cloudsmith_cli/cli/commands/quota/__init__.py +2 -0
  37. cloudsmith_cli/cli/commands/quota/command.py +20 -0
  38. cloudsmith_cli/cli/commands/quota/history.py +122 -0
  39. cloudsmith_cli/cli/commands/quota/quota.py +107 -0
  40. cloudsmith_cli/cli/commands/repos.py +330 -0
  41. cloudsmith_cli/cli/commands/resync.py +90 -0
  42. cloudsmith_cli/cli/commands/status.py +92 -0
  43. cloudsmith_cli/cli/commands/tags.py +375 -0
  44. cloudsmith_cli/cli/commands/tokens.py +318 -0
  45. cloudsmith_cli/cli/commands/upstream.py +479 -0
  46. cloudsmith_cli/cli/commands/vulnerabilities.py +141 -0
  47. cloudsmith_cli/cli/commands/whoami.py +188 -0
  48. cloudsmith_cli/cli/config.py +635 -0
  49. cloudsmith_cli/cli/decorators.py +624 -0
  50. cloudsmith_cli/cli/exceptions.py +215 -0
  51. cloudsmith_cli/cli/metadata_common.py +146 -0
  52. cloudsmith_cli/cli/saml.py +109 -0
  53. cloudsmith_cli/cli/table.py +59 -0
  54. cloudsmith_cli/cli/types.py +14 -0
  55. cloudsmith_cli/cli/utils.py +267 -0
  56. cloudsmith_cli/cli/validators.py +378 -0
  57. cloudsmith_cli/cli/webserver.py +263 -0
  58. cloudsmith_cli/core/__init__.py +1 -0
  59. cloudsmith_cli/core/api/__init__.py +1 -0
  60. cloudsmith_cli/core/api/distros.py +31 -0
  61. cloudsmith_cli/core/api/entitlements.py +130 -0
  62. cloudsmith_cli/core/api/exceptions.py +57 -0
  63. cloudsmith_cli/core/api/files.py +131 -0
  64. cloudsmith_cli/core/api/init.py +109 -0
  65. cloudsmith_cli/core/api/metadata.py +217 -0
  66. cloudsmith_cli/core/api/metrics.py +78 -0
  67. cloudsmith_cli/core/api/orgs.py +201 -0
  68. cloudsmith_cli/core/api/packages.py +309 -0
  69. cloudsmith_cli/core/api/quota.py +64 -0
  70. cloudsmith_cli/core/api/rates.py +28 -0
  71. cloudsmith_cli/core/api/repos.py +81 -0
  72. cloudsmith_cli/core/api/status.py +27 -0
  73. cloudsmith_cli/core/api/upstreams.py +72 -0
  74. cloudsmith_cli/core/api/user.py +109 -0
  75. cloudsmith_cli/core/api/version.py +15 -0
  76. cloudsmith_cli/core/api/vulnerabilities.py +230 -0
  77. cloudsmith_cli/core/cache_utils.py +160 -0
  78. cloudsmith_cli/core/config.py +140 -0
  79. cloudsmith_cli/core/credentials/__init__.py +0 -0
  80. cloudsmith_cli/core/credentials/chain.py +69 -0
  81. cloudsmith_cli/core/credentials/models.py +44 -0
  82. cloudsmith_cli/core/credentials/oidc/__init__.py +6 -0
  83. cloudsmith_cli/core/credentials/oidc/cache.py +220 -0
  84. cloudsmith_cli/core/credentials/oidc/detectors/__init__.py +122 -0
  85. cloudsmith_cli/core/credentials/oidc/detectors/aws.py +85 -0
  86. cloudsmith_cli/core/credentials/oidc/detectors/azure_devops.py +70 -0
  87. cloudsmith_cli/core/credentials/oidc/detectors/base.py +26 -0
  88. cloudsmith_cli/core/credentials/oidc/detectors/bitbucket_pipelines.py +35 -0
  89. cloudsmith_cli/core/credentials/oidc/detectors/circleci.py +40 -0
  90. cloudsmith_cli/core/credentials/oidc/detectors/generic.py +42 -0
  91. cloudsmith_cli/core/credentials/oidc/detectors/github_actions.py +64 -0
  92. cloudsmith_cli/core/credentials/oidc/detectors/gitlab_ci.py +49 -0
  93. cloudsmith_cli/core/credentials/oidc/exchange.py +87 -0
  94. cloudsmith_cli/core/credentials/provider.py +17 -0
  95. cloudsmith_cli/core/credentials/providers/__init__.py +15 -0
  96. cloudsmith_cli/core/credentials/providers/cli_flag.py +24 -0
  97. cloudsmith_cli/core/credentials/providers/credentials_file.py +24 -0
  98. cloudsmith_cli/core/credentials/providers/env_var.py +24 -0
  99. cloudsmith_cli/core/credentials/providers/keyring_provider.py +59 -0
  100. cloudsmith_cli/core/credentials/providers/oidc_provider.py +115 -0
  101. cloudsmith_cli/core/download.py +594 -0
  102. cloudsmith_cli/core/keyring.py +171 -0
  103. cloudsmith_cli/core/mcp/__init__.py +0 -0
  104. cloudsmith_cli/core/mcp/data.py +17 -0
  105. cloudsmith_cli/core/mcp/server.py +786 -0
  106. cloudsmith_cli/core/pagination.py +131 -0
  107. cloudsmith_cli/core/ratelimits.py +88 -0
  108. cloudsmith_cli/core/rest.py +255 -0
  109. cloudsmith_cli/core/utils.py +95 -0
  110. cloudsmith_cli/core/version.py +20 -0
  111. cloudsmith_cli/credential_helpers/__init__.py +7 -0
  112. cloudsmith_cli/credential_helpers/backends.py +41 -0
  113. cloudsmith_cli/credential_helpers/common.py +111 -0
  114. cloudsmith_cli/credential_helpers/custom_domains.py +281 -0
  115. cloudsmith_cli/credential_helpers/docker/__init__.py +4 -0
  116. cloudsmith_cli/credential_helpers/docker/installer.py +349 -0
  117. cloudsmith_cli/credential_helpers/docker/runtime.py +117 -0
  118. cloudsmith_cli/credential_helpers/launchers.py +175 -0
  119. cloudsmith_cli/data/VERSION +1 -0
  120. cloudsmith_cli/data/config.ini +23 -0
  121. cloudsmith_cli/data/credentials.ini +14 -0
  122. cloudsmith_cli/templates/__init__.py +3 -0
  123. cloudsmith_cli/templates/auth_error.html +45 -0
  124. cloudsmith_cli/templates/auth_success.html +37 -0
  125. cloudsmith_cli-1.20.0.dist-info/METADATA +610 -0
  126. cloudsmith_cli-1.20.0.dist-info/RECORD +130 -0
  127. cloudsmith_cli-1.20.0.dist-info/WHEEL +5 -0
  128. cloudsmith_cli-1.20.0.dist-info/entry_points.txt +2 -0
  129. cloudsmith_cli-1.20.0.dist-info/licenses/LICENSE +201 -0
  130. 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())