mirror of
				https://git.mirrors.martin98.com/https://github.com/actions/upload-artifact
				synced 2025-10-31 16:11:08 +08:00 
			
		
		
		
	Add retries to all HTTP calls + resolve dependabot alerts (#160)
* Bump @actions/artifact to version 0.5.0 * Resolve dependabot alert for node-notifier * Resolve dependabot alert for node-fetch * Bump artifact.dep.yml * Update http-client.dep.yml
This commit is contained in:
		
							parent
							
								
									e6bd6b7749
								
							
						
					
					
						commit
						e448a9b857
					
				
							
								
								
									
										2
									
								
								.licenses/npm/@actions/artifact.dep.yml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.licenses/npm/@actions/artifact.dep.yml
									
									
									
										generated
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| --- | --- | ||||||
| name: "@actions/artifact" | name: "@actions/artifact" | ||||||
| version: 0.4.0 | version: 0.5.0 | ||||||
| type: npm | type: npm | ||||||
| summary:  | summary:  | ||||||
| homepage:  | homepage:  | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.licenses/npm/@actions/http-client.dep.yml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.licenses/npm/@actions/http-client.dep.yml
									
									
									
										generated
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| --- | --- | ||||||
| name: "@actions/http-client" | name: "@actions/http-client" | ||||||
| version: 1.0.8 | version: 1.0.9 | ||||||
| type: npm | type: npm | ||||||
| summary: Actions Http Client | summary: Actions Http Client | ||||||
| homepage: https://github.com/actions/http-client#readme | homepage: https://github.com/actions/http-client#readme | ||||||
|  | |||||||
							
								
								
									
										275
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										275
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							| @ -4075,7 +4075,8 @@ function run() { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|                 core.info(`With the provided path, there will be ${searchResult.filesToUpload.length} file(s) uploaded`); |                 const s = searchResult.filesToUpload.length === 1 ? '' : 's'; | ||||||
|  |                 core.info(`With the provided path, there will be ${searchResult.filesToUpload.length} file${s} uploaded`); | ||||||
|                 core.debug(`Root artifact directory is ${searchResult.rootDirectory}`); |                 core.debug(`Root artifact directory is ${searchResult.rootDirectory}`); | ||||||
|                 const artifactClient = artifact_1.create(); |                 const artifactClient = artifact_1.create(); | ||||||
|                 const options = { |                 const options = { | ||||||
| @ -5334,6 +5335,88 @@ exports.getState = getState; | |||||||
| 
 | 
 | ||||||
| /***/ }), | /***/ }), | ||||||
| 
 | 
 | ||||||
