From 7b070c62f1889bb047b88eefca08b41f10b9032e Mon Sep 17 00:00:00 2001 From: David Schach <636977+dschach@users.noreply.github.com> Date: Fri, 27 Dec 2024 14:27:00 -0800 Subject: [PATCH] feat: add minimum priority option --- .gitignore | 11 ++++++- README.md | 1 + __tests__/util.test.ts | 74 +++++++++++++++++++++++++++++++++--------- action.yml | 13 ++++++-- src/index.ts | 8 ++++- src/util.ts | 7 ++-- src/validator.ts | 14 ++++++-- 7 files changed, 105 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 8772299..2dff79b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Dependency directory node_modules +# MacOS files +.DS_Store + # See https://github.com/github/gitignore/blob/main/Node.gitignore # Logs logs @@ -131,4 +134,10 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +# PMD cache +.pmdCache + +# Test artifacts +pmd.filelist \ No newline at end of file diff --git a/README.md b/README.md index 7f24631..7bdacb5 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ See also [Uploading a SARIF file to GitHub](https://docs.github.com/en/code-secu |`analyzeModifiedFilesOnly`|no|"true"|Instead of analyze all files under "sourcePath", only the files that have been touched in a pull request or push will be analyzed. This makes the analysis faster and helps especially bigger projects which gradually want to introduce PMD. This helps in enforcing that no new code violation is introduced.
Depending on the analyzed language, the results might be less accurate results. At the moment, this is not a problem, as PMD mostly analyzes each file individually, but that might change in the future.
If the change is very big, not all files might be analyzed. Currently the maximum number of modified files is 300.
Note: When using PMD as a code scanner in order to create "Code scanning alerts" on GitHub, all files should be analyzed in order to produce a complete picture of the project. Otherwise alerts might get closed too soon.| |`createGitHubAnnotations`|no|"true"|By default, all detected violations are added as annotations to the pull request. You can disable this by setting FALSE. This can be useful if you are using another tool for this purpose.| |`uploadSarifReport`|no|"true"|By default, the generated SARIF report will be uploaded as an artifact named "PMD Report". This can be disabled, e.g. if there are multiple executions on multiple os of this action.| +|`minimumPriority`|no|"5"|Rule priority threshold; rules with lower priority than configured here won't be shown. Valid values are integers between 1 (High) and 5 (Low). Numbers 1-5 correspond to priorities `High`, `Medium_High`, `Medium`, `Medium_Low`, `Low`. ## Outputs diff --git a/__tests__/util.test.ts b/__tests__/util.test.ts index 824a518..2eba150 100644 --- a/__tests__/util.test.ts +++ b/__tests__/util.test.ts @@ -176,7 +176,8 @@ describe('pmd-github-action-util', function () { '.', 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) const reportFile = path.join('.', 'pmd-report.sarif') await expect(fs.access(reportFile)).resolves.toBe(undefined) @@ -184,7 +185,7 @@ describe('pmd-github-action-util', function () { expect(report.runs[0].tool.driver.version).toBe('6.40.0') expect(execOutput.exitCode).toBe(0) expect(execOutput.stdout.trim()).toBe( - 'Running PMD 6.40.0 with: pmd -no-cache -d . -f sarif -R ruleset.xml -r pmd-report.sarif' + 'Running PMD 6.40.0 with: pmd -no-cache -d . -f sarif -R ruleset.xml -r pmd-report.sarif --minimum-priority 5' ) await io.rmRF(reportFile) }) @@ -207,7 +208,8 @@ describe('pmd-github-action-util', function () { '.', 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) const reportFile = path.join('.', 'pmd-report.sarif') await expect(fs.access(reportFile)).resolves.toBe(undefined) @@ -215,7 +217,7 @@ describe('pmd-github-action-util', function () { expect(report.runs[0].tool.driver.version).toBe('6.41.0') expect(execOutput.exitCode).toBe(0) expect(execOutput.stdout.trim()).toBe( - 'Running PMD 6.41.0 with: pmd --no-cache -d . -f sarif -R ruleset.xml -r pmd-report.sarif' + 'Running PMD 6.41.0 with: pmd --no-cache -d . -f sarif -R ruleset.xml -r pmd-report.sarif --minimum-priority 5' ) await io.rmRF(reportFile) }) @@ -235,7 +237,8 @@ describe('pmd-github-action-util', function () { '.', 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) ).rejects.toThrow() }) @@ -262,7 +265,8 @@ describe('pmd-github-action-util', function () { '.', 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) expect(execMock).toHaveBeenCalledWith( @@ -276,7 +280,9 @@ describe('pmd-github-action-util', function () { '-R', 'ruleset.xml', '-r', - 'pmd-report.sarif' + 'pmd-report.sarif', + '--minimum-priority', + '5' ], { ignoreReturnCode: true @@ -414,7 +420,8 @@ describe('pmd-github-action-util', function () { ['src/file1.txt', 'src/file2.txt'], 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) const pmdFilelist = path.join('.', 'pmd.filelist') await expect(fs.access(pmdFilelist)).resolves.toBe(undefined) @@ -422,7 +429,7 @@ describe('pmd-github-action-util', function () { expect(pmdFilelistContent).toBe('src/file1.txt,src/file2.txt') expect(execOutput.exitCode).toBe(0) expect(execOutput.stdout.trim()).toBe( - 'Running PMD 6.40.0 with: pmd -no-cache -filelist pmd.filelist -f sarif -R ruleset.xml -r pmd-report.sarif' + 'Running PMD 6.40.0 with: pmd -no-cache -filelist pmd.filelist -f sarif -R ruleset.xml -r pmd-report.sarif --minimum-priority 5' ) await io.rmRF(pmdFilelist) await io.rmRF(path.join('.', 'pmd-report.sarif')) @@ -446,7 +453,8 @@ describe('pmd-github-action-util', function () { ['src/file1.txt', 'src/file2.txt'], 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) const pmdFilelist = path.join('.', 'pmd.filelist') await expect(fs.access(pmdFilelist)).resolves.toBe(undefined) @@ -454,7 +462,7 @@ describe('pmd-github-action-util', function () { expect(pmdFilelistContent).toBe('src/file1.txt,src/file2.txt') expect(execOutput.exitCode).toBe(0) expect(execOutput.stdout.trim()).toBe( - 'Running PMD 6.41.0 with: pmd --no-cache --file-list pmd.filelist -f sarif -R ruleset.xml -r pmd-report.sarif' + 'Running PMD 6.41.0 with: pmd --no-cache --file-list pmd.filelist -f sarif -R ruleset.xml -r pmd-report.sarif --minimum-priority 5' ) await io.rmRF(pmdFilelist) await io.rmRF(path.join('.', 'pmd-report.sarif')) @@ -647,7 +655,8 @@ describe('pmd-github-action-util', function () { ['src/file1.txt', 'src/file2.txt'], 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) const pmdFilelist = path.join('.', 'pmd.filelist') await expect(fs.access(pmdFilelist)).resolves.toBe(undefined) @@ -655,12 +664,46 @@ describe('pmd-github-action-util', function () { expect(pmdFilelistContent).toBe('src/file1.txt,src/file2.txt') expect(execOutput.exitCode).toBe(0) expect(execOutput.stdout.trim()).toBe( - 'Running PMD 7.0.0-rc1 with: check --no-progress --no-cache --file-list pmd.filelist -f sarif -R ruleset.xml -r pmd-report.sarif' + 'Running PMD 7.0.0-rc1 with: check --no-progress --no-cache --file-list pmd.filelist -f sarif -R ruleset.xml -r pmd-report.sarif --minimum-priority 5' ) await io.rmRF(pmdFilelist) await io.rmRF(path.join('.', 'pmd-report.sarif')) }) + test('can execute PMD 7 with custom priority', async () => { + fetchMock.get( + 'https://api.github.com/repos/pmd/pmd/releases/tags/pmd_releases%2F7.0.0-rc1', + async () => + JSON.parse( + await fs.readFile(`${__dirname}/data/releases-7.0.0-rc1.json`, 'utf8') + ) + ) + nock('https://github.com') + .get( + '/pmd/pmd/releases/download/pmd_releases/7.0.0-rc1/pmd-bin-7.0.0-rc1.zip' + ) + .replyWithFile(200, `${__dirname}/data/pmd-bin-7.0.0-rc1.zip`) + + const pmdInfo = await util.downloadPmd( + '7.0.0-rc1', + 'my_test_token', + undefined + ) + const execOutput = await util.executePmd( + pmdInfo, + ['src/file1.txt', 'src/file2.txt'], + 'ruleset.xml', + 'sarif', + 'pmd-report.sarif', + '4' + ) + + expect(execOutput.stdout.trim()).toBe( + 'Running PMD 7.0.0-rc1 with: check --no-progress --no-cache --file-list pmd.filelist -f sarif -R ruleset.xml -r pmd-report.sarif --minimum-priority 4' + ) + await io.rmRF(path.join('.', 'pmd-report.sarif')) + }) + test('PMD 7 release candidates and final release version ordering', () => { // see method util#isPmd7Cli expect(semver.major('6.55.0') >= 7).toBe(false) @@ -691,7 +734,8 @@ describe('pmd-github-action-util', function () { '.', 'ruleset.xml', 'sarif', - 'pmd-report.sarif' + 'pmd-report.sarif', + '5' ) const reportFile = path.join('.', 'pmd-report.sarif') await expect(fs.access(reportFile)).resolves.toBe(undefined) @@ -699,7 +743,7 @@ describe('pmd-github-action-util', function () { expect(report.runs[0].tool.driver.version).toBe('7.0.0-SNAPSHOT') expect(execOutput.exitCode).toBe(0) expect(execOutput.stdout.trim()).toBe( - 'Running PMD 7.0.0-SNAPSHOT with: check --no-progress --no-cache -d . -f sarif -R ruleset.xml -r pmd-report.sarif' + 'Running PMD 7.0.0-SNAPSHOT with: check --no-progress --no-cache -d . -f sarif -R ruleset.xml -r pmd-report.sarif --minimum-priority 5' ) await io.rmRF(reportFile) }) diff --git a/action.yml b/action.yml index aa916fd..3497b4e 100644 --- a/action.yml +++ b/action.yml @@ -78,8 +78,8 @@ inputs: default: 'true' createGitHubAnnotations: description: >- - By default, all detected violations are added as annotations to the pull - request. You can disable this by setting FALSE. This can be useful if you + By default, all detected violations are added as annotations to the pull + request. You can disable this by setting FALSE. This can be useful if you are using another tool for this purpose. required: false default: 'true' @@ -90,6 +90,15 @@ inputs: executions on multiple os of this action. required: false default: 'true' + minimumPriority: + description: >- + The lowest priority violation that will be reported. Must be a number 1-5 + (no decimal). 1 will only show Priority 1 violations. 2 will show Priority + 1 and 2, and so on. ("High" = 1, "Medium High" = 2, "Medium" = 3, "Medium + Low" = 4, "Low" = 5) The default is 5, which will show all priorities + (1-5). + required: false + default: '5' outputs: violations: description: Number of violations found diff --git a/src/index.ts b/src/index.ts index fac80eb..dd81013 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ async function main(): Promise { let modifiedFiles let execOutput let violations + let minimumPriority const token = core.getInput('token', { required: false }) const sourcePath = validator.validateSourcePath( core.getInput('sourcePath', { required: false }) @@ -40,12 +41,17 @@ async function main(): Promise { } } + minimumPriority = validator.validateMinimumPriority( + core.getInput('minimumPriority', { required: false }) + ) + execOutput = await util.executePmd( pmdInfo, modifiedFiles || sourcePath, validator.validateRulesets(core.getInput('rulesets', { required: true })), reportFormat, - reportFile + reportFile, + minimumPriority ) core.info(`PMD exited with ${execOutput.exitCode}`) diff --git a/src/util.ts b/src/util.ts index 33656bc..99e6e98 100644 --- a/src/util.ts +++ b/src/util.ts @@ -87,7 +87,8 @@ async function executePmd( fileListOrSourcePath: string | string[], ruleset: string, reportFormat: string, - reportFile: string + reportFile: string, + minimumPriority: string ): Promise { let pmdExecutable = '/bin/run.sh pmd' if (isPmd7Cli(pmdInfo.version)) { @@ -128,7 +129,9 @@ async function executePmd( '-R', ruleset, '-r', - reportFile + reportFile, + '--minimum-priority', + minimumPriority ], { ignoreReturnCode: true diff --git a/src/validator.ts b/src/validator.ts index 66ccc57..414a108 100644 --- a/src/validator.ts +++ b/src/validator.ts @@ -20,7 +20,7 @@ function validateSourcePath(sourcePath: string): string { typeof normalized !== 'string' || normalized.match(/[ ;:"'$]/) ) { - throw Error('Invalid sourcePath') + throw new Error('Invalid sourcePath') } return normalized } @@ -41,9 +41,19 @@ function validateDownloadUrl(url: string): string { throw new Error('Invalid downloadUrl') } +function validateMinimumPriority(priority: string): string { + const priorities = ['1', '2', '3', '4', '5'] + if (typeof priority === 'string' && priorities.includes(priority)) { + // valid + return priority + } + throw new Error('Invalid minimum priority') +} + export { validateVersion, validateSourcePath, validateRulesets, - validateDownloadUrl + validateDownloadUrl, + validateMinimumPriority }