diff --git a/.changeset/real-boats-promise.md b/.changeset/real-boats-promise.md
new file mode 100644
index 00000000000..8769bcdb667
--- /dev/null
+++ b/.changeset/real-boats-promise.md
@@ -0,0 +1,5 @@
+---
+"@clerk/upgrade": minor
+---
+
+Enhancing error handling throughout the SDK upgrade flow
diff --git a/packages/upgrade/src/app.js b/packages/upgrade/src/app.js
index ee181f62fa1..10b9bff4427 100644
--- a/packages/upgrade/src/app.js
+++ b/packages/upgrade/src/app.js
@@ -63,12 +63,7 @@ export default function App(props) {
// Handle the individual SDK upgrade
if (!fromVersion && !toVersion && sdks[0] === 'nextjs') {
- return (
-
- );
+ return ;
}
// We try to guess which SDK they are using
diff --git a/packages/upgrade/src/cli.js b/packages/upgrade/src/cli.js
index 78ad8769b33..da191342805 100644
--- a/packages/upgrade/src/cli.js
+++ b/packages/upgrade/src/cli.js
@@ -17,7 +17,6 @@ const cli = meow(
--sdk Name of the SDK you're upgrading
--dir Directory you'd like to scan for files
--ignore Any files or directories you'd like to ignore
- --packageManager The package manager you're using (npm, yarn, pnpm)
--noWarnings Do not print warnings, only items that must be fixed
--disableTelemetry Do not send anonymous usage telemetry
@@ -34,7 +33,6 @@ const cli = meow(
sdk: { type: 'string', choices: sdks.map(i => i.value) },
dir: { type: 'string' },
ignore: { type: 'string', isMultiple: true },
- packageManager: { type: 'string' },
yolo: { type: 'boolean' },
noWarnings: { type: 'boolean' },
disableTelemetry: { type: 'boolean' },
diff --git a/packages/upgrade/src/components/Codemod.js b/packages/upgrade/src/components/Codemod.js
index 9350dd110ad..9498dd800f4 100644
--- a/packages/upgrade/src/components/Codemod.js
+++ b/packages/upgrade/src/components/Codemod.js
@@ -58,7 +58,7 @@ export function Codemod(props) {
>
)}
- {!result && !error && glob && codemod... ${transform}`} />}
+ {!result && !error && glob && }
{result && (
<>
diff --git a/packages/upgrade/src/components/SDKWorkflow.js b/packages/upgrade/src/components/SDKWorkflow.js
index 4c734e18ca6..bf07c29f5c0 100644
--- a/packages/upgrade/src/components/SDKWorkflow.js
+++ b/packages/upgrade/src/components/SDKWorkflow.js
@@ -16,13 +16,12 @@ import { UpgradeSDK } from './UpgradeSDK.js';
*
* @component
* @param {Object} props
- * @param {string} props.packageManager - The package manager to use for the upgrade, if needed.
* @param {string} props.sdk - The SDK to be upgraded.
*
* @returns {JSX.Element} The rendered component.
*/
export function SDKWorkflow(props) {
- const { packageManager, sdk } = props;
+ const { sdk } = props;
const [done, setDone] = useState(false);
const [runCodemod, setRunCodemod] = useState(false);
@@ -59,7 +58,6 @@ export function SDKWorkflow(props) {
<>
{upgradeComplete ? (
diff --git a/packages/upgrade/src/components/UpgradeSDK.js b/packages/upgrade/src/components/UpgradeSDK.js
index 1f52fffbb25..1fc3f3113a7 100644
--- a/packages/upgrade/src/components/UpgradeSDK.js
+++ b/packages/upgrade/src/components/UpgradeSDK.js
@@ -1,7 +1,7 @@
-import { Spinner, StatusMessage } from '@inkjs/ui';
+import { Select, Spinner, StatusMessage } from '@inkjs/ui';
import { execa } from 'execa';
import { existsSync } from 'fs';
-import { Text } from 'ink';
+import { Newline, Text } from 'ink';
import React, { useEffect, useState } from 'react';
function detectPackageManager() {
@@ -11,13 +11,12 @@ function detectPackageManager() {
return 'yarn';
} else if (existsSync('pnpm-lock.yaml')) {
return 'pnpm';
- } else {
- return 'npm';
}
+ return undefined;
}
function upgradeCommand(sdk, packageManager) {
- switch (packageManager || detectPackageManager()) {
+ switch (packageManager) {
case 'yarn':
return `yarn add @clerk/${sdk}@latest`;
case 'pnpm':
@@ -33,39 +32,85 @@ function upgradeCommand(sdk, packageManager) {
* @component
* @param {Object} props
* @param {Function} props.callback - The callback function to be called after the command execution.
- * @param {string} props.packageManager - The package manager used in the project in case we cannot detect it automatically.
* @param {string} props.sdk - The SDK for which the upgrade command is run.
* @returns {JSX.Element} The rendered component.
*
* @example
*
*/
-export function UpgradeSDK({ callback, packageManager, sdk }) {
+export function UpgradeSDK({ callback, sdk }) {
+ const [command, setCommand] = useState();
const [error, setError] = useState();
+ const [packageManager, setPackageManager] = useState(detectPackageManager());
const [result, setResult] = useState();
- const command = upgradeCommand(sdk, packageManager);
-
useEffect(() => {
+ if (!packageManager) {
+ return;
+ }
+ setCommand(previous => {
+ if (previous) {
+ return previous;
+ }
+ return upgradeCommand(sdk, packageManager);
+ });
+ if (!command) {
+ return;
+ }
+
execa({ shell: true })`${command}`
.then(res => {
setResult(res);
- callback(true);
})
.catch(err => {
setError(err);
+ })
+ .finally(() => {
+ callback(true);
});
- }, [command]);
+ }, [command, packageManager, sdk]);
return (
<>
- {!result && !error && }
+ {packageManager ? null : (
+ <>
+
+ We could not detect the package manager used in your project. Please select the package manager you are
+ using
+
+
+ >
+ )}
+ {packageManager && !result && !error && }
{result && (
@clerk/{sdk} upgraded successfully to latest!
)}
- {error && Upgrade failed!}
+ {error && (
+ <>
+
+ Running the upgrade command failed:{' '}
+
+ {command}
+
+
+
+ Please manually upgrade @clerk/{sdk} to latest in your project.
+
+
+ >
+ )}
>
);
}