Skip to content
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

feat: validate CLI installation and version during activation of CLI Integration extension #5185

Merged
merged 73 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
b4b60c2
feat: add structure for checking CLI version at activation of Core ex…
daphne-sfdc Oct 24, 2023
039da90
feat: parse result of 'sfdx --version' to get just the cli version
daphne-sfdc Oct 24, 2023
03e3f6c
feat: check for type of CLI (sfdx or sf) in addition to version number
daphne-sfdc Oct 24, 2023
7626689
feat: add checking to make sure SFDX CLI is installed + notification …
daphne-sfdc Oct 25, 2023
8174546
feat: check CLI version using regex
daphne-sfdc Oct 25, 2023
123e01a
fix: show error message instead of warning message if CLI is not inst…
daphne-sfdc Oct 25, 2023
4b899fb
fix: links in error notifications when CLI version is not supported
daphne-sfdc Oct 25, 2023
04b8ef7
feat: support internationalization of error message when CLI version …
daphne-sfdc Oct 26, 2023
c6fc6da
chore: remove logging
daphne-sfdc Oct 26, 2023
239fe35
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Oct 26, 2023
c44ae10
chore: make error messages more consistent
daphne-sfdc Oct 27, 2023
24d2204
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
CristiCanizales Oct 30, 2023
d685c79
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Nov 3, 2023
0936d57
refactor: use enums instead of returning strings
daphne-sfdc Nov 6, 2023
b2aced9
refactor: separate getCliVersion() into another function to make the …
daphne-sfdc Nov 6, 2023
7a93ee6
feat: add Jest unit tests for checkCliVersion.ts
daphne-sfdc Nov 6, 2023
d6ddd1b
fix: cliConfiguration.test.ts checks for error instead of warning whe…
daphne-sfdc Nov 6, 2023
8bcf1a7
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
CristiCanizales Nov 9, 2023
9753c0f
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Nov 9, 2023
1baa2cd
refactor: move validation of CLI installation and version from activa…
daphne-sfdc Nov 9, 2023
7b98401
fix: add error messages to avoid throwing empty errors
daphne-sfdc Nov 9, 2023
3d5383a
fix: turn off trailing commas in .prettierrc so that files can pass l…
daphne-sfdc Nov 9, 2023
8f7d0fe
chore: run prettier on checkCliVersion.ts
daphne-sfdc Nov 9, 2023
bc594e3
refactor: use constants for SFDX CLI and SF CLI versions
daphne-sfdc Nov 9, 2023
6495243
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
CristiCanizales Nov 13, 2023
ae6e582
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
CristiCanizales Nov 13, 2023
bdbdca3
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Nov 17, 2023
e24cb7f
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Nov 27, 2023
31d0115
feat: add support to throw error when both SFDX v7 and SF v2 are present
daphne-sfdc Nov 28, 2023
5bc03f7
chore: change function name from showPopupMessage() to showErrorNotif…
daphne-sfdc Nov 28, 2023
c7b3c9e
revert: revert copyright in index.ts
daphne-sfdc Nov 28, 2023
f8029c4
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
CristiCanizales Nov 28, 2023
025096d
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
CristiCanizales Nov 28, 2023
9ae6e71
chore: make Japanese error messages just the English messages without…
daphne-sfdc Nov 28, 2023
0a3feaf
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Nov 28, 2023
1df5748
fix: add missing export for SfCommandBuilder in index.ts
daphne-sfdc Dec 2, 2023
8269907
fix: add export class SfCommandBuilder to commandBuilder.ts
daphne-sfdc Dec 3, 2023
4c3e782
revert: revert changes to commandBuilder.ts
daphne-sfdc Dec 3, 2023
7432e20
fix: do not call validateCliInstallationAndVersion() in index.ts if O…
daphne-sfdc Dec 4, 2023
242b899
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Dec 4, 2023
f132d69
fix: add/fix headers for checkCliVersion.ts, sfCommandBuilder.ts, che…
daphne-sfdc Dec 4, 2023
5b0ced9
fix: organize imports in index.ts to pass linting
daphne-sfdc Dec 4, 2023
75236c6
refactor: move tests in checkCliVersion.test.ts into describe() funct…
daphne-sfdc Dec 5, 2023
2958f7e
chore: rename SFDX_CLI_DOWNLOAD_LINK to SF_CLI_DOWNLOAD_LINK
daphne-sfdc Dec 5, 2023
757eab2
chore: replace all calls to SFDX_CLI_DOWNLOAD_LINK with SF_CLI_DOWNLO…
daphne-sfdc Dec 5, 2023
04ee5fe
chore: remove last else that does nothing
daphne-sfdc Dec 5, 2023
4d59a2e
chore: change Number to number for eslint
daphne-sfdc Dec 5, 2023
d4659e3
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Dec 5, 2023
bc23525
fix: user-facing error messages after working with doc writer
daphne-sfdc Dec 5, 2023
01205e3
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Dec 14, 2023
db92e9c
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Dec 15, 2023
08560b7
fix: directly use child_process instead of CliCommandExecutor + use s…
daphne-sfdc Dec 16, 2023
de67697
fix: make checkCliVersion.test.ts unit tests run and pass with new st…
daphne-sfdc Dec 17, 2023
f512a87
chore: clean up checkCliVersion.ts
daphne-sfdc Dec 17, 2023
b04e05c
refactor: replace if/else block with switch statement
daphne-sfdc Dec 17, 2023
d73533c
Apply suggestions from Pete's code review
daphne-sfdc Dec 18, 2023
dc5da0d
chore: fix syntax errors to allow code to compile
daphne-sfdc Dec 18, 2023
f1487b1
chore: sfdx_cli_not_found -> salesforce_cli_not_found in cliConfigura…
daphne-sfdc Dec 18, 2023
2e8d6fb
revert: revert all references to SfCommandBuilder because it is no lo…
daphne-sfdc Dec 18, 2023
0d5c1e1
fix: apply Pete's suggestions from code review
daphne-sfdc Dec 19, 2023
3188d01
chore: remove comment
daphne-sfdc Dec 19, 2023
57e7d36
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Dec 19, 2023
265679a
feat: mocking jest unit tests for getSfdxCliVersion() and getSfCliVer…
daphne-sfdc Dec 21, 2023
d04d9c7
feat: add warning message that SFDX v7 will soon be deprecated
daphne-sfdc Dec 21, 2023
9c0758a
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Dec 21, 2023
e02927d
chore: allow CLI version validation to happen on Windows
daphne-sfdc Dec 21, 2023
f43b981
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
CristiCanizales Dec 22, 2023
b2ed360
refactor: consolidate getSfdxCliVersion() and getSfCliVersion() into …
daphne-sfdc Dec 26, 2023
ca8c144
chore: update warning message for SFDX CLI deprecation
daphne-sfdc Dec 26, 2023
f1c5f66
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Dec 26, 2023
1b047e9
refactor: getCliVersion() with ternary operator
daphne-sfdc Dec 28, 2023
c6e0d5e
chore: improved warning message for SFDX v7 deprecation
daphne-sfdc Jan 4, 2024
7f40890
Merge branch 'develop' into daphne/W-14196710-verify-cli-version
daphne-sfdc Jan 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/salesforcedx-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"cross-spawn": "7.0.3",
"request-light": "^0.7.0",
"rxjs": "^5.4.1",
"tree-kill": "^1.1.0"
"tree-kill": "^1.1.0",
"semver": "^7.5.4"
},
"devDependencies": {
"@types/jest": "^29.5.5",
Expand Down
73 changes: 73 additions & 0 deletions packages/salesforcedx-utils/src/cli/cliVersionStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* All rights reserved.
* 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 { execSync } from 'child_process';
import * as semver from 'semver';

export enum CliStatusEnum {
SFv2 = 1,
outdatedSFDXVersion = 2,
onlySFv1 = 3,
cliNotInstalled = 4,
bothSFDXAndSFInstalled = 5,
SFDXv7Valid = 6
}

export class CliVersionStatus {

public getCliVersion(isSfdx: boolean): string {
try {
let result;
if (isSfdx) {
result = execSync('sfdx --version');
} else {
result = execSync('sf --version');
}
return result.toString();
} catch {
return 'No CLI';
}
}
daphne-sfdc marked this conversation as resolved.
Show resolved Hide resolved

public parseCliVersion(cliVersion: string): string {
const pattern = /(?:sfdx-cli\/|@salesforce\/cli\/)(\d+\.\d+\.\d+)/;
const match = pattern.exec(cliVersion);
return match ? match[1] : '0.0.0';
}

public validateCliInstallationAndVersion(sfdxCliVersionString: string, sfCliVersionString: string): CliStatusEnum {

// Case 1: Neither SFDX CLI nor SF CLI is installed
if (semver.satisfies(sfdxCliVersionString, '0.0.0') && semver.satisfies(sfCliVersionString, '0.0.0')) {
return CliStatusEnum.cliNotInstalled;
}

// Case 2: Only SF CLI (v1) is installed (SF v1 cannot be used because it does not map sf to sfdx)
if (semver.satisfies(sfdxCliVersionString, '0.0.0') && semver.satisfies(sfCliVersionString, '1.x')) {
return CliStatusEnum.onlySFv1;
}

// Case 3: Both SFDX CLI (v7) and SF CLI (v2) are installed at the same time
if (semver.satisfies(sfCliVersionString, '2.x') && !semver.satisfies(sfdxCliVersionString, sfCliVersionString)) {
return CliStatusEnum.bothSFDXAndSFInstalled;
}

const minSFDXVersion = '7.193.2';
if (semver.satisfies(sfCliVersionString, '<2.0.0')) {
if (semver.satisfies(sfdxCliVersionString, (`<${minSFDXVersion}`))) {
// Case 4: Outdated SFDX CLI version is installed
return CliStatusEnum.outdatedSFDXVersion;
} else {
// Case 5: Valid SFDX v7 version is installed
return CliStatusEnum.SFDXv7Valid;
}
}

// Case 6: SF v2 is installed
return CliStatusEnum.SFv2;
}
}
1 change: 1 addition & 0 deletions packages/salesforcedx-utils/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export { ConfigGet } from './configGet';
export { GlobalCliEnvironment } from './globalCliEnvironment';
export { OrgDisplay } from './orgDisplay';
export { SfdxCommandBuilder } from './sfdxCommandBuilder';
export { CliStatusEnum, CliVersionStatus } from './cliVersionStatus';
187 changes: 187 additions & 0 deletions packages/salesforcedx-utils/test/jest/cli/cliVersionStatus.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* All rights reserved.
* 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 child_process from 'child_process';
import { CliStatusEnum, CliVersionStatus } from '../../../src/cli/cliVersionStatus';

describe('CliVersionStatus unit tests.', () => {

const sfV2_string = '@salesforce/cli/2.15.9 darwin-arm64 node-v18.17.1';
const sfdxV7_valid_string = 'sfdx-cli/7.209.6 win32-x64 node-v18.15.0';
const sfV1_string = '@salesforce/cli/1.87.0 darwin-arm64 node-v18.17.1';
const sfdxV7_outdated_string = 'sfdx-cli/7.183.1 darwin-arm64 node-v16.19.1';
const noSFDX_string = 'No CLI';
const noSF_string = 'No CLI';

const sfV2_parsed = '2.15.9';
const sfdxV7_valid_parsed = '7.209.6';
const sfV1_parsed = '1.87.0';
const sfdxV7_outdated_parsed = '7.183.1';
const noSFDX_parsed = '0.0.0';
const noSF_parsed = '0.0.0';

/*
Test cases that produce a result for getSfdxCliVersion() and getSfCliVersion()
*/
describe('Test cases that produce a result for getSfdxCliVersion() and getSfCliVersion()', () => {

const fakeExecution = Buffer.from('fake result');
const fakeResult = 'fake result';

let executeSpy: jest.SpyInstance;
beforeEach(() => {
executeSpy = jest
.spyOn(child_process, 'execSync')
.mockReturnValue(fakeExecution);
});

it('getSfdxCliVersion() - can get a result', async () => {
const cliVersionStatus = new CliVersionStatus();
const result = cliVersionStatus.getCliVersion(true);
expect(result).toEqual(fakeResult);
expect(executeSpy).toHaveBeenCalled();
});

it('getSfCliVersion() - can get a result', async () => {
const cliVersionStatus = new CliVersionStatus();
const result = cliVersionStatus.getCliVersion(false);
expect(result).toEqual(fakeResult);
expect(executeSpy).toHaveBeenCalled();
});
});

/*
Test cases that throw an error for getSfdxCliVersion() and getSfCliVersion()
*/
describe('Test cases that throw an error for getSfdxCliVersion() and getSfCliVersion()', () => {

const cliNotFound = 'No CLI';

let executeSpy: jest.SpyInstance;
beforeEach(() => {
executeSpy = jest
.spyOn(child_process, 'execSync')
.mockImplementationOnce(() => {
throw new Error('simulate exception in execSync()');
});
});

it('getSfdxCliVersion() - throws error', async () => {
const cliVersionStatus = new CliVersionStatus();
const result = cliVersionStatus.getCliVersion(true);
expect(result).toEqual(cliNotFound);
expect(executeSpy).toHaveBeenCalled();
});

it('getSfCliVersion() - can get a result', async () => {
const cliVersionStatus = new CliVersionStatus();
const result = cliVersionStatus.getCliVersion(false);
expect(result).toEqual(cliNotFound);
expect(executeSpy).toHaveBeenCalled();
});
});

/*
Test cases for the parseCliVersion() function
*/
describe('Test cases for the parseCliVersion() function', () => {
it('Parse valid SFDX', () => {
const c = new CliVersionStatus();
const result = c.parseCliVersion(sfdxV7_valid_string);
expect(result).toStrictEqual(sfdxV7_valid_parsed);
});

it('Parse outdated SFDX', () => {
const c = new CliVersionStatus();
const result = c.parseCliVersion(sfdxV7_outdated_string);
expect(result).toStrictEqual(sfdxV7_outdated_parsed);
});

it('Parse valid SF v2', () => {
const c = new CliVersionStatus();
const result = c.parseCliVersion(sfV2_string);
expect(result).toStrictEqual(sfV2_parsed);
});

it('Parse SFDX not installed', () => {
const c = new CliVersionStatus();
const result = c.parseCliVersion(noSFDX_string);
expect(result).toStrictEqual(noSFDX_parsed);
});

it('Parse SF v1', () => {
const c = new CliVersionStatus();
const result = c.parseCliVersion(sfV1_string);
expect(result).toStrictEqual(sfV1_parsed);
});

it('Parse SF not installed', () => {
const c = new CliVersionStatus();
const result = c.parseCliVersion(noSF_string);
expect(result).toStrictEqual(noSF_parsed);
});
});

/*
Test cases for the validateCliInstallationAndVersion() function
*/
describe('Test cases for the validateCliInstallationAndVersion() function', () => {
it('Case 1: No Salesforce CLI installed - should fail', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(noSFDX_parsed, noSF_parsed);
expect(result).toStrictEqual(CliStatusEnum.cliNotInstalled);
});

it('Case 2: Only SF v1 installed - should fail', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(noSFDX_parsed, sfV1_parsed);
expect(result).toStrictEqual(CliStatusEnum.onlySFv1);
});

it('Case 3: Both SFDX v7 (outdated) and SF v2 installed - should fail', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(sfdxV7_outdated_parsed, sfV2_parsed);
expect(result).toStrictEqual(CliStatusEnum.bothSFDXAndSFInstalled);
});

it('Case 4: Both SFDX v7 (valid) and SF v2 installed - should fail', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(sfdxV7_valid_parsed, sfV2_parsed);
expect(result).toStrictEqual(CliStatusEnum.bothSFDXAndSFInstalled);
});

it('Case 5: Only SFDX v7 (outdated) installed - should fail', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(sfdxV7_outdated_parsed, noSF_parsed);
expect(result).toStrictEqual(CliStatusEnum.outdatedSFDXVersion);
});

