danger-plugin-lint-report
Advanced tools
Comparing version 1.5.6 to 1.6.0
@@ -20,2 +20,6 @@ interface CheckstyleConfig { | ||
outputPrefix?: string; | ||
/** | ||
* Optional: Override the violation formatter to customize the output message. | ||
*/ | ||
violationFormatter?: ViolationFormatter; | ||
} |
@@ -11,3 +11,3 @@ export declare const maxParallel = 10; | ||
export declare function scan(config: CheckstyleConfig): Promise<void>; | ||
export declare function scanXmlReport(git: any, xmlReport: any, root: any, requireLineModification: any, messageCallback: (msg: any, file: any, line: any, severity: any) => void): Promise<void>; | ||
export declare function scanXmlReport(git: any, xmlReport: any, root: any, requireLineModification: any, violationCallback: (violation: Violation) => void): Promise<void>; | ||
export {}; |
@@ -25,13 +25,16 @@ "use strict"; | ||
const files = yield new Promise((resolve, reject) => glob(config.fileMask, (err, result) => (err ? reject(err) : resolve(result)))); | ||
const violationFormatter = config.violationFormatter || defaultViolationFormatter; | ||
for (const batch of Array.from({ length: Math.ceil(files.length / exports.maxParallel) }, (_, batchIdx) => files.slice(batchIdx * exports.maxParallel, (batchIdx + 1) * exports.maxParallel))) { | ||
yield Promise.all(batch.map((fileName) => __awaiter(this, void 0, void 0, function* () { | ||
const xmlReport = fs_1.readFileSync(fileName); | ||
yield scanXmlReport(git, xmlReport, root, config.requireLineModification, (msg, file, line, severity) => { | ||
yield scanXmlReport(git, xmlReport, root, config.requireLineModification, (violation) => { | ||
var severity = violation.severity; | ||
if (!config.reportSeverity) { | ||
severity = "info"; | ||
} | ||
var msg = violationFormatter.format(violation); | ||
if (config.outputPrefix) { | ||
msg = config.outputPrefix + msg; | ||
} | ||
sendViolationBySeverity(msg, file, line, severity); | ||
sendViolationBySeverity(msg, violation.file, violation.line, violation.severity); | ||
}); | ||
@@ -43,7 +46,7 @@ }))); | ||
exports.scan = scan; | ||
function scanXmlReport(git, xmlReport, root, requireLineModification, messageCallback) { | ||
function scanXmlReport(git, xmlReport, root, requireLineModification, violationCallback) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const xmlConverter = require("xml-js"); | ||
const report = xmlConverter.xml2js(xmlReport); | ||
yield checkstyle_1.scanReport(git, report, root, requireLineModification, messageCallback); | ||
yield checkstyle_1.scanReport(git, report, root, requireLineModification, violationCallback); | ||
}); | ||
@@ -70,1 +73,6 @@ } | ||
} | ||
let defaultViolationFormatter = { | ||
format: (violation) => { | ||
return violation.message; | ||
} | ||
}; |
@@ -14,2 +14,24 @@ "use strict"; | ||
const root = "/root/"; | ||
const expectedAndroidLintViolation1 = { | ||
issueId: "HardcodedText", | ||
category: "Internationalization", | ||
explanation: "Hardcoding text attributes directly in layout files is bad.", | ||
summary: "Hardcoded text", | ||
file: "feature/src/main/res/layout/fragment_password_reset.xml", | ||
line: 13, | ||
column: 9, | ||
severity: "Warning", | ||
message: "Hardcoded string Email Address, should use `@string` resource", | ||
}; | ||
const expectedAndroidLintViolation2 = { | ||
issueId: "HardcodedNumber", | ||
category: "Maintenance", | ||
explanation: "Hardcoding numbers directly in layout files is bad.", | ||
summary: "Hardcoded numbers", | ||
file: "feature/src/main/res/layout/fragment_password_reset_2.xml", | ||
line: 14, | ||
column: 10, | ||
severity: "Warning", | ||
message: "Hardcoded number 123.", | ||
}; | ||
const xmlReport = ` | ||
@@ -20,31 +42,31 @@ <?xml version="1.0" encoding="UTF-8"?> | ||
<issue | ||
id="HardcodedText" | ||
severity="Warning" | ||
message="Hardcoded string "Password", should use \`@string\` resource" | ||
category="Internationalization" | ||
id="${expectedAndroidLintViolation1.issueId}" | ||
severity="${expectedAndroidLintViolation1.severity}" | ||
message="${expectedAndroidLintViolation1.message}" | ||
category="${expectedAndroidLintViolation1.category}" | ||
priority="5" | ||
summary="Hardcoded text" | ||
explanation="Hardcoding text attributes directly in layout files is bad for several reasons:

* When creating configuration variations (for example for landscape or portrait) you have to repeat the actual text (and keep it up to date when making changes)

* The application cannot be translated to other languages by just adding new translations for existing string resources.

There are quickfixes to automatically extract this hardcoded string into a resource lookup." | ||
summary="${expectedAndroidLintViolation1.summary}" | ||
explanation="${expectedAndroidLintViolation1.explanation}" | ||
errorLine1=" android:hint="Password"" | ||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~"> | ||
<location | ||
file="/root/feature/src/main/res/layout/fragment_password_reset_2.xml" | ||
line="25" | ||
column="9"/> | ||
file="${expectedAndroidLintViolation1.file}" | ||
line="${expectedAndroidLintViolation1.line}" | ||
column="${expectedAndroidLintViolation1.column}"/> | ||
</issue> | ||
<issue | ||
id="HardcodedText" | ||
severity="Warning" | ||
message="Hardcoded string "Email Address", should use \`@string\` resource" | ||
category="Internationalization" | ||
id="${expectedAndroidLintViolation2.issueId}" | ||
severity="${expectedAndroidLintViolation2.severity}" | ||
message="${expectedAndroidLintViolation2.message}" | ||
category="${expectedAndroidLintViolation2.category}" | ||
priority="5" | ||
summary="Hardcoded text" | ||
explanation="Hardcoding text attributes directly in layout files is bad for several reasons:

* When creating configuration variations (for example for landscape or portrait) you have to repeat the actual text (and keep it up to date when making changes)

* The application cannot be translated to other languages by just adding new translations for existing string resources.

There are quickfixes to automatically extract this hardcoded string into a resource lookup." | ||
summary="${expectedAndroidLintViolation2.summary}" | ||
explanation="${expectedAndroidLintViolation2.explanation}" | ||
errorLine1=" android:hint="Email Address"" | ||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> | ||
<location | ||
file="/root/feature/src/main/res/layout/fragment_password_reset.xml" | ||
line="13" | ||
column="9"/> | ||
file="${expectedAndroidLintViolation2.file}" | ||
line="${expectedAndroidLintViolation2.line}" | ||
column="${expectedAndroidLintViolation2.column}"/> | ||
</issue> | ||
@@ -68,15 +90,15 @@ | ||
<issue | ||
id="HardcodedText" | ||
severity="Warning" | ||
message="Hardcoded string "Email Address", should use \`@string\` resource" | ||
category="Internationalization" | ||
id="${expectedAndroidLintViolation1.issueId}" | ||
severity="${expectedAndroidLintViolation1.severity}" | ||
message="${expectedAndroidLintViolation1.message}" | ||
category="${expectedAndroidLintViolation1.category}" | ||
priority="5" | ||
summary="Hardcoded text" | ||
explanation="Hardcoding text attributes directly in layout files is bad for several reasons:

* When creating configuration variations (for example for landscape or portrait) you have to repeat the actual text (and keep it up to date when making changes)

* The application cannot be translated to other languages by just adding new translations for existing string resources.

There are quickfixes to automatically extract this hardcoded string into a resource lookup." | ||
summary="${expectedAndroidLintViolation1.summary}" | ||
explanation="${expectedAndroidLintViolation1.explanation}" | ||
errorLine1=" android:hint="Email Address"" | ||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> | ||
<location | ||
file="feature/src/main/res/layout/fragment_password_reset.xml" | ||
line="13" | ||
column="9"/> | ||
file="${expectedAndroidLintViolation1.file}" | ||
line="${expectedAndroidLintViolation1.line}" | ||
column="${expectedAndroidLintViolation1.column}"/> | ||
</issue> | ||
@@ -94,3 +116,3 @@ | ||
const git = { | ||
modified_files: ["feature/src/main/res/layout/fragment_password_reset.xml"], | ||
modified_files: [expectedAndroidLintViolation1.file], | ||
created_files: [], | ||
@@ -101,3 +123,3 @@ structuredDiffForFile: () => __awaiter(void 0, void 0, void 0, function* () { return new Promise((res) => setTimeout(() => res({ chunks: [{ changes: [{ type: "add", ln: 13 }] }] }), 100)); }), | ||
global.warn = jest.fn(); | ||
mockGlob.mockImplementation(() => ["feature/src/main/res/layout/fragment_password_reset.xml"]); | ||
mockGlob.mockImplementation(() => [expectedAndroidLintViolation1.file]); | ||
yield _1.scan({ | ||
@@ -110,2 +132,26 @@ fileMask: "", | ||
})); | ||
it("uses ViolationFormatter to map Violation to string", () => __awaiter(void 0, void 0, void 0, function* () { | ||
let formatFn = jest.fn(violation => { | ||
return violation.message; | ||
}); | ||
let violationFormatter = { | ||
format: formatFn, | ||
}; | ||
const git = { | ||
modified_files: [expectedAndroidLintViolation1.file], | ||
created_files: [], | ||
structuredDiffForFile: () => __awaiter(void 0, void 0, void 0, function* () { return new Promise((res) => setTimeout(() => res({ chunks: [{ changes: [{ type: "add", ln: expectedAndroidLintViolation1.line }] }] }), 100)); }), | ||
}; | ||
global.danger = { git }; | ||
global.warn = jest.fn(); | ||
mockGlob.mockImplementation(() => [expectedAndroidLintViolation1.file]); | ||
yield _1.scan({ | ||
fileMask: "", | ||
reportSeverity: true, | ||
requireLineModification: true, | ||
violationFormatter: violationFormatter, | ||
}); | ||
expect(formatFn).toBeCalledWith(expectedAndroidLintViolation1); | ||
expect(global.warn).toBeCalledWith(formatFn(expectedAndroidLintViolation1), expectedAndroidLintViolation1.file, expectedAndroidLintViolation1.line); | ||
})); | ||
it(`scans maximum ${_1.maxParallel} files in parallel to prevent OoM exceptions`, () => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -161,40 +207,33 @@ const git = { | ||
modified_files: [ | ||
"feature/src/main/res/layout/fragment_password_reset.xml", | ||
"feature/src/main/res/layout/fragment_password_reset_2.xml", | ||
expectedAndroidLintViolation1.file, | ||
expectedAndroidLintViolation2.file, | ||
], | ||
created_files: [], | ||
}; | ||
const messageCallback = jest.fn(); | ||
yield _1.scanXmlReport(git, xmlReport, root, false, messageCallback); | ||
expect(messageCallback).toHaveBeenCalledTimes(2); | ||
const violationCallback = jest.fn(); | ||
yield _1.scanXmlReport(git, xmlReport, root, false, violationCallback); | ||
expect(violationCallback).toHaveBeenCalledTimes(2); | ||
})); | ||
it("returns correct violation data and file path with line modification turned off", () => __awaiter(void 0, void 0, void 0, function* () { | ||
const git = { | ||
modified_files: ["feature/src/main/res/layout/fragment_password_reset.xml"], | ||
modified_files: [expectedAndroidLintViolation1.file], | ||
created_files: [], | ||
}; | ||
const messageCallback = jest.fn(); | ||
yield _1.scanXmlReport(git, xmlReport, root, false, messageCallback); | ||
const msg = "Hardcoded text"; | ||
const file = "feature/src/main/res/layout/fragment_password_reset.xml"; | ||
const line = 13; | ||
const severity = "Warning"; | ||
expect(messageCallback).toBeCalledWith(msg, file, line, severity); | ||
const violationCallback = jest.fn(); | ||
yield _1.scanXmlReport(git, xmlReport, root, false, violationCallback); | ||
expect(violationCallback).toBeCalledWith(expectedAndroidLintViolation1); | ||
expect(violationCallback).toBeCalledWith(expectedAndroidLintViolation2); | ||
})); | ||
it("returns correct file location when root is different", () => __awaiter(void 0, void 0, void 0, function* () { | ||
const git = { | ||
modified_files: ["feature/src/main/res/layout/fragment_password_reset.xml"], | ||
modified_files: [expectedAndroidLintViolation1.file], | ||
created_files: [], | ||
}; | ||
mockFileExistsSync.mockImplementation((path) => [ | ||
"/otherRoot/feature/src/main/res/layout/fragment_password_reset.xml", | ||
"/otherRoot/fragment_password_reset.xml", | ||
"/otherRoot/" + expectedAndroidLintViolation1, | ||
expectedAndroidLintViolation1.file.substring(expectedAndroidLintViolation1.file.indexOf("/", 1)), | ||
].includes(path)); | ||
const messageCallback = jest.fn(); | ||
yield _1.scanXmlReport(git, xmlReport, "/otherRoot/", false, messageCallback); | ||
const msg = "Hardcoded text"; | ||
const file = "feature/src/main/res/layout/fragment_password_reset.xml"; | ||
const line = 13; | ||
const severity = "Warning"; | ||
expect(messageCallback).toBeCalledWith(msg, file, line, severity); | ||
const violationCallback = jest.fn(); | ||
yield _1.scanXmlReport(git, xmlReport, "/otherRoot/", false, violationCallback); | ||
expect(violationCallback).toBeCalledWith(expectedAndroidLintViolation1); | ||
})); | ||
@@ -211,6 +250,14 @@ it("returns correct violation data for checkstyle report with files without messages", () => __awaiter(void 0, void 0, void 0, function* () { | ||
const line = 2; | ||
const column = 21; | ||
const severity = "warning"; | ||
const expectedViolation = { | ||
file: file, | ||
line: line, | ||
column: column, | ||
severity: severity, | ||
message: msg, | ||
}; | ||
expect(messageCallback).toBeCalledTimes(1); | ||
expect(messageCallback).toBeCalledWith(msg, file, line, severity); | ||
expect(messageCallback).toBeCalledWith(expectedViolation); | ||
})); | ||
}); |
@@ -70,6 +70,10 @@ "use strict"; | ||
file: fileName, | ||
line, | ||
column, | ||
severity, | ||
message: summary, | ||
line: line, | ||
column: column, | ||
severity: severity, | ||
summary: summary, | ||
category: category, | ||
message: message, | ||
explanation: explanation, | ||
issueId: issueId, | ||
}); | ||
@@ -121,5 +125,5 @@ } | ||
file: fileName, | ||
line, | ||
column, | ||
severity, | ||
line: line, | ||
column: column, | ||
severity: severity, | ||
message: msg, | ||
@@ -126,0 +130,0 @@ }); |
import { GitDSL } from "danger"; | ||
declare type MarkdownString = string; | ||
/** | ||
@@ -9,3 +8,2 @@ * | ||
*/ | ||
export declare function scanReport(git: GitDSL, report: any, root: string, requireLineModification: boolean, messageCallback: (msg: MarkdownString, fileName: string, line: number, severity: string) => void): Promise<void>; | ||
export {}; | ||
export declare function scanReport(git: GitDSL, report: any, root: string, requireLineModification: boolean, violationCallback: (violation: Violation) => void): Promise<void>; |
@@ -23,3 +23,3 @@ "use strict"; | ||
*/ | ||
function scanReport(git, report, root, requireLineModification, messageCallback) { | ||
function scanReport(git, report, root, requireLineModification, violationCallback) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -47,5 +47,5 @@ const violations = checkstyle_parser_1.parseCheckstyle(report, root); | ||
} | ||
report_1.reportViolationsForLines(violations, fileDiffs, requireLineModification, messageCallback); | ||
report_1.reportViolationsForLines(violations, fileDiffs, requireLineModification, violationCallback); | ||
}); | ||
} | ||
exports.scanReport = scanReport; |
@@ -1,3 +0,1 @@ | ||
declare type MarkdownString = string; | ||
export declare function reportViolationsForLines(violations: Violation[], fileDiffs: FileDiff[], requireLineModification: boolean, messageCallback: (msg: MarkdownString, fileName: string, line: number, severity: string) => void): void; | ||
export {}; | ||
export declare function reportViolationsForLines(violations: Violation[], fileDiffs: FileDiff[], requireLineModification: boolean, violationCallback: (violation: Violation) => void): void; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.reportViolationsForLines = void 0; | ||
function reportViolationsForLines(violations, fileDiffs, requireLineModification, messageCallback) { | ||
function reportViolationsForLines(violations, fileDiffs, requireLineModification, violationCallback) { | ||
// we got all changed lines in fileDiffs (file => list of line) | ||
@@ -12,3 +12,3 @@ violations.forEach(violation => { | ||
if (!requireLineModification || diff.added_lines.includes(line)) { | ||
messageCallback(violation.message, violation.file, violation.line, violation.severity); | ||
violationCallback(violation); | ||
} | ||
@@ -15,0 +15,0 @@ } |
@@ -14,2 +14,6 @@ interface Violation { | ||
message: string; | ||
category?: string; | ||
summary?: string; | ||
explanation?: string; | ||
issueId?: string; | ||
} |
@@ -20,3 +20,3 @@ { | ||
], | ||
"version": "1.5.6", | ||
"version": "1.6.0", | ||
"main": "dist/index.js", | ||
@@ -23,0 +23,0 @@ "types": "dist/index.d.ts", |
@@ -76,2 +76,7 @@ # danger-plugin-lint-report | ||
outputPrefix?: string | ||
/** | ||
* Optional: Override the violation formatter to customize the output message. | ||
*/ | ||
violationFormatter?: ViolationFormatter | ||
} | ||
@@ -78,0 +83,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
137773
35
992
90