11import path from 'node:path' ;
2- import type { RunnerFunction } from '@code-pushup/models' ;
2+ import type {
3+ RunnerFunction ,
4+ TableColumnObject ,
5+ TableRowObject ,
6+ } from '@code-pushup/models' ;
37import {
48 asyncSequential ,
9+ capitalize ,
510 executeProcess ,
11+ formatAsciiTable ,
12+ logger ,
613 objectFromEntries ,
14+ objectToEntries ,
15+ pluralizeToken ,
716} from '@code-pushup/utils' ;
817import {
918 type AuditSeverity ,
1019 type DependencyGroup ,
1120 type FinalJSPackagesPluginConfig ,
21+ type PackageAuditLevel ,
1222 type PackageJsonPath ,
1323 type PackageManagerId ,
1424 dependencyGroups ,
25+ packageAuditLevels ,
1526} from '../config.js' ;
1627import { dependencyGroupToLong } from '../constants.js' ;
1728import { packageManagers } from '../package-managers/package-managers.js' ;
@@ -54,6 +65,8 @@ async function processOutdated(
5465 depGroups : DependencyGroup [ ] ,
5566 packageJsonPath : PackageJsonPath ,
5667) {
68+ logger . info ( 'Looking for outdated packages ...' ) ;
69+
5770 const pm = packageManagers [ id ] ;
5871 const { stdout } = await executeProcess ( {
5972 command : pm . command ,
@@ -62,9 +75,13 @@ async function processOutdated(
6275 ignoreExitCode : true , // outdated returns exit code 1 when outdated dependencies are found
6376 } ) ;
6477
78+ const normalizedResult = pm . outdated . unifyResult ( stdout ) ;
79+ logger . info (
80+ `Detected ${ pluralizeToken ( 'outdated package' , normalizedResult . length ) } in total` ,
81+ ) ;
82+
6583 const depTotals = await getTotalDependencies ( packageJsonPath ) ;
6684
67- const normalizedResult = pm . outdated . unifyResult ( stdout ) ;
6885 return depGroups . map ( depGroup =>
6986 outdatedResultToAuditOutput (
7087 normalizedResult ,
@@ -88,6 +105,10 @@ async function processAudit(
88105 supportedAuditDepGroups . includes ( group ) ,
89106 ) ;
90107
108+ logger . info (
109+ `Auditing packages for ${ pluralizeToken ( 'dependency group' , compatibleAuditDepGroups . length ) } (${ compatibleAuditDepGroups . join ( ', ' ) } ) ...` ,
110+ ) ;
111+
91112 const auditResults = await asyncSequential (
92113 compatibleAuditDepGroups ,
93114 async ( depGroup ) : Promise < [ DependencyGroup , AuditResult ] > => {
@@ -104,6 +125,8 @@ async function processAudit(
104125 const resultsMap = objectFromEntries ( auditResults ) ;
105126 const uniqueResults = pm . audit . postProcessResult ?.( resultsMap ) ?? resultsMap ;
106127
128+ logAuditSummary ( uniqueResults ) ;
129+
107130 return compatibleAuditDepGroups . map ( depGroup =>
108131 auditResultToAuditOutput (
109132 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -114,3 +137,66 @@ async function processAudit(
114137 ) ,
115138 ) ;
116139}
140+
141+ function logAuditSummary (
142+ results : Partial < Record < DependencyGroup , AuditResult > > ,
143+ ) : void {
144+ const { totalCount, countsPerLevel } = aggregateAuditResults ( results ) ;
145+ const formattedLevels = objectToEntries ( countsPerLevel )
146+ . filter ( ( [ , count ] ) => count > 0 )
147+ . map ( ( [ level , count ] ) => `${ count } ${ level } ` )
148+ . join ( ', ' ) ;
149+
150+ logger . info (
151+ [
152+ `Found ${ pluralizeToken ( 'vulnerability' , totalCount ) } in total` ,
153+ formattedLevels && `(${ formattedLevels } )` ,
154+ ]
155+ . filter ( Boolean )
156+ . join ( ' ' ) ,
157+ ) ;
158+
159+ if ( ! logger . isVerbose ( ) ) {
160+ return ;
161+ }
162+ logger . debug (
163+ formatAsciiTable ( {
164+ columns : [
165+ { key : 'depGroup' , label : 'Dep. group' } ,
166+ ...[ ...packageAuditLevels , 'total' ] . map (
167+ ( level ) : TableColumnObject => ( {
168+ key : level ,
169+ label : capitalize ( level ) ,
170+ align : 'right' ,
171+ } ) ,
172+ ) ,
173+ ] ,
174+ rows : objectToEntries ( results ) . map (
175+ ( [ depGroup , result ] ) : TableRowObject => ( {
176+ depGroup,
177+ ...result ?. summary ,
178+ } ) ,
179+ ) ,
180+ } ) ,
181+ ) ;
182+ }
183+
184+ function aggregateAuditResults (
185+ results : Partial < Record < DependencyGroup , AuditResult > > ,
186+ ) {
187+ const totalCount = Object . values ( results ) . reduce (
188+ ( acc , { vulnerabilities } ) => acc + vulnerabilities . length ,
189+ 0 ,
190+ ) ;
191+ const countsPerLevel = Object . values ( results ) . reduce <
192+ Record < PackageAuditLevel , number >
193+ > (
194+ ( acc , { summary } ) =>
195+ objectFromEntries (
196+ packageAuditLevels . map ( level => [ level , acc [ level ] + summary [ level ] ] ) ,
197+ ) ,
198+ objectFromEntries ( packageAuditLevels . map ( level => [ level , 0 ] ) ) ,
199+ ) ;
200+
201+ return { totalCount, countsPerLevel } ;
202+ }
0 commit comments