diff --git a/packages/code-analyzer-pmd-engine/package.json b/packages/code-analyzer-pmd-engine/package.json index 3e51aaa4..85d0b6c5 100644 --- a/packages/code-analyzer-pmd-engine/package.json +++ b/packages/code-analyzer-pmd-engine/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/code-analyzer-pmd-engine", "description": "Plugin package that adds 'pmd' and 'cpd' as engines into Salesforce Code Analyzer", - "version": "0.15.0", + "version": "0.15.1-SNAPSHOT", "author": "The Salesforce Code Analyzer Team", "license": "BSD-3-Clause", "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", diff --git a/packages/code-analyzer-pmd-engine/src/config.ts b/packages/code-analyzer-pmd-engine/src/config.ts index 27ab29c3..c59366c7 100644 --- a/packages/code-analyzer-pmd-engine/src/config.ts +++ b/packages/code-analyzer-pmd-engine/src/config.ts @@ -19,6 +19,7 @@ export type PmdEngineConfig = { // If not defined, or equal to null, then an attempt will be made to automatically discover a 'java' command from your environment. java_command: string + // !! NOTE !! - HIDDEN UNTIL A USER REQUESTS THIS - ALL LANGUAGES ARE ENABLED BY DEFAULT SO THERE MAY NOT BE A USE CASE FOR THIS YET // List of languages associated with the PMD rules to be made available for 'pmd' engine rule selection. // The languages that you may choose from are: 'apex', 'html', 'javascript' (or 'ecmascript'), 'visualforce', 'xml' // See https://pmd.github.io/pmd/tag_rule_references.html to learn about the PMD rules available for each language. @@ -42,7 +43,7 @@ export type PmdEngineConfig = { export const DEFAULT_PMD_ENGINE_CONFIG: PmdEngineConfig = { java_command: DEFAULT_JAVA_COMMAND, - rule_languages: ['apex', 'visualforce'], + rule_languages: PMD_AVAILABLE_LANGUAGES, // hidden java_classpath_entries: [], custom_rulesets: [] } @@ -55,11 +56,10 @@ export const PMD_ENGINE_CONFIG_DESCRIPTION: ConfigDescription = { valueType: "string", defaultValue: null // Using null for doc and since it indicates that the value is calculated based on the environment }, - rule_languages: { - descriptionText: getMessage('PmdConfigFieldDescription_rule_languages', toAvailableLanguagesText(PMD_AVAILABLE_LANGUAGES)), - valueType: "array", - defaultValue: DEFAULT_PMD_ENGINE_CONFIG.rule_languages, - }, + + // rule_languages - is excluded here so that it can remain hidden + // rule_languages WILL REMAIN HIDDEN UNTIL A USER REQUESTS THIS - ALL LANGUAGES ARE ENABLED BY DEFAULT SO THERE MAY NOT BE A USE CASE FOR THIS YET + java_classpath_entries: { descriptionText: getMessage('PmdConfigFieldDescription_java_classpath_entries'), valueType: "array", @@ -81,6 +81,7 @@ export type CpdEngineConfig = { // If not defined, or equal to null, then an attempt will be made to automatically discover a 'java' command from your environment. java_command: string + // !! NOTE !! - HIDDEN UNTIL A USER REQUESTS THIS - ALL LANGUAGES ARE ENABLED BY DEFAULT SO THERE MAY NOT BE A USE CASE FOR THIS YET // List of languages associated with CPD to be made available for 'cpd' engine rule selection. // The languages that you may choose from are: 'apex', 'html', 'javascript' (or 'ecmascript'), 'typescript', 'visualforce', 'xml' rule_languages: string[] @@ -97,7 +98,7 @@ export type CpdEngineConfig = { export const DEFAULT_CPD_ENGINE_CONFIG: CpdEngineConfig = { java_command: DEFAULT_JAVA_COMMAND, - rule_languages: ['apex', 'html', 'javascript', 'typescript', 'visualforce', 'xml'], + rule_languages: CPD_AVAILABLE_LANGUAGES, // hidden minimum_tokens: 100, skip_duplicate_files: false } @@ -110,11 +111,10 @@ export const CPD_ENGINE_CONFIG_DESCRIPTION: ConfigDescription = { valueType: "string", defaultValue: null // Using null for doc and since it indicates that the value is calculated based on the environment }, - rule_languages: { - descriptionText: getMessage('CpdConfigFieldDescription_rule_languages', toAvailableLanguagesText(CPD_AVAILABLE_LANGUAGES)), - valueType: "array", - defaultValue: DEFAULT_CPD_ENGINE_CONFIG.rule_languages - }, + + // rule_languages - is excluded here so that it can remain hidden + // rule_languages WILL REMAIN HIDDEN UNTIL A USER REQUESTS THIS - ALL LANGUAGES ARE ENABLED BY DEFAULT SO THERE MAY NOT BE A USE CASE FOR THIS YET + minimum_tokens: { descriptionText: getMessage('CpdConfigFieldDescription_minimum_tokens'), valueType: "number", diff --git a/packages/code-analyzer-pmd-engine/src/cpd-engine.ts b/packages/code-analyzer-pmd-engine/src/cpd-engine.ts index c946cb40..f0fe8889 100644 --- a/packages/code-analyzer-pmd-engine/src/cpd-engine.ts +++ b/packages/code-analyzer-pmd-engine/src/cpd-engine.ts @@ -126,10 +126,18 @@ export class CpdEngine extends Engine { function createRuleForLanguage(languageId: LanguageId): RuleDescription { const languageTag: string = languageId.charAt(0).toUpperCase() + languageId.slice(1); + + // We agreed that html and xml can be noisy and are less important for users to be made aware of duplicate code + // so we will be just adding Recommended tag to programming languages: apex, javascript, typescript, and visualforce + const recommendedLanguages: Set = new Set([LanguageId.APEX, LanguageId.JAVASCRIPT, LanguageId.TYPESCRIPT, LanguageId.VISUALFORCE]); + return { name: getRuleNameFromLanguage(languageId), severityLevel: SeverityLevel.Info, - tags: [COMMON_TAGS.RECOMMENDED, COMMON_TAGS.CATEGORIES.DESIGN, languageTag], + tags: [ + ... (recommendedLanguages.has(languageId) ? [COMMON_TAGS.RECOMMENDED] : []), + COMMON_TAGS.CATEGORIES.DESIGN, + languageTag], description: getMessage('DetectCopyPasteForLanguageRuleDescription', languageId), resourceUrls: ['https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html#refactoring-duplicates'] } diff --git a/packages/code-analyzer-pmd-engine/src/messages.ts b/packages/code-analyzer-pmd-engine/src/messages.ts index 72111ace..2b520bc6 100644 --- a/packages/code-analyzer-pmd-engine/src/messages.ts +++ b/packages/code-analyzer-pmd-engine/src/messages.ts @@ -10,11 +10,6 @@ const MESSAGE_CATALOG : { [key: string]: string } = { `May be provided as the name of a command that exists on the path, or an absolute file path location.\n` + `If unspecified, or specified as null, then an attempt will be made to automatically discover a 'java' command from your environment.`, - PmdConfigFieldDescription_rule_languages: - `List of languages associated with the PMD rules to be made available for 'pmd' engine rule selection.\n` + - `The languages that you may choose from are: %s.\n` + - `See https://pmd.github.io/pmd/tag_rule_references.html to learn about the PMD rules available for each language.`, - PmdConfigFieldDescription_java_classpath_entries: `List of jar files and/or folders to add the Java classpath when running PMD.\n` + `Each entry may be given as an absolute path or a relative path to 'config_root'.\n` + @@ -34,10 +29,6 @@ const MESSAGE_CATALOG : { [key: string]: string } = { `CPD ENGINE CONFIGURATION\n` + `To learn more about this configuration, visit: __LINK_COMING_SOON__`, - CpdConfigFieldDescription_rule_languages: - `List of languages associated with CPD to be made available for 'cpd' engine rule selection.\n` + - `The languages that you may choose from are: %s.`, - CpdConfigFieldDescription_minimum_tokens: `The minimum number of tokens required to be in a duplicate block of code in order to be reported as a violation.\n` + `The concept of a token may be defined differently per language, but in general it a distinct basic element of source code.\n` + diff --git a/packages/code-analyzer-pmd-engine/src/pmd-engine.ts b/packages/code-analyzer-pmd-engine/src/pmd-engine.ts index ac030671..0e17c090 100644 --- a/packages/code-analyzer-pmd-engine/src/pmd-engine.ts +++ b/packages/code-analyzer-pmd-engine/src/pmd-engine.ts @@ -79,6 +79,11 @@ export class PmdEngine extends Engine { .map(ruleName => fetchRuleInfoByRuleName(ruleInfoList, ruleName)) .filter(ruleInfo => ruleInfo !== null); + if (selectedRuleInfoList.length === 0) { + this.emitRunRulesProgressEvent(100); + return {violations: []}; + } + const pmdResults: PmdResults = await this.pmdWrapperInvoker.invokeRunCommand(selectedRuleInfoList, filesToScan, (innerPerc: number) => this.emitRunRulesProgressEvent(10 + 88*(innerPerc/100))); // 10 to 98% diff --git a/packages/code-analyzer-pmd-engine/test/plugin.test.ts b/packages/code-analyzer-pmd-engine/test/plugin.test.ts index a0a8681e..bd4a2325 100644 --- a/packages/code-analyzer-pmd-engine/test/plugin.test.ts +++ b/packages/code-analyzer-pmd-engine/test/plugin.test.ts @@ -38,11 +38,6 @@ describe('Tests for the PmdCpdEnginesPlugin', () => { it(`When describeEngineConfig is passed 'pmd' then the correct config description is returned`, async () => { expect(plugin.describeEngineConfig('pmd')).toEqual(PMD_ENGINE_CONFIG_DESCRIPTION); - - // Sanity check that we list the correct available languages: - expect(PMD_ENGINE_CONFIG_DESCRIPTION.fieldDescriptions!['rule_languages'].descriptionText).toEqual( - getMessage('PmdConfigFieldDescription_rule_languages', - `'apex', 'html', 'javascript' (or 'ecmascript'), 'visualforce', 'xml'`)); }); it('When describeEngineConfig is passed an unsupported engine name, then an error is thrown', async () => { @@ -71,7 +66,7 @@ describe('Tests for the PmdCpdEnginesPlugin', () => { expect(resolvedConfig.java_command.endsWith('java')).toEqual(true); expect(resolvedConfig).toEqual({ java_command: resolvedConfig.java_command, // Already checked that it ends with 'java' - rule_languages: ['apex', 'visualforce'], + rule_languages: ['apex', 'html', 'javascript', 'visualforce', 'xml'], java_classpath_entries: [], custom_rulesets: [] }); diff --git a/packages/code-analyzer-pmd-engine/test/pmd-engine.test.ts b/packages/code-analyzer-pmd-engine/test/pmd-engine.test.ts index 2f9e70e9..01fabcc4 100644 --- a/packages/code-analyzer-pmd-engine/test/pmd-engine.test.ts +++ b/packages/code-analyzer-pmd-engine/test/pmd-engine.test.ts @@ -33,7 +33,7 @@ describe('Tests for the getName method of PmdEngine', () => { describe('Tests for the describeRules method of PmdEngine', () => { - it('When using defaults without workspace, then apex and visualforce rules are returned', async () => { + it('When using defaults without workspace, then all language rules are returned', async () => { const engine: PmdEngine = new PmdEngine(DEFAULT_PMD_ENGINE_CONFIG); const logEvents: LogEvent[] = []; engine.onEvent(EventType.LogEvent, (e: LogEvent) => logEvents.push(e)); @@ -41,7 +41,7 @@ describe('Tests for the describeRules method of PmdEngine', () => { engine.onEvent(EventType.DescribeRulesProgressEvent, (e: DescribeRulesProgressEvent) => progressEvents.push(e)); const ruleDescriptions: RuleDescription[] = await engine.describeRules({}); - await expectRulesToMatchGoldFile(ruleDescriptions, 'rules_apexAndVisualforce.goldfile.json'); + await expectRulesToMatchGoldFile(ruleDescriptions, 'rules_allLanguages.goldfile.json'); // Also check that we have fine logs with the argument list and the duration in milliseconds const fineLogEvents: LogEvent[] = logEvents.filter(e => e.logLevel === LogLevel.Fine); @@ -66,11 +66,21 @@ describe('Tests for the describeRules method of PmdEngine', () => { await expectRulesToMatchGoldFile(ruleDescriptions, 'rules_apexOnly.goldfile.json'); }); - it('When using defaults with workspace containing only apex and xml code, then only apex rules are returned', async () => { + it('When using defaults with workspace containing only apex and visualforce code, then only apex and visualforce rules are returned', async () => { const engine: PmdEngine = new PmdEngine(DEFAULT_PMD_ENGINE_CONFIG); const workspace: Workspace = new Workspace([ path.join(TEST_DATA_FOLDER, 'samplePmdWorkspace', 'dummy.trigger'), - path.join(TEST_DATA_FOLDER, 'samplePmdWorkspace', 'dummy.xml') + path.join(TEST_DATA_FOLDER, 'samplePmdWorkspace', 'dummy.page') + ]); + const ruleDescriptions: RuleDescription[] = await engine.describeRules({workspace: workspace}); + await expectRulesToMatchGoldFile(ruleDescriptions, 'rules_apexAndVisualforce.goldfile.json'); + }); + + it('When using defaults with workspace containing only apex and text files, then only apex rules are returned', async () => { + const engine: PmdEngine = new PmdEngine(DEFAULT_PMD_ENGINE_CONFIG); + const workspace: Workspace = new Workspace([ + path.join(TEST_DATA_FOLDER, 'samplePmdWorkspace', 'dummy.trigger'), + path.join(TEST_DATA_FOLDER, 'samplePmdWorkspace', 'dummy.txt') ]); const ruleDescriptions: RuleDescription[] = await engine.describeRules({workspace: workspace}); await expectRulesToMatchGoldFile(ruleDescriptions, 'rules_apexOnly.goldfile.json'); @@ -393,7 +403,7 @@ describe('Tests for the runRules method of PmdEngine', () => { const progressEvents: RunRulesProgressEvent[] = []; engine.onEvent(EventType.RunRulesProgressEvent, (e: RunRulesProgressEvent) => progressEvents.push(e)); - const workspace: Workspace = new Workspace([path.join(TEST_DATA_FOLDER, 'samplePmdWorkspace', 'dummy.xml')]); + const workspace: Workspace = new Workspace([path.join(TEST_DATA_FOLDER, 'samplePmdWorkspace', 'dummy.txt')]); const ruleNames: string[] = ['OperationWithLimitsInLoop', 'VfUnescapeEl']; const results: EngineRunResults = await engine.runRules(ruleNames, {workspace: workspace}); diff --git a/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_allDefaultLanguages.goldfile.json b/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_allDefaultLanguages.goldfile.json index 3e606915..9e8189cf 100644 --- a/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_allDefaultLanguages.goldfile.json +++ b/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_allDefaultLanguages.goldfile.json @@ -16,7 +16,6 @@ "name": "DetectCopyPasteForHtml", "severityLevel": 5, "tags": [ - "Recommended", "Design", "Html" ], @@ -68,7 +67,6 @@ "name": "DetectCopyPasteForXml", "severityLevel": 5, "tags": [ - "Recommended", "Design", "Xml" ], diff --git a/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_apexAndHtmlOnly.goldfile.json b/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_apexAndHtmlOnly.goldfile.json index 1fe924a1..84476458 100644 --- a/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_apexAndHtmlOnly.goldfile.json +++ b/packages/code-analyzer-pmd-engine/test/test-data/cpdGoldfiles/rules_apexAndHtmlOnly.goldfile.json @@ -16,7 +16,6 @@ "name": "DetectCopyPasteForHtml", "severityLevel": 5, "tags": [ - "Recommended", "Design", "Html" ],