-
Notifications
You must be signed in to change notification settings - Fork 49
fix: Improve site creation error handling #4
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
Conversation
Basedd on the surrounding code, the lack of a return appears to be an oversight. Introducing the return means creating a site in a non-empty, non-WordPress directory no longer displays an error, and instead dismisses the modal after moving the directory's content to the OS trash. The apparent rationale for doing so is allowing the user to retry with a clean directory. A future improvement would be communicating the non-empty state to the user, allowing them to take whatever action they deem appropriate.
The flex layout caused the element to shrink.
The error messages provided from the remote process can be highly technical and unhelpful. To start, they are all prefixed with confusing technical details: > Error invoking remote method <name> Also, the error origin can be very technical itself, e.g.: > Error: ENOENT: no such file or directory, scandir '/Users/ajayghaghretiya/Library/Application Support/Studio/server-files/wordpress-versions/latest/wp-content/themes/twentytwentythree/parts' To improve the user experience, we provide a generic, user-friendly message instead, regardless of the origin.
Site creation silently failing is confusing. Instead, we should communicate the error and ask that they retry.
Ensure we can monitor escalation of this type of error.
Site creation silently failing is confusing. Instead, we should communicate the error and ask that they retry.
This is no longer presented to the end-user. We can instead rely upon the original error message.
Surrounding logic does not rely upon the `err` abbreviation.
Hoisting the `try`/`catch` to the main process invocation site ensures that all errors originating from logic within the main process method are caught. Previously, only certain portions of the logic were wrapped in `try`/`catch`, meaning some errors would go unreported.
Allow selecting the default site path (e.g., `~/Studio` on macOS) as a means of resetting prior path selections. This allows users to recover from mistakenly changing the local path to a non-empty, non-WordPress directory.
11397ce to
e3efda7
Compare
| > | ||
| <Icon | ||
| className={ error ? 'fill-red-500' : '' } | ||
| className={ cx( 'shrink-0 basis-4', error ? 'fill-red-500' : '' ) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent form validation message icons from shrinking due to sibling content.
| setSitePath( path ); | ||
| const pathResetToDefaultSitePath = | ||
| path === proposedSitePath.substring( 0, proposedSitePath.lastIndexOf( '/' ) ); | ||
| setSitePath( pathResetToDefaultSitePath ? '' : path ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow users to reset the path selection value by selecting the default Studio directory. The outcome is using the currently proposed path instead, including any future changes to the site name.
| await createSite( path, siteName ?? '' ); | ||
| } catch ( e ) { | ||
| setError( ( e as Error )?.message ); | ||
| Sentry.captureException( e ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error reporting was hoisted here from src/ipc-handlers.ts to ensure all errors originating from the remote createSite method were caught. Previously, portions of the remote method could result in displaying error messages, but not reporting them to Sentry — e.g, the error shared in https://github.com/Automattic/dotcom-forge/issues/6590 — as we did not wrap all logic in createSite with try/catch blocks.
| setError( | ||
| __( | ||
| 'An error occurred while creating the site. Verify your selected local path is an empty directory or an existing WordPress folder and try again. If this problem persists, please contact support.' | ||
| ) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A generic error message here replaces displaying the previous error messages thrown from src/ipc-handlers.ts. This was done for a few reasons:
- All error messages originating from remote methods are prefixed with a non-user-friendly message of
Error invoking remote method <method-name>. We could remove this with regular expression, but... - Error messages from remote messages could originate from numerous failures, including references to highly technical details as outlined in Automattic/dotcom-forge#6590. It is challenging to filter out these "unknown" errors aside from parsing the error message string because...
- Electron does not provide an ability to communicate custom errors across the bridge (quoted below) aside from the message itself. Parsing the message to determine known vs unknown errors feels brittle.
Errors thrown through handle in the main process are not transparent as they are serialized and only the message property from the original error is provided to the renderer process. Please refer to #24427 for details.
| if ( ! ( await isEmptyDir( path ) ) && ! isWordPressDirectory( path ) ) { | ||
| wasPathEmpty = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The combination of ! ( await isEmptyDir( path ) ) and setting wasPathEmpty = true; appears contradictory. Additionally, now that all error handling is hoisted to the renderer, I removed this assignment and related logic.
@sejas are you able to share the original intent behind this logic (when and why it should run) and whether its removal will cause problems? 🙇🏻
I shared additional thoughts in https://github.com/Automattic/local-environment/pull/135#discussion_r1571371185.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it is contradictory.
The intention was when creating a site failed, we should remove all the new files created to allow the user to recreate it again with the same folder name.
|
|
||
| if ( ! ( await isEmptyDir( path ) ) && ! isWordPressDirectory( path ) ) { | ||
| wasPathEmpty = true; | ||
| userData.sites; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kozer I noted this one reference to userData.sites did not have a return statement like all others in this method. I presumed this was oversight.
Are you able to share the original intent of returning userData.sites? Will this removal cause issue? 🙇🏻
I shared additional thoughts in https://github.com/Automattic/local-environment/pull/55#discussion_r1571371113.
sejas
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested both flows where I added a folder inside the empty folder and I received the error message 👌
After selecting Studio, the name selection worked fine.
Thanks for this PR, this kind of PRs are my favorite. Removing code and simplifying the logic. Congrats!
I think the cases were the process of creating a site could fail were reduced almost to zero, so I think we don't need the wasEmpty logic anymore.
creating-site.mp4
| if ( wasPathEmpty ) { | ||
| // Clean the path to let the user try again | ||
| await shell.trashItem( path ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is where we removed all the files after a failed site creation in an empty directory.
I'm seeing you have removed the try/catch so I guess we assume the site creation is not likely to fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm seeing you have removed the try/catch so I guess we assume the site creation is not likely to fail.
No, not necessarily. I believe site creation could still fail, the primary focus of the proposed changes is hoisting error handling higher in the stack so that all errors that might occur in createSite method are caught.
However, as you noted, I also removed the clean up logic as I am not confident it functions as expected.
Currently, I'm perplexed by the original logic, which is why I inquired about its original intent in #4 (comment). It could be that we need to retain this logic — I'm not sure. I'd like your personal perspective on the logic's intent/necessity and the overall stability of this new site creation logic.
Here is where we removed all the files after a failed site creation in an empty directory.
Correct. I am not sure when this logic would actually execute. We set wasPathEmpty = true; when the directory is a non-empty, non-WP directory, but then only run the clean up logic when the path is a WP directory. That appears contradictory to me and I'm not sure in what circumstance that situation would be possible.
I think the cases were the process of creating a site could fail were reduced almost to zero, so I think we don't need the
wasEmptylogic anymore.
Copied this quote from your top-level review comment as I felt it related to this specific discussion as well. I'm not confident it will never fail, but my hope is that we will at least catch any errors that occur and provide a helpful error message.
Thank you for helping me understand this logic! It's definitely an important piece of functionality. 🙇🏻
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting that a recent report (ref: pdKhl6-3bi-p2#comment-6383) suggests site creation can fail leaving a partial WP directory installation. My perception is that the clean up logic intended to help rectify such a situation. However, as I mentioned in #4 (comment), I lack confidence that it works as expected and I wonder if we should prompt for user permission before taking this action, as removing a directory might inadvertently discard valuable user files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sejas following up to see I you have additional insight on the findings I expressed in my previous comments.
Completely fine if we need more time to review this. I'd prefer to understand the prior logic's intention before removing it — I'd hate to introduce bugs or make the UX less stable.
Thanks in advance for the help! 🙇🏻
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dcalhoun, Ideally we could keep the logic of deleting the site if the creation fails.
I wonder if we should prompt for user permission before taking this action, as removing a directory might inadvertently discard valuable user files.
That's why I introduced the wasEmpty flag. We should wrap it around a correct if statement that correctly checks if the given folder is empty. Then we can assume the user doesn't have any "custom" files in that folder, and all the files in that folder are created by our app. Also note that the app moves that folder into the trash and don't really remove it from the disk.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sejas I interpret your latest comment to mean the logic's intention was to clean up only app-generated files after failed attempts to create a new site in an empty directory, but that I am correct in that it currently does not function as intended because of the conflicting conditionals I referenced in #4 (comment). You believe it is ideal to retain the clean up logic, provided we fix the currently broken state.
Is all of that interpretation accurate? If so, I will work to reinstate the clean up logic.
Thanks for your patience, I repeat all this back to avoid any misunderstandings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes!, all that is correct.
We can also re-introduce the correct condition, "clean up the directory when the create fails and all the files were created by Studio", in a separate PR if you prefer that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merged these changes as-is and created #68 to follow up on this specific discussion. Thanks!
Related to https://github.com/Automattic/dotcom-forge/issues/6590.
Proposed Changes
Testing Instructions
Create site from populated, non-WordPress directory
Reset a custom local path to the proposed path
~/Studioon macOS).Pre-merge Checklist