diff --git a/.circleci/config.yml b/.circleci/config.yml index acb807ac..7f818d9e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -334,16 +334,16 @@ workflows: branches: only: - dev - - release-management/release-package: - tag: dev - github-release: false - prerelease: true - requires: - - approval - filters: - branches: - only: - - dev + # - release-management/release-package: + # tag: dev + # github-release: false + # prerelease: true + # requires: + # - approval + # filters: + # branches: + # only: + # - dev - pack-and-upload-tarballs: filters: branches: @@ -351,7 +351,7 @@ workflows: - dev requires: - approval - - release-management/release-package + # - release-management/release-package - pack-and-upload-macos-installer: filters: branches: diff --git a/package.json b/package.json index c59af8ca..bf0497fc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sfdx-cli", "description": "Salesforce CLI", - "version": "7.126.0-dev.5", + "version": "7.126.0-dev.6", "author": "Salesforce", "license": "BSD-3-Clause", "bugs": "https://github.com/forcedotcom/cli/issues", diff --git a/src/hooks/postupdate.ts b/src/hooks/postupdate.ts index f29050cd..49defe38 100644 --- a/src/hooks/postupdate.ts +++ b/src/hooks/postupdate.ts @@ -4,13 +4,17 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ + import * as os from 'os'; import * as path from 'path'; -import { exec, which } from 'shelljs'; + +import { cli } from 'cli-ux'; +import { readFileSync, readJsonSync, writeFileSync } from 'fs-extra'; +import { chmod, exec } from 'shelljs'; + import { TelemetryGlobal } from '@salesforce/plugin-telemetry/lib/telemetryGlobal'; import { AppInsights } from '@salesforce/telemetry/lib/appInsights'; import { JsonMap } from '@salesforce/ts-types'; -import { cli } from 'cli-ux'; declare const global: TelemetryGlobal; @@ -21,8 +25,10 @@ function sendEvent(data: JsonMap): void { } function suggestAlternatives(): void { - cli.log('Failed to install sf. Try one of the following:'); - cli.log('- npm: npm install @salesforce/cli --global'); + cli.log('Failed to update sf. Try uninstalling the CLI and re-installing it.'); + cli.log( + 'Uninstall instructions: https://developer.salesforce.com/docs/atlas.en-us.234.0.sfdx_setup.meta/sfdx_setup/sfdx_setup_uninstall.htm' + ); if (process.platform === 'win32') { cli.log('- installer: https://developer.salesforce.com/media/salesforce-cli/sf/channels/stable/sf-x64.exe'); } else if (process.platform === 'darwin') { @@ -33,88 +39,45 @@ function suggestAlternatives(): void { } /** - * Return true if any part of the sf executable path contains a string that is known - * to be part of an npm path. - */ -function isNpmInstall(sfPath: string): boolean { - const nodePathParts = ['node', 'nodejs', '.nvm', '.asdf', 'node_modules', 'npm', '.npm']; - const sfPathParts = sfPath.split(path.sep); - return sfPathParts.filter((p) => nodePathParts.includes(p.toLowerCase())).length > 0; -} - -/** - * We want to skip the sf installation if there's an existing installation that is NOT - * from npm. In other words, if the user has already installed sf with the installer, - * we do not want to overwrite it. - */ -function isBinaryInstall(): boolean { - const existingSf = which('sf')?.stdout; - if (existingSf) return !isNpmInstall(existingSf); - return false; -} - -/** - * In order to install sf for users who use the installers, we've added - * this hook which will install sf via npm after sfdx update completes. - * - * This is not a sufficient solution as there are likely many users who - * do not have npm installed on their machine. For this reason, we are - * logging that information to app insights so that we decide which solutions - * we need to build next to ensure sf is available to all sfdx users. - * + * In order to make the bundled version of `sf` available after + * users run `sfdx update` we've added this hook which will copy + * the sfdx executable and modify it for `sf`. */ // eslint-disable-next-line @typescript-eslint/require-await const hook = async function (): Promise { - let succcess = false; + let success = false; const sfdxVersion = exec('sfdx --version', { silent: true })?.stdout || 'unknown'; - // Skip the install if there's an existing sf that was installed by an installer - if (isBinaryInstall()) { - succcess = true; - return; - } - - cli.action.start('sfdx-cli: Installing sf'); + cli.action.start('sfdx-cli: Updating sf'); try { - const npmInstallation = which('npm')?.stdout; - if (!npmInstallation) { - sendEvent({ - eventName: 'POST_SFDX_UPDATE_SF_INSTALL_ERROR', - type: 'EVENT', - message: 'npm not installed on machine', - sfdxVersion, - }); - return; - } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const pjson = readJsonSync(path.join(__dirname, '../../package.json')) as { oclif: { dirname: string } }; - const installResult = exec('npm install -g @salesforce/cli', { silent: true }); - if (installResult.code > 0) { - sendEvent({ - eventName: 'POST_SFDX_UPDATE_SF_INSTALL_ERROR', - type: 'EVENT', - message: 'npm global install failed', - stackTrace: installResult.stderr?.replace(new RegExp(os.homedir(), 'g'), AppInsights.GDPR_HIDDEN), - sfdxVersion, - }); - return; + let dataDirBin; + let sfdxExec; + let sfExec; + if (os.type() === 'Windows_NT') { + dataDirBin = path.join(process.env.LOCALAPPDATA as string, pjson.oclif.dirname, 'client', 'bin'); + sfdxExec = sfExec = path.join(dataDirBin, 'sfdx.cmd'); + sfExec = path.join(dataDirBin, 'sf.cmd'); + } else { + dataDirBin = path.join(process.env.HOME as string, pjson.oclif.dirname, 'client', 'bin'); + sfdxExec = path.join(dataDirBin, 'sfdx'); + sfExec = path.join(dataDirBin, 'sf'); } - succcess = true; - const sfVersion = exec('sf --version', { silent: true }).stdout; - sendEvent({ - eventName: 'POST_SFDX_UPDATE_SF_INSTALL_SUCCESS', - type: 'EVENT', - message: 'sf install succeeded', - sfVersion, - sfdxVersion, - }); + writeFileSync(sfExec, readFileSync(sfdxExec, { encoding: 'utf-8' }).replace(/sfdx/g, 'sf').replace(/SFDX/g, 'SF')); + chmod('+x', path.join(dataDirBin, sfExec)); + + success = true; } catch (error) { const err = error as Error; - succcess = false; + success = false; sendEvent({ - eventName: 'POST_SFDX_UPDATE_SF_INSTALL_ERROR', + eventName: 'POST_SFDX_UPDATE_SF_UPDATE_ERROR', type: 'EVENT', message: err.message, stackTrace: err?.stack?.replace(new RegExp(os.homedir(), 'g'), AppInsights.GDPR_HIDDEN), @@ -122,8 +85,8 @@ const hook = async function (): Promise { }); return; } finally { - cli.action.stop(succcess ? 'done' : 'failed'); - if (!succcess) suggestAlternatives(); + cli.action.stop(success ? 'done' : 'failed'); + if (!success) suggestAlternatives(); } };