Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

republishing and collaborating #1021

Merged
merged 17 commits into from
Oct 25, 2023
Merged

Conversation

aronatkins
Copy link
Contributor

@aronatkins aronatkins commented Oct 23, 2023

Revisit how the deployment target is selected.

Use 0.8.29 implementation when reviewing this work. In particular, that version of deploymentTarget() did not offer any separation between the "owning" account and the "deploying" account. Details recorded in the in-memory deployment record were not necessarily consistent with the on-disk deployment record. Additionally, resolving that deployment record to an actual remote application occurred much later, in applicationForTarget().
https://github.com/rstudio/rsconnect/blob/v0.8.29/R/deployApp.R

The implementation available in 1.0.0 until now did a good job consolidating this logic, but lost track of the fact that we may have a local user attempting to re-use deployment records created by some other user.

This change sees us use the following prioritized techniques to locate a deployment record:

  1. When appId is provided, it must be used to locate the target content. A target (local) account is required to make this determination. When a local deployment record is not available, the application is loaded from the server. The target deployment record does not need to be owned by the local target account.
  2. When appName is provided without appId, it must be used to locate the target content or create a new deployment target.
  3. When neither appName nor appId is provided, the user is asked to choose from the available deployment records (which must correspond to a locally available account).
  4. When there are no deployment records, a generated name is used along with a target account to remotely probe for that name (owned by the target account) before creating a new item.

Some collaboration instructions from the Connect user guide: https://docs.posit.co/connect/user/publishing/#publishing-collaboration

Related issues: #1019, #1013, #1007, #981 along with multiple internal reports.

This change may fix each of those issues, but they need more review to be sure.

prioritized set of deployment considerations:

1. appId used above all else, and may be owned by a non-local account.
2. appName can identify local or remote content, owned by a local account.
3. locally available deployments are preferred when other identifiers not provided.
4. fall-back on generated name (based on path) and user-chosen local account.
Copy link
Contributor Author

@aronatkins aronatkins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need NEWS ahead of merge.

R/applications.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Show resolved Hide resolved
R/deploymentTarget.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Show resolved Hide resolved
}
# Discover the deployment target given appId.
#
# When appId is provided, all other information is secondary. An appId is an indication from the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this comment very useful for understand the problem and where I went wrong previously.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. It took so much code-reading and reasoning about the previous workflow to see it. I'm hoping that being much more explicit will help us in the future.

appName = application$name,
appTitle = application$title %||% appTitle,
appId = application$id,
envVars = NULL,
envVars = envVars,
username = application$owner_username %||% accountDetails$name,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we change the arguments to createDeploymentTarget() to more clearly differentiate the username of the current user vs. the username of the account owner? Might need to be in a separate PR to avoid cluttering this one, but I think it's likely to make understanding the code easier in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deployment record has the account+server corresponding to local account record for the user responsible for creating the deployment record on disk. This is usually the creator, but not always (e.g. collaborator publish using appId). The username is associated with the creating user (unsure if we get this back from shinyapps.io).

I'm not sure how to best represent this possible inconsistency. Happy to file an issue for further discussion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking maybe we could rename username to something like owner_account to make it clear that this is also an account name, but it's the account name for the original author.

R/deploymentTarget.R Show resolved Hide resolved
tests/testthat/_snaps/deploymentTarget.md Outdated Show resolved Hide resolved
R/deployApp.R Outdated Show resolved Hide resolved
R/applications.R Outdated Show resolved Hide resolved
R/deployApp.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Show resolved Hide resolved
}
# Discover the deployment target given appId.
#
# When appId is provided, all other information is secondary. An appId is an indication from the
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. It took so much code-reading and reasoning about the previous workflow to see it. I'm hoping that being much more explicit will help us in the future.

R/deploymentTarget.R Show resolved Hide resolved
appName = application$name,
appTitle = application$title %||% appTitle,
appId = application$id,
envVars = NULL,
envVars = envVars,
username = application$owner_username %||% accountDetails$name,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deployment record has the account+server corresponding to local account record for the user responsible for creating the deployment record on disk. This is usually the creator, but not always (e.g. collaborator publish using appId). The username is associated with the creating user (unsure if we get this back from shinyapps.io).

I'm not sure how to best represent this possible inconsistency. Happy to file an issue for further discussion.

