diff --git a/common/__tests__/main.test.ts b/common/__tests__/main.test.ts index 76c41e99..c03d04b9 100644 --- a/common/__tests__/main.test.ts +++ b/common/__tests__/main.test.ts @@ -24,18 +24,36 @@ import * as fs from 'fs' import * as path from 'path' import * as os from 'os' -test('test passed coverage output', () => { +test('test passed coverage output using diff', () => { const result = getCoverageStats( - getCoverageFromSarif('__tests__/data/some.sarif.json') + getCoverageFromSarif('__tests__/data/some.sarif.json'), + true ) - expect(result).toEqual(passedCoverageFixture()) + expect(result).toEqual(passedCoverageFixtureDiff()) }) -test('test failed coverage output', () => { +test('test failed coverage output using diff', () => { const result = getCoverageStats( - getCoverageFromSarif('__tests__/data/empty.sarif.json') + getCoverageFromSarif('__tests__/data/empty.sarif.json'), + true ) - expect(result).toEqual(failedCoverageFixture()) + expect(result).toEqual(failedCoverageFixtureDiff()) +}) + +test('test passed coverage output using spam', () => { + const result = getCoverageStats( + getCoverageFromSarif('__tests__/data/some.sarif.json'), + false + ) + expect(result).toEqual(passedCoverageFixtureSpam()) +}) + +test('test failed coverage output using spam', () => { + const result = getCoverageStats( + getCoverageFromSarif('__tests__/data/empty.sarif.json'), + false + ) + expect(result).toEqual(failedCoverageFixtureSpam()) }) describe('getReportURL', () => { @@ -90,7 +108,25 @@ describe('getReportURL', () => { }) }) -function passedCoverageFixture(): string { +function passedCoverageFixtureSpam(): string { + return `@@ Code coverage @@ +45% total lines covered +124 lines analyzed, 56 lines covered +33% fresh lines covered +9 lines analyzed, 3 lines covered +# Calculated according to the filters of your coverage tool` +} + +function failedCoverageFixtureSpam(): string { + return `@@ Code coverage @@ +0% total lines covered +100 lines analyzed, 0 lines covered +0% fresh lines covered +100 lines analyzed, 0 lines covered +# Calculated according to the filters of your coverage tool` +} + +function passedCoverageFixtureDiff(): string { return `\`\`\`diff @@ Code coverage @@ + 45% total lines covered @@ -101,7 +137,7 @@ function passedCoverageFixture(): string { \`\`\`` } -function failedCoverageFixture(): string { +function failedCoverageFixtureDiff(): string { return `\`\`\`diff @@ Code coverage @@ - 0% total lines covered diff --git a/common/output.ts b/common/output.ts index a348a69d..2f828170 100644 --- a/common/output.ts +++ b/common/output.ts @@ -99,16 +99,19 @@ ${message} function makeConclusion( conclusion: string, - failedByThreshold: boolean + failedByThreshold: boolean, + useDiffBlock: boolean, ): string { - if (failedByThreshold) { - return `- ${conclusion}` + if (useDiffBlock) { + return failedByThreshold ? `- ${conclusion}` : `+ ${conclusion}` } else { - return `+ ${conclusion}` + return failedByThreshold + ? `${conclusion}` + : `${conclusion}` } } -export function getCoverageStats(c: Coverage): string { +export function getCoverageStats(c: Coverage, useDiffBlock: boolean): string { if (c.totalLines === 0 && c.totalCoveredLines === 0) { return '' } @@ -116,24 +119,23 @@ export function getCoverageStats(c: Coverage): string { let stats = '' if (c.totalLines !== 0) { const conclusion = `${c.totalCoverage}% total lines covered` - stats += `${makeConclusion(conclusion, c.totalCoverage < c.totalCoverageThreshold)} + stats += `${makeConclusion(conclusion, c.totalCoverage < c.totalCoverageThreshold, useDiffBlock)} ${c.totalLines} lines analyzed, ${c.totalCoveredLines} lines covered` } if (c.freshLines !== 0) { const conclusion = `${c.freshCoverage}% fresh lines covered` stats += ` -${makeConclusion(conclusion, c.freshCoverage < c.freshCoverageThreshold)} +${makeConclusion(conclusion, c.freshCoverage < c.freshCoverageThreshold, useDiffBlock)} ${c.freshLines} lines analyzed, ${c.freshCoveredLines} lines covered` } - return wrapToDiffBlock( - [ - `@@ Code coverage @@`, - `${stats}`, - `# Calculated according to the filters of your coverage tool` - ].join('\n') - ) + const coverageBlock = [ + `@@ Code coverage @@`, + `${stats}`, + `# Calculated according to the filters of your coverage tool` + ].join('\n') + return useDiffBlock ? wrapToDiffBlock(coverageBlock) : coverageBlock } export function getLicenseInfo( diff --git a/scan/dist/index.js b/scan/dist/index.js index 2d327a51..1a0a2104 100644 --- a/scan/dist/index.js +++ b/scan/dist/index.js @@ -137016,36 +137016,35 @@ function wrapToDiffBlock(message) { ${message} \`\`\``; } -function makeConclusion(conclusion, failedByThreshold) { - if (failedByThreshold) { - return `- ${conclusion}`; +function makeConclusion(conclusion, failedByThreshold, useDiffBlock) { + if (useDiffBlock) { + return failedByThreshold ? `- ${conclusion}` : `+ ${conclusion}`; } else { - return `+ ${conclusion}`; + return failedByThreshold ? `${conclusion}` : `${conclusion}`; } } -function getCoverageStats(c) { +function getCoverageStats(c, useDiffBlock) { if (c.totalLines === 0 && c.totalCoveredLines === 0) { return ""; } let stats = ""; if (c.totalLines !== 0) { const conclusion = `${c.totalCoverage}% total lines covered`; - stats += `${makeConclusion(conclusion, c.totalCoverage < c.totalCoverageThreshold)} + stats += `${makeConclusion(conclusion, c.totalCoverage < c.totalCoverageThreshold, useDiffBlock)} ${c.totalLines} lines analyzed, ${c.totalCoveredLines} lines covered`; } if (c.freshLines !== 0) { const conclusion = `${c.freshCoverage}% fresh lines covered`; stats += ` -${makeConclusion(conclusion, c.freshCoverage < c.freshCoverageThreshold)} +${makeConclusion(conclusion, c.freshCoverage < c.freshCoverageThreshold, useDiffBlock)} ${c.freshLines} lines analyzed, ${c.freshCoveredLines} lines covered`; } - return wrapToDiffBlock( - [ - `@@ Code coverage @@`, - `${stats}`, - `# Calculated according to the filters of your coverage tool` - ].join("\n") - ); + const coverageBlock = [ + `@@ Code coverage @@`, + `${stats}`, + `# Calculated according to the filters of your coverage tool` + ].join("\n"); + return useDiffBlock ? wrapToDiffBlock(coverageBlock) : coverageBlock; } function getLicenseInfo(resultsDir) { let licensesInfo = ""; @@ -137558,7 +137557,7 @@ so that the action will upload the files as the job artifacts: try { const problems = (0, annotations_1.parseSarif)(`${resultsDir}/${qodana_12.QODANA_SARIF_NAME}`); const reportUrl = (0, output_12.getReportURL)(resultsDir); - const coverageInfo = (0, output_12.getCoverageStats)((0, qodana_12.getCoverageFromSarif)(`${resultsDir}/${qodana_12.QODANA_SHORT_SARIF_NAME}`)); + const coverageInfo = (0, output_12.getCoverageStats)((0, qodana_12.getCoverageFromSarif)(`${resultsDir}/${qodana_12.QODANA_SHORT_SARIF_NAME}`), true); const licensesInfo = (0, output_12.getLicenseInfo)(resultsDir); const problemsDescriptions = annotationsToProblemDescriptors(problems.annotations); const toolName = (_a = problems.title.split("found by ")[1]) !== null && _a !== void 0 ? _a : output_12.QODANA_CHECK_NAME; diff --git a/scan/src/output.ts b/scan/src/output.ts index 9f324bd9..fc53820f 100644 --- a/scan/src/output.ts +++ b/scan/src/output.ts @@ -93,7 +93,8 @@ export async function publishOutput( const problems = parseSarif(`${resultsDir}/${QODANA_SARIF_NAME}`) const reportUrl = getReportURL(resultsDir) const coverageInfo = getCoverageStats( - getCoverageFromSarif(`${resultsDir}/${QODANA_SHORT_SARIF_NAME}`) + getCoverageFromSarif(`${resultsDir}/${QODANA_SHORT_SARIF_NAME}`), + true ) const licensesInfo: LicenseInfo = getLicenseInfo(resultsDir) diff --git a/vsts/QodanaScan/index.js b/vsts/QodanaScan/index.js index 0a5d5a22..ded668ca 100644 --- a/vsts/QodanaScan/index.js +++ b/vsts/QodanaScan/index.js @@ -16877,36 +16877,35 @@ function wrapToDiffBlock(message) { ${message} \`\`\``; } -function makeConclusion(conclusion, failedByThreshold) { - if (failedByThreshold) { - return `- ${conclusion}`; +function makeConclusion(conclusion, failedByThreshold, useDiffBlock) { + if (useDiffBlock) { + return failedByThreshold ? `- ${conclusion}` : `+ ${conclusion}`; } else { - return `+ ${conclusion}`; + return failedByThreshold ? `${conclusion}` : `${conclusion}`; } } -function getCoverageStats(c) { +function getCoverageStats(c, useDiffBlock) { if (c.totalLines === 0 && c.totalCoveredLines === 0) { return ""; } let stats = ""; if (c.totalLines !== 0) { const conclusion = `${c.totalCoverage}% total lines covered`; - stats += `${makeConclusion(conclusion, c.totalCoverage < c.totalCoverageThreshold)} + stats += `${makeConclusion(conclusion, c.totalCoverage < c.totalCoverageThreshold, useDiffBlock)} ${c.totalLines} lines analyzed, ${c.totalCoveredLines} lines covered`; } if (c.freshLines !== 0) { const conclusion = `${c.freshCoverage}% fresh lines covered`; stats += ` -${makeConclusion(conclusion, c.freshCoverage < c.freshCoverageThreshold)} +${makeConclusion(conclusion, c.freshCoverage < c.freshCoverageThreshold, useDiffBlock)} ${c.freshLines} lines analyzed, ${c.freshCoveredLines} lines covered`; } - return wrapToDiffBlock( - [ - `@@ Code coverage @@`, - `${stats}`, - `# Calculated according to the filters of your coverage tool` - ].join("\n") - ); + const coverageBlock = [ + `@@ Code coverage @@`, + `${stats}`, + `# Calculated according to the filters of your coverage tool` + ].join("\n"); + return useDiffBlock ? wrapToDiffBlock(coverageBlock) : coverageBlock; } function getLicenseInfo(resultsDir) { let licensesInfo = ""; @@ -79048,7 +79047,7 @@ so that the action will upload the files as the job artifacts: try { const problems = (0, utils_12.parseSarif)(`${resultsDir}/${qodana_12.QODANA_SARIF_NAME}`); const reportUrl = (0, output_12.getReportURL)(resultsDir); - const coverageInfo = (0, output_12.getCoverageStats)((0, qodana_12.getCoverageFromSarif)(`${resultsDir}/${qodana_12.QODANA_SHORT_SARIF_NAME}`)); + const coverageInfo = (0, output_12.getCoverageStats)((0, qodana_12.getCoverageFromSarif)(`${resultsDir}/${qodana_12.QODANA_SHORT_SARIF_NAME}`), false); const licensesInfo = (0, output_12.getLicenseInfo)(resultsDir); const problemsDescriptions = (_a = problems.problemDescriptions) !== null && _a !== void 0 ? _a : []; const toolName = (_b = problems.title.split("found by ")[1]) !== null && _b !== void 0 ? _b : output_12.QODANA_CHECK_NAME; @@ -79185,10 +79184,10 @@ var require_utils4 = __commonJS({ uploadSarif: tl2.getBoolInput("uploadSarif", false), artifactName: tl2.getInput("artifactName", false) || "qodana-report", useNightly: tl2.getBoolInput("useNightly", false), - prMode: tl2.getBoolInput("prMode", true), + prMode: tl2.getBoolInput("prMode", false), postComment: tl2.getBoolInput("postPrComment", false), pushFixes: tl2.getInput("pushFixes", false) || "none", - commitMessage: tl2.getInput("commitMessage", false) || "\u{1F916} Apply quick-fixes by Qodana", + commitMessage: tl2.getInput("commitMessage", false) || "\u{1F916} Apply quick-fixes by Qodana \n\n[skip ci]", // Not used by the Azure task additionalCacheKey: "", primaryCacheKey: "", @@ -79466,11 +79465,9 @@ ${comment_tag_pattern}`; return; } if (mode === qodana_12.BRANCH) { - if (pullRequest) { - const commitToCherryPick = (yield gitOutput(["rev-parse", "HEAD"])).stdout.trim(); - yield git(["checkout", currentBranch]); - yield git(["cherry-pick", commitToCherryPick]); - } + const commitToCherryPick = (yield gitOutput(["rev-parse", "HEAD"])).stdout.trim(); + yield git(["checkout", currentBranch]); + yield git(["cherry-pick", commitToCherryPick]); yield gitPush(currentBranch); } else if (mode === qodana_12.PULL_REQUEST) { const newBranch = `qodana/quick-fixes-${currentCommit.slice(0, 7)}`; @@ -79488,9 +79485,7 @@ ${comment_tag_pattern}`; const output = yield gitOutput(["push", "origin", branch], { ignoreReturnCode: true }); - if (output.exitCode == 1) { - tl2.warning(`Branch ${branch} already exists. Push of quick-fixes was skipped.`); - } else if (output.exitCode !== 0) { + if (output.exitCode !== 0) { tl2.warning(`Failed to push branch ${branch}: ${output.stderr}`); } }); diff --git a/vsts/QodanaScan/task.json b/vsts/QodanaScan/task.json index 0536863c..f88c9265 100644 --- a/vsts/QodanaScan/task.json +++ b/vsts/QodanaScan/task.json @@ -74,9 +74,33 @@ "name": "prMode", "type": "boolean", "label": "PR Mode", - "defaultValue": false, + "defaultValue": true, "required": false, "helpMarkDown": "Whether the PR analysis gets executed in the pull request mode." + }, + { + "name": "postPrComment", + "type": "boolean", + "label": "Post PR comment", + "defaultValue": true, + "required": false, + "helpMarkDown": "Post a comment with the Qodana results summary to the pull request." + }, + { + "name": "pushFixes", + "type": "string", + "label": "Push quick-fixes", + "defaultValue": "none", + "required": false, + "helpMarkDown": "Push Qodana fixes to the repository, can be `none`, `branch` to the current branch, or `pull-request`." + }, + { + "name": "commitMessage", + "type": "string", + "label": "Commit Message", + "defaultValue": "\uD83E\uDD16 Apply quick-fixes by Qodana\n\n[skip ci]", + "required": false, + "helpMarkDown": "Message used when quick-fixes are pushed" } ], "execution": { diff --git a/vsts/README.md b/vsts/README.md index 219a3101..2c5ceefa 100644 --- a/vsts/README.md +++ b/vsts/README.md @@ -68,7 +68,7 @@ to - or `branch`: push fixes to the original branch 3. Set the correct permissions for the job. Go to `Repositories` → `Manage repositories` → `Security`. Choose `Qodana for Azure Pipelines Build Service` user. Allow: - `Contribute` - - `Bypass policies when pushing`. Without this, the analysis will be performed twice + - `Bypass policies when pushing` if they may fail the push of quick-fixes - `Create branch` if you use `pull-request` value Also, set `persistCredentials` property to `true`. This is needed for pushing changes to the repository diff --git a/vsts/src/output.ts b/vsts/src/output.ts index 4e9df655..5fd51755 100644 --- a/vsts/src/output.ts +++ b/vsts/src/output.ts @@ -69,7 +69,8 @@ export async function publishOutput( const problems = parseSarif(`${resultsDir}/${QODANA_SARIF_NAME}`) const reportUrl = getReportURL(resultsDir) const coverageInfo = getCoverageStats( - getCoverageFromSarif(`${resultsDir}/${QODANA_SHORT_SARIF_NAME}`) + getCoverageFromSarif(`${resultsDir}/${QODANA_SHORT_SARIF_NAME}`), + false ) const licensesInfo = getLicenseInfo(resultsDir) diff --git a/vsts/src/utils.ts b/vsts/src/utils.ts index 6198db4a..72b3edbd 100644 --- a/vsts/src/utils.ts +++ b/vsts/src/utils.ts @@ -73,11 +73,12 @@ export function getInputs(): Inputs { uploadSarif: tl.getBoolInput('uploadSarif', false), artifactName: tl.getInput('artifactName', false) || 'qodana-report', useNightly: tl.getBoolInput('useNightly', false), - prMode: tl.getBoolInput('prMode', true), + prMode: tl.getBoolInput('prMode', false), postComment: tl.getBoolInput('postPrComment', false), pushFixes: tl.getInput('pushFixes', false) || 'none', commitMessage: - tl.getInput('commitMessage', false) || '🤖 Apply quick-fixes by Qodana', + tl.getInput('commitMessage', false) || + '🤖 Apply quick-fixes by Qodana \n\n[skip ci]', // Not used by the Azure task additionalCacheKey: '', primaryCacheKey: '', @@ -487,13 +488,11 @@ export async function pushQuickFixes( return } if (mode === BRANCH) { - if (pullRequest) { - const commitToCherryPick = ( - await gitOutput(['rev-parse', 'HEAD']) - ).stdout.trim() - await git(['checkout', currentBranch]) - await git(['cherry-pick', commitToCherryPick]) - } + const commitToCherryPick = ( + await gitOutput(['rev-parse', 'HEAD']) + ).stdout.trim() + await git(['checkout', currentBranch]) + await git(['cherry-pick', commitToCherryPick]) await gitPush(currentBranch) } else if (mode === PULL_REQUEST) { const newBranch = `qodana/quick-fixes-${currentCommit.slice(0, 7)}` @@ -510,11 +509,7 @@ async function gitPush(branch: string): Promise { const output = await gitOutput(['push', 'origin', branch], { ignoreReturnCode: true }) - if (output.exitCode == 1) { - tl.warning( - `Branch ${branch} already exists. Push of quick-fixes was skipped.` - ) - } else if (output.exitCode !== 0) { + if (output.exitCode !== 0) { tl.warning(`Failed to push branch ${branch}: ${output.stderr}`) } } diff --git a/vsts/vss-extension.dev.json b/vsts/vss-extension.dev.json index c2fda4e0..4fdd55b7 100644 --- a/vsts/vss-extension.dev.json +++ b/vsts/vss-extension.dev.json @@ -2,7 +2,7 @@ "manifestVersion": 1, "id": "qodana-dev", "name": "Qodana (Dev)", - "version": "2024.3.195", + "version": "2024.3.198", "publisher": "JetBrains", "targets": [ {