Skip to content

Commit cfb7ce7

Browse files
author
Matthew Lynch
authored
Merge pull request #261 from rstudio/mslynch-shinyapps-io-refactor
support for shinyapps.io
2 parents 27c043c + 33c0c18 commit cfb7ce7

22 files changed

+1552
-321
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
/rsconnect/version.py
1919
htmlcov
2020
/tests/testdata/**/rsconnect-python/
21+
test-home/
2122
/docs/docs/index.md
2223
/docs/docs/changelog.md
2324
/rsconnect-build

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ click>=7.0.0
33
coverage
44
flake8
55
funcsigs
6+
httpretty==1.1.4
67
importlib-metadata
78
ipykernel
89
ipython

rsconnect/actions.py

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,15 @@ def test_server(connect_server):
218218
raise RSConnectException("\n".join(failures))
219219

220220

221+
def test_shinyapps_server(server: api.ShinyappsServer):
222+
with api.ShinyappsClient(server) as client:
223+
try:
224+
result = client.get_current_user()
225+
server.handle_bad_response(result)
226+
except RSConnectException as exc:
227+
raise RSConnectException("Failed to verify with shinyapps.io ({}).".format(exc))
228+
229+
221230
def test_api_key(connect_server):
222231
"""
223232
Test that an API Key may be used to authenticate with the given RStudio Connect server.
@@ -313,7 +322,7 @@ def check_server_capabilities(connect_server, capability_functions, details_sour
313322
raise RSConnectException(message)
314323

315324

316-
def _make_deployment_name(connect_server, title, force_unique) -> str:
325+
def _make_deployment_name(remote_server: api.TargetableServer, title: str, force_unique: bool) -> str:
317326
"""
318327
Produce a name for a deployment based on its title. It is assumed that the
319328
title is already defaulted and validated as appropriate (meaning the title
@@ -324,7 +333,7 @@ def _make_deployment_name(connect_server, title, force_unique) -> str:
324333
that we collapse repeating underscores and, if the name is too short, it is
325334
padded to the left with underscores.
326335
327-
:param connect_server: the information needed to interact with the Connect server.
336+
:param remote_server: the information needed to interact with the Connect server.
328337
:param title: the title to start with.
329338
:param force_unique: a flag noting whether the generated name must be forced to be
330339
unique.
@@ -338,7 +347,7 @@ def _make_deployment_name(connect_server, title, force_unique) -> str:
338347

339348
# Now, make sure it's unique, if needed.
340349
if force_unique:
341-
name = api.find_unique_name(connect_server, name)
350+
name = api.find_unique_name(remote_server, name)
342351

343352
return name
344353

@@ -1447,7 +1456,7 @@ def _generate_gather_basic_deployment_info_for_python(app_mode: AppMode) -> typi
14471456
"""
14481457

14491458
def gatherer(
1450-
connect_server: api.RSConnectServer,
1459+
remote_server: api.TargetableServer,
14511460
app_store: AppStore,
14521461
directory: str,
14531462
entry_point: str,
@@ -1456,7 +1465,7 @@ def gatherer(
14561465
title: str,
14571466
) -> typing.Tuple[str, int, str, str, bool, AppMode]:
14581467
return _gather_basic_deployment_info_for_framework(
1459-
connect_server,
1468+
remote_server,
14601469
app_store,
14611470
directory,
14621471
entry_point,
@@ -1477,7 +1486,7 @@ def gatherer(
14771486

14781487

14791488
def _gather_basic_deployment_info_for_framework(
1480-
connect_server: api.RSConnectServer,
1489+
remote_server: api.TargetableServer,
14811490
app_store: AppStore,
14821491
directory: str,
14831492
entry_point: str,
@@ -1489,7 +1498,7 @@ def _gather_basic_deployment_info_for_framework(
14891498
"""
14901499
Helps to gather the necessary info for performing a deployment.
14911500
1492-
:param connect_server: the Connect server information.
1501+
:param remote_server: the server information.
14931502
:param app_store: the store for the specified directory.
14941503
:param directory: the primary file being deployed.
14951504
:param entry_point: the entry point for the API in '<module>:<object> format. if
@@ -1514,13 +1523,19 @@ def _gather_basic_deployment_info_for_framework(
15141523
if app_id is None:
15151524
# Possible redeployment - check for saved metadata.
15161525
# Use the saved app information unless overridden by the user.
1517-
app_id, existing_app_mode = app_store.resolve(connect_server.url, app_id, app_mode)
1526+
app_id, existing_app_mode = app_store.resolve(remote_server.url, app_id, app_mode)
15181527
logger.debug("Using app mode from app %s: %s" % (app_id, app_mode))
15191528
elif app_id is not None:
15201529
# Don't read app metadata if app-id is specified. Instead, we need
15211530
# to get this from Connect.
1522-
app = api.get_app_info(connect_server, app_id)
1523-
existing_app_mode = AppModes.get_by_ordinal(app.get("app_mode", 0), True)
1531+
if isinstance(remote_server, api.RSConnectServer):
1532+
app = api.get_app_info(remote_server, app_id)
1533+
existing_app_mode = AppModes.get_by_ordinal(app.get("app_mode", 0), True)
1534+
elif isinstance(remote_server, api.ShinyappsServer):
1535+
app = api.get_shinyapp_info(remote_server, app_id)
1536+
existing_app_mode = AppModes.get_by_cloud_name(app.json_data["mode"])
1537+
else:
1538+
raise RSConnectException("Unable to infer Connect client.")
15241539
if existing_app_mode and app_mode != existing_app_mode:
15251540
msg = (
15261541
"Deploying with mode '%s',\n"
@@ -1538,7 +1553,7 @@ def _gather_basic_deployment_info_for_framework(
15381553
return (
15391554
entry_point,
15401555
app_id,
1541-
_make_deployment_name(connect_server, title, app_id is None),
1556+
_make_deployment_name(remote_server, title, app_id is None),
15421557
title,
15431558
default_title,
15441559
app_mode,
@@ -1697,7 +1712,7 @@ def create_quarto_deployment_bundle(
16971712

16981713

16991714
def deploy_bundle(
1700-
connect_server: api.RSConnectServer,
1715+
remote_server: api.TargetableServer,
17011716
app_id: int,
17021717
name: str,
17031718
title: str,
@@ -1708,7 +1723,7 @@ def deploy_bundle(
17081723
"""
17091724
Deploys the specified bundle.
17101725
1711-
:param connect_server: the Connect server information.
1726+
:param remote_server: the server information.
17121727
:param app_id: the ID of the app to deploy, if this is a redeploy.
17131728
:param name: the name for the deploy.
17141729
:param title: the title for the deploy.
@@ -1718,7 +1733,17 @@ def deploy_bundle(
17181733
:return: application information about the deploy. This includes the ID of the
17191734
task that may be queried for deployment progress.
17201735
"""
1721-
return api.do_bundle_deploy(connect_server, app_id, name, title, title_is_default, bundle, env_vars)
1736+
ce = RSConnectExecutor(
1737+
server=remote_server,
1738+
app_id=app_id,
1739+
name=name,
1740+
title=title,
1741+
title_is_default=title_is_default,
1742+
bundle=bundle,
1743+
env_vars=env_vars,
1744+
)
1745+
ce.deploy_bundle()
1746+
return ce.state["deployed_info"]
17221747

17231748

17241749
def spool_deployment_log(connect_server, app, log_callback):

rsconnect/actions_content.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44
import json
55
import time
66
import traceback
7-
87
from concurrent.futures import ThreadPoolExecutor, as_completed
98
from datetime import datetime, timedelta
10-
119
import semver
1210

13-
from .api import RSConnect, emit_task_log
11+
from .api import RSConnectClient, emit_task_log
1412
from .log import logger
1513
from .models import BuildStatus, ContentGuidWithBundle
1614
from .metadata import ContentBuildStore
@@ -37,7 +35,7 @@ def build_add_content(connect_server, content_guids_with_bundle):
3735
+ "please wait for it to finish before adding new content."
3836
)
3937

40-
with RSConnect(connect_server, timeout=120) as client:
38+
with RSConnectClient(connect_server, timeout=120) as client:
4139
if len(content_guids_with_bundle) == 1:
4240
all_content = [client.content_get(content_guids_with_bundle[0].guid)]
4341
else:
@@ -228,7 +226,7 @@ def _monitor_build(connect_server, content_items):
228226

229227
def _build_content_item(connect_server, content, poll_wait):
230228
init_content_build_store(connect_server)
231-
with RSConnect(connect_server) as client:
229+
with RSConnectClient(connect_server) as client:
232230
# Pending futures will still try to execute when ThreadPoolExecutor.shutdown() is called
233231
# so just exit immediately if the current build has been aborted.
234232
# ThreadPoolExecutor.shutdown(cancel_futures=) isnt available until py3.9
@@ -292,7 +290,7 @@ def download_bundle(connect_server, guid_with_bundle):
292290
"""
293291
:param guid_with_bundle: models.ContentGuidWithBundle
294292
"""
295-
with RSConnect(connect_server, timeout=120) as client:
293+
with RSConnectClient(connect_server, timeout=120) as client:
296294
# bundle_id not provided so grab the latest
297295
if not guid_with_bundle.bundle_id:
298296
content = client.get_content(guid_with_bundle.guid)
@@ -311,7 +309,7 @@ def get_content(connect_server, guid):
311309
:param guid: a single guid as a string or list of guids.
312310
:return: a list of content items.
313311
"""
314-
with RSConnect(connect_server, timeout=120) as client:
312+
with RSConnectClient(connect_server, timeout=120) as client:
315313
if isinstance(guid, str):
316314
result = [client.get_content(guid)]
317315
else:
@@ -322,7 +320,7 @@ def get_content(connect_server, guid):
322320
def search_content(
323321
connect_server, published, unpublished, content_type, r_version, py_version, title_contains, order_by
324322
):
325-
with RSConnect(connect_server, timeout=120) as client:
323+
with RSConnectClient(connect_server, timeout=120) as client:
326324
result = client.search_content()
327325
result = _apply_content_filters(
328326
result, published, unpublished, content_type, r_version, py_version, title_contains

0 commit comments

Comments
 (0)