Skip to content
Merged
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
4 changes: 2 additions & 2 deletions rsconnect/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ def test_server(connect_server):
raise RSConnectException("\n".join(failures))


def test_rstudio_server(server: api.RStudioServer):
with api.RStudioClient(server) as client:
def test_rstudio_server(server: api.PositServer):
with api.PositClient(server) as client:
try:
result = client.get_current_user()
server.handle_bad_response(result)
Expand Down
48 changes: 24 additions & 24 deletions rsconnect/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ def handle_bad_response(self, response):
)


class RStudioServer(AbstractRemoteServer):
class PositServer(AbstractRemoteServer):
"""
A class used to represent the server of the shinyapps.io and RStudio Cloud APIs.
A class used to represent the server of the shinyapps.io and Posit Cloud APIs.
"""

def __init__(self, remote_name: str, url: str, account_name: str, token: str, secret: str):
Expand All @@ -76,7 +76,7 @@ def __init__(self, remote_name: str, url: str, account_name: str, token: str, se
self.secret = secret


class ShinyappsServer(RStudioServer):
class ShinyappsServer(PositServer):
"""
A class to encapsulate the information needed to interact with an
instance of the shinyapps.io server.
Expand All @@ -89,16 +89,16 @@ def __init__(self, url: str, account_name: str, token: str, secret: str):
super().__init__(remote_name=remote_name, url=url, account_name=account_name, token=token, secret=secret)


class CloudServer(RStudioServer):
class CloudServer(PositServer):
"""
A class to encapsulate the information needed to interact with an
instance of the RStudio Cloud server.
instance of the Posit Cloud server.
"""

def __init__(self, url: str, account_name: str, token: str, secret: str):
remote_name = "RStudio Cloud"
if url == "rstudio.cloud" or url is None:
url = "https://api.rstudio.cloud"
remote_name = "Posit Cloud"
if url in {"posit.cloud", "rstudio.cloud", None}:
url = "https://api.posit.cloud"
super().__init__(remote_name=remote_name, url=url, account_name=account_name, token=token, secret=secret)


Expand Down Expand Up @@ -475,7 +475,7 @@ def setup_remote_server(
if api_key:
self.remote_server = RSConnectServer(url, api_key, insecure, ca_data)
elif token and secret:
if url and "rstudio.cloud" in url:
if url and ("rstudio.cloud" in url or "posit.cloud" in url):
self.remote_server = CloudServer(url, account_name, token, secret)
else:
self.remote_server = ShinyappsServer(url, account_name, token, secret)
Expand All @@ -485,8 +485,8 @@ def setup_remote_server(
def setup_client(self, cookies=None, timeout=30, **kwargs):
if isinstance(self.remote_server, RSConnectServer):
self.client = RSConnectClient(self.remote_server, cookies, timeout)
elif isinstance(self.remote_server, RStudioServer):
self.client = RStudioClient(self.remote_server, timeout)
elif isinstance(self.remote_server, PositServer):
self.client = PositClient(self.remote_server, timeout)
else:
raise RSConnectException("Unable to infer Connect client.")

Expand Down Expand Up @@ -515,7 +515,7 @@ def validate_server(
):
if (url and api_key) or isinstance(self.remote_server, RSConnectServer):
self.validate_connect_server(name, url, api_key, insecure, cacert, api_key_is_required)
elif (url and token and secret) or isinstance(self.remote_server, RStudioServer):
elif (url and token and secret) or isinstance(self.remote_server, PositServer):
self.validate_rstudio_server(url, account_name, token, secret)
else:
raise RSConnectException("Unable to validate server from information provided.")
Expand Down Expand Up @@ -596,11 +596,11 @@ def validate_rstudio_server(
secret = secret or self.remote_server.secret
server = (
CloudServer(url, account_name, token, secret)
if "rstudio.cloud" in url
if "rstudio.cloud" in url or "posit.cloud" in url
else ShinyappsServer(url, account_name, token, secret)
)

with RStudioClient(server) as client:
with PositClient(server) as client:
try:
result = client.get_current_user()
server.handle_bad_response(result)
Expand Down Expand Up @@ -657,7 +657,7 @@ def check_server_capabilities(self, capability_functions):
:param details_source: the source for obtaining server details, gather_server_details(),
by default.
"""
if isinstance(self.remote_server, RStudioServer):
if isinstance(self.remote_server, PositServer):
return self

details = self.server_details
Expand Down Expand Up @@ -847,7 +847,7 @@ def validate_app_mode(self, *args, **kwargs):
if isinstance(self.remote_server, RSConnectServer):
app = get_app_info(self.remote_server, app_id)
existing_app_mode = AppModes.get_by_ordinal(app.get("app_mode", 0), True)
elif isinstance(self.remote_server, RStudioServer):
elif isinstance(self.remote_server, PositServer):
app = get_rstudio_app_info(self.remote_server, app_id)
existing_app_mode = AppModes.get_by_cloud_name(app.json_data["mode"])
else:
Expand Down Expand Up @@ -1008,14 +1008,14 @@ def __init__(
self.output_id = output_id


class RStudioClient(HTTPServer):
class PositClient(HTTPServer):
"""
An HTTP client to call the RStudio Cloud and shinyapps.io APIs.
An HTTP client to call the Posit Cloud and shinyapps.io APIs.
"""

_TERMINAL_STATUSES = {"success", "failed", "error"}

def __init__(self, rstudio_server: RStudioServer, timeout: int = 30):
def __init__(self, rstudio_server: PositServer, timeout: int = 30):
self._token = rstudio_server.token
try:
self._key = base64.b64decode(rstudio_server.secret)
Expand Down Expand Up @@ -1156,7 +1156,7 @@ class ShinyappsService:
Encapsulates operations involving multiple API calls to shinyapps.io.
"""

def __init__(self, rstudio_client: RStudioClient, server: ShinyappsServer):
def __init__(self, rstudio_client: PositClient, server: ShinyappsServer):
self._rstudio_client = rstudio_client
self._server = server

Expand Down Expand Up @@ -1202,10 +1202,10 @@ def do_deploy(self, bundle_id, app_id):

class CloudService:
"""
Encapsulates operations involving multiple API calls to RStudio Cloud.
Encapsulates operations involving multiple API calls to Posit Cloud.
"""

def __init__(self, rstudio_client: RStudioClient, server: CloudServer):
def __init__(self, rstudio_client: PositClient, server: CloudServer):
self._rstudio_client = rstudio_client
self._server = server

Expand Down Expand Up @@ -1332,7 +1332,7 @@ def get_app_info(connect_server, app_id):


def get_rstudio_app_info(server, app_id):
with RStudioClient(server) as client:
with PositClient(server) as client:
result = client.get_application(app_id)
server.handle_bad_response(result)
return result
Expand Down Expand Up @@ -1541,7 +1541,7 @@ def find_unique_name(remote_server: TargetableServer, name: str):
mapping_function=lambda client, app: app["name"],
)
elif isinstance(remote_server, ShinyappsServer):
client = RStudioClient(remote_server)
client = PositClient(remote_server)
existing_names = client.get_applications_like_name(name)
else:
# non-unique names are permitted in cloud
Expand Down
12 changes: 6 additions & 6 deletions rsconnect/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ def rstudio_args(func):
"--token",
"-T",
envvar=["SHINYAPPS_TOKEN", "RSCLOUD_TOKEN"],
help="The shinyapps.io/RStudio Cloud token.",
help="The shinyapps.io/Posit Cloud token.",
)
@click.option(
"--secret",
"-S",
envvar=["SHINYAPPS_SECRET", "RSCLOUD_SECRET"],
help="The shinyapps.io/RStudio Cloud token secret.",
help="The shinyapps.io/Posit Cloud token secret.",
)
@functools.wraps(func)
def wrapper(*args, **kwargs):
Expand Down Expand Up @@ -245,8 +245,8 @@ def cli(future):
certificate file to use for TLS. The last two items are only relevant if the
URL specifies the "https" protocol.

For RStudio Cloud, the information needed to connect includes the auth token, auth
secret, and server ('rstudio.cloud'). For shinyapps.io, the auth token, auth secret,
For Posit Cloud, the information needed to connect includes the auth token, auth
secret, and server ('posit.cloud'). For shinyapps.io, the auth token, auth secret,
server ('shinyapps.io'), and account are needed.
"""
global future_enabled
Expand Down Expand Up @@ -285,7 +285,7 @@ def _test_server_and_api(server, api_key, insecure, ca_cert):
return real_server, me


def _test_rstudio_creds(server: api.RStudioServer):
def _test_rstudio_creds(server: api.PositServer):
with cli_feedback("Checking {} credential".format(server.remote_name)):
test_rstudio_server(server)

Expand Down Expand Up @@ -434,7 +434,7 @@ def add(ctx, name, server, api_key, insecure, cacert, account, token, secret, ve
old_server = server_store.get_by_name(name)

if token:
if server and "rstudio.cloud" in server:
if server and ("rstudio.cloud" in server or "posit.cloud" in server):
real_server = api.CloudServer(server, account, token, secret)
else:
real_server = api.ShinyappsServer(server, account, token, secret)
Expand Down
6 changes: 3 additions & 3 deletions rsconnect/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ def validate_connection_options(url, api_key, insecure, cacert, account_name, to

if present_connect_options and present_shinyapps_options:
raise RSConnectException(
"Connect options ({}) may not be passed alongside shinyapps.io or RStudio Cloud options ({}).".format(
"Connect options ({}) may not be passed alongside shinyapps.io or Posit Cloud options ({}).".format(
", ".join(present_connect_options), ", ".join(present_shinyapps_options)
)
)

if url and 'rstudio.cloud' in url:
if url and ('posit.cloud' in url or 'rstudio.cloud' in url):
if len(present_cloud_options) != len(cloud_options):
raise RSConnectException(
"-T/--token and -S/--secret must be provided for RStudio Cloud."
"-T/--token and -S/--secret must be provided for Posit Cloud."
)
elif present_shinyapps_options:
if len(present_shinyapps_options) != len(shinyapps_options):
Expand Down
34 changes: 17 additions & 17 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,21 +270,21 @@ def test_deploy_manifest_cloud(self, project_application_id, project_id):

httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/users/me",
"https://api.posit.cloud/v1/users/me",
body=open("tests/testdata/rstudio-responses/get-user.json", "r").read(),
status=200,
)
httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/applications"
"https://api.posit.cloud/v1/applications"
"?filter=name:like:shinyapp&offset=0&count=100&use_advanced_filters=true",
body=open("tests/testdata/rstudio-responses/get-applications.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
)
httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/accounts/",
"https://api.posit.cloud/v1/accounts/",
body=open("tests/testdata/rstudio-responses/get-accounts.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
Expand All @@ -293,21 +293,21 @@ def test_deploy_manifest_cloud(self, project_application_id, project_id):
if project_application_id:
httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/applications/444",
"https://api.posit.cloud/v1/applications/444",
body=open("tests/testdata/rstudio-responses/get-project-application.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
)
httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/content/555",
"https://api.posit.cloud/v1/content/555",
body=open("tests/testdata/rstudio-responses/get-content.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
)
httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/content/1",
"https://api.posit.cloud/v1/content/1",
body=open("tests/testdata/rstudio-responses/create-output.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
Expand All @@ -328,15 +328,15 @@ def post_output_callback(request, uri, response_headers):

httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/applications/8442",
"https://api.posit.cloud/v1/applications/8442",
body=open("tests/testdata/rstudio-responses/get-output-application.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
)

httpretty.register_uri(
httpretty.POST,
"https://api.rstudio.cloud/v1/outputs/",
"https://api.posit.cloud/v1/outputs/",
body=post_output_callback,
)

Expand All @@ -359,7 +359,7 @@ def post_bundle_callback(request, uri, response_headers):

httpretty.register_uri(
httpretty.POST,
"https://api.rstudio.cloud/v1/bundles",
"https://api.posit.cloud/v1/bundles",
body=post_bundle_callback,
)

Expand All @@ -382,17 +382,17 @@ def post_bundle_status_callback(request, uri, response_headers):
assert parsed_request == {"status": "ready"}
except AssertionError as e:
return _error_to_response(e)
return [303, {"Location": "https://api.rstudio.cloud/v1/bundles/12640"}, ""]
return [303, {"Location": "https://api.posit.cloud/v1/bundles/12640"}, ""]

httpretty.register_uri(
httpretty.POST,
"https://api.rstudio.cloud/v1/bundles/12640/status",
"https://api.posit.cloud/v1/bundles/12640/status",
body=post_bundle_status_callback,
)

httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/bundles/12640",
"https://api.posit.cloud/v1/bundles/12640",
body=open("tests/testdata/rstudio-responses/get-accounts.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
Expand All @@ -406,19 +406,19 @@ def post_deploy_callback(request, uri, response_headers):
return _error_to_response(e)
return [
303,
{"Location": "https://api.rstudio.cloud/v1/tasks/333"},
{"Location": "https://api.posit.cloud/v1/tasks/333"},
open("tests/testdata/rstudio-responses/post-deploy.json", "r").read(),
]

httpretty.register_uri(
httpretty.POST,
"https://api.rstudio.cloud/v1/applications/8442/deploy",
"https://api.posit.cloud/v1/applications/8442/deploy",
body=post_deploy_callback,
)

httpretty.register_uri(
httpretty.GET,
"https://api.rstudio.cloud/v1/tasks/333",
"https://api.posit.cloud/v1/tasks/333",
body=open("tests/testdata/rstudio-responses/get-task.json", "r").read(),
adding_headers={"Content-Type": "application/json"},
status=200,
Expand Down Expand Up @@ -505,7 +505,7 @@ def test_add_cloud(self):
original_server_value = os.environ.pop("CONNECT_SERVER", None)
try:
httpretty.register_uri(
httpretty.GET, "https://api.rstudio.cloud/v1/users/me", body='{"id": 1000}', status=200
httpretty.GET, "https://api.posit.cloud/v1/users/me", body='{"id": 1000}', status=200
)

runner = CliRunner()
Expand All @@ -524,7 +524,7 @@ def test_add_cloud(self):
],
)
assert result.exit_code == 0, result.output
assert "RStudio Cloud credential" in result.output
assert "Posit Cloud credential" in result.output

finally:
if original_api_key_value:
Expand Down