Skip to content

Commit 3ae4cd6

Browse files
CHANGE: @W-17293079@: Update dependencies, refactor config command that fixes python_command issue
1 parent be7eb26 commit 3ae4cd6

File tree

9 files changed

+277
-136
lines changed

9 files changed

+277
-136
lines changed

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
"bugs": "https://github.com/forcedotcom/sfdx-scanner/issues",
77
"dependencies": {
88
"@oclif/core": "^3.3.2",
9-
"@salesforce/code-analyzer-core": "0.17.0",
10-
"@salesforce/code-analyzer-engine-api": "0.14.0",
11-
"@salesforce/code-analyzer-eslint-engine": "0.14.0",
12-
"@salesforce/code-analyzer-flowtest-engine": "0.14.1",
13-
"@salesforce/code-analyzer-pmd-engine": "0.14.0",
14-
"@salesforce/code-analyzer-regex-engine": "0.14.0",
15-
"@salesforce/code-analyzer-retirejs-engine": "0.14.0",
9+
"@salesforce/code-analyzer-core": "0.18.0",
10+
"@salesforce/code-analyzer-engine-api": "0.15.0",
11+
"@salesforce/code-analyzer-eslint-engine": "0.15.0",
12+
"@salesforce/code-analyzer-flowtest-engine": "0.15.0",
13+
"@salesforce/code-analyzer-pmd-engine": "0.15.0",
14+
"@salesforce/code-analyzer-regex-engine": "0.15.0",
15+
"@salesforce/code-analyzer-retirejs-engine": "0.15.0",
1616
"@salesforce/core": "^5",
1717
"@salesforce/sf-plugins-core": "^5.0.4",
1818
"@salesforce/ts-types": "^2.0.9",

src/lib/messages.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ export enum BundleName {
1717
ResultsWriter = 'results-writer',
1818
RunAction = 'run-action',
1919
RunCommand = 'run-command',
20-
RunSummaryViewer = 'run-summary-viewer',
2120
Shared = 'shared',
2221
WorkspaceUtil = 'workspace-util'
2322
}

src/lib/models/ConfigModel.ts

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import {dump as yamlDump} from 'js-yaml';
22
import {
33
CodeAnalyzer,
44
CodeAnalyzerConfig,
5-
ConfigDescription,
5+
ConfigDescription, ConfigFieldDescription,
6+
EngineConfig,
67
Rule,
78
RuleSelection,
89
SeverityLevel
@@ -83,37 +84,51 @@ abstract class YamlFormatter {
8384
return yamlCode.replace(/(\r?\n|$)/, ` ${comment}$1`);
8485
}
8586

86-
private toYamlField(fieldName: string, userValue: unknown, defaultValue: unknown): string {
87-
if (looksLikeAPathValue(userValue) && userValue === defaultValue) {
88-
// We special handle a path value when it is equal to the default value, making it equal null because
89-
// chances are it is a derived file or folder value based on the specific environment that we do not want to
90-
// actually want to hard code since checking in the config to CI/CD system may create a different value
91-
const commentText: string = getMessage(BundleName.ConfigModel, 'template.last-calculated-as', [JSON.stringify(userValue)]);
92-
return this.toYamlUncheckedFieldWithInlineComment(fieldName, null, commentText);
93-
} else if (JSON.stringify(userValue) === JSON.stringify(defaultValue)) {
94-
return this.toYamlUncheckedField(fieldName, userValue);
87+
private toYamlFieldUsingFieldDescription(fieldName: string, resolvedValue: unknown, fieldDescription: ConfigFieldDescription): string {
88+
const resolvedValueJson: string = JSON.stringify(resolvedValue);
89+
const defaultValueJson: string = JSON.stringify(fieldDescription.defaultValue);
90+
91+
if (!fieldDescription.wasSuppliedByUser && resolvedValueJson !== defaultValueJson) {
92+
// Whenever the user did not supply the value themselves but the resolved value is different from the
93+
// default value, this means the value was not a "fixed" value but a value "calculated" at runtime.
94+
// Since "calculated" values often depend on the specific environment, we do not want to actually hard code
95+
// this value into the config since checking in the config to CI/CD system may create a different value.
96+
const commentText: string = getMessage(BundleName.ConfigModel, 'template.last-calculated-as', [resolvedValueJson]);
97+
return this.toYamlUncheckedFieldWithInlineComment(fieldName, fieldDescription.defaultValue, commentText);
9598
}
9699

97-
userValue = replaceAbsolutePathsWithRelativePathsWherePossible(userValue, this.userContext.config.getConfigRoot() + path.sep);
100+
return this.toYamlField(fieldName, resolvedValue, fieldDescription.defaultValue);
101+
}
102+
103+
private toYamlField(fieldName: string, resolvedValue: unknown, defaultValue: unknown): string {
104+
const resolvedValueJson: string = JSON.stringify(resolvedValue);
105+
const defaultValueJson: string = JSON.stringify(defaultValue);
98106

99-
const commentText: string = getMessage(BundleName.ConfigModel, 'template.modified-from', [JSON.stringify(defaultValue)]);
100-
return this.toYamlUncheckedFieldWithInlineComment(fieldName, userValue, commentText);
107+
if (resolvedValueJson === defaultValueJson) {
108+
return this.toYamlUncheckedField(fieldName, resolvedValue);
109+
}
110+
111+
const commentText: string = getMessage(BundleName.ConfigModel, 'template.modified-from', [defaultValueJson]);
112+
resolvedValue = replaceAbsolutePathsWithRelativePathsWherePossible(resolvedValue, this.userContext.config.getConfigRoot() + path.sep);
113+
return this.toYamlUncheckedFieldWithInlineComment(fieldName, resolvedValue, commentText);
101114
}
102115

103116
toYaml(): string {
104-
const topLevelDescription: ConfigDescription = CodeAnalyzerConfig.getConfigDescription();
105-
return this.toYamlSectionHeadingComment(topLevelDescription.overview!) + '\n' +
117+
const topLevelDescription: ConfigDescription = this.userContext.config.getConfigDescription();
118+
return this.toYamlSectionHeadingComment(topLevelDescription.overview) + '\n' +
106119
'\n' +
107-
this.toYamlComment(topLevelDescription.fieldDescriptions!.config_root) + '\n' +
108-
this.toYamlField('config_root', this.userContext.config.getConfigRoot(), this.defaultContext.config.getConfigRoot()) + '\n' +
120+
this.toYamlComment(topLevelDescription.fieldDescriptions.config_root.descriptionText) + '\n' +
121+
this.toYamlFieldUsingFieldDescription('config_root', this.userContext.config.getConfigRoot(),
122+
topLevelDescription.fieldDescriptions.config_root) + '\n' +
109123
'\n' +
110-
this.toYamlComment(topLevelDescription.fieldDescriptions!.log_folder) + '\n' +
111-
this.toYamlField('log_folder', this.userContext.config.getLogFolder(), this.defaultContext.config.getLogFolder()) + '\n' +
124+
this.toYamlComment(topLevelDescription.fieldDescriptions.log_folder.descriptionText) + '\n' +
125+
this.toYamlFieldUsingFieldDescription('log_folder', this.userContext.config.getLogFolder(),
126+
topLevelDescription.fieldDescriptions.log_folder) + '\n' +
112127
'\n' +
113-
this.toYamlComment(topLevelDescription.fieldDescriptions!.rules) + '\n' +
128+
this.toYamlComment(topLevelDescription.fieldDescriptions.rules.descriptionText) + '\n' +
114129
this.toYamlRuleOverrides() + '\n' +
115130
'\n' +
116-
this.toYamlComment(topLevelDescription.fieldDescriptions!.engines) + '\n' +
131+
this.toYamlComment(topLevelDescription.fieldDescriptions.engines.descriptionText) + '\n' +
117132
this.toYamlEngineOverrides() + '\n' +
118133
'\n' +
119134
this.toYamlSectionHeadingComment(getMessage(BundleName.ConfigModel, 'template.common.end-of-config')) + '\n';
@@ -176,23 +191,21 @@ abstract class YamlFormatter {
176191
}
177192

178193
private toYamlEngineOverridesForEngine(engineName: string): string {
179-
const engineConfigDescriptor = this.userContext.core.getEngineConfigDescription(engineName);
180-
const userEngineConfig = this.userContext.core.getEngineConfig(engineName);
181-
const defaultEngineConfig = this.defaultContext.core.getEngineConfig(engineName);
194+
const engineConfigDescriptor: ConfigDescription = this.userContext.core.getEngineConfigDescription(engineName);
195+
const userEngineConfig: EngineConfig = this.userContext.core.getEngineConfig(engineName);
182196

183197
let yamlCode: string = '\n' +
184-
this.toYamlSectionHeadingComment(engineConfigDescriptor.overview!) + '\n' +
198+
this.toYamlSectionHeadingComment(engineConfigDescriptor.overview) + '\n' +
185199
`${engineName}:\n`;
186200
// By fiat, the field description will always include, at minimum, an entry for "disable_engine", so we can
187201
// assume that the object is not undefined.
188-
for (const configField of Object.keys(engineConfigDescriptor.fieldDescriptions!)) {
189-
const fieldDescription = engineConfigDescriptor.fieldDescriptions![configField];
190-
const defaultValue = defaultEngineConfig[configField] ?? null;
191-
const userValue = userEngineConfig[configField] ?? defaultValue;
202+
for (const configField of Object.keys(engineConfigDescriptor.fieldDescriptions)) {
203+
const fieldDescription: ConfigFieldDescription = engineConfigDescriptor.fieldDescriptions[configField];
204+
const userValue = userEngineConfig[configField] ?? fieldDescription.defaultValue;
192205
// Add a leading newline to visually break up the property from the previous one.
193206
yamlCode += '\n' +
194-
indent(this.toYamlComment(fieldDescription), 2) + '\n' +
195-
indent(this.toYamlField(configField, userValue, defaultValue), 2) + '\n';
207+
indent(this.toYamlComment(fieldDescription.descriptionText), 2) + '\n' +
208+
indent(this.toYamlFieldUsingFieldDescription(configField, userValue, fieldDescription), 2) + '\n';
196209
}
197210
return yamlCode.trimEnd();
198211
}
@@ -218,10 +231,6 @@ class StyledYamlFormatter extends YamlFormatter {
218231
}
219232
}
220233

221-
function looksLikeAPathValue(value: unknown) {
222-
return typeof(value) === 'string' && !value.includes('\n') && value.includes(path.sep);
223-
}
224-
225234
function replaceAbsolutePathsWithRelativePathsWherePossible(value: unknown, parentFolder: string): unknown {
226235
if (typeof value === 'string') {
227236
// Check if the string starts with the parent folder

test/fixtures/comparison-files/lib/actions/ConfigAction.test.ts/override-configurations/StubEngine2_forConfigWithRelativePathScenario.yml.goldfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
disable_engine: false
88

99
# Some description for top_field
10-
top_field: # Modified from: null
10+
top_field: # Modified from: {}
1111
sub_field:
1212
- optional-input-config.yml

test/lib/actions/ConfigAction.test.ts

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ describe('ConfigAction tests', () => {
252252
it.each([
253253
{prop: 'config_root'},
254254
{prop: 'log_folder'}
255-
])(`When derivable property $prop input is non-null and non-default, it is rendered as-is with no comment`, async ({prop}) => {
255+
])(`When derivable property $prop input is non-null and non-default, it is rendered as-is`, async ({prop}) => {
256256
// ==== SETUP ====
257257
// Make the config root and log folder both be the folder above this one.
258258
const parentOfCurrentDirectory = path.resolve(__dirname, '..');
@@ -264,12 +264,11 @@ describe('ConfigAction tests', () => {
264264
const output = await runActionAndGetDisplayedConfig(dependencies, ['all']);
265265

266266
// ==== ASSERTIONS ====
267-
const defaultConfig = CodeAnalyzerConfig.withDefaults();
268267
const goldFileContents = (await readGoldFile(path.join(PATH_TO_COMPARISON_DIR, 'derivables-as-non-defaults', `${prop}.yml.goldfile`)))
269268
.replace('__DUMMY_CONFIG_ROOT__', parentOfCurrentDirectory)
270269
.replace('__DUMMY_LOG_FOLDER__', parentOfCurrentDirectory)
271-
.replace('__DUMMY_DEFAULT_CONFIG_ROOT__', JSON.stringify(defaultConfig.getConfigRoot()))
272-
.replace('__DUMMY_DEFAULT_LOG_FOLDER__', JSON.stringify(defaultConfig.getLogFolder()))
270+
.replace('__DUMMY_DEFAULT_CONFIG_ROOT__', JSON.stringify(null))
271+
.replace('__DUMMY_DEFAULT_LOG_FOLDER__', JSON.stringify(null))
273272
expect(output).toContain(goldFileContents);
274273
});
275274

@@ -573,22 +572,52 @@ class StubEnginePlugin extends EngineApi.EnginePluginV1 {
573572

574573
private readonly createdEngines: Map<string, EngineApi.Engine> = new Map();
575574

575+
/*
576+
descriptionText: string;
577+
valueType: string;
578+
defaultValue: ConfigValue;
579+
*/
580+
576581
private readonly descriptionsByEngine: {[key: string]: EngineApi.ConfigDescription} = {
577582
StubEngine1: {
578583
overview: 'This is a generic overview for StubEngine1\nIt has multiple lines of text\nWhee!',
579584
fieldDescriptions: {
580-
'Property1': 'This is the description for Property1',
585+
'Property1': {
586+
descriptionText: 'This is the description for Property1',
587+
valueType: 'string',
588+
defaultValue: 'default1'
589+
},
581590
// Property2 is undocumented
582-
'Property3': 'This is the description for Property3',
583-
'Property4': 'This is the description for Property4',
584-
'Property5': 'This is the description for Property5',
585-
'Property6': 'This is the description for Property6'
591+
'Property3': {
592+
descriptionText: 'This is the description for Property3',
593+
valueType: 'string',
594+
defaultValue: 'default3'
595+
},
596+
'Property4': {
597+
descriptionText: 'This is the description for Property4',
598+
valueType: 'object',
599+
defaultValue: {SubProperty1: 10, SubProperty2: true}
600+
},
601+
'Property5': {
602+
descriptionText: 'This is the description for Property5',
603+
valueType: 'array',
604+
defaultValue: ['arr1', 'arr2']
605+
},
606+
'Property6': {
607+
descriptionText: 'This is the description for Property6',
608+
valueType: 'string',
609+
defaultValue: null
610+
},
586611
}
587612
},
588613
StubEngine2: {
589614
overview: 'Some overview for StubEngine2',
590615
fieldDescriptions: {
591-
'top_field': 'Some description for top_field'
616+
'top_field': {
617+
descriptionText: 'Some description for top_field',
618+
valueType: 'object',
619+
defaultValue: {}
620+
}
592621
}
593622
}
594623
// StubEngine3 also has no overview or documented properties.
@@ -651,6 +680,10 @@ class StubEngine1 extends EngineApi.Engine {
651680
return 'StubEngine1';
652681
}
653682

683+
getEngineVersion(): Promise<string> {
684+
return Promise.resolve("1.0.0");
685+
}
686+
654687
public describeRules(): Promise<EngineApi.RuleDescription[]> {
655688
return Promise.resolve([{
656689
name: 'Stub1Rule1',
@@ -719,6 +752,10 @@ class StubEngine2 extends EngineApi.Engine {
719752
return 'StubEngine2';
720753
}
721754

755+
getEngineVersion(): Promise<string> {
756+
return Promise.resolve("1.0.2");
757+
}
758+
722759
public describeRules(): Promise<EngineApi.RuleDescription[]> {
723760
return Promise.resolve([{
724761
name: 'Stub2Rule1',
@@ -745,6 +782,10 @@ class StubEngine3 extends EngineApi.Engine {
745782
return 'StubEngine3';
746783
}
747784

785+
getEngineVersion(): Promise<string> {
786+
return Promise.resolve("1.0.3");
787+
}
788+
748789
public describeRules(): Promise<EngineApi.RuleDescription[]> {
749790
return Promise.resolve([{
750791
name: 'Stub3Rule1',

test/lib/writers/ConfigWriter.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ describe('ConfigWriter implementations', () => {
99
describe('ConfigWriterImpl', () => {
1010

1111
let writeFileSpy: jest.SpyInstance;
12-
let writeFileInvocations: {file: fs.PathOrFileDescriptor, contents: String|ArrayBufferView}[];
12+
let writeFileInvocations: {file: fs.PathOrFileDescriptor, contents: string|ArrayBufferView}[];
1313
beforeEach(() => {
1414
writeFileInvocations = [];
1515
writeFileSpy = jest.spyOn(fs, 'writeFileSync').mockImplementation((file, contents) => {

test/stubs/SpyRunSummaryViewer.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

test/stubs/StubEnginePlugins.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export class StubEngine1 extends EngineApi.Engine {
7171
return "stubEngine1";
7272
}
7373

74+
getEngineVersion(): Promise<string> {
75+
return Promise.resolve("1.0.0");
76+
}
77+
7478
describeRules(): Promise<EngineApi.RuleDescription[]> {
7579
this.emitEvent<EngineApi.DescribeRulesProgressEvent>({
7680
type: EngineApi.EventType.DescribeRulesProgressEvent,
@@ -168,6 +172,10 @@ export class StubEngine2 extends EngineApi.Engine {
168172
return "stubEngine2";
169173
}
170174

175+
getEngineVersion(): Promise<string> {
176+
return Promise.resolve("1.2.3");
177+
}
178+
171179
describeRules(): Promise<EngineApi.RuleDescription[]> {
172180
return Promise.resolve([
173181
{
@@ -265,6 +273,10 @@ abstract class BaseTimeableEngine extends EngineApi.Engine {
265273
this.executionWaitTime = 0;
266274
}
267275

276+
getEngineVersion(): Promise<string> {
277+
return Promise.resolve("1.0.1");
278+
}
279+
268280
setRuleSelectionWaitTime(waitTime: number): void {
269281
this.selectionWaitTime = waitTime;
270282
}
@@ -366,6 +378,10 @@ export class EventConfigurableEngine1 extends EngineApi.Engine {
366378
return "eventConfigurableEngine1";
367379
}
368380

381+
getEngineVersion(): Promise<string> {
382+
return Promise.resolve("1.0.5");
383+
}
384+
369385
addEvents(...events: {logLevel: LogLevel, message: string}[]): void {
370386
this.events = [...this.events, ...events];
371387
}
@@ -428,6 +444,10 @@ export class TargetDependentEngine1 extends EngineApi.Engine {
428444
return 'targetDependentEngine1';
429445
}
430446

447+
getEngineVersion(): Promise<string> {
448+
return Promise.resolve("1.3.0");
449+
}
450+
431451
describeRules(describeOptions: EngineApi.DescribeOptions): Promise<EngineApi.RuleDescription[]> {
432452
if (!describeOptions.workspace) {
433453
return Promise.resolve([]);

0 commit comments

Comments
 (0)