Skip to content

Commit 26d0fc2

Browse files
chore: merge main, resolve conflicts
2 parents 684baa4 + 96c0e94 commit 26d0fc2

6 files changed

Lines changed: 1596 additions & 785 deletions

File tree

.github/workflows/just-nuts.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ jobs:
2323
matrix:
2424
os: [ubuntu-latest, windows-latest]
2525
repository:
26+
# - salesforcecli/plugin-agent
2627
- salesforcecli/plugin-auth
2728
- salesforcecli/plugin-apex
2829
- salesforcecli/plugin-api

README.md

Lines changed: 929 additions & 212 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@salesforce/cli",
33
"description": "The Salesforce CLI",
4-
"version": "2.86.5",
4+
"version": "2.93.0",
55
"author": "Salesforce",
66
"bin": {
77
"sf": "./bin/run.js",
@@ -56,6 +56,7 @@
5656
"@oclif/plugin-version",
5757
"@oclif/plugin-warn-if-update-available",
5858
"@oclif/plugin-which",
59+
"@salesforce/plugin-agent",
5960
"@salesforce/plugin-apex",
6061
"@salesforce/plugin-api",
6162
"@salesforce/plugin-auth",
@@ -75,14 +76,15 @@
7576
"@salesforce/plugin-user"
7677
],
7778
"jitPlugins": {
78-
"@salesforce/plugin-code-analyzer": "5.0.0-beta.3",
79-
"@salesforce/plugin-custom-metadata": "3.3.50",
80-
"@salesforce/plugin-community": "3.3.20",
79+
"@salesforce/plugin-code-analyzer": "5.1.0",
80+
"@salesforce/plugin-community": "3.3.26",
81+
"@salesforce/plugin-custom-metadata": "3.3.56",
8182
"@salesforce/plugin-dev": "2.5.1",
8283
"@salesforce/plugin-devops-center": "1.2.27",
83-
"@salesforce/plugin-signups": "2.6.22",
84+
"@salesforce/plugin-flow": "1.0.2",
85+
"@salesforce/plugin-signups": "2.6.28",
8486
"@salesforce/sfdx-plugin-lwc-test": "1.2.1",
85-
"@salesforce/sfdx-scanner": "4.11.0"
87+
"@salesforce/sfdx-scanner": "4.12.0"
8688
},
8789
"devPlugins": [
8890
"@oclif/plugin-command-snapshot",
@@ -143,37 +145,38 @@
143145
},
144146
"dependencies": {
145147
"@inquirer/select": "^2.3.5",
146-
"@oclif/core": "4.2.10",
147-
"@oclif/plugin-autocomplete": "3.2.27",
148-
"@oclif/plugin-commands": "4.1.24",
149-
"@oclif/plugin-help": "6.2.27",
150-
"@oclif/plugin-not-found": "3.2.49",
151-
"@oclif/plugin-plugins": "5.4.36",
152-
"@oclif/plugin-search": "1.2.23",
153-
"@oclif/plugin-update": "4.6.38",
154-
"@oclif/plugin-version": "2.2.27",
155-
"@oclif/plugin-warn-if-update-available": "3.1.38",
156-
"@oclif/plugin-which": "3.2.34",
148+
"@oclif/core": "4.3.1",
149+
"@oclif/plugin-autocomplete": "3.2.29",
150+
"@oclif/plugin-commands": "4.1.25",
151+
"@oclif/plugin-help": "6.2.28",
152+
"@oclif/plugin-not-found": "3.2.55",
153+
"@oclif/plugin-plugins": "5.4.39",
154+
"@oclif/plugin-search": "1.2.24",
155+
"@oclif/plugin-update": "4.6.42",
156+
"@oclif/plugin-version": "2.2.28",
157+
"@oclif/plugin-warn-if-update-available": "3.1.40",
158+
"@oclif/plugin-which": "3.2.35",
157159
"@salesforce/core": "^8.9.1",
158160
"@salesforce/kit": "^3.1.6",
159-
"@salesforce/plugin-apex": "3.6.13",
161+
"@salesforce/plugin-agent": "1.22.8",
162+
"@salesforce/plugin-apex": "3.6.19",
160163
"@salesforce/plugin-api": "1.3.3",
161-
"@salesforce/plugin-auth": "3.6.113",
162-
"@salesforce/plugin-data": "4.0.27",
163-
"@salesforce/plugin-deploy-retrieve": "3.22.4",
164-
"@salesforce/plugin-info": "3.4.54",
165-
"@salesforce/plugin-limits": "3.3.52",
164+
"@salesforce/plugin-auth": "3.6.126",
165+
"@salesforce/plugin-data": "4.0.37",
166+
"@salesforce/plugin-deploy-retrieve": "3.22.19",
167+
"@salesforce/plugin-info": "3.4.65",
168+
"@salesforce/plugin-limits": "3.3.56",
166169
"@salesforce/plugin-marketplace": "1.3.8",
167-
"@salesforce/plugin-org": "5.6.3",
170+
"@salesforce/plugin-org": "5.7.13",
168171
"@salesforce/plugin-packaging": "2.15.0",
169-
"@salesforce/plugin-schema": "3.3.59",
170-
"@salesforce/plugin-settings": "2.4.24",
171-
"@salesforce/plugin-sobject": "1.4.55",
172-
"@salesforce/plugin-telemetry": "3.6.38",
173-
"@salesforce/plugin-templates": "56.3.45",
174-
"@salesforce/plugin-trust": "3.7.83",
175-
"@salesforce/plugin-user": "3.6.18",
176-
"@salesforce/sf-plugins-core": "12.2.1",
172+
"@salesforce/plugin-schema": "3.3.65",
173+
"@salesforce/plugin-settings": "2.4.29",
174+
"@salesforce/plugin-sobject": "1.4.59",
175+
"@salesforce/plugin-telemetry": "3.6.43",
176+
"@salesforce/plugin-templates": "56.3.49",
177+
"@salesforce/plugin-trust": "3.7.97",
178+
"@salesforce/plugin-user": "3.6.25",
179+
"@salesforce/sf-plugins-core": "12.2.2",
177180
"ansis": "^3.12.0"
178181
},
179182
"pinnedDependencies": [
@@ -189,6 +192,7 @@
189192
"@oclif/plugin-warn-if-update-available",
190193
"@oclif/plugin-which",
191194
"@salesforce/sf-plugins-core",
195+
"@salesforce/plugin-agent",
192196
"@salesforce/plugin-apex",
193197
"@salesforce/plugin-api",
194198
"@salesforce/plugin-auth",
@@ -253,6 +257,7 @@
253257
"types": "dist/index.d.ts",
254258
"devDependencies": {
255259
"@oclif/plugin-command-snapshot": "^5.2.3",
260+
"@oclif/test": "^4.1.13",
256261
"@salesforce/dev-scripts": "^11.0.2",
257262
"@salesforce/plugin-release-management": "^5.7.0",
258263
"@salesforce/ts-sinon": "^1.4.30",

src/hooks/prerun.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77

88
import { type Hook } from '@oclif/core/hooks';
99

10-
// eslint-disable-next-line @typescript-eslint/require-await
11-
const hook: Hook.Prerun = async function ({ Command, config }) {
12-
if (process.argv.includes('--json')) return;
10+
const hook: Hook.Prerun = async function ({ Command, config, argv }) {
11+
if (argv.includes('--json') || process.argv.includes('--json')) return;
1312
const { plugin } = Command;
1413
if (!plugin) return;
1514
if (plugin.type === 'link') return;
@@ -20,10 +19,31 @@ const hook: Hook.Prerun = async function ({ Command, config }) {
2019
const specifiedVersion = jitPlugins[plugin.name] ?? deps[plugin.name];
2120
if (!specifiedVersion) return;
2221

23-
if (plugin.version !== specifiedVersion) {
22+
// Simple semver comparison without external library
23+
const parseVersion = (version: string): number[] =>
24+
version
25+
.replace(/^[^\d]*/, '')
26+
.split('.')
27+
.map((n) => parseInt(n, 10) || 0);
28+
29+
const isLessThan = (version1: string, version2: string): boolean => {
30+
const v1 = parseVersion(version1);
31+
const v2 = parseVersion(version2);
32+
33+
for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
34+
const num1 = v1[i] || 0;
35+
const num2 = v2[i] || 0;
36+
37+
if (num1 < num2) return true;
38+
if (num1 > num2) return false;
39+
}
40+
return false;
41+
};
42+
43+
if (isLessThan(plugin.version, specifiedVersion)) {
2444
const { ux } = await import('@oclif/core/ux');
2545
ux.warn(
26-
`Plugin ${plugin.name} (${plugin.version}) differs from the version specified by ${config.bin} (${specifiedVersion})`
46+
`Plugin ${plugin.name} (${plugin.version}) is older than the version specified by ${config.bin} (${specifiedVersion})`
2747
);
2848
}
2949
};

test/hooks/prerun.test.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright (c) 2025, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import { dirname } from 'node:path';
8+
import { fileURLToPath } from 'node:url';
9+
import { expect } from 'chai';
10+
import { runHook } from '@oclif/test';
11+
import { Config } from '@oclif/core/config';
12+
13+
function sanitize(stderr: string): string {
14+
return stderr
15+
.replaceAll('› ', ' ')
16+
.replaceAll('» ', ' ')
17+
.split('\n')
18+
.map((s) => s.trim())
19+
.join(' ');
20+
}
21+
22+
describe('Prerun Hook', () => {
23+
const WARNING_REGEX =
24+
/Warning: Plugin ([^ ]+) \((\d+\.\d+\.\d+(?:-[^)]*)?)\) is older than the version specified by ([^ ]+) \((\d+\.\d+\.\d+(?:-[^)]*)?)\)/;
25+
let config: Config;
26+
27+
before(async () => {
28+
config = await Config.load({ root: dirname(fileURLToPath(import.meta.url)) });
29+
});
30+
31+
it('should do nothing when --json is present', async () => {
32+
const { stderr } = await runHook('prerun', { argv: ['--json'] });
33+
expect(sanitize(stderr)).to.not.match(WARNING_REGEX);
34+
});
35+
36+
it('should do nothing if plugin type is "link"', async () => {
37+
const command = {
38+
type: 'link',
39+
};
40+
const { stderr } = await runHook('prerun', { Command: command, argv: [] });
41+
expect(sanitize(stderr)).to.not.match(WARNING_REGEX);
42+
});
43+
44+
it('should do nothing if plugin is not JIT or core', async () => {
45+
const command = {
46+
plugin: {
47+
type: 'core',
48+
name: '@salesforce/plugin-foo',
49+
version: '1.0.0',
50+
},
51+
};
52+
const { stderr } = await runHook('prerun', { Command: command, argv: [] });
53+
expect(sanitize(stderr)).to.not.match(WARNING_REGEX);
54+
});
55+
56+
it('should warn if plugin version is less than specified version', async () => {
57+
const command = {
58+
plugin: {
59+
type: 'core',
60+
name: '@salesforce/plugin-packaging',
61+
version: '0.0.1',
62+
},
63+
};
64+
const { stderr } = await runHook('prerun', { Command: command, argv: [] });
65+
expect(sanitize(stderr)).to.match(WARNING_REGEX);
66+
});
67+
68+
it('should not warn if plugin version is greater than specified version', async () => {
69+
const command = {
70+
plugin: {
71+
type: 'core',
72+
name: '@salesforce/plugin-packaging',
73+
version: '10000.0.0',
74+
},
75+
};
76+
const { stderr } = await runHook('prerun', { Command: command, argv: [] });
77+
expect(sanitize(stderr)).to.not.match(WARNING_REGEX);
78+
});
79+
80+
it('should not warn if plugin version is equal to specified version', async () => {
81+
const command = {
82+
plugin: {
83+
type: 'core',
84+
name: '@salesforce/plugin-packaging',
85+
version: '1.0.0',
86+
},
87+
};
88+
89+
config.pjson.dependencies = {
90+
...config.pjson.dependencies,
91+
'@salesforce/plugin-packaging': '1.0.0',
92+
};
93+
const { stderr } = await runHook('prerun', { Command: command, argv: [] }, config);
94+
expect(sanitize(stderr)).to.not.match(WARNING_REGEX);
95+
});
96+
97+
it('should warn if plugin version is an older prerelease', async () => {
98+
const command = {
99+
plugin: {
100+
type: 'core',
101+
name: '@salesforce/plugin-packaging',
102+
version: '1.0.0-beta.1',
103+
},
104+
};
105+
106+
config.pjson.dependencies = {
107+
...config.pjson.dependencies,
108+
'@salesforce/plugin-packaging': '1.0.0-beta.2',
109+
};
110+
const { stderr } = await runHook('prerun', { Command: command, argv: [] }, config);
111+
expect(sanitize(stderr)).to.match(WARNING_REGEX);
112+
});
113+
114+
it('should not warn if plugin version is a newer prerelease', async () => {
115+
const command = {
116+
plugin: {
117+
type: 'core',
118+
name: '@salesforce/plugin-packaging',
119+
version: '1.0.0-beta.2',
120+
},
121+
};
122+
123+
config.pjson.dependencies = {
124+
...config.pjson.dependencies,
125+
'@salesforce/plugin-packaging': '1.0.0-beta.1',
126+
};
127+
const { stderr } = await runHook('prerun', { Command: command, argv: [] }, config);
128+
expect(sanitize(stderr)).to.not.match(WARNING_REGEX);
129+
});
130+
131+
it('should not warn if plugin version is a newer prerelease and specified version is an older stable release', async () => {
132+
const command = {
133+
plugin: {
134+
type: 'core',
135+
name: '@salesforce/plugin-packaging',
136+
version: '1.0.0-beta.1',
137+
},
138+
};
139+
140+
config.pjson.dependencies = {
141+
...config.pjson.dependencies,
142+
'@salesforce/plugin-packaging': '1.0.0',
143+
};
144+
const { stderr } = await runHook('prerun', { Command: command, argv: [] }, config);
145+
expect(sanitize(stderr)).to.not.match(WARNING_REGEX);
146+
});
147+
148+
it('should warn if plugin version is an older prerelease and specified version is a newer stable release', async () => {
149+
const command = {
150+
plugin: {
151+
type: 'core',
152+
name: '@salesforce/plugin-packaging',
153+
version: '1.0.0-beta.1',
154+
},
155+
};
156+
config.pjson.dependencies = {
157+
...config.pjson.dependencies,
158+
'@salesforce/plugin-packaging': '1.0.1',
159+
};
160+
const { stderr } = await runHook('prerun', { Command: command, argv: [] }, config);
161+
expect(sanitize(stderr)).to.match(WARNING_REGEX);
162+
});
163+
});

0 commit comments

Comments
 (0)