@@ -16,6 +16,8 @@ import JobSearch = jobsearch.JobSearch;
1616import jobqueue = require( './jobqueue' ) ;
1717import JobQueue = jobqueue . JobQueue ;
1818
19+ import unzip = require( './unzip' ) ;
20+
1921import * as Util from './util' ;
2022
2123export enum JobState {
@@ -26,7 +28,8 @@ export enum JobState {
2628 Done , // 4
2729 Joined , // 5
2830 Queued , // 6
29- Cut // 7
31+ Cut , // 7
32+ Downloading // 8
3033}
3134
3235export class Job {
@@ -98,6 +101,8 @@ export class Job {
98101 } else if ( oldState == JobState . Streaming ) {
99102 validStateChange = ( newState == JobState . Finishing ) ;
100103 } else if ( oldState == JobState . Finishing ) {
104+ validStateChange = ( newState == JobState . Downloading || newState == JobState . Done ) ;
105+ } else if ( oldState == JobState . Downloading ) {
101106 validStateChange = ( newState == JobState . Done ) ;
102107 } else if ( oldState == JobState . Done || oldState == JobState . Joined || oldState == JobState . Cut ) {
103108 validStateChange = false ; // these are terminal states
@@ -118,6 +123,8 @@ export class Job {
118123 this . initialize ( ) ;
119124 } else if ( this . state == JobState . Streaming ) {
120125 this . streamConsole ( ) ;
126+ } else if ( this . state == JobState . Downloading ) {
127+ this . downloadResults ( ) ;
121128 } else if ( this . state == JobState . Finishing ) {
122129 this . finish ( ) ;
123130 } else {
@@ -143,6 +150,7 @@ export class Job {
143150 return this . state == JobState . New ||
144151 this . state == JobState . Locating ||
145152 this . state == JobState . Streaming ||
153+ this . state == JobState . Downloading ||
146154 this . state == JobState . Finishing
147155 }
148156
@@ -299,7 +307,11 @@ export class Job {
299307 thisJob . debug ( "parsedBody for: " + resultUrl + ": " + JSON . stringify ( parsedBody ) ) ;
300308 if ( parsedBody . result ) {
301309 thisJob . setParsedExecutionResult ( parsedBody ) ;
302- thisJob . stopWork ( 0 , JobState . Done ) ;
310+ if ( thisJob . queue . taskOptions . teamBuildPluginAvailable ) {
311+ thisJob . stopWork ( 0 , JobState . Downloading ) ;
312+ } else {
313+ thisJob . stopWork ( 0 , JobState . Done ) ;
314+ }
303315 } else {
304316 // result not updated yet -- keep trying
305317 thisJob . stopWork ( thisJob . queue . taskOptions . pollIntervalMillis , thisJob . state ) ;
@@ -308,6 +320,81 @@ export class Job {
308320 } ) . auth ( thisJob . queue . taskOptions . username , thisJob . queue . taskOptions . password , true ) ;
309321 }
310322 }
323+
324+ downloadResults ( ) : void {
325+ var thisJob : Job = this ;
326+ var downloadUrl : string = Util . addUrlSegment ( thisJob . executableUrl , 'team-results/zip' ) ;
327+ tl . debug ( 'downloadResults(), url:' + downloadUrl ) ;
328+
329+ var downloadRequest = request . get ( { url : downloadUrl , strictSSL : thisJob . queue . taskOptions . strictSSL } )
330+ . auth ( thisJob . queue . taskOptions . username , thisJob . queue . taskOptions . password , true )
331+ . on ( "error" , err => {
332+ Util . handleConnectionResetError ( err ) ; // something went bad
333+ thisJob . stopWork ( thisJob . queue . taskOptions . pollIntervalMillis , thisJob . state ) ;
334+ } )
335+ . on ( "response" , response => {
336+ tl . debug ( 'downloadResults(), url:' + downloadUrl + ' , response.statusCode: ' + response . statusCode + ', response.statusMessage: ' + response . statusMessage ) ;
337+ if ( response . statusCode == 404 ) { // expected if there are no results
338+ tl . debug ( 'no results to download' ) ;
339+ thisJob . stopWork ( 0 , JobState . Done ) ;
340+ } else if ( response . statusCode == 200 ) { // successfully found results
341+ var destinationFolder : string = path . join ( thisJob . queue . taskOptions . saveResultsTo , thisJob . name + '/' )
342+ var fileName = path . join ( destinationFolder , 'team-results.zip' ) ;
343+
344+ try {
345+ // Create the destination folder if it doesn't exist
346+ if ( ! tl . exist ( destinationFolder ) ) {
347+ tl . debug ( 'creating results destination folder: ' + destinationFolder ) ;
348+ tl . mkdirP ( destinationFolder ) ;
349+ }
350+
351+ tl . debug ( 'downloading results file: ' + fileName ) ;
352+
353+ let file = fs . createWriteStream ( fileName ) ;
354+ downloadRequest . pipe ( file )
355+ . on ( "error" , err => { throw err ; } )
356+ . on ( "finish" , function fileFinished ( ) {
357+ tl . debug ( 'successfully downloaded results to: ' + fileName ) ;
358+ try {
359+ unzip . unzip ( fileName , destinationFolder ) ;
360+ thisJob . stopWork ( 0 , JobState . Done ) ;
361+ } catch ( e ) {
362+ tl . warning ( 'unable to extract results file' )
363+ tl . debug ( e . message ) ;
364+ tl . _writeError ( e ) ;
365+ thisJob . stopWork ( 0 , JobState . Done ) ;
366+ }
367+ } ) ;
368+ } catch ( e ) {
369+ // don't fail the job if the results can not be downloaded successfully
370+ tl . warning ( 'unable to download results to file: ' + fileName + ' for Jenkins Job: ' + thisJob . executableUrl ) ;
371+ tl . warning ( e . message ) ;
372+ tl . _writeError ( e ) ;
373+ thisJob . stopWork ( 0 , JobState . Done ) ;
374+ }
375+ } else { // an unexepected error with results
376+ try {
377+ var warningMessage : string = ( response . statusCode >= 500 ) ?
378+ 'A Jenkins error occurred while retrieving results. Results could not be downloaded.' : // Jenkins server error
379+ 'Jenkins results could not be downloaded.' ; // Any other error
380+ tl . warning ( warningMessage ) ;
381+ var warningStream : any = new Util . StringWritable ( { decodeStrings : false } ) ;
382+ downloadRequest . pipe ( warningStream )
383+ . on ( "error" , err => { throw err ; } )
384+ . on ( "finish" , function finsished ( ) {
385+ tl . warning ( warningStream ) ;
386+ thisJob . stopWork ( 0 , JobState . Done ) ;
387+ } ) ;
388+ } catch ( e ) {
389+ // don't fail the job if the results can not be downloaded successfully
390+ tl . warning ( e . message ) ;
391+ tl . _writeError ( e ) ;
392+ thisJob . stopWork ( 0 , JobState . Done ) ;
393+ }
394+ }
395+ } ) ;
396+ }
397+
311398 /**
312399 * Streams the Jenkins console.
313400 *
0 commit comments