Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
already-saved server can be made the default without re-adding it using
`rsconnect server set-default -n <name>`. The new `rsconnect server` command
group also aliases `add`, `list`, `remove`, `details`, and `bootstrap`.
These commands are now listed under `rsconnect server` in `rsconnect --help`;
the top-level forms (`rsconnect add`, etc.) continue to work unchanged.
- New `environment` subcommand for managing execution environments on Connect.
- New `integration` subcommand for managing OAuth integrations on Connect.

Expand Down
1 change: 1 addition & 0 deletions docs/commands/add.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
::: mkdocs-click
:module: rsconnect.main
:command: add
:prog_name: rsconnect server add
1 change: 1 addition & 0 deletions docs/commands/bootstrap.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
::: mkdocs-click
:module: rsconnect.main
:command: bootstrap
:prog_name: rsconnect server bootstrap
1 change: 1 addition & 0 deletions docs/commands/details.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
::: mkdocs-click
:module: rsconnect.main
:command: details
:prog_name: rsconnect server details
1 change: 1 addition & 0 deletions docs/commands/list.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
::: mkdocs-click
:module: rsconnect.main
:command: list_servers
:prog_name: rsconnect server list
1 change: 1 addition & 0 deletions docs/commands/remove.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
::: mkdocs-click
:module: rsconnect.main
:command: remove
:prog_name: rsconnect server remove
13 changes: 7 additions & 6 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,21 @@ nav:
- Server Administration: server-administration.md
- CLI reference:
- rsconnect:
- add: commands/add.md
- bootstrap: commands/bootstrap.md
- content: commands/content.md
- deploy: commands/deploy.md
- details: commands/details.md
- environment: commands/environment.md
- info: commands/info.md
- integration: commands/integration.md
- list: commands/list.md
- login: commands/login.md
- logout: commands/logout.md
- quickstart: commands/quickstart.md
- remove: commands/remove.md
- set-default: commands/set-default.md
- server:
- add: commands/add.md
- bootstrap: commands/bootstrap.md
- details: commands/details.md
- list: commands/list.md
- remove: commands/remove.md
- set-default: commands/set-default.md
- system: commands/system.md
- version: commands/version.md
- write-manifest: commands/write-manifest.md
Expand Down
22 changes: 21 additions & 1 deletion rsconnect/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,27 @@ def wrapper(*args: P.args, **kwargs: P.kwargs):
return wrapper


@click.group(no_args_is_help=True)
class ServerAliasHidingGroup(click.Group):
"""Root command group that omits the server-management commands from the
top-level ``--help`` listing.

``add``, ``list``, ``remove``, and ``details`` are also registered under
the ``server`` group, which is their advertised home. They remain fully
invokable at the top level (e.g. ``rsconnect add``) and are still offered
by shell completion; this only declutters ``rsconnect --help``.
"""

def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
aliased = set(server_group.commands)
original = self.commands
self.commands = {name: cmd for name, cmd in original.items() if name not in aliased}
try:
super().format_commands(ctx, formatter)
finally:
self.commands = original


@click.group(cls=ServerAliasHidingGroup, no_args_is_help=True)
@click.option("--future", "-u", is_flag=True, hidden=True, help="Enables future functionality.")
def cli(future: bool):
"""
Expand Down
31 changes: 31 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1928,6 +1928,37 @@ def test_top_level_list_still_works(self, tmp_path):
assert result.exit_code == 0, result.output
assert "s1" in result.output

@staticmethod
def _command_names(help_output):
# Click renders each command row with a 2-space indent; wrapped
# help text is indented further, so match only the command rows.
section = help_output.split("Commands:", 1)[1]
return [
line.strip().split()[0]
for line in section.splitlines()
if line.startswith(" ") and not line.startswith(" ") and line.strip()
]

def test_server_aliases_hidden_from_top_level_help(self):
runner = CliRunner()
result = runner.invoke(cli, ["--help"])
assert result.exit_code == 0, result.output
names = self._command_names(result.output)
assert "server" in names
for hidden in ("add", "list", "remove", "details", "bootstrap"):
assert hidden not in names, "%s should be hidden from top-level help" % hidden

def test_hidden_top_level_alias_still_runs(self, tmp_path):
from rsconnect.metadata import ServerStore

store = ServerStore(base_dir=str(tmp_path))
store.set("s1", "http://s1.local", api_key="key1")
runner = CliRunner()
with mock.patch("rsconnect.main.server_store", store):
result = runner.invoke(cli, ["remove", "--name", "s1"])
assert result.exit_code == 0, result.output
assert "Removed" in result.output


class TestDeployGit(TestCase):
"""Tests for deploy git CLI command."""
Expand Down
Loading