Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions messages/rules-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ We're continually improving Salesforce Code Analyzer. Tell us what you think! Gi

<%= config.bin %> <%= command.id %> --rule-selector eslint:Recommended

- List Flow Analyzer rules from an authenticated org (required for that engine):

<%= config.bin %> <%= command.id %> --rule-selector flowAnalyzer --target-org my-org

- List all the rules for the "eslint" engine:

<%= config.bin %> <%= command.id %> --rule-selector eslint
Expand Down Expand Up @@ -92,6 +96,16 @@ Each targeted file must live within the workspace specified by the –-workspace

If you specify `--workspace` but not `--target`, then all the files within your workspace are targeted.

# flags.target-org.summary

Target org username or alias for remote analysis engines.

# flags.target-org.description

Specify the username or alias of a Salesforce org when listing rules from engines that require remote connectivity, such as Flow Analyzer. The org must be authenticated with the Salesforce CLI.

Flow Analyzer requires this flag (or `engines.flowAnalyzer.target_org` in your `code-analyzer.yml`). Other engines ignore it.

# flags.rule-selector.summary

Selection of rules, based on engine name, severity level, rule name, tag, or a combination of criteria separated by colons.
Expand Down
8 changes: 7 additions & 1 deletion messages/run-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ We're continually improving Salesforce Code Analyzer. Tell us what you think! Gi

<%= config.bin %> <%= command.id %> --rule-selector retire-js:Recommended --target ./other-source --target ./force-app/**/*.cls

- Analyze only specific flows with the "flowAnalyzer" engine; target one flow by path, plus every flow whose file name starts with "Account_" in any folder (quote globs so your shell doesn't expand them). Only the targeted flows are sent to your org:

<%= config.bin %> <%= command.id %> --rule-selector flowAnalyzer --target-org my-org --target ./force-app/main/default/flows/My_Flow.flow-meta.xml --target "./force-app/**/Account_*.flow-meta.xml"

- Specify a custom configuration file and output the results to the "results.csv" file in CSV format; the commands fails if it finds a violation that exceeds the moderate severity level (3):

<%= config.bin %> <%= command.id %> --config-file ./code-analyzer2.yml --output-file results.csv --severity-threshold 3
Expand Down Expand Up @@ -92,7 +96,9 @@ Target org username or alias for remote analysis engines.

# flags.target-org.description

Specify the username or alias of a Salesforce org when using engines that require remote connectivity, such as ApexGuru. The org must be authenticated with the Salesforce CLI.
Specify the username or alias of a Salesforce org when using engines that require remote connectivity, such as ApexGuru or Flow Analyzer. The org must be authenticated with the Salesforce CLI.

Flow Analyzer requires this flag (or `engines.flowAnalyzer.target_org` in your `code-analyzer.yml`).

# flags.rule-selector.summary

Expand Down
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.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@salesforce/code-analyzer-engine-api": "0.42.0",
"@salesforce/code-analyzer-eslint-engine": "0.47.0",
"@salesforce/code-analyzer-flow-engine": "0.41.0",
"@salesforce/code-analyzer-flowanalyzer-engine": "file:../code-analyzer-core/packages/code-analyzer-flowanalyzer-engine",
"@salesforce/code-analyzer-pmd-engine": "0.46.0",
"@salesforce/code-analyzer-regex-engine": "0.40.0",
"@salesforce/code-analyzer-retirejs-engine": "0.39.0",
Expand Down
9 changes: 8 additions & 1 deletion src/commands/code-analyzer/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export default class RulesCommand extends SfCommand<void> implements Displayable
multiple: true,
delimiter: ','
}),
'target-org': Flags.string({
summary: getMessage(BundleName.RulesCommand, 'flags.target-org.summary'),
description: getMessage(BundleName.RulesCommand, 'flags.target-org.description'),
// eslint-disable-next-line sf-plugin/dash-o
char: 'o'
}),
'rule-selector': Flags.string({
summary: getMessage(BundleName.RulesCommand, 'flags.rule-selector.summary'),
description: getMessage(BundleName.RulesCommand, 'flags.rule-selector.description'),
Expand Down Expand Up @@ -75,7 +81,8 @@ export default class RulesCommand extends SfCommand<void> implements Displayable
'output-file': outputFiles,
'rule-selector': parsedFlags['rule-selector'].flatMap(s => s.replace(/\s+/g, ' ').trim().split(' ')),
'workspace': parsedFlags['workspace'],
'target': parsedFlags['target']
'target': parsedFlags['target'],
'target-org': parsedFlags['target-org']
};

await action.execute(rulesInput);
Expand Down
6 changes: 5 additions & 1 deletion src/lib/actions/RulesAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type RulesInput = {
'output-file'?: string[];
workspace?: string[];
target?: string[];
'target-org'?: string;
view?: string;
}

Expand All @@ -40,7 +41,10 @@ export class RulesAction {
}

public async execute(input: RulesInput): Promise<void> {
const config: CodeAnalyzerConfig = this.dependencies.configFactory.create(input['config-file']);
const cliOverrides = input['target-org'] !== undefined
? {targetOrg: input['target-org']}
: undefined;
const config: CodeAnalyzerConfig = this.dependencies.configFactory.create(input['config-file'], cliOverrides);
const logWriter: LogFileWriter = await LogFileWriter.fromConfig(config);
this.dependencies.actionSummaryViewer.viewPreExecutionSummary(logWriter.getLogDestination());
// We always add a Logger Listener to the appropriate listeners list, because we should Always Be Logging.
Expand Down
9 changes: 8 additions & 1 deletion src/lib/factories/CodeAnalyzerConfigFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class CodeAnalyzerConfigFactoryImpl implements CodeAnalyzerConfigFactory
};
}

