@@ -93,37 +93,53 @@ pub(crate) async fn build_details_handler(
93
93
. ok_or ( AxumNope :: BuildNotFound ) ?;
94
94
95
95
let ( output, all_log_filenames, current_filename) = if let Some ( output) = row. output {
96
+ // legacy case, for old builds the build log was stored in the database.
96
97
( output, Vec :: new ( ) , None )
97
98
} else {
99
+ // for newer builds we have the build logs stored in S3.
100
+ // For a long time only for one target, then we started storing the logs for other targets
101
+ // toFor a long time only for one target, then we started storing the logs for other
102
+ // targets. In any case, all the logfiles are put into a folder we can just query.
98
103
let prefix = format ! ( "build-logs/{}/" , id) ;
104
+ let all_log_filenames: Vec < _ > = storage
105
+ . list_prefix ( & prefix) // the result from S3 is ordered by key
106
+ . await
107
+ . map_ok ( |path| {
108
+ path. strip_prefix ( & prefix)
109
+ . expect ( "since we query for the prefix, it has to be always there" )
110
+ . to_owned ( )
111
+ } )
112
+ . try_collect ( )
113
+ . await ?;
99
114
100
- if let Some ( current_filename) = params
101
- . filename
102
- . or ( row. default_target . map ( |target| format ! ( "{}.txt" , target) ) )
103
- {
104
- let path = format ! ( "{prefix}{current_filename}" ) ;
105
- let file = File :: from_path ( & storage, & path, & config) . await ?;
106
- (
107
- String :: from_utf8 ( file. 0 . content ) . context ( "non utf8" ) ?,
108
- storage
109
- . list_prefix ( & prefix) // the result from S3 is ordered by key
110
- . await
111
- . map_ok ( |path| {
112
- path. strip_prefix ( & prefix)
113
- . expect ( "since we query for the prefix, it has to be always there" )
114
- . to_owned ( )
115
- } )
116
- . try_collect ( )
117
- . await ?,
118
- Some ( current_filename) ,
119
- )
115
+ let current_filename = if let Some ( filename) = params. filename {
116
+ // if we have a given filename in the URL, we use that one.
117
+ Some ( filename)
118
+ } else if let Some ( default_target) = row. default_target {
119
+ // without a filename in the URL, we try to show the build log
120
+ // for the default target, if we have one.
121
+ let wanted_filename = format ! ( "{default_target}.txt" ) ;
122
+ if all_log_filenames. contains ( & wanted_filename) {
123
+ Some ( wanted_filename)
124
+ } else {
125
+ None
126
+ }
120
127
} else {
121
128
// this can only happen when `releases.default_target` is NULL,
122
129
// which is the case for in-progress builds or builds which errored
123
130
// before we could determine the target.
124
131
// For the "error" case we show `row.errors`, which should contain what we need to see.
125
- ( "" . into ( ) , Vec :: new ( ) , None )
126
- }
132
+ None
133
+ } ;
134
+
135
+ let file_content = if let Some ( ref filename) = current_filename {
136
+ let file = File :: from_path ( & storage, & format ! ( "{prefix}{filename}" ) , & config) . await ?;
137
+ String :: from_utf8 ( file. 0 . content ) . context ( "non utf8" ) ?
138
+ } else {
139
+ "" . to_string ( )
140
+ } ;
141
+
142
+ ( file_content, all_log_filenames, current_filename)
127
143
} ;
128
144
129
145
Ok ( BuildDetailsPage {
@@ -197,6 +213,44 @@ mod tests {
197
213
} ) ;
198
214
}
199
215
216
+ #[ test]
217
+ fn test_partial_build_result_plus_default_target_from_previous_build ( ) {
218
+ async_wrapper ( |env| async move {
219
+ let mut conn = env. async_db ( ) . await . async_conn ( ) . await ;
220
+ let ( release_id, build_id) = fake_release_that_failed_before_build (
221
+ & mut conn,
222
+ "foo" ,
223
+ "0.1.0" ,
224
+ "some random error" ,
225
+ )
226
+ . await ?;
227
+
228
+ sqlx:: query!(
229
+ "UPDATE releases SET default_target = 'x86_64-unknown-linux-gnu' WHERE id = $1" ,
230
+ release_id. 0
231
+ )
232
+ . execute ( & mut * conn)
233
+ . await ?;
234
+
235
+ let page = kuchikiki:: parse_html ( ) . one (
236
+ env. web_app ( )
237
+ . await
238
+ . get ( & format ! ( "/crate/foo/0.1.0/builds/{build_id}" ) )
239
+ . await ?
240
+ . error_for_status ( ) ?
241
+ . text ( )
242
+ . await ?,
243
+ ) ;
244
+
245
+ let info_text = page. select ( "pre" ) . unwrap ( ) . next ( ) . unwrap ( ) . text_contents ( ) ;
246
+
247
+ assert ! ( info_text. contains( "# pre-build errors" ) , "{}" , info_text) ;
248
+ assert ! ( info_text. contains( "some random error" ) , "{}" , info_text) ;
249
+
250
+ Ok ( ( ) )
251
+ } ) ;
252
+ }
253
+
200
254
#[ test]
201
255
fn db_build_logs ( ) {
202
256
async_wrapper ( |env| async move {
0 commit comments