mirror of
https://github.com/github/codeql-action.git
synced 2025-12-24 08:10:06 +08:00
* Bump the npm group with 11 updates Bumps the npm group with 11 updates: | Package | From | To | | --- | --- | --- | | [@actions/artifact](https://github.com/actions/toolkit/tree/HEAD/packages/artifact) | `1.1.1` | `1.1.2` | | [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) | `1.10.0` | `1.10.1` | | [uuid](https://github.com/uuidjs/uuid) | `9.0.0` | `9.0.1` | | [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid) | `9.0.3` | `9.0.4` | | [@types/adm-zip](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/adm-zip) | `0.5.0` | `0.5.1` | | [@types/js-yaml](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/js-yaml) | `4.0.5` | `4.0.6` | | [@types/semver](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/semver) | `7.5.1` | `7.5.2` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `6.5.0` | `6.7.2` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `6.6.0` | `6.7.2` | | [eslint](https://github.com/eslint/eslint) | `8.48.0` | `8.49.0` | | [sinon](https://github.com/sinonjs/sinon) | `15.2.0` | `16.0.0` | Updates `@actions/artifact` from 1.1.1 to 1.1.2 - [Changelog](https://github.com/actions/toolkit/blob/main/packages/artifact/RELEASES.md) - [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/artifact) Updates `@actions/core` from 1.10.0 to 1.10.1 - [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md) - [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core) Updates `uuid` from 9.0.0 to 9.0.1 - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v9.0.0...v9.0.1) Updates `@types/uuid` from 9.0.3 to 9.0.4 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/uuid) Updates `@types/adm-zip` from 0.5.0 to 0.5.1 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/adm-zip) Updates `@types/js-yaml` from 4.0.5 to 4.0.6 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/js-yaml) Updates `@types/semver` from 7.5.1 to 7.5.2 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/semver) Updates `@typescript-eslint/eslint-plugin` from 6.5.0 to 6.7.2 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.2/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.6.0 to 6.7.2 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.7.2/packages/parser) Updates `eslint` from 8.48.0 to 8.49.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.48.0...v8.49.0) Updates `sinon` from 15.2.0 to 16.0.0 - [Release notes](https://github.com/sinonjs/sinon/releases) - [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md) - [Commits](https://github.com/sinonjs/sinon/compare/v15.2.0...v16.0.0) --- updated-dependencies: - dependency-name: "@actions/artifact" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@actions/core" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm - dependency-name: uuid dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/uuid" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/adm-zip" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/js-yaml" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/semver" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm - dependency-name: sinon dependency-type: direct:development update-type: version-update:semver-major dependency-group: npm ... Signed-off-by: dependabot[bot] <support@github.com> * Update checked-in dependencies --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
296 lines
16 KiB
JavaScript
296 lines
16 KiB
JavaScript
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = 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) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
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());
|
|
});
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.DownloadHttpClient = void 0;
|
|
const fs = __importStar(require("fs"));
|
|
const core = __importStar(require("@actions/core"));
|
|
const zlib = __importStar(require("zlib"));
|
|
const utils_1 = require("./utils");
|
|
const url_1 = require("url");
|
|
const status_reporter_1 = require("./status-reporter");
|
|
const perf_hooks_1 = require("perf_hooks");
|
|
const http_manager_1 = require("./http-manager");
|
|
const config_variables_1 = require("./config-variables");
|
|
const requestUtils_1 = require("./requestUtils");
|
|
class DownloadHttpClient {
|
|
constructor() {
|
|
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
|
|
this.statusReporter = new status_reporter_1.StatusReporter(1000);
|
|
}
|
|
/**
|
|
* Gets a list of all artifacts that are in a specific container
|
|
*/
|
|
listArtifacts() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const artifactUrl = (0, utils_1.getArtifactUrl)();
|
|
// 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 headers = (0, utils_1.getDownloadHeaders)('application/json');
|
|
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();
|
|
return JSON.parse(body);
|
|
});
|
|
}
|
|
/**
|
|
* Fetches a set of container items that describe the contents of an artifact
|
|
* @param artifactName the name of the artifact
|
|
* @param containerUrl the artifact container URL for the run
|
|
*/
|
|
getContainerItems(artifactName, containerUrl) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
// the itemPath search parameter controls which containers will be returned
|
|
const resourceUrl = new url_1.URL(containerUrl);
|
|
resourceUrl.searchParams.append('itemPath', artifactName);
|
|
// 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 headers = (0, utils_1.getDownloadHeaders)('application/json');
|
|
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();
|
|
return JSON.parse(body);
|
|
});
|
|
}
|
|
/**
|
|
* Concurrently downloads all the files that are part of an artifact
|
|
* @param downloadItems information about what items to download and where to save them
|
|
*/
|
|
downloadSingleArtifact(downloadItems) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const DOWNLOAD_CONCURRENCY = (0, config_variables_1.getDownloadFileConcurrency)();
|
|
// limit the number of files downloaded at a single time
|
|
core.debug(`Download file concurrency is set to ${DOWNLOAD_CONCURRENCY}`);
|
|
const parallelDownloads = [...new Array(DOWNLOAD_CONCURRENCY).keys()];
|
|
let currentFile = 0;
|
|
let downloadedFiles = 0;
|
|
core.info(`Total number of files that will be downloaded: ${downloadItems.length}`);
|
|
this.statusReporter.setTotalNumberOfFilesToProcess(downloadItems.length);
|
|
this.statusReporter.start();
|
|
yield Promise.all(parallelDownloads.map((index) => __awaiter(this, void 0, void 0, function* () {
|
|
while (currentFile < downloadItems.length) {
|
|
const currentFileToDownload = downloadItems[currentFile];
|
|
currentFile += 1;
|
|
const startTime = perf_hooks_1.performance.now();
|
|
yield this.downloadIndividualFile(index, currentFileToDownload.sourceLocation, currentFileToDownload.targetPath);
|
|
if (core.isDebug()) {
|
|
core.debug(`File: ${++downloadedFiles}/${downloadItems.length}. ${currentFileToDownload.targetPath} took ${(perf_hooks_1.performance.now() - startTime).toFixed(3)} milliseconds to finish downloading`);
|
|
}
|
|
this.statusReporter.incrementProcessedCount();
|
|
}
|
|
})))
|
|
.catch(error => {
|
|
throw new Error(`Unable to download the artifact: ${error}`);
|
|
})
|
|
.finally(() => {
|
|
this.statusReporter.stop();
|
|
// safety dispose all connections
|
|
this.downloadHttpManager.disposeAndReplaceAllClients();
|
|
});
|
|
});
|
|
}
|
|
/**
|
|
* Downloads an individual file
|
|
* @param httpClientIndex the index of the http client that is used to make all of the calls
|
|
* @param artifactLocation origin location where a file will be downloaded from
|
|
* @param downloadPath destination location for the file being downloaded
|
|
*/
|
|
downloadIndividualFile(httpClientIndex, artifactLocation, downloadPath) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
let retryCount = 0;
|
|
const retryLimit = (0, config_variables_1.getRetryLimit)();
|
|
let destinationStream = fs.createWriteStream(downloadPath);
|
|
const headers = (0, utils_1.getDownloadHeaders)('application/json', true, true);
|
|
// a single GET request is used to download a file
|
|
const makeDownloadRequest = () => __awaiter(this, void 0, void 0, function* () {
|
|
const client = this.downloadHttpManager.getClient(httpClientIndex);
|
|
return yield client.get(artifactLocation, headers);
|
|
});
|
|
// check the response headers to determine if the file was compressed using gzip
|
|
const isGzip = (incomingHeaders) => {
|
|
return ('content-encoding' in incomingHeaders &&
|
|
incomingHeaders['content-encoding'] === 'gzip');
|
|
};
|
|
// 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 is a retryAfterValue value provided,
|
|
// it will be used
|
|
const backOff = (retryAfterValue) => __awaiter(this, void 0, void 0, function* () {
|
|
retryCount++;
|
|
if (retryCount > retryLimit) {
|
|
return Promise.reject(new Error(`Retry limit has been reached. Unable to download ${artifactLocation}`));
|
|
}
|
|
else {
|
|
this.downloadHttpManager.disposeAndReplaceClient(httpClientIndex);
|
|
if (retryAfterValue) {
|
|
// 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`);
|
|
yield (0, utils_1.sleep)(retryAfterValue);
|
|
}
|
|
else {
|
|
// Back off using an exponential value that depends on the retry count
|
|
const backoffTime = (0, utils_1.getExponentialRetryTimeInMilliseconds)(retryCount);
|
|
core.info(`Exponential backoff for retry #${retryCount}. Waiting for ${backoffTime} milliseconds before continuing the download`);
|
|
yield (0, utils_1.sleep)(backoffTime);
|
|
}
|
|
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();
|
|
// await until file is created at downloadpath; node15 and up fs.createWriteStream had not created a file yet
|
|
yield new Promise(resolve => {
|
|
destinationStream.on('close', resolve);
|
|
if (destinationStream.writableFinished) {
|
|
resolve();
|
|
}
|
|
});
|
|
yield (0, utils_1.rmFile)(fileDownloadPath);
|
|
destinationStream = fs.createWriteStream(fileDownloadPath);
|
|
});
|
|
// keep trying to download a file until a retry limit has been reached
|
|
while (retryCount <= retryLimit) {
|
|
let response;
|
|
try {
|
|
response = yield makeDownloadRequest();
|
|
}
|
|
catch (error) {
|
|
// if an error is caught, it is usually indicative of a timeout so retry the download
|
|
core.info('An error occurred while attempting to download a file');
|
|
// eslint-disable-next-line no-console
|
|
console.log(error);
|
|
// increment the retryCount and use exponential backoff to wait before making the next request
|
|
yield backOff();
|
|
continue;
|
|
}
|
|
let forceRetry = false;
|
|
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
|
|
// 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
|
|
try {
|
|
const isGzipped = isGzip(response.message.headers);
|
|
yield this.pipeResponseToFile(response, destinationStream, isGzipped);
|
|
if (isGzipped ||
|
|
isAllBytesReceived(response.message.headers['content-length'], yield (0, utils_1.getFileSize)(downloadPath))) {
|
|
return;
|
|
}
|
|
else {
|
|
forceRetry = true;
|
|
}
|
|
}
|
|
catch (error) {
|
|
// retry on error, most likely streams were corrupted
|
|
forceRetry = true;
|
|
}
|
|
}
|
|
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`);
|
|
resetDestinationStream(downloadPath);
|
|
// if a throttled status code is received, try to get the retryAfter header value, else differ to standard exponential backoff
|
|
(0, utils_1.isThrottledStatusCode)(response.message.statusCode)
|
|
? yield backOff((0, utils_1.tryGetRetryAfterValueTimeInMilliseconds)(response.message.headers))
|
|
: yield backOff();
|
|
}
|
|
else {
|
|
// Some unexpected response code, fail immediately and stop the download
|
|
(0, utils_1.displayHttpDiagnostics)(response);
|
|
return Promise.reject(new Error(`Unexpected http ${response.message.statusCode} during download for ${artifactLocation}`));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Pipes the response from downloading an individual file to the appropriate destination stream while decoding gzip content if necessary
|
|
* @param response the http response received when downloading a file
|
|
* @param destinationStream the stream where the file should be written to
|
|
* @param isGzip a boolean denoting if the content is compressed using gzip and if we need to decode it
|
|
*/
|
|
pipeResponseToFile(response, destinationStream, isGzip) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
yield new Promise((resolve, reject) => {
|
|
if (isGzip) {
|
|
const gunzip = zlib.createGunzip();
|
|
response.message
|
|
.on('error', error => {
|
|
core.info(`An error occurred while attempting to read the response stream`);
|
|
gunzip.close();
|
|
destinationStream.close();
|
|
reject(error);
|
|
})
|
|
.pipe(gunzip)
|
|
.on('error', error => {
|
|
core.info(`An error occurred while attempting to decompress the response stream`);
|
|
destinationStream.close();
|
|
reject(error);
|
|
})
|
|
.pipe(destinationStream)
|
|
.on('close', () => {
|
|
resolve();
|
|
})
|
|
.on('error', error => {
|
|
core.info(`An error occurred while writing a downloaded file to ${destinationStream.path}`);
|
|
reject(error);
|
|
});
|
|
}
|
|
else {
|
|
response.message
|
|
.on('error', error => {
|
|
core.info(`An error occurred while attempting to read the response stream`);
|
|
destinationStream.close();
|
|
reject(error);
|
|
})
|
|
.pipe(destinationStream)
|
|
.on('close', () => {
|
|
resolve();
|
|
})
|
|
.on('error', error => {
|
|
core.info(`An error occurred while writing a downloaded file to ${destinationStream.path}`);
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
return;
|
|
});
|
|
}
|
|
}
|
|
exports.DownloadHttpClient = DownloadHttpClient;
|
|
//# sourceMappingURL=download-http-client.js.map
|