// Apply target-org override to apexguru engine config
// Apply target-org override to engines that require an explicit org
if (cliOverrides.targetOrg) {
const enginesSection = mergedConfig.engines as Record<string, Record<string, unknown>> | undefined;
mergedConfig = {
Expand All @@ -102,6 +102,10 @@ export class CodeAnalyzerConfigFactoryImpl implements CodeAnalyzerConfigFactory
apexguru: {
...(enginesSection?.apexguru || {}),
target_org: cliOverrides.targetOrg
},
flowAnalyzer: {
...(enginesSection?.flowAnalyzer || {}),
target_org: cliOverrides.targetOrg
}
}
};
Expand All @@ -122,6 +126,9 @@ export class CodeAnalyzerConfigFactoryImpl implements CodeAnalyzerConfigFactory
configObject.engines = {
apexguru: {
target_org: cliOverrides.targetOrg
},
flowAnalyzer: {
target_org: cliOverrides.targetOrg
}
};
}
Expand Down
4 changes: 3 additions & 1 deletion src/lib/factories/EnginePluginsFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as FlowEngineModule from '@salesforce/code-analyzer-flow-engine';
import * as SfgeEngineModule from '@salesforce/code-analyzer-sfge-engine';
import * as ApexGuruEngineModule from '@salesforce/code-analyzer-apexguru-engine';
import * as UIBundleEngineModule from '@salesforce/code-analyzer-uibundle-engine';
import * as FlowAnalyzerEngineModule from '@salesforce/code-analyzer-flowanalyzer-engine';

export interface EnginePluginsFactory {
create(): EnginePlugin[];
Expand All @@ -22,7 +23,8 @@ export class EnginePluginsFactoryImpl implements EnginePluginsFactory {
FlowEngineModule.createEnginePlugin(),
SfgeEngineModule.createEnginePlugin(),
ApexGuruEngineModule.createEnginePlugin(),
UIBundleEngineModule.createEnginePlugin()
UIBundleEngineModule.createEnginePlugin(),
FlowAnalyzerEngineModule.createEnginePlugin()
];
}
}
16 changes: 16 additions & 0 deletions test/commands/code-analyzer/rules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,22 @@ describe('`code-analyzer rules` unit tests', () => {
});
});

describe('--target-org', () => {
it('Can be supplied with a value', async () => {
const inputValue = 'test-org';
await runRulesCommand(['--target-org', inputValue]);
expect(executeSpy).toHaveBeenCalled();
expect(receivedActionInput).toHaveProperty('target-org', inputValue);
});

it('Can be referenced by its shortname, -o', async () => {
const inputValue = 'my-org';
await runRulesCommand(['-o', inputValue]);
expect(executeSpy).toHaveBeenCalled();
expect(receivedActionInput).toHaveProperty('target-org', inputValue);
});
});

