Skip to content

Commit 1dd0e7a

Browse files
authored
Output the preview url in case of drafts (#681)
* return preview_url from deploy
1 parent 04be902 commit 1dd0e7a

File tree

3 files changed

+42
-14
lines changed

3 files changed

+42
-14
lines changed

rsconnect/api.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@
4646
# they should both come from the same typing module.
4747
# https://peps.python.org/pep-0655/#usage-in-python-3-11
4848
if sys.version_info >= (3, 11):
49-
from typing import NotRequired, TypedDict
49+
from typing import TypedDict
5050
else:
51-
from typing_extensions import NotRequired, TypedDict
51+
from typing_extensions import TypedDict
5252

5353
from . import validation
5454
from .bundle import _default_title
@@ -331,10 +331,11 @@ def __init__(self, url: str):
331331

332332

333333
class RSConnectClientDeployResult(TypedDict):
334-
task_id: NotRequired[str]
334+
task_id: str | None
335335
app_id: str
336-
app_guid: str
336+
app_guid: str | None
337337
app_url: str
338+
preview_url: str | None
338339
title: str | None
339340

340341

@@ -569,11 +570,17 @@ def deploy(
569570

570571
task = self.content_deploy(app_guid, app_bundle["id"], activate=activate)
571572

573+
# http://ADDRESS/preview/APP_GUID/BUNDLE_ID
574+
# Using replace makes this a bit more robust to changes in the URL structure
575+
# like connect being served on a subpath.
576+
preview_url = app["url"].replace("/content/", "/preview/") + f"/{app_bundle['id']}"
577+
572578
return {
573579
"task_id": task["task_id"],
574580
"app_id": app_id,
575581
"app_guid": app["guid"],
576582
"app_url": app["url"],
583+
"preview_url": preview_url if not activate else None,
577584
"title": app["title"],
578585
}
579586

@@ -1079,12 +1086,14 @@ def deploy_bundle(self, activate: bool = True):
10791086
print("Application successfully deployed to {}".format(prepare_deploy_result.app_url))
10801087
webbrowser.open_new(prepare_deploy_result.app_url)
10811088

1082-
self.deployed_info = {
1083-
"app_url": prepare_deploy_result.app_url,
1084-
"app_id": prepare_deploy_result.app_id,
1085-
"app_guid": None,
1086-
"title": self.title,
1087-
}
1089+
self.deployed_info = RSConnectClientDeployResult(
1090+
app_url=prepare_deploy_result.app_url,
1091+
app_id=str(prepare_deploy_result.app_id),
1092+
app_guid=None,
1093+
task_id=None,
1094+
preview_url=None,
1095+
title=self.title,
1096+
)
10881097
return self
10891098

10901099
def emit_task_log(
@@ -1127,7 +1136,9 @@ def emit_task_log(
11271136
app_dashboard_url = app_config.get("config_url")
11281137
log_callback.info("Deployment completed successfully.")
11291138
log_callback.info("\t Dashboard content URL: %s", app_dashboard_url)
1130-
log_callback.info("\t Direct content URL: %s", self.deployed_info["app_url"])
1139+
log_callback.info(
1140+
"\t Direct content URL: %s", self.deployed_info["preview_url"] or self.deployed_info["app_url"]
1141+
)
11311142

11321143
return self
11331144

rsconnect/http_support.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,15 @@ def _do_request(
405405
for key, value in response.getheaders():
406406
logger.debug("--> %s: %s" % (key, value))
407407
logger.debug("Body:")
408-
logger.debug("--> %s" % response_body)
408+
if response.getheader("Content-Type", "").startswith("application/json"):
409+
# Only print JSON responses.
410+
# Otherwise we end up dumping entire web pages to the log.
411+
try:
412+
logger.debug("--> %s" % response_body)
413+
except json.JSONDecodeError:
414+
logger.debug("--> <invalid JSON>")
415+
else:
416+
logger.debug("--> <non-json-response>")
409417
finally:
410418
if local_connection:
411419
self.__exit__()

tests/test_main.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def test_deploy(self):
113113
],
114114
)
115115
@httpretty.activate(verbose=True, allow_net_connect=False)
116-
def test_deploy_draft(self, command, target, expected_activate):
116+
def test_deploy_draft(self, command, target, expected_activate, caplog):
117117
original_api_key_value = os.environ.pop("CONNECT_API_KEY", None)
118118
original_server_value = os.environ.pop("CONNECT_SERVER", None)
119119

@@ -146,7 +146,7 @@ def test_deploy_draft(self, command, target, expected_activate):
146146
"id": "1234-5678-9012-3456",
147147
"guid": "1234-5678-9012-3456",
148148
"title": "app5",
149-
"url": "http://fake_server/apps/1234-5678-9012-3456",
149+
"url": "http://fake_server/content/1234-5678-9012-3456",
150150
}
151151
),
152152
adding_headers={"Content-Type": "application/json"},
@@ -241,10 +241,19 @@ def post_application_deploy_callback(request, uri, response_headers):
241241
# Do not validate app mode, so that the "target" content doesn't matter.
242242
"rsconnect.api.RSConnectExecutor.validate_app_mode",
243243
new=lambda self_, *args, **kwargs: self_,
244+
), caplog.at_level(
245+
"INFO"
244246
):
245247
result = runner.invoke(cli, args)
246248
assert result.exit_code == 0, result.output
247249
assert deploy_api_invoked == [True]
250+
assert "Deployment completed successfully." in caplog.text
251+
if expected_activate:
252+
assert "Direct content URL: http://fake_server/content/1234-5678-9012-3456" in caplog.text
253+
else:
254+
assert (
255+
"Direct content URL: http://fake_server/preview/1234-5678-9012-3456/FAKE_BUNDLE_ID" in caplog.text
256+
)
248257
finally:
249258
if original_api_key_value:
250259
os.environ["CONNECT_API_KEY"] = original_api_key_value

0 commit comments

Comments
 (0)