Skip to content

Commit

Permalink
fix(cli): avoid npx during upgrade command (#10479)
Browse files Browse the repository at this point in the history
**Problem**
Fixes #10466.

During `yarn rw upgrade` we check the version of `npx` installed. It's
entirely possible that `npx` is not available or installed.

We only do this check because we have to handle dedupe differently
between yarn v1 and yarn >v1. We specify that redwood projects should be
using yarn v4 using `"packageManager": "[email protected]"` in the
`package.json`. Therefore when following the recommended setup users
should not be using yarn v1 in their redwood projects.

**Changes**
1. Avoid `npx` version check.
2. Skip dedupe step if for some reason have yarn v1. When this happens
we log a warning message to tell the user to run a command manually to
dedupe.
  • Loading branch information
Josh-Walker-GM committed Apr 19, 2024
1 parent 942f296 commit 793c537
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 39 deletions.
3 changes: 3 additions & 0 deletions .changesets/10479.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- fix(cli): avoid `npx` during upgrade command (#10479) by @Josh-Walker-GM

This change fixes a problem with the `yarn rw upgrade` command when you don't have `npx` installed. If you don't have `npx` installed you will now have to manually run a command to dedupe dependencies rather than this being done for you automatically during the upgrade command. If this is the case, the `npx` command will be logged to the console when you run `yarn rw upgrade`.
75 changes: 36 additions & 39 deletions packages/cli/src/commands/upgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const builder = (yargs) => {
yargs
.example(
'rw upgrade -t 0.20.1-canary.5',
'Specify a version. URL for Version History:\nhttps://www.npmjs.com/package/@redwoodjs/core'
'Specify a version. URL for Version History:\nhttps://www.npmjs.com/package/@redwoodjs/core',
)
.option('dry-run', {
alias: 'd',
Expand Down Expand Up @@ -49,11 +49,11 @@ export const builder = (yargs) => {
.epilogue(
`Also see the ${terminalLink(
'Redwood CLI Reference for the upgrade command',
'https://redwoodjs.com/docs/cli-commands#upgrade'
'https://redwoodjs.com/docs/cli-commands#upgrade',
)}.\nAnd the ${terminalLink(
'GitHub releases page',
'https://github.com/redwoodjs/redwood/releases'
)} for more information on the current release.`
'https://github.com/redwoodjs/redwood/releases',
)} for more information on the current release.`,
)
}

Expand All @@ -76,8 +76,8 @@ export const validateTag = (tag) => {
// Stop execution
throw new Error(
c.error(
"Invalid tag supplied. Supported values: 'rc', 'canary', 'latest', 'next', 'experimental', or a valid semver version\n"
)
"Invalid tag supplied. Supported values: 'rc', 'canary', 'latest', 'next', 'experimental', or a valid semver version\n",
),
)
}

Expand Down Expand Up @@ -132,19 +132,19 @@ export const handler = async ({ dryRun, tag, verbose, dedupe }) => {
const version = ctx.versionToUpgradeTo
const messageSections = [
`One more thing...\n\n ${c.warning(
`🎉 Your project has been upgraded to RedwoodJS ${version}!`
`🎉 Your project has been upgraded to RedwoodJS ${version}!`,
)} \n\n`,
]
// Show links when switching to 'latest' or 'rc', undefined is essentially an alias of 'latest'
if ([undefined, 'latest', 'rc'].includes(tag)) {
messageSections.push(
` Please review the release notes for any manual steps: \n ❖ ${terminalLink(
`Redwood community discussion`,
`https://community.redwoodjs.com/search?q=${version}%23announcements`
`https://community.redwoodjs.com/search?q=${version}%23announcements`,
)}\n ❖ ${terminalLink(
`GitHub Release notes`,
`https://github.com/redwoodjs/redwood/releases` // intentionally not linking to specific version
)} \n\n`
`https://github.com/redwoodjs/redwood/releases`, // intentionally not linking to specific version
)} \n\n`,
)
}
// @MARK
Expand All @@ -157,14 +157,14 @@ export const handler = async ({ dryRun, tag, verbose, dedupe }) => {
isValidRedwoodJSTag(tag)
) {
additionalMessages.push(
` ❖ You may want to update your redwood.toml config so that \`notifications.versionUpdates\` includes "${tag}"\n`
` ❖ You may want to update your redwood.toml config so that \`notifications.versionUpdates\` includes "${tag}"\n`,
)
}
// Append additional messages with a header
if (additionalMessages.length > 0) {
messageSections.push(
` 📢 ${c.warning(`We'd also like to remind you that:`)} \n`,
...additionalMessages
...additionalMessages,
)
}
}
Expand All @@ -175,7 +175,7 @@ export const handler = async ({ dryRun, tag, verbose, dedupe }) => {
{
renderer: verbose && 'verbose',
rendererOptions: { collapseSubtasks: false },
}
},
)

