dependency-cruiser 13.0.5 → 13.1.0-beta-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/main/resolve-options/normalize.mjs +2 -3
- package/src/meta.js +1 -1
- package/src/report/azure-devops.mjs +222 -0
- package/src/report/index.mjs +25 -26
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import has from "lodash/has.js";
|
|
3
|
-
import omit from "lodash/omit.js";
|
|
4
2
|
import enhancedResolve from "enhanced-resolve";
|
|
3
|
+
import omit from "lodash/omit.js";
|
|
5
4
|
import { scannableExtensions } from "../../extract/transpile/meta.mjs";
|
|
6
5
|
import {
|
|
7
|
-
ruleSetHasLicenseRule,
|
|
8
6
|
ruleSetHasDeprecationRule,
|
|
7
|
+
ruleSetHasLicenseRule,
|
|
9
8
|
} from "../../graph-utl/rule-set.mjs";
|
|
10
9
|
|
|
11
10
|
const DEFAULT_CACHE_DURATION = 4000;
|
package/src/meta.js
CHANGED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { EOL } from "node:os";
|
|
2
|
+
import {
|
|
3
|
+
formatPercentage,
|
|
4
|
+
formatViolation as _formatViolation,
|
|
5
|
+
} from "./utl/index.mjs";
|
|
6
|
+
|
|
7
|
+
const SEVERITY2VSO_TYPE = new Map([
|
|
8
|
+
// "error" | "warn" | "info" | "ignore
|
|
9
|
+
["error", "error"],
|
|
10
|
+
["warn", "warning"],
|
|
11
|
+
// azure devops doesn't seem to understand 'info'. We still want to
|
|
12
|
+
// show them, though, hence:
|
|
13
|
+
["info", "warning"],
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {import("../../types/shared-types.js").SeverityType} pSeverity
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
function formatSeverity(pSeverity) {
|
|
21
|
+
return SEVERITY2VSO_TYPE.get(pSeverity) ?? "warning";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {import("../../types/violations.js").IViolation} pViolation
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
28
|
+
function formatModuleViolation(pViolation) {
|
|
29
|
+
return `${pViolation.rule.name}: ${pViolation.from}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param {import("../../types/violations.js").IViolation} pViolation
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
37
|
+
function formatDependencyViolation(pViolation) {
|
|
38
|
+
return `${pViolation.rule.name}: ${pViolation.from} -> ${pViolation.to}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {import("../../types/violations.js").IViolation} pViolation
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function formatCycleViolation(pViolation) {
|
|
46
|
+
return `${pViolation.rule.name}: ${
|
|
47
|
+
pViolation.from
|
|
48
|
+
} -> ${pViolation.cycle.join(" -> ")}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {import("../../types/violations.js").IViolation} pViolation
|
|
53
|
+
* @returns {string}
|
|
54
|
+
*/
|
|
55
|
+
function formatReachabilityViolation(pViolation) {
|
|
56
|
+
return `${pViolation.rule.name}: ${pViolation.from} -> ${
|
|
57
|
+
pViolation.to
|
|
58
|
+
} (via ${pViolation.via.join(" -> ")})`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {import("../../types/violations.js").IViolation} pViolation
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
function formatInstabilityViolation(pViolation) {
|
|
66
|
+
return `${pViolation.rule.name}: ${pViolation.from} -> ${
|
|
67
|
+
pViolation.to
|
|
68
|
+
} (instability: ${formatPercentage(
|
|
69
|
+
pViolation.metrics.from.instability
|
|
70
|
+
)} -> ${formatPercentage(pViolation.metrics.to.instability)})`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {import("../../types/violations.js").IViolation} pViolation
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function formatViolation(pViolation) {
|
|
78
|
+
const lViolationType2Formatter = {
|
|
79
|
+
module: formatModuleViolation,
|
|
80
|
+
dependency: formatDependencyViolation,
|
|
81
|
+
cycle: formatCycleViolation,
|
|
82
|
+
reachability: formatReachabilityViolation,
|
|
83
|
+
instability: formatInstabilityViolation,
|
|
84
|
+
};
|
|
85
|
+
let lFormattedViolators = _formatViolation(
|
|
86
|
+
pViolation,
|
|
87
|
+
lViolationType2Formatter,
|
|
88
|
+
formatDependencyViolation
|
|
89
|
+
);
|
|
90
|
+
return `##vso[task.logissue type=${formatSeverity(
|
|
91
|
+
pViolation.rule.severity
|
|
92
|
+
)};sourcepath=${pViolation.from}]${lFormattedViolators}${EOL}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
*
|
|
97
|
+
* @param {number} pNumberOfErrors
|
|
98
|
+
* @param {number} pNumberOfWarns
|
|
99
|
+
* @param {number} pNumberOfInfos
|
|
100
|
+
*
|
|
101
|
+
* @returns
|
|
102
|
+
*/
|
|
103
|
+
function formatResultStatus(
|
|
104
|
+
pNumberOfErrors,
|
|
105
|
+
pNumberOfWarns,
|
|
106
|
+
pNumberOfInfos,
|
|
107
|
+
pNumberOfIgnored
|
|
108
|
+
) {
|
|
109
|
+
if (pNumberOfErrors > 0) {
|
|
110
|
+
return "Failed";
|
|
111
|
+
}
|
|
112
|
+
if (pNumberOfWarns + pNumberOfInfos + pNumberOfIgnored > 0) {
|
|
113
|
+
return "SucceededWithIssues";
|
|
114
|
+
}
|
|
115
|
+
return "Succeeded";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function formatMeta(pMeta) {
|
|
119
|
+
const lWarningCount = pMeta.warn + pMeta.info;
|
|
120
|
+
const lError = `${pMeta.error} error`;
|
|
121
|
+
const lWarn = `${lWarningCount} warning/ informational`;
|
|
122
|
+
const lIgnore = (pMeta?.ignore ?? 0) > 0 ? `, ${pMeta.ignore} ignored` : "";
|
|
123
|
+
|
|
124
|
+
return `${lError}, ${lWarn}${lIgnore}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function sumMeta(pMeta) {
|
|
128
|
+
return pMeta.error + pMeta.warn + pMeta.info;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
*
|
|
133
|
+
* @param {number} pNumberOfIgnored
|
|
134
|
+
* @returns {string}
|
|
135
|
+
*/
|
|
136
|
+
function formatIgnoreWarning(pNumberOfIgnored) {
|
|
137
|
+
return (pNumberOfIgnored ?? 0) > 0
|
|
138
|
+
? ` - ${pNumberOfIgnored} violations ignored `
|
|
139
|
+
: "";
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
*
|
|
144
|
+
* @param {import("../../types/cruise-result.js").ISummary} pSummary
|
|
145
|
+
*/
|
|
146
|
+
function formatResultMessage(pSummary) {
|
|
147
|
+
let lStatSummary = `${pSummary.totalCruised} modules, ${
|
|
148
|
+
pSummary?.totalDependenciesCruised ?? 0
|
|
149
|
+
} dependencies cruised`;
|
|
150
|
+
|
|
151
|
+
if (sumMeta(pSummary) > 0) {
|
|
152
|
+
return `${sumMeta(pSummary)} dependency violations (${formatMeta(
|
|
153
|
+
pSummary
|
|
154
|
+
)}). ${lStatSummary}`;
|
|
155
|
+
} else {
|
|
156
|
+
return `no dependency violations found${formatIgnoreWarning(
|
|
157
|
+
pSummary.ignore
|
|
158
|
+
)} (${lStatSummary})`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
*
|
|
164
|
+
* @param {import("../../types/cruise-result.js").ISummary} pSummary
|
|
165
|
+
*/
|
|
166
|
+
function formatSummary(pSummary) {
|
|
167
|
+
return `##vso[task.complete result=${formatResultStatus(
|
|
168
|
+
pSummary.error,
|
|
169
|
+
pSummary.warn,
|
|
170
|
+
pSummary.info,
|
|
171
|
+
pSummary?.ignore ?? 0
|
|
172
|
+
)};]${formatResultMessage(pSummary)}${EOL}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Returns a bunch of Azure DevOps log messages:
|
|
177
|
+
* - for each violation in the passed results: the severity, source found, violated rule & some additional info
|
|
178
|
+
* - a summary line
|
|
179
|
+
*
|
|
180
|
+
* Background documentation:
|
|
181
|
+
* https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#task-commands
|
|
182
|
+
*
|
|
183
|
+
* @param {import("../../types/dependency-cruiser.js").ICruiseResult} pResults
|
|
184
|
+
* @returns {import("../../types/dependency-cruiser.js").IReporterOutput}
|
|
185
|
+
*/
|
|
186
|
+
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
187
|
+
export default function azureDevOps(pResults) {
|
|
188
|
+
const lViolations = (pResults?.summary?.violations ?? []).filter(
|
|
189
|
+
(pViolation) => pViolation.rule.severity !== "ignore"
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
output: lViolations
|
|
194
|
+
.map(formatViolation)
|
|
195
|
+
.join("")
|
|
196
|
+
.concat(formatSummary(pResults.summary)),
|
|
197
|
+
exitCode: pResults.summary.error,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/*
|
|
202
|
+
Some notes from the documentation over at https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#task-commands
|
|
203
|
+
|
|
204
|
+
Warnings and errors:
|
|
205
|
+
|
|
206
|
+
##vso[task.logissue type=warning;sourcepath=consoleapp/main.cs;linenumber=1;columnnumber=1;code=100;]Found something that could be a problem.
|
|
207
|
+
|
|
208
|
+
Progress
|
|
209
|
+
##vso[task.setprogress]current operation
|
|
210
|
+
|
|
211
|
+
Complete
|
|
212
|
+
##vso[task.complete]current operation
|
|
213
|
+
|
|
214
|
+
Message grouping
|
|
215
|
+
##[group]Beginning of a group
|
|
216
|
+
##[warning]Warning message
|
|
217
|
+
##[error]Error message
|
|
218
|
+
##[section]Start of a section
|
|
219
|
+
##[debug]Debug text
|
|
220
|
+
##[command]Command-line being run
|
|
221
|
+
##[endgroup]
|
|
222
|
+
*/
|
package/src/report/index.mjs
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import { getExternalPluginReporter } from "./plugins.mjs";
|
|
2
2
|
|
|
3
|
-
const TYPE2MODULE =
|
|
4
|
-
anon
|
|
5
|
-
csv
|
|
6
|
-
dot
|
|
7
|
-
ddot
|
|
8
|
-
cdot
|
|
9
|
-
archi
|
|
10
|
-
fdot
|
|
11
|
-
flat
|
|
12
|
-
"err-html"
|
|
13
|
-
markdown
|
|
14
|
-
"err-long"
|
|
15
|
-
err
|
|
16
|
-
html
|
|
17
|
-
json
|
|
18
|
-
teamcity
|
|
19
|
-
text
|
|
20
|
-
baseline
|
|
21
|
-
metrics
|
|
22
|
-
mermaid
|
|
23
|
-
null
|
|
24
|
-
|
|
3
|
+
const TYPE2MODULE = new Map([
|
|
4
|
+
["anon", "./anon/index.mjs"],
|
|
5
|
+
["csv", "./csv.mjs"],
|
|
6
|
+
["dot", "./dot/dot-module.mjs"],
|
|
7
|
+
["ddot", "./dot/dot-folder.mjs"],
|
|
8
|
+
["cdot", "./dot/dot-custom.mjs"],
|
|
9
|
+
["archi", "./dot/dot-custom.mjs"],
|
|
10
|
+
["fdot", "./dot/dot-flat.mjs"],
|
|
11
|
+
["flat", "./dot/dot-flat.mjs"],
|
|
12
|
+
["err-html", "./error-html/index.mjs"],
|
|
13
|
+
["markdown", "./markdown.mjs"],
|
|
14
|
+
["err-long", "./error-long.mjs"],
|
|
15
|
+
["err", "./error.mjs"],
|
|
16
|
+
["html", "./html/index.mjs"],
|
|
17
|
+
["json", "./json.mjs"],
|
|
18
|
+
["teamcity", "./teamcity.mjs"],
|
|
19
|
+
["text", "./text.mjs"],
|
|
20
|
+
["baseline", "./baseline.mjs"],
|
|
21
|
+
["metrics", "./metrics.mjs"],
|
|
22
|
+
["mermaid", "./mermaid.mjs"],
|
|
23
|
+
["null", "./null.mjs"],
|
|
24
|
+
["azure-devops", "./azure-devops.mjs"],
|
|
25
|
+
]);
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Returns the reporter function associated with given output type,
|
|
@@ -37,9 +38,7 @@ async function getReporter(pOutputType) {
|
|
|
37
38
|
if (pOutputType?.startsWith("plugin:")) {
|
|
38
39
|
lReturnValue = await getExternalPluginReporter(pOutputType);
|
|
39
40
|
} else {
|
|
40
|
-
const lModuleToImport =
|
|
41
|
-
// eslint-disable-next-line security/detect-object-injection
|
|
42
|
-
TYPE2MODULE[pOutputType] || "./identity.mjs";
|
|
41
|
+
const lModuleToImport = TYPE2MODULE.get(pOutputType) ?? "./identity.mjs";
|
|
43
42
|
const lModule = await import(lModuleToImport);
|
|
44
43
|
lReturnValue = lModule.default;
|
|
45
44
|
}
|
|
@@ -52,7 +51,7 @@ async function getReporter(pOutputType) {
|
|
|
52
51
|
* @returns {import("../../types/shared-types.js").OutputType[]} -
|
|
53
52
|
*/
|
|
54
53
|
function getAvailableReporters() {
|
|
55
|
-
return
|
|
54
|
+
return Array.from(TYPE2MODULE.keys());
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
export default {
|