R/deploymentTarget.R Show resolved Hide resolved
tests/testthat/_snaps/deploymentTarget.md Outdated Show resolved Hide resolved
R/deploymentTarget.R Outdated Show resolved Hide resolved
deploymentTarget ==> findDeploymentTarget
deploymentTargetFromAppId ==> findDeploymentTargetByAppId
deploymentTargetFromAppName ==> findDeploymentTargetByAppName
updateDeploymentTarget ==> updateDeployment
createDeploymentTarget ==> createDeployment
This rewrite showed that from-disk deployment records had different field
names than the records created on-the-fly. In particular, "appName" and
"appTitle" were used by the "deployment target", while "name" and "title" were
used for on-disk deployment records. This made it challenging to use the same
helpers.

All deployment objects, either read from disk or created in-memory now use
"name" and "title".

This is a step towards always using deployment records.
@aronatkins aronatkins force-pushed the aron-republishing-and-collaborating branch from 32b66af to e97ab2b Compare October 24, 2023 16:00
))
})

test_that("updateDeployment ignores NULL updates", {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding these tests let me see that we were mixing records from disk which used name and records created on-the-fly which used appName. We are now consistent.

Copy link
Member

@hadley hadley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a nice improvement to code clarity!

R/applications.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Show resolved Hide resolved
R/deployments.R Outdated Show resolved Hide resolved
Copy link
Contributor

@toph-allen toph-allen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. A lot clearer for posterity too.

R/deploymentTarget.R Show resolved Hide resolved
R/deploymentTarget.R Show resolved Hide resolved
R/deploymentTarget.R Outdated Show resolved Hide resolved
R/deploymentTarget.R Show resolved Hide resolved
R/deploymentTarget.R Show resolved Hide resolved
tests/testthat/test-deploymentTarget.R Show resolved Hide resolved
@aronatkins aronatkins merged commit db8c35e into main Oct 25, 2023
10 checks passed
@aronatkins aronatkins deleted the aron-republishing-and-collaborating branch October 25, 2023 13:38
aronatkins added a commit that referenced this pull request Oct 26, 2023
@ChaitaC
Copy link

ChaitaC commented Nov 1, 2023

Verified the fix for #1013

Before the fix, when using CRAN Version 1.1.1

── Preparing for deployment ────────────────────────────────────────────────────
✔ Deploying "shinyappsIO" to "server: shinyapps.io / username: chaitatest"
ℹ Creating application on server...
Error in `POST()`:
! <https://api.shinyapps.io/v1/applications/> failed with HTTP status
  409
Application exists with name: shinyappsIO
Backtrace:
    ▆
 1. └─rsconnect::deployApp(...)
 2.   └─client$createApplication(...)
 3.     └─rsconnect:::POST_JSON(service, authInfo, "/applications/", json)
 4.       └─rsconnect:::POST(...)
 5.         └─rsconnect:::httpRequestWithBody(...)
 6.           └─rsconnect:::handleResponse(httpResponse, error_call = error_call)
 7.             └─rsconnect (local) reportError(json$error)
 8.               └─cli::cli_abort(...)
 9.                 └─rlang::abort(...)
Execution halted

Using the development version from GitHub, the existing app can be redeployed and replaced without any issue.

── Deployment complete ─────────────────────────────────────────────────────────
✔ Successfully deployed to <https://chaitatest.shinyapps.io/SHinyappsIO/>
Deployment completed: https://chaitatest.shinyapps.io/SHinyappsIO/

@ChaitaC
Copy link

ChaitaC commented Nov 8, 2023

Verified #981
Verified #1007

Collaborator publishing works without any issues. A collaborator can update the content as long as he has an accurate rsconnect dir.

@ChaitaC
Copy link

ChaitaC commented Nov 8, 2023

⚠️ If a user lacks the necessary permissions to collaborate but possesses the required rsconnect directory, the following error message is displayed:

Screenshot 2023-11-08 at 3 09 50 PM

✅ When a user possesses the appropriate collaborative privileges, the interface appears as follows:
Screenshot 2023-11-08 at 3 11 07 PM

@ChaitaC
Copy link

ChaitaC commented Nov 8, 2023

@aronatkins the error message 39] in it does not make sense. See for image #1021 (comment)

this is an edge case though

@aronatkins
Copy link
Contributor Author

I have filed #1026 to track the escape codes that are presented by the IDE when the target content has been deleted (or is not visible to the user).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants