|
|
@ -27,7 +27,11 @@ exports.create = create;
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
|
|
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
|
|
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
o[k2] = m[k];
|
|
|
|
o[k2] = m[k];
|
|
|
@ -40,7 +44,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -78,9 +82,9 @@ class DefaultArtifactClient {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
core.info(`Starting artifact upload
|
|
|
|
core.info(`Starting artifact upload
|
|
|
|
For more detailed logs during the artifact upload process, enable step-debugging: https://docs.github.com/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging#enabling-step-debug-logging`);
|
|
|
|
For more detailed logs during the artifact upload process, enable step-debugging: https://docs.github.com/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging#enabling-step-debug-logging`);
|
|
|
|
path_and_artifact_name_validation_1.checkArtifactName(name);
|
|
|
|
(0, path_and_artifact_name_validation_1.checkArtifactName)(name);
|
|
|
|
// Get specification for the files being uploaded
|
|
|
|
// Get specification for the files being uploaded
|
|
|
|
const uploadSpecification = upload_specification_1.getUploadSpecification(name, rootDirectory, files);
|
|
|
|
const uploadSpecification = (0, upload_specification_1.getUploadSpecification)(name, rootDirectory, files);
|
|
|
|
const uploadResponse = {
|
|
|
|
const uploadResponse = {
|
|
|
|
artifactName: name,
|
|
|
|
artifactName: name,
|
|
|
|
artifactItems: [],
|
|
|
|
artifactItems: [],
|
|
|
@ -139,20 +143,20 @@ Note: The size of downloaded zips can differ significantly from the reported siz
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const items = yield downloadHttpClient.getContainerItems(artifactToDownload.name, artifactToDownload.fileContainerResourceUrl);
|
|
|
|
const items = yield downloadHttpClient.getContainerItems(artifactToDownload.name, artifactToDownload.fileContainerResourceUrl);
|
|
|
|
if (!path) {
|
|
|
|
if (!path) {
|
|
|
|
path = config_variables_1.getWorkSpaceDirectory();
|
|
|
|
path = (0, config_variables_1.getWorkSpaceDirectory)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path = path_1.normalize(path);
|
|
|
|
path = (0, path_1.normalize)(path);
|
|
|
|
path = path_1.resolve(path);
|
|
|
|
path = (0, path_1.resolve)(path);
|
|
|
|
// During upload, empty directories are rejected by the remote server so there should be no artifacts that consist of only empty directories
|
|
|
|
// During upload, empty directories are rejected by the remote server so there should be no artifacts that consist of only empty directories
|
|
|
|
const downloadSpecification = download_specification_1.getDownloadSpecification(name, items.value, path, (options === null || options === void 0 ? void 0 : options.createArtifactFolder) || false);
|
|
|
|
const downloadSpecification = (0, download_specification_1.getDownloadSpecification)(name, items.value, path, (options === null || options === void 0 ? void 0 : options.createArtifactFolder) || false);
|
|
|
|
if (downloadSpecification.filesToDownload.length === 0) {
|
|
|
|
if (downloadSpecification.filesToDownload.length === 0) {
|
|
|
|
core.info(`No downloadable files were found for the artifact: ${artifactToDownload.name}`);
|
|
|
|
core.info(`No downloadable files were found for the artifact: ${artifactToDownload.name}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
// Create all necessary directories recursively before starting any download
|
|
|
|
// Create all necessary directories recursively before starting any download
|
|
|
|
yield utils_1.createDirectoriesForArtifact(downloadSpecification.directoryStructure);
|
|
|
|
yield (0, utils_1.createDirectoriesForArtifact)(downloadSpecification.directoryStructure);
|
|
|
|
core.info('Directory structure has been setup for the artifact');
|
|
|
|
core.info('Directory structure has been set up for the artifact');
|
|
|
|
yield utils_1.createEmptyFilesForArtifact(downloadSpecification.emptyFilesToCreate);
|
|
|
|
yield (0, utils_1.createEmptyFilesForArtifact)(downloadSpecification.emptyFilesToCreate);
|
|
|
|
yield downloadHttpClient.downloadSingleArtifact(downloadSpecification.filesToDownload);
|
|
|
|
yield downloadHttpClient.downloadSingleArtifact(downloadSpecification.filesToDownload);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
return {
|
|
|
@ -171,10 +175,10 @@ Note: The size of downloaded zips can differ significantly from the reported siz
|
|
|
|
return response;
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!path) {
|
|
|
|
if (!path) {
|
|
|
|
path = config_variables_1.getWorkSpaceDirectory();
|
|
|
|
path = (0, config_variables_1.getWorkSpaceDirectory)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path = path_1.normalize(path);
|
|
|
|
path = (0, path_1.normalize)(path);
|
|
|
|
path = path_1.resolve(path);
|
|
|
|
path = (0, path_1.resolve)(path);
|
|
|
|
let downloadedArtifacts = 0;
|
|
|
|
let downloadedArtifacts = 0;
|
|
|
|
while (downloadedArtifacts < artifacts.count) {
|
|
|
|
while (downloadedArtifacts < artifacts.count) {
|
|
|
|
const currentArtifactToDownload = artifacts.value[downloadedArtifacts];
|
|
|
|
const currentArtifactToDownload = artifacts.value[downloadedArtifacts];
|
|
|
@ -182,13 +186,13 @@ Note: The size of downloaded zips can differ significantly from the reported siz
|
|
|
|
core.info(`starting download of artifact ${currentArtifactToDownload.name} : ${downloadedArtifacts}/${artifacts.count}`);
|
|
|
|
core.info(`starting download of artifact ${currentArtifactToDownload.name} : ${downloadedArtifacts}/${artifacts.count}`);
|
|
|
|
// Get container entries for the specific artifact
|
|
|
|
// Get container entries for the specific artifact
|
|
|
|
const items = yield downloadHttpClient.getContainerItems(currentArtifactToDownload.name, currentArtifactToDownload.fileContainerResourceUrl);
|
|
|
|
const items = yield downloadHttpClient.getContainerItems(currentArtifactToDownload.name, currentArtifactToDownload.fileContainerResourceUrl);
|
|
|
|
const downloadSpecification = download_specification_1.getDownloadSpecification(currentArtifactToDownload.name, items.value, path, true);
|
|
|
|
const downloadSpecification = (0, download_specification_1.getDownloadSpecification)(currentArtifactToDownload.name, items.value, path, true);
|
|
|
|
if (downloadSpecification.filesToDownload.length === 0) {
|
|
|
|
if (downloadSpecification.filesToDownload.length === 0) {
|
|
|
|
core.info(`No downloadable files were found for any artifact ${currentArtifactToDownload.name}`);
|
|
|
|
core.info(`No downloadable files were found for any artifact ${currentArtifactToDownload.name}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
yield utils_1.createDirectoriesForArtifact(downloadSpecification.directoryStructure);
|
|
|
|
yield (0, utils_1.createDirectoriesForArtifact)(downloadSpecification.directoryStructure);
|
|
|
|
yield utils_1.createEmptyFilesForArtifact(downloadSpecification.emptyFilesToCreate);
|
|
|
|
yield (0, utils_1.createEmptyFilesForArtifact)(downloadSpecification.emptyFilesToCreate);
|
|
|
|
yield downloadHttpClient.downloadSingleArtifact(downloadSpecification.filesToDownload);
|
|
|
|
yield downloadHttpClient.downloadSingleArtifact(downloadSpecification.filesToDownload);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
response.push({
|
|
|
|
response.push({
|
|
|
@ -211,7 +215,7 @@ exports.DefaultArtifactClient = DefaultArtifactClient;
|
|
|
|
"use strict";
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
|
exports.getRetentionDays = exports.getWorkSpaceDirectory = exports.getWorkFlowRunId = exports.getRuntimeUrl = exports.getRuntimeToken = exports.getDownloadFileConcurrency = exports.getInitialRetryIntervalInMilliseconds = exports.getRetryMultiplier = exports.getRetryLimit = exports.getUploadChunkSize = exports.getUploadFileConcurrency = void 0;
|
|
|
|
exports.isGhes = exports.getRetentionDays = exports.getWorkSpaceDirectory = exports.getWorkFlowRunId = exports.getRuntimeUrl = exports.getRuntimeToken = exports.getDownloadFileConcurrency = exports.getInitialRetryIntervalInMilliseconds = exports.getRetryMultiplier = exports.getRetryLimit = exports.getUploadChunkSize = exports.getUploadFileConcurrency = void 0;
|
|
|
|
// The number of concurrent uploads that happens at the same time
|
|
|
|
// The number of concurrent uploads that happens at the same time
|
|
|
|
function getUploadFileConcurrency() {
|
|
|
|
function getUploadFileConcurrency() {
|
|
|
|
return 2;
|
|
|
|
return 2;
|
|
|
@ -280,6 +284,11 @@ function getRetentionDays() {
|
|
|
|
return process.env['GITHUB_RETENTION_DAYS'];
|
|
|
|
return process.env['GITHUB_RETENTION_DAYS'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exports.getRetentionDays = getRetentionDays;
|
|
|
|
exports.getRetentionDays = getRetentionDays;
|
|
|
|
|
|
|
|
function isGhes() {
|
|
|
|
|
|
|
|
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
|
|
|
|
|
|
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.isGhes = isGhes;
|
|
|
|
//# sourceMappingURL=config-variables.js.map
|
|
|
|
//# sourceMappingURL=config-variables.js.map
|
|
|
|
|
|
|
|
|
|
|
|
/***/ }),
|
|
|
|
/***/ }),
|
|
|
@ -601,7 +610,11 @@ exports["default"] = CRC64;
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
|
|
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
|
|
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
o[k2] = m[k];
|
|
|
|
o[k2] = m[k];
|
|
|
@ -614,7 +627,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -641,7 +654,7 @@ const config_variables_1 = __nccwpck_require__(2222);
|
|
|
|
const requestUtils_1 = __nccwpck_require__(755);
|
|
|
|
const requestUtils_1 = __nccwpck_require__(755);
|
|
|
|
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((0, config_variables_1.getDownloadFileConcurrency)(), '@actions/artifact-download');
|
|
|
|
// downloads are usually significantly faster than uploads so display status information every second
|
|
|
|
// downloads are usually significantly faster than uploads so display status information every second
|
|
|
|
this.statusReporter = new status_reporter_1.StatusReporter(1000);
|
|
|
|
this.statusReporter = new status_reporter_1.StatusReporter(1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -650,11 +663,11 @@ class DownloadHttpClient {
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
listArtifacts() {
|
|
|
|
listArtifacts() {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
const artifactUrl = utils_1.getArtifactUrl();
|
|
|
|
const artifactUrl = (0, utils_1.getArtifactUrl)();
|
|
|
|
// 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 = (0, utils_1.getDownloadHeaders)('application/json');
|
|
|
|
const response = yield requestUtils_1.retryHttpClientRequest('List Artifacts', () => __awaiter(this, void 0, void 0, function* () { return client.get(artifactUrl, headers); }));
|
|
|
|
const response = yield (0, 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();
|
|
|
|
return JSON.parse(body);
|
|
|
|
return JSON.parse(body);
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -671,8 +684,8 @@ class DownloadHttpClient {
|
|
|
|
resourceUrl.searchParams.append('itemPath', artifactName);
|
|
|
|
resourceUrl.searchParams.append('itemPath', artifactName);
|
|
|
|
// 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 = (0, utils_1.getDownloadHeaders)('application/json');
|
|
|
|
const response = yield requestUtils_1.retryHttpClientRequest('Get Container Items', () => __awaiter(this, void 0, void 0, function* () { return client.get(resourceUrl.toString(), headers); }));
|
|
|
|
const response = yield (0, 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();
|
|
|
|
return JSON.parse(body);
|
|
|
|
return JSON.parse(body);
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -683,7 +696,7 @@ class DownloadHttpClient {
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
downloadSingleArtifact(downloadItems) {
|
|
|
|
downloadSingleArtifact(downloadItems) {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
const DOWNLOAD_CONCURRENCY = config_variables_1.getDownloadFileConcurrency();
|
|
|
|
const DOWNLOAD_CONCURRENCY = (0, config_variables_1.getDownloadFileConcurrency)();
|
|
|
|
// limit the number of files downloaded at a single time
|
|
|
|
// limit the number of files downloaded at a single time
|
|
|
|
core.debug(`Download file concurrency is set to ${DOWNLOAD_CONCURRENCY}`);
|
|
|
|
core.debug(`Download file concurrency is set to ${DOWNLOAD_CONCURRENCY}`);
|
|
|
|
const parallelDownloads = [...new Array(DOWNLOAD_CONCURRENCY).keys()];
|
|
|
|
const parallelDownloads = [...new Array(DOWNLOAD_CONCURRENCY).keys()];
|
|
|
@ -723,9 +736,9 @@ class DownloadHttpClient {
|
|
|
|
downloadIndividualFile(httpClientIndex, artifactLocation, downloadPath) {
|
|
|
|
downloadIndividualFile(httpClientIndex, artifactLocation, downloadPath) {
|
|
|
|
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 = (0, config_variables_1.getRetryLimit)();
|
|
|
|
let destinationStream = fs.createWriteStream(downloadPath);
|
|
|
|
let destinationStream = fs.createWriteStream(downloadPath);
|
|
|
|
const headers = utils_1.getDownloadHeaders('application/json', true, true);
|
|
|
|
const headers = (0, 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* () {
|
|
|
|
const client = this.downloadHttpManager.getClient(httpClientIndex);
|
|
|
|
const client = this.downloadHttpManager.getClient(httpClientIndex);
|
|
|
@ -749,13 +762,13 @@ 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 utils_1.sleep(retryAfterValue);
|
|
|
|
yield (0, 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 = (0, 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 utils_1.sleep(backoffTime);
|
|
|
|
yield (0, utils_1.sleep)(backoffTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
core.info(`Finished backoff for retry #${retryCount}, continuing with download`);
|
|
|
|
core.info(`Finished backoff for retry #${retryCount}, continuing with download`);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -779,7 +792,7 @@ class DownloadHttpClient {
|
|
|
|
resolve();
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
yield utils_1.rmFile(fileDownloadPath);
|
|
|
|
yield (0, utils_1.rmFile)(fileDownloadPath);
|
|
|
|
destinationStream = fs.createWriteStream(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
|
|
|
@ -798,7 +811,7 @@ class DownloadHttpClient {
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let forceRetry = false;
|
|
|
|
let forceRetry = false;
|
|
|
|
if (utils_1.isSuccessStatusCode(response.message.statusCode)) {
|
|
|
|
if ((0, 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
|
|
|
@ -806,7 +819,7 @@ class DownloadHttpClient {
|
|
|
|
const isGzipped = isGzip(response.message.headers);
|
|
|
|
const isGzipped = isGzip(response.message.headers);
|
|
|
|
yield this.pipeResponseToFile(response, destinationStream, isGzipped);
|
|
|
|
yield this.pipeResponseToFile(response, destinationStream, isGzipped);
|
|
|
|
if (isGzipped ||
|
|
|
|
if (isGzipped ||
|
|
|
|
isAllBytesReceived(response.message.headers['content-length'], yield utils_1.getFileSize(downloadPath))) {
|
|
|
|
isAllBytesReceived(response.message.headers['content-length'], yield (0, utils_1.getFileSize)(downloadPath))) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
@ -818,17 +831,17 @@ class DownloadHttpClient {
|
|
|
|
forceRetry = true;
|
|
|
|
forceRetry = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (forceRetry || utils_1.isRetryableStatusCode(response.message.statusCode)) {
|
|
|
|
if (forceRetry || (0, 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);
|
|
|
|
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)
|
|
|
|
(0, utils_1.isThrottledStatusCode)(response.message.statusCode)
|
|
|
|
? yield backOff(utils_1.tryGetRetryAfterValueTimeInMilliseconds(response.message.headers))
|
|
|
|
? yield backOff((0, utils_1.tryGetRetryAfterValueTimeInMilliseconds)(response.message.headers))
|
|
|
|
: yield backOff();
|
|
|
|
: yield backOff();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
// Some unexpected response code, fail immediately and stop the download
|
|
|
|
// Some unexpected response code, fail immediately and stop the download
|
|
|
|
utils_1.displayHttpDiagnostics(response);
|
|
|
|
(0, utils_1.displayHttpDiagnostics)(response);
|
|
|
|
return Promise.reject(new Error(`Unexpected http ${response.message.statusCode} during download for ${artifactLocation}`));
|
|
|
|
return Promise.reject(new Error(`Unexpected http ${response.message.statusCode} during download for ${artifactLocation}`));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -847,14 +860,14 @@ class DownloadHttpClient {
|
|
|
|
const gunzip = zlib.createGunzip();
|
|
|
|
const gunzip = zlib.createGunzip();
|
|
|
|
response.message
|
|
|
|
response.message
|
|
|
|
.on('error', error => {
|
|
|
|
.on('error', error => {
|
|
|
|
core.error(`An error occurred while attempting to read the response stream`);
|
|
|
|
core.info(`An error occurred while attempting to read the response stream`);
|
|
|
|
gunzip.close();
|
|
|
|
gunzip.close();
|
|
|
|
destinationStream.close();
|
|
|
|
destinationStream.close();
|
|
|
|
reject(error);
|
|
|
|
reject(error);
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.pipe(gunzip)
|
|
|
|
.pipe(gunzip)
|
|
|
|
.on('error', error => {
|
|
|
|
.on('error', error => {
|
|
|
|
core.error(`An error occurred while attempting to decompress the response stream`);
|
|
|
|
core.info(`An error occurred while attempting to decompress the response stream`);
|
|
|
|
destinationStream.close();
|
|
|
|
destinationStream.close();
|
|
|
|
reject(error);
|
|
|
|
reject(error);
|
|
|
|
})
|
|
|
|
})
|
|
|
@ -863,14 +876,14 @@ class DownloadHttpClient {
|
|
|
|
resolve();
|
|
|
|
resolve();
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.on('error', error => {
|
|
|
|
.on('error', error => {
|
|
|
|
core.error(`An error occurred while writing a downloaded file to ${destinationStream.path}`);
|
|
|
|
core.info(`An error occurred while writing a downloaded file to ${destinationStream.path}`);
|
|
|
|
reject(error);
|
|
|
|
reject(error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
response.message
|
|
|
|
response.message
|
|
|
|
.on('error', error => {
|
|
|
|
.on('error', error => {
|
|
|
|
core.error(`An error occurred while attempting to read the response stream`);
|
|
|
|
core.info(`An error occurred while attempting to read the response stream`);
|
|
|
|
destinationStream.close();
|
|
|
|
destinationStream.close();
|
|
|
|
reject(error);
|
|
|
|
reject(error);
|
|
|
|
})
|
|
|
|
})
|
|
|
@ -879,7 +892,7 @@ class DownloadHttpClient {
|
|
|
|
resolve();
|
|
|
|
resolve();
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.on('error', error => {
|
|
|
|
.on('error', error => {
|
|
|
|
core.error(`An error occurred while writing a downloaded file to ${destinationStream.path}`);
|
|
|
|
core.info(`An error occurred while writing a downloaded file to ${destinationStream.path}`);
|
|
|
|
reject(error);
|
|
|
|
reject(error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -900,7 +913,11 @@ exports.DownloadHttpClient = DownloadHttpClient;
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
|
|
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
|
|
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
o[k2] = m[k];
|
|
|
|
o[k2] = m[k];
|
|
|
@ -913,7 +930,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -991,7 +1008,7 @@ class HttpManager {
|
|
|
|
throw new Error('There must be at least one client');
|
|
|
|
throw new Error('There must be at least one client');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.userAgent = userAgent;
|
|
|
|
this.userAgent = userAgent;
|
|
|
|
this.clients = new Array(clientCount).fill(utils_1.createHttpClient(userAgent));
|
|
|
|
this.clients = new Array(clientCount).fill((0, utils_1.createHttpClient)(userAgent));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getClient(index) {
|
|
|
|
getClient(index) {
|
|
|
|
return this.clients[index];
|
|
|
|
return this.clients[index];
|
|
|
@ -1000,7 +1017,7 @@ class HttpManager {
|
|
|
|
// for more information see: https://github.com/actions/http-client/blob/04e5ad73cd3fd1f5610a32116b0759eddf6570d2/index.ts#L292
|
|
|
|
// for more information see: https://github.com/actions/http-client/blob/04e5ad73cd3fd1f5610a32116b0759eddf6570d2/index.ts#L292
|
|
|
|
disposeAndReplaceClient(index) {
|
|
|
|
disposeAndReplaceClient(index) {
|
|
|
|
this.clients[index].dispose();
|
|
|
|
this.clients[index].dispose();
|
|
|
|
this.clients[index] = utils_1.createHttpClient(this.userAgent);
|
|
|
|
this.clients[index] = (0, utils_1.createHttpClient)(this.userAgent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
disposeAndReplaceAllClients() {
|
|
|
|
disposeAndReplaceAllClients() {
|
|
|
|
for (const [index] of this.clients.entries()) {
|
|
|
|
for (const [index] of this.clients.entries()) {
|
|
|
@ -1061,7 +1078,7 @@ Invalid characters include: ${Array.from(invalidArtifactNameCharacters.values())
|
|
|
|
These characters are not allowed in the artifact name due to limitations with certain file systems such as NTFS. To maintain file system agnostic behavior, these characters are intentionally not allowed to prevent potential problems with downloads on different file systems.`);
|
|
|
|
These characters are not allowed in the artifact name due to limitations with certain file systems such as NTFS. To maintain file system agnostic behavior, these characters are intentionally not allowed to prevent potential problems with downloads on different file systems.`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
core_1.info(`Artifact name is valid!`);
|
|
|
|
(0, core_1.info)(`Artifact name is valid!`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exports.checkArtifactName = checkArtifactName;
|
|
|
|
exports.checkArtifactName = checkArtifactName;
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -1094,7 +1111,11 @@ exports.checkArtifactFilePath = checkArtifactFilePath;
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
|
|
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
|
|
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
o[k2] = m[k];
|
|
|
|
o[k2] = m[k];
|
|
|
@ -1107,7 +1128,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -1137,14 +1158,14 @@ function retry(name, operation, customErrorMessages, maxAttempts) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
response = yield operation();
|
|
|
|
response = yield operation();
|
|
|
|
statusCode = response.message.statusCode;
|
|
|
|
statusCode = response.message.statusCode;
|
|
|
|
if (utils_1.isSuccessStatusCode(statusCode)) {
|
|
|
|
if ((0, utils_1.isSuccessStatusCode)(statusCode)) {
|
|
|
|
return response;
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Extra error information that we want to display if a particular response code is hit
|
|
|
|
// Extra error information that we want to display if a particular response code is hit
|
|
|
|
if (statusCode) {
|
|
|
|
if (statusCode) {
|
|
|
|
customErrorInformation = customErrorMessages.get(statusCode);
|
|
|
|
customErrorInformation = customErrorMessages.get(statusCode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
isRetryable = utils_1.isRetryableStatusCode(statusCode);
|
|
|
|
isRetryable = (0, utils_1.isRetryableStatusCode)(statusCode);
|
|
|
|
errorMessage = `Artifact service responded with ${statusCode}`;
|
|
|
|
errorMessage = `Artifact service responded with ${statusCode}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (error) {
|
|
|
|
catch (error) {
|
|
|
@ -1154,16 +1175,16 @@ function retry(name, operation, customErrorMessages, maxAttempts) {
|
|
|
|
if (!isRetryable) {
|
|
|
|
if (!isRetryable) {
|
|
|
|
core.info(`${name} - Error is not retryable`);
|
|
|
|
core.info(`${name} - Error is not retryable`);
|
|
|
|
if (response) {
|
|
|
|
if (response) {
|
|
|
|
utils_1.displayHttpDiagnostics(response);
|
|
|
|
(0, utils_1.displayHttpDiagnostics)(response);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
core.info(`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`);
|
|
|
|
core.info(`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`);
|
|
|
|
yield utils_1.sleep(utils_1.getExponentialRetryTimeInMilliseconds(attempt));
|
|
|
|
yield (0, utils_1.sleep)((0, utils_1.getExponentialRetryTimeInMilliseconds)(attempt));
|
|
|
|
attempt++;
|
|
|
|
attempt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (response) {
|
|
|
|
if (response) {
|
|
|
|
utils_1.displayHttpDiagnostics(response);
|
|
|
|
(0, utils_1.displayHttpDiagnostics)(response);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (customErrorInformation) {
|
|
|
|
if (customErrorInformation) {
|
|
|
|
throw Error(`${name} failed: ${customErrorInformation}`);
|
|
|
|
throw Error(`${name} failed: ${customErrorInformation}`);
|
|
|
@ -1172,7 +1193,7 @@ function retry(name, operation, customErrorMessages, maxAttempts) {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exports.retry = retry;
|
|
|
|
exports.retry = retry;
|
|
|
|
function retryHttpClientRequest(name, method, customErrorMessages = new Map(), maxAttempts = config_variables_1.getRetryLimit()) {
|
|
|
|
function retryHttpClientRequest(name, method, customErrorMessages = new Map(), maxAttempts = (0, config_variables_1.getRetryLimit)()) {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return yield retry(name, method, customErrorMessages, maxAttempts);
|
|
|
|
return yield retry(name, method, customErrorMessages, maxAttempts);
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -1214,14 +1235,14 @@ class StatusReporter {
|
|
|
|
this.totalFileStatus = setInterval(() => {
|
|
|
|
this.totalFileStatus = setInterval(() => {
|
|
|
|
// display 1 decimal place without any rounding
|
|
|
|
// display 1 decimal place without any rounding
|
|
|
|
const percentage = this.formatPercentage(this.processedCount, this.totalNumberOfFilesToProcess);
|
|
|
|
const percentage = this.formatPercentage(this.processedCount, this.totalNumberOfFilesToProcess);
|
|
|
|
core_1.info(`Total file count: ${this.totalNumberOfFilesToProcess} ---- Processed file #${this.processedCount} (${percentage.slice(0, percentage.indexOf('.') + 2)}%)`);
|
|
|
|
(0, core_1.info)(`Total file count: ${this.totalNumberOfFilesToProcess} ---- Processed file #${this.processedCount} (${percentage.slice(0, percentage.indexOf('.') + 2)}%)`);
|
|
|
|
}, this.displayFrequencyInMilliseconds);
|
|
|
|
}, this.displayFrequencyInMilliseconds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if there is a large file that is being uploaded in chunks, this is used to display extra information about the status of the upload
|
|
|
|
// if there is a large file that is being uploaded in chunks, this is used to display extra information about the status of the upload
|
|
|
|
updateLargeFileStatus(fileName, chunkStartIndex, chunkEndIndex, totalUploadFileSize) {
|
|
|
|
updateLargeFileStatus(fileName, chunkStartIndex, chunkEndIndex, totalUploadFileSize) {
|
|
|
|
// display 1 decimal place without any rounding
|
|
|
|
// display 1 decimal place without any rounding
|
|
|
|
const percentage = this.formatPercentage(chunkEndIndex, totalUploadFileSize);
|
|
|
|
const percentage = this.formatPercentage(chunkEndIndex, totalUploadFileSize);
|
|
|
|
core_1.info(`Uploaded ${fileName} (${percentage.slice(0, percentage.indexOf('.') + 2)}%) bytes ${chunkStartIndex}:${chunkEndIndex}`);
|
|
|
|
(0, core_1.info)(`Uploaded ${fileName} (${percentage.slice(0, percentage.indexOf('.') + 2)}%) bytes ${chunkStartIndex}:${chunkEndIndex}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stop() {
|
|
|
|
stop() {
|
|
|
|
if (this.totalFileStatus) {
|
|
|
|
if (this.totalFileStatus) {
|
|
|
@ -1248,7 +1269,11 @@ exports.StatusReporter = StatusReporter;
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
|
|
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
|
|
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
o[k2] = m[k];
|
|
|
|
o[k2] = m[k];
|
|
|
@ -1261,7 +1286,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -1286,19 +1311,34 @@ exports.createGZipFileInBuffer = exports.createGZipFileOnDisk = void 0;
|
|
|
|
const fs = __importStar(__nccwpck_require__(7147));
|
|
|
|
const fs = __importStar(__nccwpck_require__(7147));
|
|
|
|
const zlib = __importStar(__nccwpck_require__(9796));
|
|
|
|
const zlib = __importStar(__nccwpck_require__(9796));
|
|
|
|
const util_1 = __nccwpck_require__(3837);
|
|
|
|
const util_1 = __nccwpck_require__(3837);
|
|
|
|
const stat = util_1.promisify(fs.stat);
|
|
|
|
const stat = (0, util_1.promisify)(fs.stat);
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* GZipping certain files that are already compressed will likely not yield further size reductions. Creating large temporary gzip
|
|
|
|
* GZipping certain files that are already compressed will likely not yield further size reductions. Creating large temporary gzip
|
|
|
|
* files then will just waste a lot of time before ultimately being discarded (especially for very large files).
|
|
|
|
* files then will just waste a lot of time before ultimately being discarded (especially for very large files).
|
|
|
|
* If any of these types of files are encountered then on-disk gzip creation will be skipped and the original file will be uploaded as-is
|
|
|
|
* If any of these types of files are encountered then on-disk gzip creation will be skipped and the original file will be uploaded as-is
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
const gzipExemptFileExtensions = [
|
|
|
|
const gzipExemptFileExtensions = [
|
|
|
|
|
|
|
|
'.gz',
|
|
|
|
'.gzip',
|
|
|
|
'.gzip',
|
|
|
|
|
|
|
|
'.tgz',
|
|
|
|
|
|
|
|
'.taz',
|
|
|
|
|
|
|
|
'.Z',
|
|
|
|
|
|
|
|
'.taZ',
|
|
|
|
|
|
|
|
'.bz2',
|
|
|
|
|
|
|
|
'.tbz',
|
|
|
|
|
|
|
|
'.tbz2',
|
|
|
|
|
|
|
|
'.tz2',
|
|
|
|
|
|
|
|
'.lz',
|
|
|
|
|
|
|
|
'.lzma',
|
|
|
|
|
|
|
|
'.tlz',
|
|
|
|
|
|
|
|
'.lzo',
|
|
|
|
|
|
|
|
'.xz',
|
|
|
|
|
|
|
|
'.txz',
|
|
|
|
|
|
|
|
'.zst',
|
|
|
|
|
|
|
|
'.zstd',
|
|
|
|
|
|
|
|
'.tzst',
|
|
|
|
'.zip',
|
|
|
|
'.zip',
|
|
|
|
'.tar.lz',
|
|
|
|
'.7z' // 7ZIP
|
|
|
|
'.tar.gz',
|
|
|
|
|
|
|
|
'.tar.bz2',
|
|
|
|
|
|
|
|
'.7z'
|
|
|
|
|
|
|
|
];
|
|
|
|
];
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Creates a Gzip compressed file of an original file at the provided temporary filepath location
|
|
|
|
* Creates a Gzip compressed file of an original file at the provided temporary filepath location
|
|
|
@ -1327,7 +1367,7 @@ function createGZipFileOnDisk(originalFilePath, tempFilePath) {
|
|
|
|
outputStream.on('error', error => {
|
|
|
|
outputStream.on('error', error => {
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.log(error);
|
|
|
|
console.log(error);
|
|
|
|
reject;
|
|
|
|
reject(error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -1341,22 +1381,29 @@ exports.createGZipFileOnDisk = createGZipFileOnDisk;
|
|
|
|
function createGZipFileInBuffer(originalFilePath) {
|
|
|
|
function createGZipFileInBuffer(originalFilePath) {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
|
|
var e_1, _a;
|
|
|
|
var _a, e_1, _b, _c;
|
|
|
|
const inputStream = fs.createReadStream(originalFilePath);
|
|
|
|
const inputStream = fs.createReadStream(originalFilePath);
|
|
|
|
const gzip = zlib.createGzip();
|
|
|
|
const gzip = zlib.createGzip();
|
|
|
|
inputStream.pipe(gzip);
|
|
|
|
inputStream.pipe(gzip);
|
|
|
|
// read stream into buffer, using experimental async iterators see https://github.com/nodejs/readable-stream/issues/403#issuecomment-479069043
|
|
|
|
// read stream into buffer, using experimental async iterators see https://github.com/nodejs/readable-stream/issues/403#issuecomment-479069043
|
|
|
|
const chunks = [];
|
|
|
|
const chunks = [];
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
for (var gzip_1 = __asyncValues(gzip), gzip_1_1; gzip_1_1 = yield gzip_1.next(), !gzip_1_1.done;) {
|
|
|
|
for (var _d = true, gzip_1 = __asyncValues(gzip), gzip_1_1; gzip_1_1 = yield gzip_1.next(), _a = gzip_1_1.done, !_a;) {
|
|
|
|
const chunk = gzip_1_1.value;
|
|
|
|
_c = gzip_1_1.value;
|
|
|
|
chunks.push(chunk);
|
|
|
|
_d = false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const chunk = _c;
|
|
|
|
|
|
|
|
chunks.push(chunk);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
finally {
|
|
|
|
|
|
|
|
_d = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
|
|
finally {
|
|
|
|
finally {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
if (gzip_1_1 && !gzip_1_1.done && (_a = gzip_1.return)) yield _a.call(gzip_1);
|
|
|
|
if (!_d && !_a && (_b = gzip_1.return)) yield _b.call(gzip_1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
finally { if (e_1) throw e_1.error; }
|
|
|
|
finally { if (e_1) throw e_1.error; }
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1376,7 +1423,11 @@ exports.createGZipFileInBuffer = createGZipFileInBuffer;
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
|
|
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
|
|
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
o[k2] = m[k];
|
|
|
|
o[k2] = m[k];
|
|
|
@ -1389,7 +1440,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -1418,10 +1469,10 @@ const http_client_1 = __nccwpck_require__(6255);
|
|
|
|
const http_manager_1 = __nccwpck_require__(6527);
|
|
|
|
const http_manager_1 = __nccwpck_require__(6527);
|
|
|
|
const upload_gzip_1 = __nccwpck_require__(606);
|
|
|
|
const upload_gzip_1 = __nccwpck_require__(606);
|
|
|
|
const requestUtils_1 = __nccwpck_require__(755);
|
|
|
|
const requestUtils_1 = __nccwpck_require__(755);
|
|
|
|
const stat = util_1.promisify(fs.stat);
|
|
|
|
const stat = (0, util_1.promisify)(fs.stat);
|
|
|
|
class UploadHttpClient {
|
|
|
|
class UploadHttpClient {
|
|
|
|
constructor() {
|
|
|
|
constructor() {
|
|
|
|
this.uploadHttpManager = new http_manager_1.HttpManager(config_variables_1.getUploadFileConcurrency(), '@actions/artifact-upload');
|
|
|
|
this.uploadHttpManager = new http_manager_1.HttpManager((0, config_variables_1.getUploadFileConcurrency)(), '@actions/artifact-upload');
|
|
|
|
this.statusReporter = new status_reporter_1.StatusReporter(10000);
|
|
|
|
this.statusReporter = new status_reporter_1.StatusReporter(10000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -1437,28 +1488,30 @@ class UploadHttpClient {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
// calculate retention period
|
|
|
|
// calculate retention period
|
|
|
|
if (options && options.retentionDays) {
|
|
|
|
if (options && options.retentionDays) {
|
|
|
|
const maxRetentionStr = config_variables_1.getRetentionDays();
|
|
|
|
const maxRetentionStr = (0, config_variables_1.getRetentionDays)();
|
|
|
|
parameters.RetentionDays = utils_1.getProperRetention(options.retentionDays, maxRetentionStr);
|
|
|
|
parameters.RetentionDays = (0, utils_1.getProperRetention)(options.retentionDays, maxRetentionStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const data = JSON.stringify(parameters, null, 2);
|
|
|
|
const data = JSON.stringify(parameters, null, 2);
|
|
|
|
const artifactUrl = utils_1.getArtifactUrl();
|
|
|
|
const artifactUrl = (0, utils_1.getArtifactUrl)();
|
|
|
|
// 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 = (0, utils_1.getUploadHeaders)('application/json', false);
|
|
|
|
// Extra information to display when a particular HTTP code is returned
|
|
|
|
// Extra information to display when a particular HTTP code is returned
|
|
|
|
// If a 403 is returned when trying to create a file container, the customer has exceeded
|
|
|
|
// 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
|
|
|
|
const customErrorMessages = new Map([
|
|
|
|
const customErrorMessages = new Map([
|
|
|
|
[
|
|
|
|
[
|
|
|
|
http_client_1.HttpCodes.Forbidden,
|
|
|
|
http_client_1.HttpCodes.Forbidden,
|
|
|
|
'Artifact storage quota has been hit. Unable to upload any new artifacts'
|
|
|
|
(0, config_variables_1.isGhes)()
|
|
|
|
|
|
|
|
? 'Please reference [Enabling GitHub Actions for GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@3.8/admin/github-actions/enabling-github-actions-for-github-enterprise-server) to ensure Actions storage is configured correctly.'
|
|
|
|
|
|
|
|
: 'Artifact storage quota has been hit. Unable to upload any new artifacts'
|
|
|
|
],
|
|
|
|
],
|
|
|
|
[
|
|
|
|
[
|
|
|
|
http_client_1.HttpCodes.BadRequest,
|
|
|
|
http_client_1.HttpCodes.BadRequest,
|
|
|
|
`The artifact name ${artifactName} is not valid. Request URL ${artifactUrl}`
|
|
|
|
`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 response = yield (0, 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();
|
|
|
|
const body = yield response.readBody();
|
|
|
|
return JSON.parse(body);
|
|
|
|
return JSON.parse(body);
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -1471,8 +1524,8 @@ class UploadHttpClient {
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
uploadArtifactToFileContainer(uploadUrl, filesToUpload, options) {
|
|
|
|
uploadArtifactToFileContainer(uploadUrl, filesToUpload, options) {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
const FILE_CONCURRENCY = config_variables_1.getUploadFileConcurrency();
|
|
|
|
const FILE_CONCURRENCY = (0, config_variables_1.getUploadFileConcurrency)();
|
|
|
|
const MAX_CHUNK_SIZE = config_variables_1.getUploadChunkSize();
|
|
|
|
const MAX_CHUNK_SIZE = (0, config_variables_1.getUploadChunkSize)();
|
|
|
|
core.debug(`File Concurrency: ${FILE_CONCURRENCY}, and Chunk Size: ${MAX_CHUNK_SIZE}`);
|
|
|
|
core.debug(`File Concurrency: ${FILE_CONCURRENCY}, and Chunk Size: ${MAX_CHUNK_SIZE}`);
|
|
|
|
const parameters = [];
|
|
|
|
const parameters = [];
|
|
|
|
// by default, file uploads will continue if there is an error unless specified differently in the options
|
|
|
|
// by default, file uploads will continue if there is an error unless specified differently in the options
|
|
|
@ -1562,7 +1615,7 @@ class UploadHttpClient {
|
|
|
|
// with named pipes the file size is reported as zero in that case don't read the file in memory
|
|
|
|
// with named pipes the file size is reported as zero in that case don't read the file in memory
|
|
|
|
if (!isFIFO && totalFileSize < 65536) {
|
|
|
|
if (!isFIFO && totalFileSize < 65536) {
|
|
|
|
core.debug(`${parameters.file} is less than 64k in size. Creating a gzip file in-memory to potentially reduce the upload size`);
|
|
|
|
core.debug(`${parameters.file} is less than 64k in size. Creating a gzip file in-memory to potentially reduce the upload size`);
|
|
|
|
const buffer = yield upload_gzip_1.createGZipFileInBuffer(parameters.file);
|
|
|
|
const buffer = yield (0, upload_gzip_1.createGZipFileInBuffer)(parameters.file);
|
|
|
|
// An open stream is needed in the event of a failure and we need to retry. If a NodeJS.ReadableStream is directly passed in,
|
|
|
|
// An open stream is needed in the event of a failure and we need to retry. If a NodeJS.ReadableStream is directly passed in,
|
|
|
|
// it will not properly get reset to the start of the stream if a chunk upload needs to be retried
|
|
|
|
// it will not properly get reset to the start of the stream if a chunk upload needs to be retried
|
|
|
|
let openUploadStream;
|
|
|
|
let openUploadStream;
|
|
|
@ -1602,7 +1655,7 @@ class UploadHttpClient {
|
|
|
|
const tempFile = yield tmp.file();
|
|
|
|
const tempFile = yield tmp.file();
|
|
|
|
core.debug(`${parameters.file} is greater than 64k in size. Creating a gzip file on-disk ${tempFile.path} to potentially reduce the upload size`);
|
|
|
|
core.debug(`${parameters.file} is greater than 64k in size. Creating a gzip file on-disk ${tempFile.path} to potentially reduce the upload size`);
|
|
|
|
// create a GZip file of the original file being uploaded, the original file should not be modified in any way
|
|
|
|
// create a GZip file of the original file being uploaded, the original file should not be modified in any way
|
|
|
|
uploadFileSize = yield upload_gzip_1.createGZipFileOnDisk(parameters.file, tempFile.path);
|
|
|
|
uploadFileSize = yield (0, upload_gzip_1.createGZipFileOnDisk)(parameters.file, tempFile.path);
|
|
|
|
let uploadFilePath = tempFile.path;
|
|
|
|
let uploadFilePath = tempFile.path;
|
|
|
|
// compression did not help with size reduction, use the original file for upload and delete the temp GZip file
|
|
|
|
// compression did not help with size reduction, use the original file for upload and delete the temp GZip file
|
|
|
|
// for named pipes totalFileSize is zero, this assumes compression did help
|
|
|
|
// for named pipes totalFileSize is zero, this assumes compression did help
|
|
|
@ -1675,22 +1728,22 @@ class UploadHttpClient {
|
|
|
|
uploadChunk(httpClientIndex, resourceUrl, openStream, start, end, uploadFileSize, isGzip, totalFileSize) {
|
|
|
|
uploadChunk(httpClientIndex, resourceUrl, openStream, start, end, uploadFileSize, isGzip, totalFileSize) {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
// open a new stream and read it to compute the digest
|
|
|
|
// open a new stream and read it to compute the digest
|
|
|
|
const digest = yield utils_1.digestForStream(openStream());
|
|
|
|
const digest = yield (0, utils_1.digestForStream)(openStream());
|
|
|
|
// prepare all the necessary headers before making any http call
|
|
|
|
// prepare all the necessary headers before making any http call
|
|
|
|
const headers = utils_1.getUploadHeaders('application/octet-stream', true, isGzip, totalFileSize, end - start + 1, utils_1.getContentRange(start, end, uploadFileSize), digest);
|
|
|
|
const headers = (0, utils_1.getUploadHeaders)('application/octet-stream', true, isGzip, totalFileSize, end - start + 1, (0, utils_1.getContentRange)(start, end, uploadFileSize), digest);
|
|
|
|
const uploadChunkRequest = () => __awaiter(this, void 0, void 0, function* () {
|
|
|
|
const uploadChunkRequest = () => __awaiter(this, void 0, void 0, function* () {
|
|
|
|
const client = this.uploadHttpManager.getClient(httpClientIndex);
|
|
|
|
const client = this.uploadHttpManager.getClient(httpClientIndex);
|
|
|
|
return yield client.sendStream('PUT', resourceUrl, openStream(), headers);
|
|
|
|
return yield client.sendStream('PUT', resourceUrl, openStream(), headers);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
let retryCount = 0;
|
|
|
|
let retryCount = 0;
|
|
|
|
const retryLimit = config_variables_1.getRetryLimit();
|
|
|
|
const retryLimit = (0, config_variables_1.getRetryLimit)();
|
|
|
|
// Increments the current retry count and then checks if the retry limit has been reached
|
|
|
|
// Increments the current retry count and then checks if the retry limit has been reached
|
|
|
|
// If there have been too many retries, fail so the download stops
|
|
|
|
// If there have been too many retries, fail so the download stops
|
|
|
|
const incrementAndCheckRetryLimit = (response) => {
|
|
|
|
const incrementAndCheckRetryLimit = (response) => {
|
|
|
|
retryCount++;
|
|
|
|
retryCount++;
|
|
|
|
if (retryCount > retryLimit) {
|
|
|
|
if (retryCount > retryLimit) {
|
|
|
|
if (response) {
|
|
|
|
if (response) {
|
|
|
|
utils_1.displayHttpDiagnostics(response);
|
|
|
|
(0, utils_1.displayHttpDiagnostics)(response);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
core.info(`Retry limit has been reached for chunk at offset ${start} to ${resourceUrl}`);
|
|
|
|
core.info(`Retry limit has been reached for chunk at offset ${start} to ${resourceUrl}`);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
@ -1701,12 +1754,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 utils_1.sleep(retryAfterValue);
|
|
|
|
yield (0, utils_1.sleep)(retryAfterValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
const backoffTime = utils_1.getExponentialRetryTimeInMilliseconds(retryCount);
|
|
|
|
const backoffTime = (0, 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 utils_1.sleep(backoffTime);
|
|
|
|
yield (0, 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;
|
|
|
@ -1731,21 +1784,21 @@ class UploadHttpClient {
|
|
|
|
// Always read the body of the response. There is potential for a resource leak if the body is not read which will
|
|
|
|
// Always read the body of the response. There is potential for a resource leak if the body is not read which will
|
|
|
|
// result in the connection remaining open along with unintended consequences when trying to dispose of the client
|
|
|
|
// result in the connection remaining open along with unintended consequences when trying to dispose of the client
|
|
|
|
yield response.readBody();
|
|
|
|
yield response.readBody();
|
|
|
|
if (utils_1.isSuccessStatusCode(response.message.statusCode)) {
|
|
|
|
if ((0, utils_1.isSuccessStatusCode)(response.message.statusCode)) {
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (utils_1.isRetryableStatusCode(response.message.statusCode)) {
|
|
|
|
else if ((0, utils_1.isRetryableStatusCode)(response.message.statusCode)) {
|
|
|
|
core.info(`A ${response.message.statusCode} status code has been received, will attempt to retry the upload`);
|
|
|
|
core.info(`A ${response.message.statusCode} status code has been received, will attempt to retry the upload`);
|
|
|
|
if (incrementAndCheckRetryLimit(response)) {
|
|
|
|
if (incrementAndCheckRetryLimit(response)) {
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
utils_1.isThrottledStatusCode(response.message.statusCode)
|
|
|
|
(0, utils_1.isThrottledStatusCode)(response.message.statusCode)
|
|
|
|
? yield backOff(utils_1.tryGetRetryAfterValueTimeInMilliseconds(response.message.headers))
|
|
|
|
? yield backOff((0, utils_1.tryGetRetryAfterValueTimeInMilliseconds)(response.message.headers))
|
|
|
|
: yield backOff();
|
|
|
|
: yield backOff();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
core.error(`Unexpected response. Unable to upload chunk to ${resourceUrl}`);
|
|
|
|
core.error(`Unexpected response. Unable to upload chunk to ${resourceUrl}`);
|
|
|
|
utils_1.displayHttpDiagnostics(response);
|
|
|
|
(0, utils_1.displayHttpDiagnostics)(response);
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1758,14 +1811,14 @@ 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 resourceUrl = new url_1.URL(utils_1.getArtifactUrl());
|
|
|
|
const resourceUrl = new url_1.URL((0, utils_1.getArtifactUrl)());
|
|
|
|
resourceUrl.searchParams.append('artifactName', artifactName);
|
|
|
|
resourceUrl.searchParams.append('artifactName', artifactName);
|
|
|
|
const parameters = { Size: size };
|
|
|
|
const parameters = { Size: size };
|
|
|
|
const data = JSON.stringify(parameters, null, 2);
|
|
|
|
const data = JSON.stringify(parameters, null, 2);
|
|
|
|
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 headers = utils_1.getUploadHeaders('application/json', false);
|
|
|
|
const headers = (0, utils_1.getUploadHeaders)('application/json', false);
|
|
|
|
// Extra information to display when a particular HTTP code is returned
|
|
|
|
// Extra information to display when a particular HTTP code is returned
|
|
|
|
const customErrorMessages = new Map([
|
|
|
|
const customErrorMessages = new Map([
|
|
|
|
[
|
|
|
|
[
|
|
|
@ -1774,7 +1827,7 @@ class UploadHttpClient {
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
// 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
|
|
|
|
// 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);
|
|
|
|
const response = yield (0, requestUtils_1.retryHttpClientRequest)('Finalize artifact upload', () => __awaiter(this, void 0, void 0, function* () { return client.patch(resourceUrl.toString(), data, headers); }), customErrorMessages);
|
|
|
|
yield response.readBody();
|
|
|
|
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}`);
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -1792,7 +1845,11 @@ exports.UploadHttpClient = UploadHttpClient;
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
|
|
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
|
|
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
|
o[k2] = m[k];
|
|
|
|
o[k2] = m[k];
|
|
|
@ -1805,7 +1862,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
__setModuleDefault(result, mod);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -1827,12 +1884,12 @@ function getUploadSpecification(artifactName, rootDirectory, artifactFiles) {
|
|
|
|
if (!fs.existsSync(rootDirectory)) {
|
|
|
|
if (!fs.existsSync(rootDirectory)) {
|
|
|
|
throw new Error(`Provided rootDirectory ${rootDirectory} does not exist`);
|
|
|
|
throw new Error(`Provided rootDirectory ${rootDirectory} does not exist`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!fs.lstatSync(rootDirectory).isDirectory()) {
|
|
|
|
if (!fs.statSync(rootDirectory).isDirectory()) {
|
|
|
|
throw new Error(`Provided rootDirectory ${rootDirectory} is not a valid directory`);
|
|
|
|
throw new Error(`Provided rootDirectory ${rootDirectory} is not a valid directory`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
|
|
|
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
|
|
|
rootDirectory = path_1.normalize(rootDirectory);
|
|
|
|
rootDirectory = (0, path_1.normalize)(rootDirectory);
|
|
|
|
rootDirectory = path_1.resolve(rootDirectory);
|
|
|
|
rootDirectory = (0, path_1.resolve)(rootDirectory);
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
Example to demonstrate behavior
|
|
|
|
Example to demonstrate behavior
|
|
|
|
|
|
|
|
|
|
|
@ -1856,16 +1913,16 @@ function getUploadSpecification(artifactName, rootDirectory, artifactFiles) {
|
|
|
|
if (!fs.existsSync(file)) {
|
|
|
|
if (!fs.existsSync(file)) {
|
|
|
|
throw new Error(`File ${file} does not exist`);
|
|
|
|
throw new Error(`File ${file} does not exist`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!fs.lstatSync(file).isDirectory()) {
|
|
|
|
if (!fs.statSync(file).isDirectory()) {
|
|
|
|
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
|
|
|
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
|
|
|
file = path_1.normalize(file);
|
|
|
|
file = (0, path_1.normalize)(file);
|
|
|
|
file = path_1.resolve(file);
|
|
|
|
file = (0, path_1.resolve)(file);
|
|
|
|
if (!file.startsWith(rootDirectory)) {
|
|
|
|
if (!file.startsWith(rootDirectory)) {
|
|
|
|
throw new Error(`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`);
|
|
|
|
throw new Error(`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check for forbidden characters in file paths that will be rejected during upload
|
|
|
|
// Check for forbidden characters in file paths that will be rejected during upload
|
|
|
|
const uploadPath = file.replace(rootDirectory, '');
|
|
|
|
const uploadPath = file.replace(rootDirectory, '');
|
|
|
|
path_and_artifact_name_validation_1.checkArtifactFilePath(uploadPath);
|
|
|
|
(0, path_and_artifact_name_validation_1.checkArtifactFilePath)(uploadPath);
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
uploadFilePath denotes where the file will be uploaded in the file container on the server. During a run, if multiple artifacts are uploaded, they will all
|
|
|
|
uploadFilePath denotes where the file will be uploaded in the file container on the server. During a run, if multiple artifacts are uploaded, they will all
|
|
|
|
be saved in the same container. The artifact name is used as the root directory in the container to separate and distinguish uploaded artifacts
|
|
|
|
be saved in the same container. The artifact name is used as the root directory in the container to separate and distinguish uploaded artifacts
|
|
|
@ -1878,12 +1935,12 @@ function getUploadSpecification(artifactName, rootDirectory, artifactFiles) {
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
specifications.push({
|
|
|
|
specifications.push({
|
|
|
|
absoluteFilePath: file,
|
|
|
|
absoluteFilePath: file,
|
|
|
|
uploadFilePath: path_1.join(artifactName, uploadPath)
|
|
|
|
uploadFilePath: (0, path_1.join)(artifactName, uploadPath)
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
// Directories are rejected by the server during upload
|
|
|
|
// Directories are rejected by the server during upload
|
|
|
|
core_1.debug(`Removing ${file} from rawSearchResults because it is a directory`);
|
|
|
|
(0, core_1.debug)(`Removing ${file} from rawSearchResults because it is a directory`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return specifications;
|
|
|
|
return specifications;
|
|
|
@ -1928,10 +1985,10 @@ function getExponentialRetryTimeInMilliseconds(retryCount) {
|
|
|
|
throw new Error('RetryCount should not be negative');
|
|
|
|
throw new Error('RetryCount should not be negative');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (retryCount === 0) {
|
|
|
|
else if (retryCount === 0) {
|
|
|
|
return config_variables_1.getInitialRetryIntervalInMilliseconds();
|
|
|
|
return (0, config_variables_1.getInitialRetryIntervalInMilliseconds)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const minTime = config_variables_1.getInitialRetryIntervalInMilliseconds() * config_variables_1.getRetryMultiplier() * retryCount;
|
|
|
|
const minTime = (0, config_variables_1.getInitialRetryIntervalInMilliseconds)() * (0, config_variables_1.getRetryMultiplier)() * retryCount;
|
|
|
|
const maxTime = minTime * config_variables_1.getRetryMultiplier();
|
|
|
|
const maxTime = minTime * (0, config_variables_1.getRetryMultiplier)();
|
|
|
|
// returns a random number between the minTime (inclusive) and the maxTime (exclusive)
|
|
|
|
// returns a random number between the minTime (inclusive) and the maxTime (exclusive)
|
|
|
|
return Math.trunc(Math.random() * (maxTime - minTime) + minTime);
|
|
|
|
return Math.trunc(Math.random() * (maxTime - minTime) + minTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1999,13 +2056,13 @@ function tryGetRetryAfterValueTimeInMilliseconds(headers) {
|
|
|
|
if (headers['retry-after']) {
|
|
|
|
if (headers['retry-after']) {
|
|
|
|
const retryTime = Number(headers['retry-after']);
|
|
|
|
const retryTime = Number(headers['retry-after']);
|
|
|
|
if (!isNaN(retryTime)) {
|
|
|
|
if (!isNaN(retryTime)) {
|
|
|
|
core_1.info(`Retry-After header is present with a value of ${retryTime}`);
|
|
|
|
(0, core_1.info)(`Retry-After header is present with a value of ${retryTime}`);
|
|
|
|
return retryTime * 1000;
|
|
|
|
return retryTime * 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
core_1.info(`Returned retry-after header value: ${retryTime} is non-numeric and cannot be used`);
|
|
|
|
(0, core_1.info)(`Returned retry-after header value: ${retryTime} is non-numeric and cannot be used`);
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
core_1.info(`No retry-after header was found. Dumping all headers for diagnostic purposes`);
|
|
|
|
(0, core_1.info)(`No retry-after header was found. Dumping all headers for diagnostic purposes`);
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.log(headers);
|
|
|
|
console.log(headers);
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
@ -2089,13 +2146,13 @@ function getUploadHeaders(contentType, isKeepAlive, isGzip, uncompressedLength,
|
|
|
|
exports.getUploadHeaders = getUploadHeaders;
|
|
|
|
exports.getUploadHeaders = getUploadHeaders;
|
|
|
|
function createHttpClient(userAgent) {
|
|
|
|
function createHttpClient(userAgent) {
|
|
|
|
return new http_client_1.HttpClient(userAgent, [
|
|
|
|
return new http_client_1.HttpClient(userAgent, [
|
|
|
|
new auth_1.BearerCredentialHandler(config_variables_1.getRuntimeToken())
|
|
|
|
new auth_1.BearerCredentialHandler((0, config_variables_1.getRuntimeToken)())
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exports.createHttpClient = createHttpClient;
|
|
|
|
exports.createHttpClient = createHttpClient;
|
|
|
|
function getArtifactUrl() {
|
|
|
|
function getArtifactUrl() {
|
|
|
|
const artifactUrl = `${config_variables_1.getRuntimeUrl()}_apis/pipelines/workflows/${config_variables_1.getWorkFlowRunId()}/artifacts?api-version=${getApiVersion()}`;
|
|
|
|
const artifactUrl = `${(0, config_variables_1.getRuntimeUrl)()}_apis/pipelines/workflows/${(0, config_variables_1.getWorkFlowRunId)()}/artifacts?api-version=${getApiVersion()}`;
|
|
|
|
core_1.debug(`Artifact Url: ${artifactUrl}`);
|
|
|
|
(0, core_1.debug)(`Artifact Url: ${artifactUrl}`);
|
|
|
|
return artifactUrl;
|
|
|
|
return artifactUrl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exports.getArtifactUrl = getArtifactUrl;
|
|
|
|
exports.getArtifactUrl = getArtifactUrl;
|
|
|
@ -2109,7 +2166,7 @@ exports.getArtifactUrl = getArtifactUrl;
|
|
|
|
* Other information such as the headers, the response code and message might be useful, so this is displayed.
|
|
|
|
* Other information such as the headers, the response code and message might be useful, so this is displayed.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
function displayHttpDiagnostics(response) {
|
|
|
|
function displayHttpDiagnostics(response) {
|
|
|
|
core_1.info(`##### Begin Diagnostic HTTP information #####
|
|
|
|
(0, core_1.info)(`##### Begin Diagnostic HTTP information #####
|
|
|
|
Status Code: ${response.message.statusCode}
|
|
|
|
Status Code: ${response.message.statusCode}
|
|
|
|
Status Message: ${response.message.statusMessage}
|
|
|
|
Status Message: ${response.message.statusMessage}
|
|
|
|
Header Information: ${JSON.stringify(response.message.headers, undefined, 2)}
|
|
|
|
Header Information: ${JSON.stringify(response.message.headers, undefined, 2)}
|
|
|
@ -2137,7 +2194,7 @@ exports.createEmptyFilesForArtifact = createEmptyFilesForArtifact;
|
|
|
|
function getFileSize(filePath) {
|
|
|
|
function getFileSize(filePath) {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
|
|
const stats = yield fs_1.promises.stat(filePath);
|
|
|
|
const stats = yield fs_1.promises.stat(filePath);
|
|
|
|
core_1.debug(`${filePath} size:(${stats.size}) blksize:(${stats.blksize}) blocks:(${stats.blocks})`);
|
|
|
|
(0, core_1.debug)(`${filePath} size:(${stats.size}) blksize:(${stats.blksize}) blocks:(${stats.blocks})`);
|
|
|
|
return stats.size;
|
|
|
|
return stats.size;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -2156,7 +2213,7 @@ function getProperRetention(retentionInput, retentionSetting) {
|
|
|
|
if (retentionSetting) {
|
|
|
|
if (retentionSetting) {
|
|
|
|
const maxRetention = parseInt(retentionSetting);
|
|
|
|
const maxRetention = parseInt(retentionSetting);
|
|
|
|
if (!isNaN(maxRetention) && maxRetention < retention) {
|
|
|
|
if (!isNaN(maxRetention) && maxRetention < retention) {
|
|
|
|
core_1.warning(`Retention days is greater than the max value allowed by the repository setting, reduce retention to ${maxRetention} days`);
|
|
|
|
(0, core_1.warning)(`Retention days is greater than the max value allowed by the repository setting, reduce retention to ${maxRetention} days`);
|
|
|
|
retention = maxRetention;
|
|
|
|
retention = maxRetention;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|