1
- use crate :: format:: { GzFormatter , JsonEachRowFormatter , JsonFormatter } ;
1
+ use crate :: format:: { JsonEachRowFormatter , JsonFormatter } ;
2
2
use anyhow:: { Context , Result } ;
3
3
use qlty_types:: tests:: v1:: { CoverageMetadata , FileCoverage , ReportFile } ;
4
+ use std:: collections:: HashMap ;
4
5
use std:: fs:: File ;
5
6
use std:: io:: Read ;
6
7
use std:: path:: { Path , PathBuf } ;
7
8
use zip:: { write:: FileOptions , ZipWriter } ;
8
9
9
- fn compress_files ( files : Vec < String > , output_file : & Path ) -> Result < ( ) > {
10
+ fn compress_files ( files : HashMap < String , PathBuf > , output_file : & Path ) -> Result < ( ) > {
10
11
// Create the output ZIP file
11
12
let zip_file = File :: create ( output_file) ?;
12
13
let mut zip = ZipWriter :: new ( zip_file) ;
@@ -15,20 +16,16 @@ fn compress_files(files: Vec<String>, output_file: &Path) -> Result<()> {
15
16
. compression_method ( zip:: CompressionMethod :: Deflated ) // Compression method
16
17
. unix_permissions ( 0o755 ) ;
17
18
18
- // Iterate over the list of files to compress
19
- for file_path in files {
20
- let path = Path :: new ( & file_path) ;
21
-
22
- if path. is_file ( ) {
19
+ for ( name, file_path) in & files {
20
+ if file_path. is_file ( ) {
23
21
// Add the file to the archive
24
- // Use path as filename in case multiple files with same name
25
- zip. start_file ( path. to_string_lossy ( ) , options) ?;
22
+ zip. start_file ( name, options) ?;
26
23
27
24
// Write the file content to the archive
28
- let mut file = File :: open ( path ) ?;
25
+ let mut file = File :: open ( file_path ) ?;
29
26
std:: io:: copy ( & mut file, & mut zip) ?;
30
27
} else {
31
- eprintln ! ( "Skipping non-file: {}" , file_path) ;
28
+ eprintln ! ( "Skipping non-file: {}" , file_path. to_string_lossy ( ) ) ;
32
29
}
33
30
}
34
31
@@ -54,34 +51,44 @@ impl CoverageExport {
54
51
fn export ( & self ) -> Result < ( ) > {
55
52
let directory = self . to . as_ref ( ) . unwrap ( ) ;
56
53
57
- GzFormatter :: new ( JsonEachRowFormatter :: new ( self . report_files . clone ( ) ) )
58
- . write_to_file ( & directory. join ( "report_files.json.gz " ) ) ?;
54
+ JsonEachRowFormatter :: new ( self . report_files . clone ( ) )
55
+ . write_to_file ( & directory. join ( "report_files.jsonl " ) ) ?;
59
56
60
- GzFormatter :: new ( JsonEachRowFormatter :: new ( self . file_coverages . clone ( ) ) )
61
- . write_to_file ( & directory. join ( "file_coverages.json.gz " ) ) ?;
57
+ JsonEachRowFormatter :: new ( self . file_coverages . clone ( ) )
58
+ . write_to_file ( & directory. join ( "file_coverages.jsonl " ) ) ?;
62
59
63
60
JsonFormatter :: new ( self . metadata . clone ( ) )
64
61
. write_to_file ( & directory. join ( "metadata.json" ) ) ?;
65
62
66
- let raw_file_paths = self
67
- . report_files
68
- . iter ( )
69
- . map ( |report_file| & report_file. path )
70
- . cloned ( )
71
- . collect ( ) ;
63
+ let zip_file_contents = self . compute_zip_file_contents ( directory) ?;
72
64
73
- compress_files ( raw_file_paths , & directory. join ( "raw_files .zip" ) )
65
+ compress_files ( zip_file_contents , & directory. join ( "coverage .zip" ) )
74
66
}
75
67
76
68
pub fn total_size_bytes ( & self ) -> Result < u64 > {
77
- let mut bytes: u64 = 0 ;
69
+ Ok ( self . read_file ( "coverage.zip" ) ?. len ( ) as u64 )
70
+ }
78
71
79
- bytes += self . read_file ( "report_files.json.gz" ) ?. len ( ) as u64 ;
80
- bytes += self . read_file ( "file_coverages.json.gz" ) ?. len ( ) as u64 ;
81
- bytes += self . read_file ( "metadata.json" ) ?. len ( ) as u64 ;
82
- bytes += self . read_file ( "raw_files.zip" ) ?. len ( ) as u64 ;
72
+ fn compute_zip_file_contents ( & self , directory : & Path ) -> Result < HashMap < String , PathBuf > > {
73
+ let mut files_to_zip = HashMap :: new ( ) ;
74
+
75
+ files_to_zip. insert (
76
+ "report_files.jsonl" . to_string ( ) ,
77
+ directory. join ( "report_files.jsonl" ) ,
78
+ ) ;
79
+ files_to_zip. insert (
80
+ "file_coverages.jsonl" . to_string ( ) ,
81
+ directory. join ( "file_coverages.jsonl" ) ,
82
+ ) ;
83
+ files_to_zip. insert ( "metadata.json" . to_string ( ) , directory. join ( "metadata.json" ) ) ;
84
+
85
+ for report_file in & self . report_files {
86
+ let actual_path = PathBuf :: from ( & report_file. path ) ;
87
+ let zip_file_name = PathBuf :: from ( "raw_files" ) . join ( & report_file. path ) ;
88
+ files_to_zip. insert ( zip_file_name. to_string_lossy ( ) . into_owned ( ) , actual_path) ;
89
+ }
83
90
84
- Ok ( bytes )
91
+ Ok ( files_to_zip )
85
92
}
86
93
87
94
pub fn read_file < P : AsRef < Path > > ( & self , filename : P ) -> Result < Vec < u8 > > {
@@ -97,3 +104,68 @@ impl CoverageExport {
97
104
Ok ( buffer)
98
105
}
99
106
}
107
+
108
+ #[ cfg( test) ]
109
+ mod tests {
110
+ use super :: * ;
111
+ use std:: io:: Write ;
112
+ use tempfile:: { tempdir, TempDir } ;
113
+ use zip:: read:: ZipArchive ;
114
+
115
+ #[ test]
116
+ fn test_export_to ( ) {
117
+ let destination_binding = tempdir ( ) . unwrap ( ) ;
118
+ let destination = destination_binding. path ( ) ;
119
+
120
+ let raw_files_temp_binding = TempDir :: new_in ( "." ) . unwrap ( ) ;
121
+ let raw_files_dir = raw_files_temp_binding. path ( ) ;
122
+
123
+ let f1 = & raw_files_dir. join ( "coverage.lcov" ) ;
124
+ let mut file = File :: create ( f1) . unwrap ( ) ;
125
+ writeln ! ( file, "D" ) . unwrap ( ) ;
126
+
127
+ let metadata = CoverageMetadata :: default ( ) ;
128
+ let relative_raw_file_path = raw_files_dir
129
+ . file_name ( )
130
+ . map ( |name| {
131
+ Path :: new ( name)
132
+ . join ( "coverage.lcov" )
133
+ . to_string_lossy ( )
134
+ . into_owned ( )
135
+ } )
136
+ . unwrap_or_default ( ) ;
137
+
138
+ // the ReportFile path is what is supplied by a user as one of the path arguments to `qlty coverage publish path/to/coverage.lcov`
139
+ // that path could be relative or absolute (but probably more typically relative)
140
+ let report_files = vec ! [ ReportFile {
141
+ path: relative_raw_file_path. clone( ) ,
142
+ ..Default :: default ( )
143
+ } ] ;
144
+ let file_coverages = vec ! [ FileCoverage :: default ( ) ] ;
145
+
146
+ let mut export = CoverageExport {
147
+ metadata,
148
+ report_files,
149
+ file_coverages,
150
+ to : None ,
151
+ } ;
152
+
153
+ export. export_to ( Some ( destination. to_path_buf ( ) ) ) . unwrap ( ) ;
154
+
155
+ assert ! ( destination. join( "coverage.zip" ) . exists( ) ) ;
156
+
157
+ // Verify the contents of the zip file
158
+ let zip_file = File :: open ( destination. join ( "coverage.zip" ) ) . unwrap ( ) ;
159
+ let mut zip = ZipArchive :: new ( zip_file) . unwrap ( ) ;
160
+
161
+ assert ! ( zip. by_name( "report_files.jsonl" ) . is_ok( ) ) ;
162
+ assert ! ( zip. by_name( "file_coverages.jsonl" ) . is_ok( ) ) ;
163
+ assert ! ( zip. by_name( "metadata.json" ) . is_ok( ) ) ;
164
+ let raw_file_path = PathBuf :: from ( "raw_files" )
165
+ . join ( raw_files_dir. file_name ( ) . unwrap ( ) )
166
+ . join ( "coverage.lcov" ) ;
167
+ assert ! ( zip
168
+ . by_name( raw_file_path. to_string_lossy( ) . into_owned( ) . as_str( ) )
169
+ . is_ok( ) ) ;
170
+ }
171
+ }
0 commit comments