Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
0e76188
initial work to support shinyapps.io hosting
Jun 22, 2022
7173bd0
clearer date formatting for shinyapps.io signatures
Jun 27, 2022
983b824
better S3 error handling and shinyapps server connection/auth check
Jun 27, 2022
59d05ac
Merge pull request #259 from mslynch/mslynch-shinyapps-io
Jun 27, 2022
578b6d8
Merge remote-tracking branch 'origin/mslynch-shinyapps-io' into shiny…
bcwu Jun 27, 2022
7aaeb95
Merge branch 'bcwu-refactor' into mslynch-shinyapps-io-refactor
Jun 27, 2022
eabc315
fix refactor merge issues and tests
Jun 28, 2022
c574b9b
infer target type from `add` options
Jun 28, 2022
0a1e70f
ca_data needs to fetch ca_data
bcwu Jun 28, 2022
5c318c6
working redeploys for shinyapps
Jun 29, 2022
4e5adce
Merge branch 'bcwu-refactor' into mslynch-shinyapps-io-refactor
Jun 29, 2022
8a06359
working manifest shinyapps.io deploys
Jun 29, 2022
e3b67a3
add account option to `add` command
Jun 29, 2022
f3aafa8
update setup_connect_server & setup_client for ShinyappsClient
bcwu Jun 28, 2022
f959dc7
Split validate_server for Connect and Shinyapps
bcwu Jun 30, 2022
cc22ea0
remove target in metadata to maintain backward compatibility
bcwu Jun 30, 2022
5a854f6
Merge branch 'bcwu-refactor' into merge-shinyapps-io
bcwu Jun 30, 2022
9f8fcff
working no-server-nickname deploy for shinyapps
Jun 30, 2022
360001e
Merge remote-tracking branch 'origin/mslynch-shinyapps-io-refactor' i…
bcwu Jun 30, 2022
b69d5ef
update setup when token and secret not in ServerStore
bcwu Jun 30, 2022
7255c2b
python 3.5 compatibility
Jun 30, 2022
e4fea58
drop parameters from ServerStore.resolve()
bcwu Jun 30, 2022
c6481c7
Merge branch 'bcwu-merge-shinyapps' into mslynch-shinyapps-io-refactor
Jun 30, 2022
cea8e60
reuse RSConnectExecutor deploy_bundle in actions.deploy_bundle
Jun 30, 2022
86f9b5f
fix tests
Jun 30, 2022
69d15eb
rename connect_server to remote_server
bcwu Jun 30, 2022
8f27ecc
account_name is from server_data.account
bcwu Jun 30, 2022
3e4b0a7
remove target from server add
bcwu Jun 30, 2022
d2a4370
implement getting app mode from shinyapps.io
Jun 30, 2022
53f6e21
Merge branch 'bcwu-merge-shinyapps' into mslynch-shinyapps-io-refactor
Jun 30, 2022
556f6ec
remove redundant lines
Jun 30, 2022
7925cb0
tweak connect server validation
Jun 30, 2022
4c87cc5
implement auto naming for shinyapps
Jun 30, 2022
64b1141
use mock for adding shinyapps credential test
Jul 1, 2022
13e64c3
format and linting fixes
Jul 1, 2022
b6b7e56
type checking fixes
Jul 1, 2022
2c8e15f
type checking fixes
Jul 1, 2022
380974d
python 3.5 compatibility
Jul 1, 2022
9049966
python 3.5 compatibility
Jul 1, 2022
d107182
python 3.5 compatibility
Jul 1, 2022
4131296
fix test_add_shinyapps and test_add_shinyapps_missing_options for mis…
Jul 1, 2022
3d159e1
fix shinyapps tests for possibly-present environment variables
Jul 1, 2022
fe5dda7
Merge branch 'master' into mslynch-shinyapps-io-refactor
Jul 1, 2022
371ec5d
fix formatting
Jul 1, 2022
c3babe8
refactor validation
Jul 1, 2022
7658448
remove extraneous file
Jul 1, 2022
104710e
refactor kwarg calls in test for clarity
Jul 1, 2022
30c5d7b
add mocked-http test for deploying shiny app to shinyapps.io
Jul 5, 2022
c0f425b
fix formatting
Jul 5, 2022
dc89ec6
fix formatting
Jul 5, 2022
feb886f
show response body for http call failures
Jul 5, 2022
db8b08c
remove tar.gz assertions against properties that vary by platform
Jul 5, 2022
8a0d95f
tweak test json loading for ci
Jul 5, 2022
27d3836
tweak test json loading for ci
Jul 5, 2022
78e0877
initialize S3 client like other clients
Jul 5, 2022
1a9d1a5
log task id and allow more time for task completion
Jul 5, 2022
bea0a02
rename account to account_name
Jul 5, 2022
a257f84
better remote target inference
Jul 5, 2022
35bdddc
Merge branch 'master' into mslynch-shinyapps-io-refactor
Jul 5, 2022
25d0d17
import RSConnectException from exception instead of api
Jul 5, 2022
f502e44
more exhaustive type checks for connect/shinyapps
Jul 5, 2022
8b18d78
error handling for shinyapps.io task failures
Jul 6, 2022
0c3146b
make shinyapps output consistent with rsconnect
Jul 6, 2022
4b1a941
rename load_json -> _load_json
Jul 6, 2022
8dbce3b
formatting
Jul 6, 2022
0cc9202
Merge branch 'master' into mslynch-shinyapps-io-refactor
Jul 7, 2022
72c58f4
Merge branch 'master' into mslynch-shinyapps-io-refactor
Jul 8, 2022
6dc0a55
remove redundant click decorators
Jul 8, 2022
33c0c18
remove validate_new_server_options in favor of validate_connection_op…
Jul 8, 2022
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
/rsconnect/version.py
htmlcov
/tests/testdata/**/rsconnect-python/
test-home/
/docs/docs/index.md
/docs/docs/changelog.md
/rsconnect-build
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ click>=7.0.0
coverage
flake8
funcsigs
httpretty==1.1.4
importlib-metadata
ipykernel
ipython
Expand Down
53 changes: 39 additions & 14 deletions rsconnect/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,15 @@ def test_server(connect_server):
raise RSConnectException("\n".join(failures))


