@@ -3551,7 +3551,7 @@ class DefaultArtifactClient {
35513551 }
35523552 else {
35533553 // Create an entry for the artifact in the file container
3554- const response = yield uploadHttpClient . createArtifactInFileContainer ( name ) ;
3554+ const response = yield uploadHttpClient . createArtifactInFileContainer ( name , options ) ;
35553555 if ( ! response . fileContainerResourceUrl ) {
35563556 core . debug ( response . toString ( ) ) ;
35573557 throw new Error ( 'No URL provided by the Artifact Service to upload an artifact to' ) ;
@@ -3720,6 +3720,10 @@ function getWorkSpaceDirectory() {
37203720 return workspaceDirectory ;
37213721}
37223722exports . getWorkSpaceDirectory = getWorkSpaceDirectory ;
3723+ function getRetentionDays ( ) {
3724+ return process . env [ 'GITHUB_RETENTION_DAYS' ] ;
3725+ }
3726+ exports . getRetentionDays = getRetentionDays ;
37233727//# sourceMappingURL=config-variables.js.map
37243728
37253729/***/ } ) ,
@@ -4951,7 +4955,6 @@ exports.getDownloadSpecification = getDownloadSpecification;
49514955"use strict" ;
49524956
49534957Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
4954- const url = __webpack_require__ ( 835 ) ;
49554958const http = __webpack_require__ ( 605 ) ;
49564959const https = __webpack_require__ ( 211 ) ;
49574960const pm = __webpack_require__ ( 950 ) ;
@@ -5000,7 +5003,7 @@ var MediaTypes;
50005003 * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
50015004 */
50025005function getProxyUrl ( serverUrl ) {
5003- let proxyUrl = pm . getProxyUrl ( url . parse ( serverUrl ) ) ;
5006+ let proxyUrl = pm . getProxyUrl ( new URL ( serverUrl ) ) ;
50045007 return proxyUrl ? proxyUrl . href : '' ;
50055008}
50065009exports . getProxyUrl = getProxyUrl ;
@@ -5019,6 +5022,15 @@ const HttpResponseRetryCodes = [
50195022const RetryableHttpVerbs = [ 'OPTIONS' , 'GET' , 'DELETE' , 'HEAD' ] ;
50205023const ExponentialBackoffCeiling = 10 ;
50215024const ExponentialBackoffTimeSlice = 5 ;
5025+ class HttpClientError extends Error {
5026+ constructor ( message , statusCode ) {
5027+ super ( message ) ;
5028+ this . name = 'HttpClientError' ;
5029+ this . statusCode = statusCode ;
5030+ Object . setPrototypeOf ( this , HttpClientError . prototype ) ;
5031+ }
5032+ }
5033+ exports . HttpClientError = HttpClientError ;
50225034class HttpClientResponse {
50235035 constructor ( message ) {
50245036 this . message = message ;
@@ -5037,7 +5049,7 @@ class HttpClientResponse {
50375049}
50385050exports . HttpClientResponse = HttpClientResponse ;
50395051function isHttps ( requestUrl ) {
5040- let parsedUrl = url . parse ( requestUrl ) ;
5052+ let parsedUrl = new URL ( requestUrl ) ;
50415053 return parsedUrl . protocol === 'https:' ;
50425054}
50435055exports . isHttps = isHttps ;
@@ -5142,7 +5154,7 @@ class HttpClient {
51425154 if ( this . _disposed ) {
51435155 throw new Error ( 'Client has already been disposed.' ) ;
51445156 }
5145- let parsedUrl = url . parse ( requestUrl ) ;
5157+ let parsedUrl = new URL ( requestUrl ) ;
51465158 let info = this . _prepareRequest ( verb , parsedUrl , headers ) ;
51475159 // Only perform retries on reads since writes may not be idempotent.
51485160 let maxTries = this . _allowRetries && RetryableHttpVerbs . indexOf ( verb ) != - 1
@@ -5181,7 +5193,7 @@ class HttpClient {
51815193 // if there's no location to redirect to, we won't
51825194 break ;
51835195 }
5184- let parsedRedirectUrl = url . parse ( redirectUrl ) ;
5196+ let parsedRedirectUrl = new URL ( redirectUrl ) ;
51855197 if ( parsedUrl . protocol == 'https:' &&
51865198 parsedUrl . protocol != parsedRedirectUrl . protocol &&
51875199 ! this . _allowRedirectDowngrade ) {
@@ -5297,7 +5309,7 @@ class HttpClient {
52975309 * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
52985310 */
52995311 getAgent ( serverUrl ) {
5300- let parsedUrl = url . parse ( serverUrl ) ;
5312+ let parsedUrl = new URL ( serverUrl ) ;
53015313 return this . _getAgent ( parsedUrl ) ;
53025314 }
53035315 _prepareRequest ( method , requestUrl , headers ) {
@@ -5370,7 +5382,7 @@ class HttpClient {
53705382 maxSockets : maxSockets ,
53715383 keepAlive : this . _keepAlive ,
53725384 proxy : {
5373- proxyAuth : proxyUrl . auth ,
5385+ proxyAuth : ` ${ proxyUrl . username } : ${ proxyUrl . password } ` ,
53745386 host : proxyUrl . hostname ,
53755387 port : proxyUrl . port
53765388 }
@@ -5465,12 +5477,8 @@ class HttpClient {
54655477 else {
54665478 msg = 'Failed request: (' + statusCode + ')' ;
54675479 }
5468- let err = new Error ( msg ) ;
5469- // attach statusCode and body obj (if available) to the error object
5470- err [ 'statusCode' ] = statusCode ;
5471- if ( response . result ) {
5472- err [ 'result' ] = response . result ;
5473- }
5480+ let err = new HttpClientError ( msg , statusCode ) ;
5481+ err . result = response . result ;
54745482 reject ( err ) ;
54755483 }
54765484 else {
@@ -6002,12 +6010,17 @@ class UploadHttpClient {
60026010 * @param {string } artifactName Name of the artifact being created
60036011 * @returns The response from the Artifact Service if the file container was successfully created
60046012 */
6005- createArtifactInFileContainer ( artifactName ) {
6013+ createArtifactInFileContainer ( artifactName , options ) {
60066014 return __awaiter ( this , void 0 , void 0 , function * ( ) {
60076015 const parameters = {
60086016 Type : 'actions_storage' ,
60096017 Name : artifactName
60106018 } ;
6019+ // calculate retention period
6020+ if ( options && options . retentionDays ) {
6021+ const maxRetentionStr = config_variables_1 . getRetentionDays ( ) ;
6022+ parameters . RetentionDays = utils_1 . getProperRetention ( options . retentionDays , maxRetentionStr ) ;
6023+ }
60116024 const data = JSON . stringify ( parameters , null , 2 ) ;
60126025 const artifactUrl = utils_1 . getArtifactUrl ( ) ;
60136026 // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
@@ -6886,7 +6899,7 @@ class DownloadHttpClient {
68866899 return __awaiter ( this , void 0 , void 0 , function * ( ) {
68876900 let retryCount = 0 ;
68886901 const retryLimit = config_variables_1 . getRetryLimit ( ) ;
6889- const destinationStream = fs . createWriteStream ( downloadPath ) ;
6902+ let destinationStream = fs . createWriteStream ( downloadPath ) ;
68906903 const headers = utils_1 . getDownloadHeaders ( 'application/json' , true , true ) ;
68916904 // a single GET request is used to download a file
68926905 const makeDownloadRequest = ( ) => __awaiter ( this , void 0 , void 0 , function * ( ) {
@@ -6922,11 +6935,29 @@ class DownloadHttpClient {
69226935 core . info ( `Finished backoff for retry #${ retryCount } , continuing with download` ) ;
69236936 }
69246937 } ) ;
6938+ const isAllBytesReceived = ( expected , received ) => {
6939+ // be lenient, if any input is missing, assume success, i.e. not truncated
6940+ if ( ! expected ||
6941+ ! received ||
6942+ process . env [ 'ACTIONS_ARTIFACT_SKIP_DOWNLOAD_VALIDATION' ] ) {
6943+ core . info ( 'Skipping download validation.' ) ;
6944+ return true ;
6945+ }
6946+ return parseInt ( expected ) === received ;
6947+ } ;
6948+ const resetDestinationStream = ( fileDownloadPath ) => __awaiter ( this , void 0 , void 0 , function * ( ) {
6949+ destinationStream . close ( ) ;
6950+ yield utils_1 . rmFile ( fileDownloadPath ) ;
6951+ destinationStream = fs . createWriteStream ( fileDownloadPath ) ;
6952+ } ) ;
69256953 // keep trying to download a file until a retry limit has been reached
69266954 while ( retryCount <= retryLimit ) {
69276955 let response ;
69286956 try {
69296957 response = yield makeDownloadRequest ( ) ;
6958+ if ( core . isDebug ( ) ) {
6959+ utils_1 . displayHttpDiagnostics ( response ) ;
6960+ }
69306961 }
69316962 catch ( error ) {
69326963 // if an error is caught, it is usually indicative of a timeout so retry the download
@@ -6937,14 +6968,30 @@ class DownloadHttpClient {
69376968 yield backOff ( ) ;
69386969 continue ;
69396970 }
6971+ let forceRetry = false ;
69406972 if ( utils_1 . isSuccessStatusCode ( response . message . statusCode ) ) {
69416973 // The body contains the contents of the file however calling response.readBody() causes all the content to be converted to a string
69426974 // which can cause some gzip encoded data to be lost
69436975 // Instead of using response.readBody(), response.message is a readableStream that can be directly used to get the raw body contents
6944- return this . pipeResponseToFile ( response , destinationStream , isGzip ( response . message . headers ) ) ;
6976+ try {
6977+ const isGzipped = isGzip ( response . message . headers ) ;
6978+ yield this . pipeResponseToFile ( response , destinationStream , isGzipped ) ;
6979+ if ( isGzipped ||
6980+ isAllBytesReceived ( response . message . headers [ 'content-length' ] , yield utils_1 . getFileSize ( downloadPath ) ) ) {
6981+ return ;
6982+ }
6983+ else {
6984+ forceRetry = true ;
6985+ }
6986+ }
6987+ catch ( error ) {
6988+ // retry on error, most likely streams were corrupted
6989+ forceRetry = true ;
6990+ }
69456991 }
6946- else if ( utils_1 . isRetryableStatusCode ( response . message . statusCode ) ) {
6992+ if ( forceRetry || utils_1 . isRetryableStatusCode ( response . message . statusCode ) ) {
69476993 core . info ( `A ${ response . message . statusCode } response code has been received while attempting to download an artifact` ) ;
6994+ resetDestinationStream ( downloadPath ) ;
69486995 // if a throttled status code is received, try to get the retryAfter header value, else differ to standard exponential backoff
69496996 utils_1 . isThrottledStatusCode ( response . message . statusCode )
69506997 ? yield backOff ( utils_1 . tryGetRetryAfterValueTimeInMilliseconds ( response . message . headers ) )
@@ -6970,24 +7017,40 @@ class DownloadHttpClient {
69707017 if ( isGzip ) {
69717018 const gunzip = zlib . createGunzip ( ) ;
69727019 response . message
7020+ . on ( 'error' , error => {
7021+ core . error ( `An error occurred while attempting to read the response stream` ) ;
7022+ gunzip . close ( ) ;
7023+ destinationStream . close ( ) ;
7024+ reject ( error ) ;
7025+ } )
69737026 . pipe ( gunzip )
7027+ . on ( 'error' , error => {
7028+ core . error ( `An error occurred while attempting to decompress the response stream` ) ;
7029+ destinationStream . close ( ) ;
7030+ reject ( error ) ;
7031+ } )
69747032 . pipe ( destinationStream )
69757033 . on ( 'close' , ( ) => {
69767034 resolve ( ) ;
69777035 } )
69787036 . on ( 'error' , error => {
6979- core . error ( `An error has been encountered while decompressing and writing a downloaded file to ${ destinationStream . path } ` ) ;
7037+ core . error ( `An error occurred while writing a downloaded file to ${ destinationStream . path } ` ) ;
69807038 reject ( error ) ;
69817039 } ) ;
69827040 }
69837041 else {
69847042 response . message
7043+ . on ( 'error' , error => {
7044+ core . error ( `An error occurred while attempting to read the response stream` ) ;
7045+ destinationStream . close ( ) ;
7046+ reject ( error ) ;
7047+ } )
69857048 . pipe ( destinationStream )
69867049 . on ( 'close' , ( ) => {
69877050 resolve ( ) ;
69887051 } )
69897052 . on ( 'error' , error => {
6990- core . error ( `An error has been encountered while writing a downloaded file to ${ destinationStream . path } ` ) ;
7053+ core . error ( `An error occurred while writing a downloaded file to ${ destinationStream . path } ` ) ;
69917054 reject ( error ) ;
69927055 } ) ;
69937056 }
@@ -7520,6 +7583,35 @@ function createEmptyFilesForArtifact(emptyFilesToCreate) {
75207583 } ) ;
75217584}
75227585exports . createEmptyFilesForArtifact = createEmptyFilesForArtifact ;
7586+ function getFileSize ( filePath ) {
7587+ return __awaiter ( this , void 0 , void 0 , function * ( ) {
7588+ const stats = yield fs_1 . promises . stat ( filePath ) ;
7589+ core_1 . debug ( `${ filePath } size:(${ stats . size } ) blksize:(${ stats . blksize } ) blocks:(${ stats . blocks } )` ) ;
7590+ return stats . size ;
7591+ } ) ;
7592+ }
7593+ exports . getFileSize = getFileSize ;
7594+ function rmFile ( filePath ) {
7595+ return __awaiter ( this , void 0 , void 0 , function * ( ) {
7596+ yield fs_1 . promises . unlink ( filePath ) ;
7597+ } ) ;
7598+ }
7599+ exports . rmFile = rmFile ;
7600+ function getProperRetention ( retentionInput , retentionSetting ) {
7601+ if ( retentionInput < 0 ) {
7602+ throw new Error ( 'Invalid retention, minimum value is 1.' ) ;
7603+ }
7604+ let retention = retentionInput ;
7605+ if ( retentionSetting ) {
7606+ const maxRetention = parseInt ( retentionSetting ) ;
7607+ if ( ! isNaN ( maxRetention ) && maxRetention < retention ) {
7608+ core_1 . warning ( `Retention days is greater than the max value allowed by the repository setting, reduce retention to ${ maxRetention } days` ) ;
7609+ retention = maxRetention ;
7610+ }
7611+ }
7612+ return retention ;
7613+ }
7614+ exports . getProperRetention = getProperRetention ;
75237615//# sourceMappingURL=utils.js.map
75247616
75257617/***/ } ) ,
@@ -7600,12 +7692,11 @@ var isArray = Array.isArray || function (xs) {
76007692/***/ } ) ,
76017693
76027694/***/ 950 :
7603- /***/ ( function ( __unusedmodule , exports , __webpack_require__ ) {
7695+ /***/ ( function ( __unusedmodule , exports ) {
76047696
76057697"use strict" ;
76067698
76077699Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
7608- const url = __webpack_require__ ( 835 ) ;
76097700function getProxyUrl ( reqUrl ) {
76107701 let usingSsl = reqUrl . protocol === 'https:' ;
76117702 let proxyUrl ;
@@ -7620,7 +7711,7 @@ function getProxyUrl(reqUrl) {
76207711 proxyVar = process . env [ 'http_proxy' ] || process . env [ 'HTTP_PROXY' ] ;
76217712 }
76227713 if ( proxyVar ) {
7623- proxyUrl = url . parse ( proxyVar ) ;
7714+ proxyUrl = new URL ( proxyVar ) ;
76247715 }
76257716 return proxyUrl ;
76267717}
0 commit comments