@@ -4,7 +4,7 @@ import Reporter from './reporter.js'
44 * CSV report generator that extends the base formatter class.
55 * Handles creation and formatting of CSV reports for GitHub Actions data.
66 */
7- export default class Csv extends Reporter {
7+ export default class CsvReporter extends Reporter {
88 /**
99 * Creates a new CSV report instance.
1010 * @param {string } path - The file path where the CSV will be saved
@@ -16,105 +16,113 @@ export default class Csv extends Reporter {
1616 }
1717
1818 /**
19- * Saves data as a CSV file.
19+ * Saves workflow data as a CSV file.
20+ * Includes workflow details and optional columns based on configuration.
2021 * @returns {Promise<void> } A promise that resolves when the file is saved
2122 */
2223 async save ( ) {
23- // Create headers based on configuration
24- const headers = this . #createHeaders( )
25-
26- // Process rows according to the headers to ensure consistent column order
27- const rows = this . data . map ( workflow => {
28- const row = [ ]
29-
30- // Add each column in the order defined by headers
31- for ( const header of headers ) {
32- if ( header === 'runs-on' && workflow . runsOn ) {
33- // Special case for runsOn which has a different property name
34- row . push ( this . #formatValue( workflow . runsOn ) )
35- } else {
36- // For all other columns, use the header name as the property key
37- row . push ( this . #formatValue( workflow [ header ] ) )
24+ try {
25+ // Create headers based on configuration
26+ const headers = this . createHeaders ( )
27+
28+ // Process rows according to the headers to ensure consistent column order
29+ const rows = this . data . map ( workflow => {
30+ const row = [ ]
31+
32+ // Add each column in the order defined by headers
33+ for ( const header of headers ) {
34+ if ( header === 'runs-on' && workflow . runsOn ) {
35+ // Special case for runsOn which has a different property name
36+ row . push ( this . formatValue ( workflow . runsOn ) )
37+ } else {
38+ // For all other columns, use the header name as the property key
39+ row . push ( this . formatValue ( workflow [ header ] ) )
40+ }
3841 }
39- }
4042
41- return row
42- } )
43+ return row
44+ } )
4345
44- // Format each row, properly escaping values
45- const csvRows = rows . map ( row =>
46- row
47- . map ( value => {
48- if ( value === null || value === undefined ) {
49- return ''
50- }
46+ // Format each row, properly escaping values
47+ const csvRows = rows . map ( row =>
48+ row
49+ . map ( value => {
50+ if ( value === null || value === undefined ) {
51+ return ''
52+ }
5153
52- const strValue = String ( value )
53- if ( strValue . includes ( ',' ) || strValue . includes ( '"' ) || strValue . includes ( '\n' ) ) {
54- return `"${ strValue . replace ( / " / g, '""' ) } "`
55- }
54+ const strValue = String ( value )
55+ if ( strValue . includes ( ',' ) || strValue . includes ( '"' ) || strValue . includes ( '\n' ) ) {
56+ return `"${ strValue . replace ( / " / g, '""' ) } "`
57+ }
5658
57- return strValue
58- } )
59- . join ( ',' ) ,
60- )
59+ return strValue
60+ } )
61+ . join ( ',' ) ,
62+ )
6163
62- // Combine headers and data
63- const csvContent = [ headers . join ( ',' ) , ...csvRows ] . join ( '\n' )
64+ // Combine headers and data
65+ const csvContent = [ headers . join ( ',' ) , ...csvRows ] . join ( '\n' )
6466
65- // Write the CSV data to the specified file path
66- await this . saveFile ( this . path , csvContent )
67+ // Write the CSV data to the specified file path
68+ await this . saveFile ( this . path , csvContent )
69+ } catch ( error ) {
70+ throw new Error ( `Failed to save CSV report: ${ error . message } ` )
71+ }
6772 }
6873
6974 /**
70- * Saves unique "uses" values as a separate CSV file.
75+ * Saves unique "uses" values as a separate file.
7176 * @returns {Promise<void> } A promise that resolves when the unique uses file is saved
7277 */
7378 async saveUnique ( ) {
74- // Create a unique file name by inserting '-unique' before the extension
75- const uniquePath = this . createUniquePath ( 'csv' )
76-
77- // Extract unique "uses" entries from the data
78- const allUniqueUses = this . extractUniqueUses ( )
79- const uniqueUses = new Set ( )
80-
81- // Filter out local actions starting with './'
82- for ( const use of allUniqueUses ) {
83- if ( ! use . startsWith ( './' ) ) {
84- uniqueUses . add ( use )
79+ try {
80+ // Create a unique file name using the base class method
81+ const uniquePath = this . createUniquePath ( 'csv' )
82+
83+ // Extract unique "uses" entries from the data
84+ const allUniqueUses = this . extractUniqueUses ( )
85+ const uniqueUses = new Set ( )
86+
87+ // Filter out local actions starting with './'
88+ for ( const use of allUniqueUses ) {
89+ if ( ! use . startsWith ( './' ) ) {
90+ uniqueUses . add ( use )
91+ }
8592 }
86- }
8793
88- // Create headers for the unique CSV
89- const headers = [ 'uses' ]
94+ // Create headers for the unique CSV
95+ const headers = [ 'uses' ]
9096
91- // Format unique uses into CSV rows
92- const uniqueRows = Array . from ( uniqueUses ) . map ( use => {
93- const formattedValue = this . # formatValue( use )
97+ // Format unique uses into CSV rows
98+ const uniqueRows = Array . from ( uniqueUses ) . map ( use => {
99+ const formattedValue = this . formatValue ( use )
94100
95- // Properly escape values with quotes if they contain commas
96- if ( typeof formattedValue === 'string' && formattedValue . includes ( ',' ) ) {
97- return [ `"${ formattedValue . replace ( / " / g, '""' ) } "` ]
98- }
99- return [ formattedValue ]
100- } )
101+ // Properly escape values with quotes if they contain commas
102+ if ( typeof formattedValue === 'string' && formattedValue . includes ( ',' ) ) {
103+ return [ `"${ formattedValue . replace ( / " / g, '""' ) } "` ]
104+ }
105+ return [ formattedValue ]
106+ } )
101107
102- // Sort unique uses alphabetically
103- uniqueRows . sort ( ( a , b ) => a [ 0 ] . localeCompare ( b [ 0 ] ) )
108+ // Sort unique uses alphabetically
109+ uniqueRows . sort ( ( a , b ) => a [ 0 ] . localeCompare ( b [ 0 ] ) )
104110
105- // Combine headers with properly formatted rows
106- const csvContent = [ headers . join ( ',' ) , ...uniqueRows . map ( row => row . join ( ',' ) ) ] . join ( '\n' )
111+ // Combine headers with properly formatted rows
112+ const csvContent = [ headers . join ( ',' ) , ...uniqueRows . map ( row => row . join ( ',' ) ) ] . join ( '\n' )
107113
108- // Write the unique CSV data to the file
109- await this . saveFile ( uniquePath , csvContent )
114+ // Write the unique CSV data to the file
115+ await this . saveFile ( uniquePath , csvContent )
116+ } catch ( error ) {
117+ throw new Error ( `Failed to save unique uses CSV report: ${ error . message } ` )
118+ }
110119 }
111120
112121 /**
113- * Creates consistent headers for CSV reports based on enabled options.
122+ * Creates headers for CSV reports based on enabled options.
114123 * @returns {string[] } Array of header columns
115- * @private
116124 */
117- # createHeaders( ) {
125+ createHeaders ( ) {
118126 // Define the table header with all columns
119127 const headers = [ 'owner' , 'repo' , 'name' , 'workflow' , 'state' , 'created_at' , 'updated_at' , 'last_run_at' ]
120128
@@ -131,12 +139,10 @@ export default class Csv extends Reporter {
131139
132140 /**
133141 * Formats a value for CSV output, handling objects and other types appropriately.
134- * Special formatting is applied to match the expected output format in reports.
135142 * @param {* } value - The value to format
136143 * @returns {string|number|boolean } - The formatted value
137- * @private
138144 */
139- # formatValue( value ) {
145+ formatValue ( value ) {
140146 if ( value === null || value === undefined ) {
141147 return ''
142148 }
@@ -159,12 +165,11 @@ export default class Csv extends Reporter {
159165 return ''
160166 }
161167
162- // Special handling for listeners, permissions, and other complex objects
163- // Format as simplified key-value pairs without excessive quoting to match sample output
168+ // Special handling for complex objects
164169 if ( typeof value === 'object' && ! Array . isArray ( value ) ) {
165170 try {
166171 // Convert the object to a string without excessive quotes
167- return this . # formatObjectForCsv( value )
172+ return this . formatObjectForCsv ( value )
168173 } catch ( error ) {
169174 // Fallback to standard JSON string if custom formatting fails
170175 return JSON . stringify ( value )
@@ -176,12 +181,11 @@ export default class Csv extends Reporter {
176181 }
177182
178183 /**
179- * Formats an object for CSV output with custom formatting that matches the sample output .
184+ * Formats an object for CSV output with custom formatting.
180185 * @param {Object } obj - The object to format
181186 * @returns {string } - Formatted string representation
182- * @private
183187 */
184- # formatObjectForCsv( obj ) {
188+ formatObjectForCsv ( obj ) {
185189 // For workflow_call objects, use special formatting
186190 if ( obj . workflow_call ) {
187191 return 'workflow_call'
@@ -197,7 +201,7 @@ export default class Csv extends Reporter {
197201 result = objEntries
198202 . map ( ( [ key , value ] ) => {
199203 if ( typeof value === 'object' && value !== null ) {
200- return `${ key } : ${ this . # formatObjectForCsv( value ) } `
204+ return `${ key } : ${ this . formatObjectForCsv ( value ) } `
201205 }
202206 return `${ key } : ${ value } `
203207 } )
0 commit comments