Skip to content
Merged
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
8 changes: 8 additions & 0 deletions messages/describe.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ the name of the rule

The name of the rule.

# flags.previewPmd7Summary

use PMD version %s to describe PMD and CPD rules

# flags.previewPmd7Description

Uses PMD version %s instead of %s to describe PMD and CPD rules.

# output.noMatchingRules

No rules were found with the name '%s'.
Expand Down
8 changes: 8 additions & 0 deletions messages/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ select rules by engine

Selects rules by engine. Enter multiple engines as a comma-separated list.

# flags.previewPmd7Summary

use PMD version %s to list PMD and CPD rules

# flags.previewPmd7Description

Uses PMD version %s instead of %s to list PMD and CPD rules.

# rulesetDeprecation

The 'ruleset' command parameter is deprecated. Use 'category' instead
Expand Down
8 changes: 8 additions & 0 deletions messages/run-pathless.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ specify location of PMD rule reference XML file to customize rule selection

Specifies the location of PMD rule reference XML file to customize rule selection.

# flags.previewPmd7Summary

use PMD version %s when running PMD and CPD

# flags.previewPmd7Description

Uses PMD version %s instead of %s when running PMD and CPD engines.

# flags.verboseViolationsSummary

return retire-js violation message details
Expand Down
172 changes: 126 additions & 46 deletions pmd-cataloger/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,11 @@ plugins {
group = "sfdx"
version = "1.0"

val distDir = "$buildDir/../../dist"
val pmdVersion = "6.55.0"
val pmdFile = "pmd-bin-$pmdVersion.zip"
val pmdUrl = "https://github.com/pmd/pmd/releases/download/pmd_releases%2F${pmdVersion}/${pmdFile}"
val skippableJarRegexes = setOf("""^common_[\d\.-]*\.jar""".toRegex(),
"""^fastparse.*\.jar""".toRegex(),
"""^groovy.*\.jar""".toRegex(),
"""^lenses.*\.jar""".toRegex(),
"""^parsers.*\.jar""".toRegex(),
"""^pmd-(cpp|cs|dart|fortran|go|groovy|jsp|kotlin|lua|matlab|modelica|objectivec|perl|php|plsql|python|ruby|scala|swift|ui)[-_\d\.]*\.jar""".toRegex(),
"""^protobuf-java-[\d\.]*\.jar""".toRegex(),
"""^scala.*\.jar""".toRegex(),
"""^sourcecode_[\d\.-]*\.jar""".toRegex(),
"""^trees_[\d\.-]*\.jar""".toRegex()
)

repositories {
mavenCentral()
google()
}

jacoco {
toolVersion = "0.8.7"
}

tasks.register<de.undercouch.gradle.tasks.download.Download>("downloadPmd") {
src(pmdUrl)
dest(buildDir)
overwrite(false)
}

tasks.register<Copy>("installPmd") {
dependsOn("downloadPmd")
from(zipTree("$buildDir/$pmdFile"))
exclude { details: FileTreeElement ->
skippableJarRegexes.any {it.containsMatchIn(details.file.name)}
}
into("$distDir/pmd")
// TODO include("just the *.jars etc. we care about")
includeEmptyDirs = false
eachFile {
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
}
}

dependencies {
implementation(project(":cli-messaging"))
implementation ("com.googlecode.json-simple:json-simple:1.1.1") {
Expand All @@ -73,25 +33,145 @@ dependencies {
testImplementation(files("$buildDir/../../test/test-jars/apex/testjar-categories-and-rulesets-1.jar"))
}


// ======== MODIFY PLUGIN PROPERTIES ===================================================================================
java.sourceCompatibility = JavaVersion.VERSION_1_8

application {
mainClass.set("sfdc.sfdx.scanner.pmd.Main");
}

// Running the cli locally needs the dist exploded, so just do that
// automatically with build for ease of use.
jacoco {
toolVersion = "0.8.7"
}

val distDir = "$buildDir/../../dist"


// ======== DEFINE/UPDATE PMD-CATALOGER DIST RELATED TASKS =============================================================
val pmdCatalogerDistDir = "$distDir/pmd-cataloger"

tasks.named<Sync>("installDist") {
into("$distDir/pmd-cataloger")
// The installDist task comes with the distribution plugin which comes with the applciation plugin. We modify it here:
into(pmdCatalogerDistDir)
}

tasks.register<Delete>("deletePmdCatalogerDist") {
delete(pmdCatalogerDistDir)
}

// ======== DEFINE/UPDATE PMD6 DIST RELATED TASKS =====================================================================
val pmd6DistDir = "$distDir/pmd"
val pmd6Version = "6.55.0"
val pmd6File = "pmd-bin-$pmd6Version.zip"

tasks.register<de.undercouch.gradle.tasks.download.Download>("downloadPmd6") {
src("https://github.com/pmd/pmd/releases/download/pmd_releases%2F${pmd6Version}/${pmd6File}")
dest(buildDir)
overwrite(false)
}

tasks.register<Copy>("installPmd6") {
dependsOn("downloadPmd6")
from(zipTree("$buildDir/$pmd6File"))

// I went to https://github.com/pmd/pmd/tree/pmd_releases/6.55.0 and for each of the languages that we support
// (apex, java, visualforce, xml), I took a look at its direct and indirect dependencies at
// https://central.sonatype.com/artifact/net.sourceforge.pmd/pmd-apex/dependencies
// by selecting the 6.55.0 dropdown and clicking on "Dependencies" and selecting "All Dependencies".
// For completeness, I listed the modules and all their compile time dependencies (direct and indirect).
// Duplicates don't matter since we use setOf.
val pmd6ModulesToInclude = setOf(
// LANGUAGE MODULE DEPENDENCIES (direct and indirect)
"pmd-apex", "animal-sniffer-annotations", "antlr", "antlr-runtime", "antlr4-runtime", "aopalliance", "asm", "cglib", "commons-lang3", "error_prone_annotations", "gson", "j2objc-annotations", "javax.inject", "jcommander", "jol-core", "jsr305", "logback-classic", "logback-core", "pmd-apex-jorje", "pmd-core", "saxon", "slf4j-api", "stringtemplate",
"pmd-java", "antlr4-runtime", "asm", "commons-lang3", "gson", "jcommander", "pmd-core", "saxon",
"pmd-visualforce", "animal-sniffer-annotations", "antlr", "antlr-runtime", "antlr4-runtime", "aopalliance", "asm", "cglib", "commons-lang3", "error_prone_annotations", "gson", "j2objc-annotations", "javax.inject", "jcommander", "jol-core", "jsr305", "logback-classic", "logback-core", "pmd-apex", "pmd-apex-jorje", "pmd-core", "saxon", "slf4j-api", "stringtemplate",
"pmd-xml", "antr4-runtime", "asm", "commons-lang3", "gson", "jcommander", "pmd-core", "saxon"
)

val pmd6JarsToIncludeRegexes = mutableSetOf("""^LICENSE""".toRegex())
pmd6ModulesToInclude.forEach {
pmd6JarsToIncludeRegexes.add("""^$it-.*\.jar""".toRegex())
}

include { details: FileTreeElement -> pmd6JarsToIncludeRegexes.any { it.containsMatchIn(details.file.name) } }
into(pmd6DistDir)
includeEmptyDirs = false
eachFile {
// We drop the parent "pmd-bin-6.55.0" folder and put files directly into our "pmd" folder
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
}
}

tasks.register<Delete>("deletePmd6Dist") {
delete(pmd6DistDir)
}

tasks.named("assemble") {

// TODO: These currently do not get cleaned with ./gradlew clean which can cause a lot of confusion.
// ======== DEFINE/UPDATE PMD7 DIST RELATED TASKS =====================================================================
val pmd7DistDir = "$distDir/pmd7"
val pmd7Version = "7.0.0-rc4"
val pmd7File = "pmd-dist-$pmd7Version-bin.zip"

tasks.register<de.undercouch.gradle.tasks.download.Download>("downloadPmd7") {
src("https://github.com/pmd/pmd/releases/download/pmd_releases%2F${pmd7Version}/${pmd7File}")
dest(buildDir)
overwrite(false)
}

tasks.register<Copy>("installPmd7") {
dependsOn("downloadPmd7")
from(zipTree("$buildDir/$pmd7File"))

// I went to https://github.com/pmd/pmd/tree/pmd_releases/7.0.0-rc4 and for each of the languages that we support
// (apex, java, visualforce, xml), I took a look at its direct and indirect dependencies at
// https://central.sonatype.com/artifact/net.sourceforge.pmd/pmd-apex/dependencies
// by selecting the 7.0.0-rc4 dropdown and clicking on "Dependencies" and selecting "All Dependencies".
// For completeness, I listed the modules and all their compile time dependencies (direct and indirect).
// Duplicates don't matter since we use setOf.
val pmd7ModulesToInclude = setOf(
// LANGUAGE MODULE DEPENDENCIES (direct and indirect)
"pmd-apex", "Saxon-HE", "animal-sniffer-annotations", "antlr", "antlr-runtime", "antlr4-runtime", "aopalliance", "apex-parser", "apexlink", "asm", "cglib", "checker-qual", "commons-lang3", "error_prone_annotations", "failureaccess", "geny_2.13", "gson", "guava", "j2objc-annotations", "javax.inject", "jsr305", "jul-to-slf4j", "listenablefuture", "nice-xml-messages", "pcollections", "pkgforce_2.13", "pmd-apex-jorje", "pmd-core", "runforce", "scala-collection-compat_2.13", "scala-json-rpc-upickle-json-serializer_2.13", "scala-json-rpc_2.13", "scala-library", "scala-parallel-collections_2.13", "scala-reflect", "scala-xml_2.13", "slf4j-api", "stringtemplate", "ujson_2.13", "upack_2.13", "upickle-core_2.13", "upickle-implicits_2.13", "upickle_2.13",
"pmd-java", "Saxon-HE", "antlr4-runtime", "asm", "checker-qual", "commons-lang3", "gson", "jul-to-slf4j", "nice-xml-messages", "pcollections", "pmd-core", "slf4j-api",
"pmd-visualforce", "Saxon-HE", "animal-sniffer-annotations", "antlr", "antlr-runtime", "antlr4-runtime", "aopalliance", "apex-parser", "apexlink", "asm", "cglib", "checker-qual", "commons-lang3", "error_prone_annotations", "failureaccess", "geny_2.13", "gson", "guava", "j2objc-annotations", "javax.inject", "jsr305", "jul-to-slf4j", "listenablefuture", "nice-xml-messages", "pcollections", "pkgforce_2.13", "pmd-apex", "pmd-apex-jorje", "pmd-core", "runforce", "scala-collection-compat_2.13", "scala-json-rpc-upickle-json-serializer_2.13", "scala-json-rpc_2.13", "scala-library", "scala-parallel-collections_2.13", "scala-reflect", "scala-xml_2.13", "slf4j-api", "stringtemplate", "ujson_2.13", "upack_2.13", "upickle-core_2.13", "upickle-implicits_2.13", "upickle_2.13",
"pmd-xml", "Saxon-HE", "antlr4-runtime", "asm", "checker-qual", "commons-lang3", "gson", "jul-to-slf4j", "nice-xml-messages", "pcollections", "pmd-core", "slf4j-api",
// MAIN CLI MODULE DEPENDENCIES (direct and indirect)
"pmd-cli", "Saxon-HE", "antlr4-runtime", "asm", "checker-qual", "commons-lang3", "gson", "jline", "jul-to-slf4j", "nice-xml-messages", "pcollections", "picocli", "pmd-core", "pmd-ui", "progressbar", "slf4j-api", "slf4j-simple",
)
val pmd7JarsToIncludeRegexes = mutableSetOf("""^LICENSE""".toRegex())
pmd7ModulesToInclude.forEach {
pmd7JarsToIncludeRegexes.add("""^$it-.*\.jar""".toRegex())
}

include { details: FileTreeElement -> pmd7JarsToIncludeRegexes.any { it.containsMatchIn(details.file.name) } }
into(pmd7DistDir)
includeEmptyDirs = false
eachFile {
// We drop the parent "pmd-bin-7.0.0-rc4" folder and put files directly into our "pmd7" folder
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
}
}

tasks.register<Delete>("deletePmd7Dist") {
delete(pmd7DistDir)
}


// ======== ATTACH TASKS TO ASSEMBLE AND CLEAN ========================================================================
tasks.assemble {
dependsOn("installDist")
dependsOn("installPmd")
dependsOn("installPmd6")
dependsOn("installPmd7")
}

tasks.clean {
dependsOn("deletePmdCatalogerDist")
dependsOn("deletePmd6Dist")
dependsOn("deletePmd7Dist")
}


// ======== TEST RELATED TASKS =========================================================================================
tasks.test {
// Use JUnit 5
useJUnitPlatform()
Expand Down
6 changes: 4 additions & 2 deletions src/Constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os = require('os');
import path = require('path');

export const PMD_VERSION = '6.55.0';
export const PMD6_VERSION = '6.55.0';
export const PMD7_VERSION = '7.0.0-rc4';
export const PMD_APPEXCHANGE_RULES_VERSION = '0.12';
export const SFGE_VERSION = '1.0.1-pilot';
export const DEFAULT_SCANNER_PATH = path.join(os.homedir(), '.sfdx-scanner');
Expand Down Expand Up @@ -132,7 +133,8 @@ export enum Severity {
}

// Here, current dir __dirname = <base_dir>/sfdx-scanner/src
export const PMD_LIB = path.join(__dirname, '..', 'dist', 'pmd', 'lib');
export const PMD6_LIB = path.join(__dirname, '..', 'dist', 'pmd', 'lib');
export const PMD7_LIB = path.join(__dirname, '..', 'dist', 'pmd7', 'lib');

// Here, current dir __dirname = <base_dir>/sfdx-scanner/src
export const APPEXCHANGE_PMD_LIB = path.join(__dirname, '..', 'pmd-appexchange', 'lib');
17 changes: 17 additions & 0 deletions src/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {RuleEngine} from './lib/services/RuleEngine';
import {RulePathManager} from './lib/RulePathManager';
import {RuleCatalog} from './lib/services/RuleCatalog';
import {BundleName, getMessage} from "./MessageCatalog";
import {Pmd6CommandInfo, PmdCommandInfo} from "./lib/pmd/PmdCommandInfo";
/**
* Converts an array of RuleEngines to a sorted, comma delimited
* string of their names.
Expand All @@ -23,6 +24,14 @@ function enginesToString(engines: RuleEngine[]): string {
// See https://stackoverflow.com/questions/137975/what-are-drawbacks-or-disadvantages-of-singleton-pattern


// We all should hate global state. But our team agreed that we have a bit of refactoring to do before we can more
// easily swap out the pmd version. So this is meant to be a temporary solution until we do that refactoring.
declare global {
// eslint-disable-next-line no-var
var _activePmdCommandInfo: PmdCommandInfo;
}
globalThis._activePmdCommandInfo = new Pmd6CommandInfo();

// This is probably more appropriately called a ProviderFactory (Salesforce Core folks know this code smell all too well)
export const Controller = {
container,
Expand Down Expand Up @@ -92,5 +101,13 @@ export const Controller = {
}

return engines;
},

setActivePmdCommandInfo(pmdCommandInfo: PmdCommandInfo): void {
globalThis._activePmdCommandInfo = pmdCommandInfo;
},

getActivePmdCommandInfo: (): PmdCommandInfo => {
return globalThis._activePmdCommandInfo;
}
};
7 changes: 6 additions & 1 deletion src/commands/scanner/rule/describe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {BundleName, getMessage} from "../../../MessageCatalog";
import {Logger} from "@salesforce/core";
import {Display} from "../../../lib/Display";
import {RuleDescribeAction} from "../../../lib/actions/RuleDescribeAction";
import {PMD6_VERSION, PMD7_VERSION} from "../../../Constants";

/**
* Defines the "rule describe" command for the "scanner" cli.
Expand All @@ -28,7 +29,11 @@ export default class Describe extends ScannerCommand {
}),
verbose: Flags.boolean({
summary: getMessage(BundleName.Common, 'flags.verboseSummary')
})
}),
"preview-pmd7": Flags.boolean({
summary: getMessage(BundleName.Describe, 'flags.previewPmd7Summary', [PMD7_VERSION]),
description: getMessage(BundleName.Describe, 'flags.previewPmd7Description', [PMD7_VERSION, PMD6_VERSION])
}),
};

protected createAction(_logger: Logger, display: Display): Action {
Expand Down
8 changes: 6 additions & 2 deletions src/commands/scanner/rule/list.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Flags} from '@salesforce/sf-plugins-core';
import {Action, ScannerCommand} from '../../../lib/ScannerCommand';
import {AllowedEngineFilters} from '../../../Constants';
import {AllowedEngineFilters, PMD6_VERSION, PMD7_VERSION} from '../../../Constants';
import {BundleName, getMessage} from "../../../MessageCatalog";
import {Logger} from "@salesforce/core";
import {Display} from "../../../lib/Display";
Expand Down Expand Up @@ -56,7 +56,11 @@ export default class List extends ScannerCommand {
options: [...AllowedEngineFilters],
delimiter: ',',
multiple: true
})()
})(),
"preview-pmd7": Flags.boolean({
summary: getMessage(BundleName.List, 'flags.previewPmd7Summary', [PMD7_VERSION]),
description: getMessage(BundleName.List, 'flags.previewPmd7Description', [PMD7_VERSION, PMD6_VERSION])
}),
};

protected createAction(_logger: Logger, display: Display): Action {
Expand Down
7 changes: 6 additions & 1 deletion src/commands/scanner/run.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Flags} from '@salesforce/sf-plugins-core';
import {PathlessEngineFilters} from '../../Constants';
import {PathlessEngineFilters, PMD6_VERSION, PMD7_VERSION} from '../../Constants';
import {ScannerRunCommand} from '../../lib/ScannerRunCommand';
import {EngineOptionsFactory, RunEngineOptionsFactory} from "../../lib/EngineOptionsFactory";
import {InputProcessor, InputProcessorImpl} from "../../lib/InputProcessor";
Expand Down Expand Up @@ -69,6 +69,11 @@ export default class Run extends ScannerRunCommand {
summary: getMessage(BundleName.Run, 'flags.pmdConfigSummary'),
description: getMessage(BundleName.Run, 'flags.pmdConfigDescription')
}),
"preview-pmd7": Flags.boolean({
summary: getMessage(BundleName.Run, 'flags.previewPmd7Summary', [PMD7_VERSION]),
description: getMessage(BundleName.Run, 'flags.previewPmd7Description', [PMD7_VERSION, PMD6_VERSION])
}),

// TODO: This flag was implemented for W-7791882, and it's suboptimal. It leaks the abstraction and pollutes the command.
// It should be replaced during the 3.0 release cycle.
env: Flags.string({
Expand Down
Loading