describe.each([
{flag: '--workspace', shortflag: '-w', property: 'workspace'},
{flag: '--target', shortflag: '-t', property: 'target'},
Expand Down
33 changes: 33 additions & 0 deletions test/lib/actions/RulesAction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,39 @@ describe('RulesAction tests', () => {
expect(viewerCallHistory[0]).toEqual([]);
});

describe('target-org', () => {
it('passes target-org through to engine config', async () => {
const targetOrg = 'my-test-org';
const configFactorySpy = vi.spyOn(defaultDependencies.configFactory, 'create');
const action = RulesAction.createAction(defaultDependencies);
const input: RulesInput = {
'rule-selector': ['all'],
'target-org': targetOrg
};

await action.execute(input);

expect(configFactorySpy).toHaveBeenCalledWith(
undefined,
expect.objectContaining({
targetOrg: targetOrg
})
);
});

it('does not include a target-org override when target-org is not provided', async () => {
const configFactorySpy = vi.spyOn(defaultDependencies.configFactory, 'create');
const action = RulesAction.createAction(defaultDependencies);
const input: RulesInput = {
'rule-selector': ['all']
};

await action.execute(input);

expect(configFactorySpy).toHaveBeenCalledWith(undefined, undefined);
});
});

it('Throws an error when an engine throws an error', async () => {
const dependencies: RulesDependencies = {
...defaultDependencies,
Expand Down
12 changes: 12 additions & 0 deletions test/lib/factories/CodeAnalyzerConfigFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ describe('CodeAnalyzerConfigFactoryImpl', () => {
expect(testedConfig.getEngineOverridesFor('apexguru')).toEqual({
target_org: 'my-org@example.com'
});
expect(testedConfig.getEngineOverridesFor('flowAnalyzer')).toEqual({
target_org: 'my-org@example.com'
});
});

it('When config file exists (without engines) and targetOrg override is provided, applies it to apexguru engine', () => {
Expand All @@ -301,6 +304,9 @@ describe('CodeAnalyzerConfigFactoryImpl', () => {
expect(testedConfig.getEngineOverridesFor('apexguru')).toEqual({
target_org: 'my-org@example.com'
});
expect(testedConfig.getEngineOverridesFor('flowAnalyzer')).toEqual({
target_org: 'my-org@example.com'
});
// Original config values should still be loaded
expect(testedConfig.getRuleOverridesFor('stubEngine1')).toEqual({
stub1RuleC: {
Expand All @@ -321,6 +327,9 @@ describe('CodeAnalyzerConfigFactoryImpl', () => {
expect(testedConfig.getEngineOverridesFor('apexguru')).toEqual({
target_org: 'my-org@example.com'
});
expect(testedConfig.getEngineOverridesFor('flowAnalyzer')).toEqual({
target_org: 'my-org@example.com'
});
});

it('When both noSuppressions and targetOrg overrides are provided, both are applied', () => {
Expand All @@ -334,6 +343,9 @@ describe('CodeAnalyzerConfigFactoryImpl', () => {
expect(testedConfig.getEngineOverridesFor('apexguru')).toEqual({
target_org: 'my-org@example.com'
});
expect(testedConfig.getEngineOverridesFor('flowAnalyzer')).toEqual({
target_org: 'my-org@example.com'
});
});
});
});
Expand Down
3 changes: 2 additions & 1 deletion test/lib/factories/EnginePluginsFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('EnginePluginsFactoryImpl', () => {
const pluginsFactory = new EnginePluginsFactoryImpl();
const enginePlugins = pluginsFactory.create();

expect(enginePlugins).toHaveLength(8);
expect(enginePlugins).toHaveLength(9);
expect(enginePlugins[0].getAvailableEngineNames()).toEqual(['eslint']);
expect(enginePlugins[1].getAvailableEngineNames()).toEqual(['pmd', 'cpd']);
expect(enginePlugins[2].getAvailableEngineNames()).toEqual(['retire-js']);
Expand All @@ -15,5 +15,6 @@ describe('EnginePluginsFactoryImpl', () => {
expect(enginePlugins[5].getAvailableEngineNames()).toEqual(['sfge']);
expect(enginePlugins[6].getAvailableEngineNames()).toEqual(['apexguru']);
expect(enginePlugins[7].getAvailableEngineNames()).toEqual(['uibundle']);
expect(enginePlugins[8].getAvailableEngineNames()).toEqual(['flowAnalyzer']);
});
});