def test_shinyapps_server(server: api.ShinyappsServer):
with api.ShinyappsClient(server) as client:
try:
result = client.get_current_user()
server.handle_bad_response(result)
except RSConnectException as exc:
raise RSConnectException("Failed to verify with shinyapps.io ({}).".format(exc))


def test_api_key(connect_server):
"""
Test that an API Key may be used to authenticate with the given RStudio Connect server.
Expand Down Expand Up @@ -313,7 +322,7 @@ def check_server_capabilities(connect_server, capability_functions, details_sour
raise RSConnectException(message)


def _make_deployment_name(connect_server, title, force_unique) -> str:
def _make_deployment_name(remote_server: api.TargetableServer, title: str, force_unique: bool) -> str:
"""
Produce a name for a deployment based on its title. It is assumed that the
title is already defaulted and validated as appropriate (meaning the title
Expand All @@ -324,7 +333,7 @@ def _make_deployment_name(connect_server, title, force_unique) -> str:
that we collapse repeating underscores and, if the name is too short, it is
padded to the left with underscores.

:param connect_server: the information needed to interact with the Connect server.
:param remote_server: the information needed to interact with the Connect server.
:param title: the title to start with.
:param force_unique: a flag noting whether the generated name must be forced to be
unique.
Expand All @@ -338,7 +347,7 @@ def _make_deployment_name(connect_server, title, force_unique) -> str:

# Now, make sure it's unique, if needed.
if force_unique:
name = api.find_unique_name(connect_server, name)
name = api.find_unique_name(remote_server, name)

return name

Expand Down Expand Up @@ -1447,7 +1456,7 @@ def _generate_gather_basic_deployment_info_for_python(app_mode: AppMode) -> typi
"""

def gatherer(
connect_server: api.RSConnectServer,
remote_server: api.TargetableServer,
app_store: AppStore,
directory: str,
entry_point: str,
Expand All @@ -1456,7 +1465,7 @@ def gatherer(
title: str,
) -> typing.Tuple[str, int, str, str, bool, AppMode]:
return _gather_basic_deployment_info_for_framework(
connect_server,
remote_server,
app_store,
directory,
entry_point,
Expand All @@ -1477,7 +1486,7 @@ def gatherer(


def _gather_basic_deployment_info_for_framework(
connect_server: api.RSConnectServer,
remote_server: api.TargetableServer,
app_store: AppStore,
directory: str,
entry_point: str,
Expand All @@ -1489,7 +1498,7 @@ def _gather_basic_deployment_info_for_framework(
"""
Helps to gather the necessary info for performing a deployment.

:param connect_server: the Connect server information.
:param remote_server: the server information.
:param app_store: the store for the specified directory.
:param directory: the primary file being deployed.
:param entry_point: the entry point for the API in '<module>:<object> format. if
Expand All @@ -1514,13 +1523,19 @@ def _gather_basic_deployment_info_for_framework(
if app_id is None:
# Possible redeployment - check for saved metadata.
# Use the saved app information unless overridden by the user.
app_id, existing_app_mode = app_store.resolve(connect_server.url, app_id, app_mode)
app_id, existing_app_mode = app_store.resolve(remote_server.url, app_id, app_mode)
logger.debug("Using app mode from app %s: %s" % (app_id, app_mode))
elif app_id is not None:
# Don't read app metadata if app-id is specified. Instead, we need
# to get this from Connect.
app = api.get_app_info(connect_server, app_id)
existing_app_mode = AppModes.get_by_ordinal(app.get("app_mode", 0), True)
if isinstance(remote_server, api.RSConnectServer):
app = api.get_app_info(remote_server, app_id)
existing_app_mode = AppModes.get_by_ordinal(app.get("app_mode", 0), True)
elif isinstance(remote_server, api.ShinyappsServer):
app = api.get_shinyapp_info(remote_server, app_id)
existing_app_mode = AppModes.get_by_cloud_name(app.json_data["mode"])
else:
raise RSConnectException("Unable to infer Connect client.")
if existing_app_mode and app_mode != existing_app_mode:
msg = (
"Deploying with mode '%s',\n"
Expand All @@ -1538,7 +1553,7 @@ def _gather_basic_deployment_info_for_framework(
return (
entry_point,
app_id,
_make_deployment_name(connect_server, title, app_id is None),
_make_deployment_name(remote_server, title, app_id is None),
title,
default_title,
app_mode,
Expand Down Expand Up @@ -1697,7 +1712,7 @@ def create_quarto_deployment_bundle(


def deploy_bundle(
connect_server: api.RSConnectServer,
remote_server: api.TargetableServer,
app_id: int,
name: str,
title: str,
Expand All @@ -1708,7 +1723,7 @@ def deploy_bundle(
"""
Deploys the specified bundle.

:param connect_server: the Connect server information.
:param remote_server: the server information.
:param app_id: the ID of the app to deploy, if this is a redeploy.
:param name: the name for the deploy.
:param title: the title for the deploy.
Expand All @@ -1718,7 +1733,17 @@ def deploy_bundle(
:return: application information about the deploy. This includes the ID of the
task that may be queried for deployment progress.
"""
return api.do_bundle_deploy(connect_server, app_id, name, title, title_is_default, bundle, env_vars)
ce = RSConnectExecutor(
server=remote_server,
app_id=app_id,
name=name,
title=title,
title_is_default=title_is_default,
bundle=bundle,
env_vars=env_vars,
)
ce.deploy_bundle()
return ce.state["deployed_info"]


def spool_deployment_log(connect_server, app, log_callback):
Expand Down
14 changes: 6 additions & 8 deletions rsconnect/actions_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
import json
import time
import traceback

from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime, timedelta

import semver

from .api import RSConnect, emit_task_log
from .api import RSConnectClient, emit_task_log
from .log import logger
from .models import BuildStatus, ContentGuidWithBundle
from .metadata import ContentBuildStore
Expand All @@ -37,7 +35,7 @@ def build_add_content(connect_server, content_guids_with_bundle):
+ "please wait for it to finish before adding new content."
)

with RSConnect(connect_server, timeout=120) as client:
with RSConnectClient(connect_server, timeout=120) as client:
if len(content_guids_with_bundle) == 1:
all_content = [client.content_get(content_guids_with_bundle[0].guid)]
else:
Expand Down Expand Up @@ -228,7 +226,7 @@ def _monitor_build(connect_server, content_items):

def _build_content_item(connect_server, content, poll_wait):
init_content_build_store(connect_server)
with RSConnect(connect_server) as client:
with RSConnectClient(connect_server) as client:
# Pending futures will still try to execute when ThreadPoolExecutor.shutdown() is called
# so just exit immediately if the current build has been aborted.
# ThreadPoolExecutor.shutdown(cancel_futures=) isnt available until py3.9
Expand Down Expand Up @@ -292,7 +290,7 @@ def download_bundle(connect_server, guid_with_bundle):
"""
:param guid_with_bundle: models.ContentGuidWithBundle
"""
with RSConnect(connect_server, timeout=120) as client:
with RSConnectClient(connect_server, timeout=120) as client:
# bundle_id not provided so grab the latest
if not guid_with_bundle.bundle_id:
content = client.get_content(guid_with_bundle.guid)
Expand All @@ -311,7 +309,7 @@ def get_content(connect_server, guid):
:param guid: a single guid as a string or list of guids.
:return: a list of content items.
"""
with RSConnect(connect_server, timeout=120) as client:
with RSConnectClient(connect_server, timeout=120) as client:
if isinstance(guid, str):
result = [client.get_content(guid)]
else:
Expand All @@ -322,7 +320,7 @@ def get_content(connect_server, guid):
def search_content(
connect_server, published, unpublished, content_type, r_version, py_version, title_contains, order_by
):
with RSConnect(connect_server, timeout=120) as client:
with RSConnectClient(connect_server, timeout=120) as client:
result = client.search_content()
result = _apply_content_filters(
result, published, unpublished, content_type, r_version, py_version, title_contains
Expand Down
Loading