it('Case 6: Only SFDX v7 (valid) installed - should activate Core extension', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(sfdxV7_valid_parsed, noSF_parsed);
expect(result).toStrictEqual(CliStatusEnum.SFDXv7Valid);
});

it('Case 7: SFDX v7 (outdated) and SF v1 installed - should fail', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(sfdxV7_outdated_parsed, sfV1_parsed);
expect(result).toStrictEqual(CliStatusEnum.outdatedSFDXVersion);
});

it('Case 8: SFDX v7 (valid) and SF v1 installed - should activate Core extension', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(sfdxV7_valid_parsed, sfV1_parsed);
expect(result).toStrictEqual(CliStatusEnum.SFDXv7Valid);
});

it('Case 9: Only SF v2 installed - should activate Core extension', () => {
const c = new CliVersionStatus();
const result = c.validateCliInstallationAndVersion(sfV2_parsed, sfV2_parsed);
expect(result).toStrictEqual(CliStatusEnum.SFv2);
});
});
});
4 changes: 2 additions & 2 deletions packages/salesforcedx-vscode-core/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export const STATUS_BAR_MSG_TIMEOUT_MS = 5000;
export const APEX_CODE_DEBUG_LEVEL = 'FINEST';
export const VISUALFORCE_DEBUG_LEVEL = 'FINER';
export const ENV_SF_DISABLE_TELEMETRY = 'SF_DISABLE_TELEMETRY';
export const SFDX_CLI_DOWNLOAD_LINK =
'https://developer.salesforce.com/tools/sfdxcli';
export const SF_CLI_DOWNLOAD_LINK =
'https://developer.salesforce.com/tools/salesforcecli';
export const TARGET_ORG_KEY = 'target-org';
export const PKG_ID_PREFIX = '04t';

Expand Down
Loading
Loading