From 6876c40259b907b9766a53ee3ca819c5bba96e4d Mon Sep 17 00:00:00 2001
From: Vicente Jr Yuchitcho <chitchu@users.noreply.github.com>
Date: Sun, 26 Feb 2017 03:48:53 +1100
Subject: [PATCH] Gracefully handle initial installation error (#1512)

* Gracefully handle initial installation error

* Print out message when problem occurs
* Delete project folder on errors

* Fix directory deleting message

Resolves #1505
---
 packages/create-react-app/index.js | 25 ++++++++++++++++++++++++-
 tasks/e2e-installs.sh              | 26 ++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/packages/create-react-app/index.js b/packages/create-react-app/index.js
index 6b7dce9b6..d5afee43b 100755
--- a/packages/create-react-app/index.js
+++ b/packages/create-react-app/index.js
@@ -182,7 +182,30 @@ function run(root, appName, version, verbose, originalDirectory, template) {
 
   install(allDependencies, verbose, function(code, command, args) {
     if (code !== 0) {
-      console.error(chalk.cyan(command + ' ' + args.join(' ')) + ' failed');
+      console.log();
+      console.error('Aborting installation.', chalk.cyan(command + ' ' + args.join(' ')), 'has failed.');
+      // On 'exit' we will delete these files from target directory.
+      var knownGeneratedFiles = [
+        'package.json', 'npm-debug.log', 'yarn-error.log', 'yarn-debug.log', 'node_modules'
+      ];
+      var currentFiles = fs.readdirSync(path.join(root));
+      currentFiles.forEach(function (file) {
+        knownGeneratedFiles.forEach(function (fileToMatch) {
+          // This will catch `(npm-debug|yarn-error|yarn-debug).log*` files
+          // and the rest of knownGeneratedFiles.
+          if ((fileToMatch.match(/.log/g) && file.indexOf(fileToMatch) === 0) || file === fileToMatch) {
+            console.log('Deleting generated file...', chalk.cyan(file));
+            fs.removeSync(path.join(root, file));
+          }
+        });
+      });
+      var remainingFiles = fs.readdirSync(path.join(root));
+      if (!remainingFiles.length) {
+        // Delete target folder if empty
+        console.log('Deleting', chalk.cyan(appName + '/'), 'from', chalk.cyan(path.resolve(root, '..')));
+        fs.removeSync(path.join(root));
+      }
+      console.log('Done.');
       process.exit(1);
     }
 
diff --git a/tasks/e2e-installs.sh b/tasks/e2e-installs.sh
index d3427f8c8..ac25da7e6 100755
--- a/tasks/e2e-installs.sh
+++ b/tasks/e2e-installs.sh
@@ -119,6 +119,32 @@ cd test-app-fork
 # Check corresponding scripts version is installed.
 exists node_modules/react-scripts-fork
 
+# ******************************************************************************
+# Test project folder is deleted on failing package installation
+# ******************************************************************************
+
+cd $temp_app_path
+# we will install a non-existing package to simulate a failed installataion.
+create_react_app --scripts-version=`date +%s` test-app-should-not-exist || true
+# confirm that the project folder was deleted
+test ! -d test-app-should-not-exist
+
+# ******************************************************************************
+# Test project folder is not deleted when creating app over existing folder
+# ******************************************************************************
+
+cd $temp_app_path
+mkdir test-app-should-remain
+echo '## Hello' > ./test-app-should-remain/README.md
+# we will install a non-existing package to simulate a failed installataion.
+create_react_app --scripts-version=`date +%s` test-app-should-remain || true
+# confirm the file exist
+test -e test-app-should-remain/README.md
+# confirm only README.md is the only file in the directory
+if [ "$(ls -1 ./test-app-should-remain | wc -l | tr -d '[:space:]')" != "1" ]; then
+  false
+fi
+
 # ******************************************************************************
 # Test nested folder path as the project name
 # ******************************************************************************
-- 
GitLab