await tasks.run()
Expand All @@ -192,11 +192,11 @@ async function yarnInstall({ verbose }) {
stdio: verbose ? 'inherit' : 'pipe',

cwd: getPaths().base,
}
},
)
} catch (e) {
throw new Error(
'Could not finish installation. Please run `yarn install` and then `yarn dedupe`, before continuing'
'Could not finish installation. Please run `yarn install` and then `yarn dedupe`, before continuing',
)
}
}
Expand All @@ -205,7 +205,7 @@ async function setLatestVersionToContext(ctx, tag) {
try {
const foundVersion = await latestVersion(
'@redwoodjs/core',
tag ? { version: tag } : {}
tag ? { version: tag } : {},
)

ctx.versionToUpgradeTo = foundVersion
Expand All @@ -220,12 +220,12 @@ async function setLatestVersionToContext(ctx, tag) {
*/
function updatePackageJsonVersion(pkgPath, version, { dryRun, verbose }) {
const pkg = JSON.parse(
fs.readFileSync(path.join(pkgPath, 'package.json'), 'utf-8')
fs.readFileSync(path.join(pkgPath, 'package.json'), 'utf-8'),
)

if (pkg.dependencies) {
for (const depName of Object.keys(pkg.dependencies).filter(
(x) => x.startsWith('@redwoodjs/') && x !== '@redwoodjs/studio'
(x) => x.startsWith('@redwoodjs/') && x !== '@redwoodjs/studio',
)) {
if (verbose || dryRun) {
console.log(` - ${depName}: ${pkg.dependencies[depName]} => ${version}`)
Expand All @@ -235,11 +235,11 @@ function updatePackageJsonVersion(pkgPath, version, { dryRun, verbose }) {
}
if (pkg.devDependencies) {
for (const depName of Object.keys(pkg.devDependencies).filter(
(x) => x.startsWith('@redwoodjs/') && x !== '@redwoodjs/studio'
(x) => x.startsWith('@redwoodjs/') && x !== '@redwoodjs/studio',
)) {
if (verbose || dryRun) {
console.log(
` - ${depName}: ${pkg.devDependencies[depName]} => ${version}`
` - ${depName}: ${pkg.devDependencies[depName]} => ${version}`,
)
}
pkg.devDependencies[depName] = `${version}`
Expand All @@ -249,7 +249,7 @@ function updatePackageJsonVersion(pkgPath, version, { dryRun, verbose }) {
if (!dryRun) {
fs.writeFileSync(
path.join(pkgPath, 'package.json'),
JSON.stringify(pkg, undefined, 2)
JSON.stringify(pkg, undefined, 2),
)
}
}
Expand All @@ -274,7 +274,7 @@ function updateRedwoodDepsForAllSides(ctx, options) {
updatePackageJsonVersion(basePath, ctx.versionToUpgradeTo, options),
skip: () => !fs.existsSync(pkgJsonPath),
}
})
}),
)
}

Expand Down Expand Up @@ -318,13 +318,13 @@ async function updatePackageVersionsFromTemplate(ctx, { dryRun, verbose }) {
if (!depName.startsWith('@redwoodjs/')) {
if (verbose || dryRun) {
console.log(
` - ${depName}: ${localPackageJson.dependencies[depName]} => ${depVersion}`
` - ${depName}: ${localPackageJson.dependencies[depName]} => ${depVersion}`,
)
}

localPackageJson.dependencies[depName] = depVersion
}
}
},
)

Object.entries(templatePackageJson.devDependencies || {}).forEach(
Expand All @@ -333,25 +333,25 @@ async function updatePackageVersionsFromTemplate(ctx, { dryRun, verbose }) {
if (!depName.startsWith('@redwoodjs/')) {
if (verbose || dryRun) {
console.log(
` - ${depName}: ${localPackageJson.devDependencies[depName]} => ${depVersion}`
` - ${depName}: ${localPackageJson.devDependencies[depName]} => ${depVersion}`,
)
}

localPackageJson.devDependencies[depName] = depVersion
}
}
},
)

if (!dryRun) {
fs.writeFileSync(
pkgJsonPath,
JSON.stringify(localPackageJson, null, 2)
JSON.stringify(localPackageJson, null, 2),
)
}
},
skip: () => !fs.existsSync(pkgJsonPath),
}
})
}),
)
}

Expand All @@ -366,7 +366,7 @@ async function refreshPrismaClient(task, { verbose }) {
} catch (e) {
task.skip('Refreshing the Prisma client caused an Error.')
console.log(
'You may need to update your prisma client manually: $ yarn rw prisma generate'
'You may need to update your prisma client manually: $ yarn rw prisma generate',
)
console.log(c.error(e.message))
}
Expand All @@ -390,11 +390,6 @@ export const getCmdMajorVersion = async (command) => {
const dedupeDeps = async (task, { verbose }) => {
try {
const yarnVersion = await getCmdMajorVersion('yarn')
const npxVersion = await getCmdMajorVersion('npx')
let npxArgs = []
if (npxVersion > 6) {
npxArgs = ['--yes']
}

const baseExecaArgsForDedupe = {
shell: true,
Expand All @@ -404,16 +399,18 @@ const dedupeDeps = async (task, { verbose }) => {
if (yarnVersion > 1) {
await execa('yarn', ['dedupe'], baseExecaArgsForDedupe)
} else {
await execa(
'npx',
[...npxArgs, 'yarn-deduplicate'],
baseExecaArgsForDedupe
// Redwood projects should not be using yarn 1.x as we specify a version of yarn in the package.json
// with "packageManager": "[email protected]" or similar.
// Although we could (and previous did) automatically run `npx yarn-deduplicate` here, that would require
// the user to have `npx` installed, which is not guaranteed and we do not wish to enforce that.
task.skip(
"Yarn 1.x doesn't support dedupe directly. Please upgrade yarn or use npx with `npx yarn-deduplicate` manually.",
)
}
} catch (e) {
console.log(c.error(e.message))
throw new Error(
'Could not finish de-duplication. For yarn 1.x, please run `npx yarn-deduplicate`, or for yarn 3 run `yarn dedupe` before continuing'
'Could not finish de-duplication. For yarn 1.x, please run `npx yarn-deduplicate`, or for yarn 3 run `yarn dedupe` before continuing',
)
}
await yarnInstall({ verbose })
Expand Down

0 comments on commit 793c537

Please sign in to comment.