|  | /***/ 489: | ||||||
|  | /***/ (function(__unusedmodule, exports, __webpack_require__) { | ||||||
|  | 
 | ||||||
|  | "use strict"; | ||||||
|  | 
 | ||||||
|  | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||||||
|  |     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||||||
|  |     return new (P || (P = Promise))(function (resolve, reject) { | ||||||
|  |         function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||||||
|  |         function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||||||
|  |         function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||||||
|  |         step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||||||
|  |     }); | ||||||
|  | }; | ||||||
|  | var __importStar = (this && this.__importStar) || function (mod) { | ||||||
|  |     if (mod && mod.__esModule) return mod; | ||||||
|  |     var result = {}; | ||||||
|  |     if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||||||
|  |     result["default"] = mod; | ||||||
|  |     return result; | ||||||
|  | }; | ||||||
|  | Object.defineProperty(exports, "__esModule", { value: true }); | ||||||
|  | const utils_1 = __webpack_require__(870); | ||||||
|  | const core = __importStar(__webpack_require__(470)); | ||||||
|  | const config_variables_1 = __webpack_require__(401); | ||||||
|  | function retry(name, operation, customErrorMessages, maxAttempts) { | ||||||
|  |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|  |         let response = undefined; | ||||||
|  |         let statusCode = undefined; | ||||||
|  |         let isRetryable = false; | ||||||
|  |         let errorMessage = ''; | ||||||
|  |         let customErrorInformation = undefined; | ||||||
|  |         let attempt = 1; | ||||||
|  |         while (attempt <= maxAttempts) { | ||||||
|  |             try { | ||||||
|  |                 response = yield operation(); | ||||||
|  |                 statusCode = response.message.statusCode; | ||||||
|  |                 if (utils_1.isSuccessStatusCode(statusCode)) { | ||||||
|  |                     return response; | ||||||
|  |                 } | ||||||
|  |                 // Extra error information that we want to display if a particular response code is hit
 | ||||||
|  |                 if (statusCode) { | ||||||
|  |                     customErrorInformation = customErrorMessages.get(statusCode); | ||||||
|  |                 } | ||||||
|  |                 isRetryable = utils_1.isRetryableStatusCode(statusCode); | ||||||
|  |                 errorMessage = `Artifact service responded with ${statusCode}`; | ||||||
|  |             } | ||||||
|  |             catch (error) { | ||||||
|  |                 isRetryable = true; | ||||||
|  |                 errorMessage = error.message; | ||||||
|  |             } | ||||||
|  |             if (!isRetryable) { | ||||||
|  |                 core.info(`${name} - Error is not retryable`); | ||||||
|  |                 if (response) { | ||||||
|  |                     utils_1.displayHttpDiagnostics(response); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             core.info(`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`); | ||||||
|  |             yield utils_1.sleep(utils_1.getExponentialRetryTimeInMilliseconds(attempt)); | ||||||
|  |             attempt++; | ||||||
|  |         } | ||||||
|  |         if (response) { | ||||||
|  |             utils_1.displayHttpDiagnostics(response); | ||||||
|  |         } | ||||||
|  |         if (customErrorInformation) { | ||||||
|  |             throw Error(`${name} failed: ${customErrorInformation}`); | ||||||
|  |         } | ||||||
|  |         throw Error(`${name} failed: ${errorMessage}`); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | exports.retry = retry; | ||||||
|  | function retryHttpClientRequest(name, method, customErrorMessages = new Map(), maxAttempts = config_variables_1.getRetryLimit()) { | ||||||
|  |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|  |         return yield retry(name, method, customErrorMessages, maxAttempts); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | exports.retryHttpClientRequest = retryHttpClientRequest; | ||||||
|  | //# sourceMappingURL=requestUtils.js.map
 | ||||||
|  | 
 | ||||||
|  | /***/ }), | ||||||
|  | 
 | ||||||
| /***/ 532: | /***/ 532: | ||||||
| /***/ (function(__unusedmodule, exports, __webpack_require__) { | /***/ (function(__unusedmodule, exports, __webpack_require__) { | ||||||
| 
 | 
 | ||||||
| @ -5408,7 +5491,6 @@ exports.getDownloadSpecification = getDownloadSpecification; | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| Object.defineProperty(exports, "__esModule", { value: true }); | Object.defineProperty(exports, "__esModule", { value: true }); | ||||||
| const url = __webpack_require__(835); |  | ||||||
| const http = __webpack_require__(605); | const http = __webpack_require__(605); | ||||||
| const https = __webpack_require__(211); | const https = __webpack_require__(211); | ||||||
| const pm = __webpack_require__(950); | const pm = __webpack_require__(950); | ||||||
| @ -5457,7 +5539,7 @@ var MediaTypes; | |||||||
|  * @param serverUrl  The server URL where the request will be sent. For example, https://api.github.com
 |  * @param serverUrl  The server URL where the request will be sent. For example, https://api.github.com
 | ||||||
|  */ |  */ | ||||||
| function getProxyUrl(serverUrl) { | function getProxyUrl(serverUrl) { | ||||||
|     let proxyUrl = pm.getProxyUrl(url.parse(serverUrl)); |     let proxyUrl = pm.getProxyUrl(new URL(serverUrl)); | ||||||
|     return proxyUrl ? proxyUrl.href : ''; |     return proxyUrl ? proxyUrl.href : ''; | ||||||
| } | } | ||||||
| exports.getProxyUrl = getProxyUrl; | exports.getProxyUrl = getProxyUrl; | ||||||
| @ -5476,6 +5558,15 @@ const HttpResponseRetryCodes = [ | |||||||
| const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; | const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; | ||||||
| const ExponentialBackoffCeiling = 10; | const ExponentialBackoffCeiling = 10; | ||||||
| const ExponentialBackoffTimeSlice = 5; | const ExponentialBackoffTimeSlice = 5; | ||||||
|  | class HttpClientError extends Error { | ||||||
|  |     constructor(message, statusCode) { | ||||||
|  |         super(message); | ||||||
|  |         this.name = 'HttpClientError'; | ||||||
|  |         this.statusCode = statusCode; | ||||||
|  |         Object.setPrototypeOf(this, HttpClientError.prototype); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | exports.HttpClientError = HttpClientError; | ||||||
| class HttpClientResponse { | class HttpClientResponse { | ||||||
|     constructor(message) { |     constructor(message) { | ||||||
|         this.message = message; |         this.message = message; | ||||||
| @ -5494,7 +5585,7 @@ class HttpClientResponse { | |||||||
| } | } | ||||||
| exports.HttpClientResponse = HttpClientResponse; | exports.HttpClientResponse = HttpClientResponse; | ||||||
| function isHttps(requestUrl) { | function isHttps(requestUrl) { | ||||||
|     let parsedUrl = url.parse(requestUrl); |     let parsedUrl = new URL(requestUrl); | ||||||
|     return parsedUrl.protocol === 'https:'; |     return parsedUrl.protocol === 'https:'; | ||||||
| } | } | ||||||
| exports.isHttps = isHttps; | exports.isHttps = isHttps; | ||||||
| @ -5599,7 +5690,7 @@ class HttpClient { | |||||||
|         if (this._disposed) { |         if (this._disposed) { | ||||||
|             throw new Error('Client has already been disposed.'); |             throw new Error('Client has already been disposed.'); | ||||||
|         } |         } | ||||||
|         let parsedUrl = url.parse(requestUrl); |         let parsedUrl = new URL(requestUrl); | ||||||
|         let info = this._prepareRequest(verb, parsedUrl, headers); |         let info = this._prepareRequest(verb, parsedUrl, headers); | ||||||
|         // Only perform retries on reads since writes may not be idempotent.
 |         // Only perform retries on reads since writes may not be idempotent.
 | ||||||
|         let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1 |         let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1 | ||||||
| @ -5638,7 +5729,7 @@ class HttpClient { | |||||||
|                     // if there's no location to redirect to, we won't
 |                     // if there's no location to redirect to, we won't
 | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 let parsedRedirectUrl = url.parse(redirectUrl); |                 let parsedRedirectUrl = new URL(redirectUrl); | ||||||
|                 if (parsedUrl.protocol == 'https:' && |                 if (parsedUrl.protocol == 'https:' && | ||||||
|                     parsedUrl.protocol != parsedRedirectUrl.protocol && |                     parsedUrl.protocol != parsedRedirectUrl.protocol && | ||||||
|                     !this._allowRedirectDowngrade) { |                     !this._allowRedirectDowngrade) { | ||||||
| @ -5754,7 +5845,7 @@ class HttpClient { | |||||||
|      * @param serverUrl  The server URL where the request will be sent. For example, https://api.github.com
 |      * @param serverUrl  The server URL where the request will be sent. For example, https://api.github.com
 | ||||||
|      */ |      */ | ||||||
|     getAgent(serverUrl) { |     getAgent(serverUrl) { | ||||||
|         let parsedUrl = url.parse(serverUrl); |         let parsedUrl = new URL(serverUrl); | ||||||
|         return this._getAgent(parsedUrl); |         return this._getAgent(parsedUrl); | ||||||
|     } |     } | ||||||
|     _prepareRequest(method, requestUrl, headers) { |     _prepareRequest(method, requestUrl, headers) { | ||||||
| @ -5827,7 +5918,7 @@ class HttpClient { | |||||||
|                 maxSockets: maxSockets, |                 maxSockets: maxSockets, | ||||||
|                 keepAlive: this._keepAlive, |                 keepAlive: this._keepAlive, | ||||||
|                 proxy: { |                 proxy: { | ||||||
|                     proxyAuth: proxyUrl.auth, |                     proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`, | ||||||
|                     host: proxyUrl.hostname, |                     host: proxyUrl.hostname, | ||||||
|                     port: proxyUrl.port |                     port: proxyUrl.port | ||||||
|                 } |                 } | ||||||
| @ -5922,12 +6013,8 @@ class HttpClient { | |||||||
|                 else { |                 else { | ||||||
|                     msg = 'Failed request: (' + statusCode + ')'; |                     msg = 'Failed request: (' + statusCode + ')'; | ||||||
|                 } |                 } | ||||||
|                 let err = new Error(msg); |                 let err = new HttpClientError(msg, statusCode); | ||||||
|                 // attach statusCode and body obj (if available) to the error object
 |                 err.result = response.result; | ||||||
|                 err['statusCode'] = statusCode; |  | ||||||
|                 if (response.result) { |  | ||||||
|                     err['result'] = response.result; |  | ||||||
|                 } |  | ||||||
|                 reject(err); |                 reject(err); | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
| @ -6760,8 +6847,10 @@ const util_1 = __webpack_require__(669); | |||||||
| const url_1 = __webpack_require__(835); | const url_1 = __webpack_require__(835); | ||||||
| const perf_hooks_1 = __webpack_require__(630); | const perf_hooks_1 = __webpack_require__(630); | ||||||
| const status_reporter_1 = __webpack_require__(176); | const status_reporter_1 = __webpack_require__(176); | ||||||
|  | const http_client_1 = __webpack_require__(539); | ||||||
| const http_manager_1 = __webpack_require__(452); | const http_manager_1 = __webpack_require__(452); | ||||||
| const upload_gzip_1 = __webpack_require__(647); | const upload_gzip_1 = __webpack_require__(647); | ||||||
|  | const requestUtils_1 = __webpack_require__(489); | ||||||
| const stat = util_1.promisify(fs.stat); | const stat = util_1.promisify(fs.stat); | ||||||
| class UploadHttpClient { | class UploadHttpClient { | ||||||
|     constructor() { |     constructor() { | ||||||
| @ -6789,20 +6878,22 @@ class UploadHttpClient { | |||||||
|             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 |             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 | ||||||
|             const client = this.uploadHttpManager.getClient(0); |             const client = this.uploadHttpManager.getClient(0); | ||||||
|             const headers = utils_1.getUploadHeaders('application/json', false); |             const headers = utils_1.getUploadHeaders('application/json', false); | ||||||
|             const rawResponse = yield client.post(artifactUrl, data, headers); |             // Extra information to display when a particular HTTP code is returned
 | ||||||
|             const body = yield rawResponse.readBody(); |             // If a 403 is returned when trying to create a file container, the customer has exceeded
 | ||||||
|             if (utils_1.isSuccessStatusCode(rawResponse.message.statusCode) && body) { |  | ||||||
|                 return JSON.parse(body); |  | ||||||
|             } |  | ||||||
|             else if (utils_1.isForbiddenStatusCode(rawResponse.message.statusCode)) { |  | ||||||
|                 // if a 403 is returned when trying to create a file container, the customer has exceeded
 |  | ||||||
|             // their storage quota so no new artifact containers can be created
 |             // their storage quota so no new artifact containers can be created
 | ||||||
|                 throw new Error(`Artifact storage quota has been hit. Unable to upload any new artifacts`); |             const customErrorMessages = new Map([ | ||||||
|             } |                 [ | ||||||
|             else { |                     http_client_1.HttpCodes.Forbidden, | ||||||
|                 utils_1.displayHttpDiagnostics(rawResponse); |                     'Artifact storage quota has been hit. Unable to upload any new artifacts' | ||||||
|                 throw new Error(`Unable to create a container for the artifact ${artifactName} at ${artifactUrl}`); |                 ], | ||||||
|             } |                 [ | ||||||
|  |                     http_client_1.HttpCodes.BadRequest, | ||||||
|  |                     `The artifact name ${artifactName} is not valid. Request URL ${artifactUrl}` | ||||||
|  |                 ] | ||||||
|  |             ]); | ||||||
|  |             const response = yield requestUtils_1.retryHttpClientRequest('Create Artifact Container', () => __awaiter(this, void 0, void 0, function* () { return client.post(artifactUrl, data, headers); }), customErrorMessages); | ||||||
|  |             const body = yield response.readBody(); | ||||||
|  |             return JSON.parse(body); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|     /** |     /** | ||||||
| @ -7026,12 +7117,12 @@ class UploadHttpClient { | |||||||
|                 this.uploadHttpManager.disposeAndReplaceClient(httpClientIndex); |                 this.uploadHttpManager.disposeAndReplaceClient(httpClientIndex); | ||||||
|                 if (retryAfterValue) { |                 if (retryAfterValue) { | ||||||
|                     core.info(`Backoff due to too many requests, retry #${retryCount}. Waiting for ${retryAfterValue} milliseconds before continuing the upload`); |                     core.info(`Backoff due to too many requests, retry #${retryCount}. Waiting for ${retryAfterValue} milliseconds before continuing the upload`); | ||||||
|                     yield new Promise(resolve => setTimeout(resolve, retryAfterValue)); |                     yield utils_1.sleep(retryAfterValue); | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     const backoffTime = utils_1.getExponentialRetryTimeInMilliseconds(retryCount); |                     const backoffTime = utils_1.getExponentialRetryTimeInMilliseconds(retryCount); | ||||||
|                     core.info(`Exponential backoff for retry #${retryCount}. Waiting for ${backoffTime} milliseconds before continuing the upload at offset ${start}`); |                     core.info(`Exponential backoff for retry #${retryCount}. Waiting for ${backoffTime} milliseconds before continuing the upload at offset ${start}`); | ||||||
|                     yield new Promise(resolve => setTimeout(resolve, backoffTime)); |                     yield utils_1.sleep(backoffTime); | ||||||
|                 } |                 } | ||||||
|                 core.info(`Finished backoff for retry #${retryCount}, continuing with upload`); |                 core.info(`Finished backoff for retry #${retryCount}, continuing with upload`); | ||||||
|                 return; |                 return; | ||||||
| @ -7083,7 +7174,6 @@ class UploadHttpClient { | |||||||
|      */ |      */ | ||||||
|     patchArtifactSize(size, artifactName) { |     patchArtifactSize(size, artifactName) { | ||||||
|         return __awaiter(this, void 0, void 0, function* () { |         return __awaiter(this, void 0, void 0, function* () { | ||||||
|             const headers = utils_1.getUploadHeaders('application/json', false); |  | ||||||
|             const resourceUrl = new url_1.URL(utils_1.getArtifactUrl()); |             const resourceUrl = new url_1.URL(utils_1.getArtifactUrl()); | ||||||
|             resourceUrl.searchParams.append('artifactName', artifactName); |             resourceUrl.searchParams.append('artifactName', artifactName); | ||||||
|             const parameters = { Size: size }; |             const parameters = { Size: size }; | ||||||
| @ -7091,19 +7181,18 @@ class UploadHttpClient { | |||||||
|             core.debug(`URL is ${resourceUrl.toString()}`); |             core.debug(`URL is ${resourceUrl.toString()}`); | ||||||
|             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 |             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 | ||||||
|             const client = this.uploadHttpManager.getClient(0); |             const client = this.uploadHttpManager.getClient(0); | ||||||
|             const response = yield client.patch(resourceUrl.toString(), data, headers); |             const headers = utils_1.getUploadHeaders('application/json', false); | ||||||
|             const body = yield response.readBody(); |             // Extra information to display when a particular HTTP code is returned
 | ||||||
|             if (utils_1.isSuccessStatusCode(response.message.statusCode)) { |             const customErrorMessages = new Map([ | ||||||
|  |                 [ | ||||||
|  |                     http_client_1.HttpCodes.NotFound, | ||||||
|  |                     `An Artifact with the name ${artifactName} was not found` | ||||||
|  |                 ] | ||||||
|  |             ]); | ||||||
|  |             // TODO retry for all possible response codes, the artifact upload is pretty much complete so it at all costs we should try to finish this
 | ||||||
|  |             const response = yield requestUtils_1.retryHttpClientRequest('Finalize artifact upload', () => __awaiter(this, void 0, void 0, function* () { return client.patch(resourceUrl.toString(), data, headers); }), customErrorMessages); | ||||||
|  |             yield response.readBody(); | ||||||
|             core.debug(`Artifact ${artifactName} has been successfully uploaded, total size in bytes: ${size}`); |             core.debug(`Artifact ${artifactName} has been successfully uploaded, total size in bytes: ${size}`); | ||||||
|             } |  | ||||||
|             else if (response.message.statusCode === 404) { |  | ||||||
|                 throw new Error(`An Artifact with the name ${artifactName} was not found`); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 utils_1.displayHttpDiagnostics(response); |  | ||||||
|                 core.info(body); |  | ||||||
|                 throw new Error(`Unable to finish uploading artifact ${artifactName} to ${resourceUrl}`); |  | ||||||
|             } |  | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -7523,6 +7612,7 @@ const status_reporter_1 = __webpack_require__(176); | |||||||
| const perf_hooks_1 = __webpack_require__(630); | const perf_hooks_1 = __webpack_require__(630); | ||||||
| const http_manager_1 = __webpack_require__(452); | const http_manager_1 = __webpack_require__(452); | ||||||
| const config_variables_1 = __webpack_require__(401); | const config_variables_1 = __webpack_require__(401); | ||||||
|  | const requestUtils_1 = __webpack_require__(489); | ||||||
| class DownloadHttpClient { | class DownloadHttpClient { | ||||||
|     constructor() { |     constructor() { | ||||||
|         this.downloadHttpManager = new http_manager_1.HttpManager(config_variables_1.getDownloadFileConcurrency(), '@actions/artifact-download'); |         this.downloadHttpManager = new http_manager_1.HttpManager(config_variables_1.getDownloadFileConcurrency(), '@actions/artifact-download'); | ||||||
| @ -7538,13 +7628,9 @@ class DownloadHttpClient { | |||||||
|             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 |             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 | ||||||
|             const client = this.downloadHttpManager.getClient(0); |             const client = this.downloadHttpManager.getClient(0); | ||||||
|             const headers = utils_1.getDownloadHeaders('application/json'); |             const headers = utils_1.getDownloadHeaders('application/json'); | ||||||
|             const response = yield client.get(artifactUrl, headers); |             const response = yield requestUtils_1.retryHttpClientRequest('List Artifacts', () => __awaiter(this, void 0, void 0, function* () { return client.get(artifactUrl, headers); })); | ||||||
|             const body = yield response.readBody(); |             const body = yield response.readBody(); | ||||||
|             if (utils_1.isSuccessStatusCode(response.message.statusCode) && body) { |  | ||||||
|             return JSON.parse(body); |             return JSON.parse(body); | ||||||
|             } |  | ||||||
|             utils_1.displayHttpDiagnostics(response); |  | ||||||
|             throw new Error(`Unable to list artifacts for the run. Resource Url ${artifactUrl}`); |  | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|     /** |     /** | ||||||
| @ -7560,13 +7646,9 @@ class DownloadHttpClient { | |||||||
|             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 |             // use the first client from the httpManager, `keep-alive` is not used so the connection will close immediately
 | ||||||
|             const client = this.downloadHttpManager.getClient(0); |             const client = this.downloadHttpManager.getClient(0); | ||||||
|             const headers = utils_1.getDownloadHeaders('application/json'); |             const headers = utils_1.getDownloadHeaders('application/json'); | ||||||
|             const response = yield client.get(resourceUrl.toString(), headers); |             const response = yield requestUtils_1.retryHttpClientRequest('Get Container Items', () => __awaiter(this, void 0, void 0, function* () { return client.get(resourceUrl.toString(), headers); })); | ||||||
|             const body = yield response.readBody(); |             const body = yield response.readBody(); | ||||||
|             if (utils_1.isSuccessStatusCode(response.message.statusCode) && body) { |  | ||||||
|             return JSON.parse(body); |             return JSON.parse(body); | ||||||
|             } |  | ||||||
|             utils_1.displayHttpDiagnostics(response); |  | ||||||
|             throw new Error(`Unable to get ContainersItems from ${resourceUrl}`); |  | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|     /** |     /** | ||||||
| @ -7616,7 +7698,7 @@ class DownloadHttpClient { | |||||||
|         return __awaiter(this, void 0, void 0, function* () { |         return __awaiter(this, void 0, void 0, function* () { | ||||||
|             let retryCount = 0; |             let retryCount = 0; | ||||||
|             const retryLimit = config_variables_1.getRetryLimit(); |             const retryLimit = config_variables_1.getRetryLimit(); | ||||||
|             const destinationStream = fs.createWriteStream(downloadPath); |             let destinationStream = fs.createWriteStream(downloadPath); | ||||||
|             const headers = utils_1.getDownloadHeaders('application/json', true, true); |             const headers = utils_1.getDownloadHeaders('application/json', true, true); | ||||||
|             // a single GET request is used to download a file
 |             // a single GET request is used to download a file
 | ||||||
|             const makeDownloadRequest = () => __awaiter(this, void 0, void 0, function* () { |             const makeDownloadRequest = () => __awaiter(this, void 0, void 0, function* () { | ||||||
| @ -7641,22 +7723,40 @@ class DownloadHttpClient { | |||||||
|                     if (retryAfterValue) { |                     if (retryAfterValue) { | ||||||
|                         // Back off by waiting the specified time denoted by the retry-after header
 |                         // Back off by waiting the specified time denoted by the retry-after header
 | ||||||
|                         core.info(`Backoff due to too many requests, retry #${retryCount}. Waiting for ${retryAfterValue} milliseconds before continuing the download`); |                         core.info(`Backoff due to too many requests, retry #${retryCount}. Waiting for ${retryAfterValue} milliseconds before continuing the download`); | ||||||
|                         yield new Promise(resolve => setTimeout(resolve, retryAfterValue)); |                         yield utils_1.sleep(retryAfterValue); | ||||||
|                     } |                     } | ||||||
|                     else { |                     else { | ||||||
|                         // Back off using an exponential value that depends on the retry count
 |                         // Back off using an exponential value that depends on the retry count
 | ||||||
|                         const backoffTime = utils_1.getExponentialRetryTimeInMilliseconds(retryCount); |                         const backoffTime = utils_1.getExponentialRetryTimeInMilliseconds(retryCount); | ||||||
|                         core.info(`Exponential backoff for retry #${retryCount}. Waiting for ${backoffTime} milliseconds before continuing the download`); |                         core.info(`Exponential backoff for retry #${retryCount}. Waiting for ${backoffTime} milliseconds before continuing the download`); | ||||||
|                         yield new Promise(resolve => setTimeout(resolve, backoffTime)); |                         yield utils_1.sleep(backoffTime); | ||||||
|                     } |                     } | ||||||
|                     core.info(`Finished backoff for retry #${retryCount}, continuing with download`); |                     core.info(`Finished backoff for retry #${retryCount}, continuing with download`); | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|  |             const isAllBytesReceived = (expected, received) => { | ||||||
|  |                 // be lenient, if any input is missing, assume success, i.e. not truncated
 | ||||||
|  |                 if (!expected || | ||||||
|  |                     !received || | ||||||
|  |                     process.env['ACTIONS_ARTIFACT_SKIP_DOWNLOAD_VALIDATION']) { | ||||||
|  |                     core.info('Skipping download validation.'); | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |                 return parseInt(expected) === received; | ||||||
|  |             }; | ||||||
|  |             const resetDestinationStream = (fileDownloadPath) => __awaiter(this, void 0, void 0, function* () { | ||||||
|  |                 destinationStream.close(); | ||||||
|  |                 yield utils_1.rmFile(fileDownloadPath); | ||||||
|  |                 destinationStream = fs.createWriteStream(fileDownloadPath); | ||||||
|  |             }); | ||||||
|             // keep trying to download a file until a retry limit has been reached
 |             // keep trying to download a file until a retry limit has been reached
 | ||||||
|             while (retryCount <= retryLimit) { |             while (retryCount <= retryLimit) { | ||||||
|                 let response; |                 let response; | ||||||
|                 try { |                 try { | ||||||
|                     response = yield makeDownloadRequest(); |                     response = yield makeDownloadRequest(); | ||||||
|  |                     if (core.isDebug()) { | ||||||
|  |                         utils_1.displayHttpDiagnostics(response); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 catch (error) { |                 catch (error) { | ||||||
|                     // if an error is caught, it is usually indicative of a timeout so retry the download
 |                     // if an error is caught, it is usually indicative of a timeout so retry the download
 | ||||||
| @ -7667,14 +7767,30 @@ class DownloadHttpClient { | |||||||
|                     yield backOff(); |                     yield backOff(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|  |                 let forceRetry = false; | ||||||
|                 if (utils_1.isSuccessStatusCode(response.message.statusCode)) { |                 if (utils_1.isSuccessStatusCode(response.message.statusCode)) { | ||||||
|                     // The body contains the contents of the file however calling response.readBody() causes all the content to be converted to a string
 |                     // The body contains the contents of the file however calling response.readBody() causes all the content to be converted to a string
 | ||||||
|                     // which can cause some gzip encoded data to be lost
 |                     // which can cause some gzip encoded data to be lost
 | ||||||
|                     // Instead of using response.readBody(), response.message is a readableStream that can be directly used to get the raw body contents
 |                     // Instead of using response.readBody(), response.message is a readableStream that can be directly used to get the raw body contents
 | ||||||
|                     return this.pipeResponseToFile(response, destinationStream, isGzip(response.message.headers)); |                     try { | ||||||
|  |                         const isGzipped = isGzip(response.message.headers); | ||||||
|  |                         yield this.pipeResponseToFile(response, destinationStream, isGzipped); | ||||||
|  |                         if (isGzipped || | ||||||
|  |                             isAllBytesReceived(response.message.headers['content-length'], yield utils_1.getFileSize(downloadPath))) { | ||||||
|  |                             return; | ||||||
|                         } |                         } | ||||||
|                 else if (utils_1.isRetryableStatusCode(response.message.statusCode)) { |                         else { | ||||||
|  |                             forceRetry = true; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     catch (error) { | ||||||
|  |                         // retry on error, most likely streams were corrupted
 | ||||||
|  |                         forceRetry = true; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (forceRetry || utils_1.isRetryableStatusCode(response.message.statusCode)) { | ||||||
|                     core.info(`A ${response.message.statusCode} response code has been received while attempting to download an artifact`); |                     core.info(`A ${response.message.statusCode} response code has been received while attempting to download an artifact`); | ||||||
|  |                     resetDestinationStream(downloadPath); | ||||||
|                     // if a throttled status code is received, try to get the retryAfter header value, else differ to standard exponential backoff
 |                     // if a throttled status code is received, try to get the retryAfter header value, else differ to standard exponential backoff
 | ||||||
|                     utils_1.isThrottledStatusCode(response.message.statusCode) |                     utils_1.isThrottledStatusCode(response.message.statusCode) | ||||||
|                         ? yield backOff(utils_1.tryGetRetryAfterValueTimeInMilliseconds(response.message.headers)) |                         ? yield backOff(utils_1.tryGetRetryAfterValueTimeInMilliseconds(response.message.headers)) | ||||||
| @ -7700,24 +7816,40 @@ class DownloadHttpClient { | |||||||
|                 if (isGzip) { |                 if (isGzip) { | ||||||
|                     const gunzip = zlib.createGunzip(); |                     const gunzip = zlib.createGunzip(); | ||||||
|                     response.message |                     response.message | ||||||
|  |                         .on('error', error => { | ||||||
|  |                         core.error(`An error occurred while attempting to read the response stream`); | ||||||
|  |                         gunzip.close(); | ||||||
|  |                         destinationStream.close(); | ||||||
|  |                         reject(error); | ||||||
|  |                     }) | ||||||
|                         .pipe(gunzip) |                         .pipe(gunzip) | ||||||
|  |                         .on('error', error => { | ||||||
|  |                         core.error(`An error occurred while attempting to decompress the response stream`); | ||||||
|  |                         destinationStream.close(); | ||||||
|  |                         reject(error); | ||||||
|  |                     }) | ||||||
|                         .pipe(destinationStream) |                         .pipe(destinationStream) | ||||||
|                         .on('close', () => { |                         .on('close', () => { | ||||||
|                         resolve(); |                         resolve(); | ||||||
|                     }) |                     }) | ||||||
|                         .on('error', error => { |                         .on('error', error => { | ||||||
|                         core.error(`An error has been encountered while decompressing and writing a downloaded file to ${destinationStream.path}`); |                         core.error(`An error occurred while writing a downloaded file to ${destinationStream.path}`); | ||||||
|                         reject(error); |                         reject(error); | ||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     response.message |                     response.message | ||||||
|  |                         .on('error', error => { | ||||||
|  |                         core.error(`An error occurred while attempting to read the response stream`); | ||||||
|  |                         destinationStream.close(); | ||||||
|  |                         reject(error); | ||||||
|  |                     }) | ||||||
|                         .pipe(destinationStream) |                         .pipe(destinationStream) | ||||||
|                         .on('close', () => { |                         .on('close', () => { | ||||||
|                         resolve(); |                         resolve(); | ||||||
|                     }) |                     }) | ||||||
|                         .on('error', error => { |                         .on('error', error => { | ||||||
|                         core.error(`An error has been encountered while writing a downloaded file to ${destinationStream.path}`); |                         core.error(`An error occurred while writing a downloaded file to ${destinationStream.path}`); | ||||||
|                         reject(error); |                         reject(error); | ||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
| @ -8250,6 +8382,20 @@ function createEmptyFilesForArtifact(emptyFilesToCreate) { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
| exports.createEmptyFilesForArtifact = createEmptyFilesForArtifact; | exports.createEmptyFilesForArtifact = createEmptyFilesForArtifact; | ||||||
|  | function getFileSize(filePath) { | ||||||
|  |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|  |         const stats = yield fs_1.promises.stat(filePath); | ||||||
|  |         core_1.debug(`${filePath} size:(${stats.size}) blksize:(${stats.blksize}) blocks:(${stats.blocks})`); | ||||||
|  |         return stats.size; | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | exports.getFileSize = getFileSize; | ||||||
|  | function rmFile(filePath) { | ||||||
|  |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|  |         yield fs_1.promises.unlink(filePath); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | exports.rmFile = rmFile; | ||||||
| function getProperRetention(retentionInput, retentionSetting) { | function getProperRetention(retentionInput, retentionSetting) { | ||||||
|     if (retentionInput < 0) { |     if (retentionInput < 0) { | ||||||
|         throw new Error('Invalid retention, minimum value is 1.'); |         throw new Error('Invalid retention, minimum value is 1.'); | ||||||
| @ -8265,6 +8411,12 @@ function getProperRetention(retentionInput, retentionSetting) { | |||||||
|     return retention; |     return retention; | ||||||
| } | } | ||||||
| exports.getProperRetention = getProperRetention; | exports.getProperRetention = getProperRetention; | ||||||
|  | function sleep(milliseconds) { | ||||||
|  |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|  |         return new Promise(resolve => setTimeout(resolve, milliseconds)); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | exports.sleep = sleep; | ||||||
| //# sourceMappingURL=utils.js.map
 | //# sourceMappingURL=utils.js.map
 | ||||||
| 
 | 
 | ||||||
| /***/ }), | /***/ }), | ||||||
| @ -8583,12 +8735,11 @@ exports.Pattern = Pattern; | |||||||
| /***/ }), | /***/ }), | ||||||
| 
 | 
 | ||||||
| /***/ 950: | /***/ 950: | ||||||
| /***/ (function(__unusedmodule, exports, __webpack_require__) { | /***/ (function(__unusedmodule, exports) { | ||||||
| 
 | 
 | ||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| Object.defineProperty(exports, "__esModule", { value: true }); | Object.defineProperty(exports, "__esModule", { value: true }); | ||||||
| const url = __webpack_require__(835); |  | ||||||
| function getProxyUrl(reqUrl) { | function getProxyUrl(reqUrl) { | ||||||
|     let usingSsl = reqUrl.protocol === 'https:'; |     let usingSsl = reqUrl.protocol === 'https:'; | ||||||
|     let proxyUrl; |     let proxyUrl; | ||||||
| @ -8603,7 +8754,7 @@ function getProxyUrl(reqUrl) { | |||||||
|         proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY']; |         proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY']; | ||||||
|     } |     } | ||||||
|     if (proxyVar) { |     if (proxyVar) { | ||||||
|         proxyUrl = url.parse(proxyVar); |         proxyUrl = new URL(proxyVar); | ||||||
|     } |     } | ||||||
|     return proxyUrl; |     return proxyUrl; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										3369
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3369
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -29,7 +29,7 @@ | |||||||
|   }, |   }, | ||||||
|   "homepage": "https://github.com/actions/upload-artifact#readme", |   "homepage": "https://github.com/actions/upload-artifact#readme", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@actions/artifact": "^0.4.0", |     "@actions/artifact": "^0.5.0", | ||||||
|     "@actions/core": "^1.2.6", |     "@actions/core": "^1.2.6", | ||||||
|     "@actions/glob": "^0.1.0", |     "@actions/glob": "^0.1.0", | ||||||
|     "@actions/io": "^1.0.2" |     "@actions/io": "^1.0.2" | ||||||
| @ -41,10 +41,10 @@ | |||||||
|     "@zeit/ncc": "^0.22.1", |     "@zeit/ncc": "^0.22.1", | ||||||
|     "concurrently": "^5.1.0", |     "concurrently": "^5.1.0", | ||||||
|     "eslint": "^7.4.0", |     "eslint": "^7.4.0", | ||||||
|     "eslint-plugin-github": "^3.4.1", |     "eslint-plugin-github": "^4.1.1", | ||||||
|     "eslint-plugin-jest": "^23.8.2", |     "eslint-plugin-jest": "^23.8.2", | ||||||
|     "glob": "^7.1.6", |     "glob": "^7.1.6", | ||||||
|     "jest": "^26.1.0", |     "jest": "^26.6.3", | ||||||
|     "jest-circus": "^26.1.0", |     "jest-circus": "^26.1.0", | ||||||
|     "prettier": "^2.0.4", |     "prettier": "^2.0.4", | ||||||
|     "ts-jest": "^25.3.1", |     "ts-jest": "^25.3.1", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Konrad Pabjan
						Konrad Pabjan