mirror of
https://github.com/github/codeql-action.git
synced 2025-12-06 15:58:06 +08:00
Compare commits
2 Commits
codeql-bun
...
henrymerce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14567d9b12 | ||
|
|
5edc73a9a0 |
69
.github/workflows/codeql.yml
vendored
69
.github/workflows/codeql.yml
vendored
@@ -1,80 +1,15 @@
|
||||
name: "CodeQL action"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, releases/v2]
|
||||
pull_request:
|
||||
branches: [main, releases/v2]
|
||||
# Run checks on reopened draft PRs to support triggering PR checks on draft PRs that were opened
|
||||
# by other workflows.
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
schedule:
|
||||
# Weekly on Sunday.
|
||||
- cron: '30 1 * * 0'
|
||||
on: push
|
||||
|
||||
env:
|
||||
CODEQL_ACTION_TESTING_ENVIRONMENT: codeql-action-pr-checks
|
||||
|
||||
jobs:
|
||||
# Identify the CodeQL tool versions to use in the analysis job.
|
||||
check-codeql-versions:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
versions: ${{ steps.compare.outputs.versions }}
|
||||
|
||||
permissions:
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Init with default CodeQL bundle from the VM image
|
||||
id: init-default
|
||||
uses: ./init
|
||||
with:
|
||||
languages: javascript
|
||||
- name: Remove empty database
|
||||
# allows us to run init a second time
|
||||
run: |
|
||||
rm -rf "$RUNNER_TEMP/codeql_databases"
|
||||
- name: Init with latest CodeQL bundle
|
||||
id: init-latest
|
||||
uses: ./init
|
||||
with:
|
||||
tools: latest
|
||||
languages: javascript
|
||||
- name: Compare default and latest CodeQL bundle versions
|
||||
id: compare
|
||||
env:
|
||||
CODEQL_DEFAULT: ${{ steps.init-default.outputs.codeql-path }}
|
||||
CODEQL_LATEST: ${{ steps.init-latest.outputs.codeql-path }}
|
||||
run: |
|
||||
CODEQL_VERSION_DEFAULT="$("$CODEQL_DEFAULT" version --format terse)"
|
||||
CODEQL_VERSION_LATEST="$("$CODEQL_LATEST" version --format terse)"
|
||||
echo "Default CodeQL bundle version is $CODEQL_VERSION_DEFAULT"
|
||||
echo "Latest CodeQL bundle version is $CODEQL_VERSION_LATEST"
|
||||
|
||||
# If we're running on a pull request, run with both bundles, even if `tools: latest` would
|
||||
# be the same as `tools: null`. This allows us to make the job for each of the bundles a
|
||||
# required status check.
|
||||
#
|
||||
# If we're running on push or schedule, then we can skip running with `tools: latest` when it would be
|
||||
# the same as running with `tools: null`.
|
||||
if [[ "$GITHUB_EVENT_NAME" != "pull_request" && "$CODEQL_VERSION_DEFAULT" == "$CODEQL_VERSION_LATEST" ]]; then
|
||||
VERSIONS_JSON='[null]'
|
||||
else
|
||||
VERSIONS_JSON='[null, "latest"]'
|
||||
fi
|
||||
|
||||
# Output a JSON-encoded list with the distinct versions to test against.
|
||||
echo "Suggested matrix config for analysis job: $VERSIONS_JSON"
|
||||
echo "versions=${VERSIONS_JSON}" >> $GITHUB_OUTPUT
|
||||
|
||||
build:
|
||||
needs: [check-codeql-versions]
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest,windows-latest,macos-latest]
|
||||
tools: ${{ fromJson(needs.check-codeql-versions.outputs.versions) }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
@@ -89,7 +24,7 @@ jobs:
|
||||
with:
|
||||
languages: javascript
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
tools: ${{ matrix.tools }}
|
||||
tools: https://github.com/dsp-testing/codeql-cli-nightlies/releases/download/codeql-bundle-20230801/codeql-bundle-linux64.tar.gz
|
||||
# confirm steps.init.outputs.codeql-path points to the codeql binary
|
||||
- name: Print CodeQL Version
|
||||
run: ${{steps.init.outputs.codeql-path}} version --format=json
|
||||
|
||||
65
lib/setup-codeql.js
generated
65
lib/setup-codeql.js
generated
@@ -31,6 +31,7 @@ const fs = __importStar(require("fs"));
|
||||
const path = __importStar(require("path"));
|
||||
const perf_hooks_1 = require("perf_hooks");
|
||||
const toolcache = __importStar(require("@actions/tool-cache"));
|
||||
const check_disk_space_1 = __importDefault(require("check-disk-space"));
|
||||
const del_1 = __importDefault(require("del"));
|
||||
const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
|
||||
const semver = __importStar(require("semver"));
|
||||
@@ -88,14 +89,14 @@ function tryGetCodeQLCliVersionForRelease(release, logger) {
|
||||
return undefined;
|
||||
}
|
||||
else if (cliVersionsFromMarkerFiles.length === 0) {
|
||||
logger.debug(`Failed to find the CodeQL CLI version for release ${release.tag_name}.`);
|
||||
logger.info(`Failed to find the CodeQL CLI version for release ${release.tag_name}.`);
|
||||
return undefined;
|
||||
}
|
||||
return cliVersionsFromMarkerFiles[0];
|
||||
}
|
||||
async function tryFindCliVersionDotcomOnly(tagName, logger) {
|
||||
try {
|
||||
logger.debug(`Fetching the GitHub Release for the CodeQL bundle tagged ${tagName}.`);
|
||||
logger.info(`Fetching the GitHub Release for the CodeQL bundle tagged ${tagName}.`);
|
||||
const apiClient = api.getApiClient();
|
||||
const codeQLActionRepository = getCodeQLActionRepository(logger);
|
||||
const release = await apiClient.rest.repos.getReleaseByTag({
|
||||
@@ -106,7 +107,7 @@ async function tryFindCliVersionDotcomOnly(tagName, logger) {
|
||||
return tryGetCodeQLCliVersionForRelease(release.data, logger);
|
||||
}
|
||||
catch (e) {
|
||||
logger.debug(`Failed to find the CLI version for the CodeQL bundle tagged ${tagName}. ${(0, util_1.wrapError)(e).message}`);
|
||||
logger.info(`Failed to find the CLI version for the CodeQL bundle tagged ${tagName}. ${(0, util_1.wrapError)(e).message}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -181,7 +182,7 @@ async function getCodeQLBundleDownloadURL(tagName, apiDetails, variant, logger)
|
||||
function tryGetBundleVersionFromTagName(tagName, logger) {
|
||||
const match = tagName.match(/^codeql-bundle-(.*)$/);
|
||||
if (match === null || match.length < 2) {
|
||||
logger.debug(`Could not determine bundle version from tag ${tagName}.`);
|
||||
logger.info(`Could not determine bundle version from tag ${tagName}.`);
|
||||
return undefined;
|
||||
}
|
||||
return match[1];
|
||||
@@ -189,7 +190,7 @@ function tryGetBundleVersionFromTagName(tagName, logger) {
|
||||
function tryGetTagNameFromUrl(url, logger) {
|
||||
const match = url.match(/\/(codeql-bundle-.*)\//);
|
||||
if (match === null || match.length < 2) {
|
||||
logger.debug(`Could not determine tag name for URL ${url}.`);
|
||||
logger.info(`Could not determine tag name for URL ${url}.`);
|
||||
return undefined;
|
||||
}
|
||||
return match[1];
|
||||
@@ -204,7 +205,7 @@ function tryGetBundleVersionFromUrl(url, logger) {
|
||||
exports.tryGetBundleVersionFromUrl = tryGetBundleVersionFromUrl;
|
||||
function convertToSemVer(version, logger) {
|
||||
if (!semver.valid(version)) {
|
||||
logger.debug(`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`);
|
||||
logger.info(`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`);
|
||||
version = `0.0.0-${version}`;
|
||||
}
|
||||
const s = semver.clean(version);
|
||||
@@ -228,7 +229,7 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) {
|
||||
.filter(({ folder }) => fs.existsSync(path.join(folder, "pinned-version")));
|
||||
if (candidates.length === 1) {
|
||||
const candidate = candidates[0];
|
||||
logger.debug(`CodeQL tools version ${candidate.version} in toolcache overriding version ${humanReadableVersion}.`);
|
||||
logger.info(`CodeQL tools version ${candidate.version} in toolcache overriding version ${humanReadableVersion}.`);
|
||||
return {
|
||||
codeqlFolder: candidate.folder,
|
||||
sourceType: "toolcache",
|
||||
@@ -236,10 +237,10 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) {
|
||||
};
|
||||
}
|
||||
else if (candidates.length === 0) {
|
||||
logger.debug("Did not find any candidate pinned versions of the CodeQL tools in the toolcache.");
|
||||
logger.info("Did not find any candidate pinned versions of the CodeQL tools in the toolcache.");
|
||||
}
|
||||
else {
|
||||
logger.debug("Could not use CodeQL tools from the toolcache since more than one candidate pinned " +
|
||||
logger.info("Could not use CodeQL tools from the toolcache since more than one candidate pinned " +
|
||||
"version was found in the toolcache.");
|
||||
}
|
||||
return undefined;
|
||||
@@ -301,7 +302,7 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian
|
||||
tagName ??
|
||||
url ??
|
||||
"unknown";
|
||||
logger.debug("Attempting to obtain CodeQL tools. " +
|
||||
logger.info("Attempting to obtain CodeQL tools. " +
|
||||
`CLI version: ${cliVersion ?? "unknown"}, ` +
|
||||
`bundle tag name: ${tagName ?? "unknown"}, ` +
|
||||
`URL: ${url ?? "unspecified"}.`);
|
||||
@@ -311,26 +312,26 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian
|
||||
codeqlFolder = toolcache.find("CodeQL", cliVersion);
|
||||
// Fall back to matching `x.y.z-<tagName>`.
|
||||
if (!codeqlFolder) {
|
||||
logger.debug("Didn't find a version of the CodeQL tools in the toolcache with a version number " +
|
||||
logger.info("Didn't find a version of the CodeQL tools in the toolcache with a version number " +
|
||||
`exactly matching ${cliVersion}.`);
|
||||
const allVersions = toolcache.findAllVersions("CodeQL");
|
||||
logger.debug(`Found the following versions of the CodeQL tools in the toolcache: ${JSON.stringify(allVersions)}.`);
|
||||
logger.info(`Found the following versions of the CodeQL tools in the toolcache: ${JSON.stringify(allVersions)}.`);
|
||||
// If there is exactly one version of the CodeQL tools in the toolcache, and that version is
|
||||
// the form `x.y.z-<tagName>`, then use it.
|
||||
const candidateVersions = allVersions.filter((version) => version.startsWith(`${cliVersion}-`));
|
||||
if (candidateVersions.length === 1) {
|
||||
logger.debug(`Exactly one version of the CodeQL tools starting with ${cliVersion} found in the ` +
|
||||
logger.info(`Exactly one version of the CodeQL tools starting with ${cliVersion} found in the ` +
|
||||
"toolcache, using that.");
|
||||
codeqlFolder = toolcache.find("CodeQL", candidateVersions[0]);
|
||||
}
|
||||
else if (candidateVersions.length === 0) {
|
||||
logger.debug(`Didn't find any versions of the CodeQL tools starting with ${cliVersion} ` +
|
||||
logger.info(`Didn't find any versions of the CodeQL tools starting with ${cliVersion} ` +
|
||||
`in the toolcache. Trying next fallback method.`);
|
||||
}
|
||||
else {
|
||||
logger.warning(`Found ${candidateVersions.length} versions of the CodeQL tools starting with ` +
|
||||
`${cliVersion} in the toolcache, but at most one was expected.`);
|
||||
logger.debug("Trying next fallback method.");
|
||||
logger.info("Trying next fallback method.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,7 +342,7 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian
|
||||
codeqlFolder = toolcache.find("CodeQL", fallbackVersion);
|
||||
}
|
||||
else {
|
||||
logger.debug("Could not determine a fallback toolcache version number for CodeQL tools version " +
|
||||
logger.info("Could not determine a fallback toolcache version number for CodeQL tools version " +
|
||||
`${humanReadableVersion}.`);
|
||||
}
|
||||
}
|
||||
@@ -391,7 +392,7 @@ async function tryGetFallbackToolcacheVersion(cliVersion, tagName, logger) {
|
||||
return undefined;
|
||||
}
|
||||
const fallbackVersion = convertToSemVer(bundleVersion, logger);
|
||||
logger.debug(`Computed a fallback toolcache version number of ${fallbackVersion} for CodeQL version ` +
|
||||
logger.info(`Computed a fallback toolcache version number of ${fallbackVersion} for CodeQL version ` +
|
||||
`${cliVersion ?? tagName}.`);
|
||||
return fallbackVersion;
|
||||
}
|
||||
@@ -408,34 +409,38 @@ async function downloadCodeQL(codeqlURL, maybeBundleVersion, maybeCliVersion, ap
|
||||
// We also don't want to send an authorization header if there's already a token provided in the URL.
|
||||
let authorization = undefined;
|
||||
if (searchParams.has("token")) {
|
||||
logger.debug("CodeQL tools URL contains an authorization token.");
|
||||
logger.info("CodeQL tools URL contains an authorization token.");
|
||||
}
|
||||
else if (codeqlURL.startsWith(`${apiDetails.url}/`)) {
|
||||
logger.debug("Providing an authorization token to download CodeQL tools.");
|
||||
logger.info("Providing an authorization token to download CodeQL tools.");
|
||||
authorization = `token ${apiDetails.auth}`;
|
||||
}
|
||||
else {
|
||||
logger.debug("Downloading CodeQL tools without an authorization token.");
|
||||
logger.info("Downloading CodeQL tools without an authorization token.");
|
||||
}
|
||||
await printDiskSpace(logger);
|
||||
logger.info(`Downloading CodeQL tools from ${codeqlURL}. This may take a while.`);
|
||||
const dest = path.join(tempDir, (0, uuid_1.v4)());
|
||||
const finalHeaders = Object.assign({ "User-Agent": "CodeQL Action" }, headers);
|
||||
const toolsDownloadStart = perf_hooks_1.performance.now();
|
||||
const codeqlPath = await toolcache.downloadTool(codeqlURL, dest, authorization, finalHeaders);
|
||||
const toolsDownloadDurationMs = Math.round(perf_hooks_1.performance.now() - toolsDownloadStart);
|
||||
logger.debug(`Finished downloading CodeQL bundle to ${codeqlPath} (${toolsDownloadDurationMs} ms).`);
|
||||
logger.info(`Finished downloading CodeQL bundle to ${codeqlPath} (${toolsDownloadDurationMs} ms).`);
|
||||
await printDiskSpace(logger);
|
||||
const codeqlExtracted = await toolcache.extractTar(codeqlPath);
|
||||
logger.debug(`Finished extracting CodeQL bundle to ${codeqlExtracted}.`);
|
||||
logger.info(`Finished extracting CodeQL bundle to ${codeqlExtracted}.`);
|
||||
await printDiskSpace(logger);
|
||||
try {
|
||||
await (0, del_1.default)(codeqlPath, { force: true });
|
||||
logger.debug("Deleted CodeQL bundle archive.");
|
||||
logger.info("Deleted CodeQL bundle archive.");
|
||||
}
|
||||
catch (e) {
|
||||
logger.warning("Failed to delete CodeQL bundle archive.");
|
||||
}
|
||||
await printDiskSpace(logger);
|
||||
const bundleVersion = maybeBundleVersion ?? tryGetBundleVersionFromUrl(codeqlURL, logger);
|
||||
if (bundleVersion === undefined) {
|
||||
logger.debug("Could not cache CodeQL tools because we could not determine the bundle version from the " +
|
||||
logger.info("Could not cache CodeQL tools because we could not determine the bundle version from the " +
|
||||
`URL ${codeqlURL}.`);
|
||||
return {
|
||||
toolsVersion: maybeCliVersion ?? "unknown",
|
||||
@@ -461,9 +466,13 @@ async function downloadCodeQL(codeqlURL, maybeBundleVersion, maybeCliVersion, ap
|
||||
const toolcacheVersion = maybeCliVersion?.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)
|
||||
? `${maybeCliVersion}-${bundleVersion}`
|
||||
: convertToSemVer(bundleVersion, logger);
|
||||
const codeqlFolder = await toolcache.cacheDir(codeqlExtracted, "CodeQL", toolcacheVersion);
|
||||
await printDiskSpace(logger);
|
||||
await (0, del_1.default)(codeqlExtracted, { force: true });
|
||||
await printDiskSpace(logger);
|
||||
return {
|
||||
toolsVersion: maybeCliVersion ?? toolcacheVersion,
|
||||
codeqlFolder: await toolcache.cacheDir(codeqlExtracted, "CodeQL", toolcacheVersion),
|
||||
codeqlFolder,
|
||||
toolsDownloadDurationMs,
|
||||
};
|
||||
}
|
||||
@@ -502,7 +511,7 @@ async function setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defau
|
||||
break;
|
||||
case "toolcache":
|
||||
codeqlFolder = source.codeqlFolder;
|
||||
logger.debug(`CodeQL found in cache ${codeqlFolder}`);
|
||||
logger.info(`CodeQL found in cache ${codeqlFolder}`);
|
||||
toolsSource = ToolsSource.Toolcache;
|
||||
break;
|
||||
case "download": {
|
||||
@@ -519,4 +528,8 @@ async function setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defau
|
||||
return { codeqlFolder, toolsDownloadDurationMs, toolsSource, toolsVersion };
|
||||
}
|
||||
exports.setupCodeQLBundle = setupCodeQLBundle;
|
||||
async function printDiskSpace(logger) {
|
||||
const diskSpaceInfo = await (0, check_disk_space_1.default)(process.platform === "win32" ? path.parse(process.cwd()).root : "/");
|
||||
logger.info(`Disk space info: ${diskSpaceInfo.free / (1024 * 1024 * 1024)} GB free of ${diskSpaceInfo.size / (1024 * 1024 * 1024)} GB`);
|
||||
}
|
||||
//# sourceMappingURL=setup-codeql.js.map
|
||||
File diff suppressed because one or more lines are too long
8
node_modules/.package-lock.json
generated
vendored
8
node_modules/.package-lock.json
generated
vendored
@@ -1751,6 +1751,14 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/check-disk-space": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz",
|
||||
"integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
|
||||
21
node_modules/check-disk-space/LICENSE
generated
vendored
Normal file
21
node_modules/check-disk-space/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2019 Alexandre Demode
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
53
node_modules/check-disk-space/README.md
generated
vendored
Normal file
53
node_modules/check-disk-space/README.md
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
# Check disk space
|
||||
|
||||
[](https://github.com/Alex-D/check-disk-space/actions/workflows/ci.yml)
|
||||
[](https://www.npmjs.com/package/check-disk-space)
|
||||
[](LICENSE)
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
Light multi-platform disk space checker without third party for Node.js.
|
||||
|
||||
- Works on Linux, macOS and Windows
|
||||
- Take care of mounting points on unix-like systems
|
||||
- No dependencies
|
||||
- TypeScript support
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
`npm install check-disk-space`
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
// ES
|
||||
import checkDiskSpace from 'check-disk-space'
|
||||
|
||||
// CommonJS
|
||||
const checkDiskSpace = require('check-disk-space').default
|
||||
|
||||
// On Windows
|
||||
checkDiskSpace('C:/blabla/bla').then((diskSpace) => {
|
||||
console.log(diskSpace)
|
||||
// {
|
||||
// diskPath: 'C:',
|
||||
// free: 12345678,
|
||||
// size: 98756432
|
||||
// }
|
||||
// Note: `free` and `size` are in bytes
|
||||
})
|
||||
|
||||
// On Linux or macOS
|
||||
checkDiskSpace('/mnt/mygames').then((diskSpace) => {
|
||||
console.log(diskSpace)
|
||||
// {
|
||||
// diskPath: '/',
|
||||
// free: 12345678,
|
||||
// size: 98756432
|
||||
// }
|
||||
// Note: `free` and `size` are in bytes
|
||||
})
|
||||
```
|
||||
210
node_modules/check-disk-space/dist/check-disk-space.cjs
generated
vendored
Normal file
210
node_modules/check-disk-space/dist/check-disk-space.cjs
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var node_child_process = require('node:child_process');
|
||||
var promises = require('node:fs/promises');
|
||||
var node_os = require('node:os');
|
||||
var node_path = require('node:path');
|
||||
var node_process = require('node:process');
|
||||
var node_util = require('node:util');
|
||||
|
||||
class InvalidPathError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'InvalidPathError';
|
||||
// Set the prototype explicitly.
|
||||
Object.setPrototypeOf(this, InvalidPathError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
class NoMatchError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'NoMatchError';
|
||||
// Set the prototype explicitly.
|
||||
Object.setPrototypeOf(this, NoMatchError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if directory exists
|
||||
*
|
||||
* @param directoryPath - The file/folder path
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
async function isDirectoryExisting(directoryPath, dependencies) {
|
||||
try {
|
||||
await dependencies.fsAccess(directoryPath);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first existing parent path
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
async function getFirstExistingParentPath(directoryPath, dependencies) {
|
||||
let parentDirectoryPath = directoryPath;
|
||||
let parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies);
|
||||
while (!parentDirectoryFound) {
|
||||
parentDirectoryPath = dependencies.pathNormalize(parentDirectoryPath + '/..');
|
||||
parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies);
|
||||
}
|
||||
return parentDirectoryPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if PowerShell 3 is available based on Windows version
|
||||
*
|
||||
* Note: 6.* is Windows 7
|
||||
* Note: PowerShell 3 is natively available since Windows 8
|
||||
*
|
||||
* @param dependencies - Dependencies Injection Container
|
||||
*/
|
||||
async function hasPowerShell3(dependencies) {
|
||||
const major = parseInt(dependencies.release.split('.')[0], 10);
|
||||
if (major <= 6) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await dependencies.cpExecFile('where', ['powershell'], { windowsHide: true });
|
||||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check disk space
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
function checkDiskSpace(directoryPath, dependencies = {
|
||||
platform: node_process.platform,
|
||||
release: node_os.release(),
|
||||
fsAccess: promises.access,
|
||||
pathNormalize: node_path.normalize,
|
||||
pathSep: node_path.sep,
|
||||
cpExecFile: node_util.promisify(node_child_process.execFile),
|
||||
}) {
|
||||
// Note: This function contains other functions in order
|
||||
// to wrap them in a common context and make unit tests easier
|
||||
/**
|
||||
* Maps command output to a normalized object {diskPath, free, size}
|
||||
*
|
||||
* @param stdout - The command output
|
||||
* @param filter - To filter drives (only used for win32)
|
||||
* @param mapping - Map between column index and normalized column name
|
||||
* @param coefficient - The size coefficient to get bytes instead of kB
|
||||
*/
|
||||
function mapOutput(stdout, filter, mapping, coefficient) {
|
||||
const parsed = stdout
|
||||
.split('\n') // Split lines
|
||||
.map(line => line.trim()) // Trim all lines
|
||||
.filter(line => line.length !== 0) // Remove empty lines
|
||||
.slice(1) // Remove header
|
||||
.map(line => line.split(/\s+(?=[\d/])/)); // Split on spaces to get columns
|
||||
const filtered = parsed.filter(filter);
|
||||
if (filtered.length === 0) {
|
||||
throw new NoMatchError();
|
||||
}
|
||||
const diskData = filtered[0];
|
||||
return {
|
||||
diskPath: diskData[mapping.diskPath],
|
||||
free: parseInt(diskData[mapping.free], 10) * coefficient,
|
||||
size: parseInt(diskData[mapping.size], 10) * coefficient,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Run the command and do common things between win32 and unix
|
||||
*
|
||||
* @param cmd - The command to execute
|
||||
* @param filter - To filter drives (only used for win32)
|
||||
* @param mapping - Map between column index and normalized column name
|
||||
* @param coefficient - The size coefficient to get bytes instead of kB
|
||||
*/
|
||||
async function check(cmd, filter, mapping, coefficient = 1) {
|
||||
const [file, ...args] = cmd;
|
||||
/* istanbul ignore if */
|
||||
if (file === undefined) {
|
||||
return Promise.reject(new Error('cmd must contain at least one item'));
|
||||
}
|
||||
try {
|
||||
const { stdout } = await dependencies.cpExecFile(file, args, { windowsHide: true });
|
||||
return mapOutput(stdout, filter, mapping, coefficient);
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Build the check call for win32
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
*/
|
||||
async function checkWin32(directoryPath) {
|
||||
if (directoryPath.charAt(1) !== ':') {
|
||||
return Promise.reject(new InvalidPathError(`The following path is invalid (should be X:\\...): ${directoryPath}`));
|
||||
}
|
||||
const powershellCmd = [
|
||||
'powershell',
|
||||
'Get-CimInstance -ClassName Win32_LogicalDisk | Select-Object Caption, FreeSpace, Size',
|
||||
];
|
||||
const wmicCmd = [
|
||||
'wmic',
|
||||
'logicaldisk',
|
||||
'get',
|
||||
'size,freespace,caption',
|
||||
];
|
||||
const cmd = await hasPowerShell3(dependencies) ? powershellCmd : wmicCmd;
|
||||
return check(cmd, driveData => {
|
||||
// Only get the drive which match the path
|
||||
const driveLetter = driveData[0];
|
||||
return directoryPath.toUpperCase().startsWith(driveLetter.toUpperCase());
|
||||
}, {
|
||||
diskPath: 0,
|
||||
free: 1,
|
||||
size: 2,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Build the check call for unix
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
*/
|
||||
async function checkUnix(directoryPath) {
|
||||
if (!dependencies.pathNormalize(directoryPath).startsWith(dependencies.pathSep)) {
|
||||
return Promise.reject(new InvalidPathError(`The following path is invalid (should start by ${dependencies.pathSep}): ${directoryPath}`));
|
||||
}
|
||||
const pathToCheck = await getFirstExistingParentPath(directoryPath, dependencies);
|
||||
return check([
|
||||
'df',
|
||||
'-Pk',
|
||||
'--',
|
||||
pathToCheck,
|
||||
], () => true, // We should only get one line, so we did not need to filter
|
||||
{
|
||||
diskPath: 5,
|
||||
free: 3,
|
||||
size: 1,
|
||||
}, 1024);
|
||||
}
|
||||
// Call the right check depending on the OS
|
||||
if (dependencies.platform === 'win32') {
|
||||
return checkWin32(directoryPath);
|
||||
}
|
||||
return checkUnix(directoryPath);
|
||||
}
|
||||
|
||||
exports.InvalidPathError = InvalidPathError;
|
||||
exports.NoMatchError = NoMatchError;
|
||||
exports.default = checkDiskSpace;
|
||||
exports.getFirstExistingParentPath = getFirstExistingParentPath;
|
||||
53
node_modules/check-disk-space/dist/check-disk-space.d.ts
generated
vendored
Normal file
53
node_modules/check-disk-space/dist/check-disk-space.d.ts
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import { access } from 'node:fs/promises';
|
||||
import { normalize, sep } from 'node:path';
|
||||
|
||||
declare class InvalidPathError extends Error {
|
||||
name: string;
|
||||
constructor(message?: string);
|
||||
}
|
||||
|
||||
declare class NoMatchError extends Error {
|
||||
name: string;
|
||||
constructor(message?: string);
|
||||
}
|
||||
|
||||
type Dependencies = {
|
||||
platform: NodeJS.Platform;
|
||||
release: string;
|
||||
fsAccess: typeof access;
|
||||
pathNormalize: typeof normalize;
|
||||
pathSep: typeof sep;
|
||||
cpExecFile: (file: string, args: ReadonlyArray<string> | undefined | null, options: {
|
||||
windowsHide: true;
|
||||
}) => Promise<{
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the first existing parent path
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
declare function getFirstExistingParentPath(directoryPath: string, dependencies: Dependencies): Promise<string>;
|
||||
|
||||
/**
|
||||
* `free` and `size` are in bytes
|
||||
*/
|
||||
type DiskSpace = {
|
||||
diskPath: string;
|
||||
free: number;
|
||||
size: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check disk space
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
declare function checkDiskSpace(directoryPath: string, dependencies?: Dependencies): Promise<DiskSpace>;
|
||||
|
||||
export { Dependencies, DiskSpace, InvalidPathError, NoMatchError, checkDiskSpace as default, getFirstExistingParentPath };
|
||||
203
node_modules/check-disk-space/dist/check-disk-space.mjs
generated
vendored
Normal file
203
node_modules/check-disk-space/dist/check-disk-space.mjs
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
import { execFile } from 'node:child_process';
|
||||
import { access } from 'node:fs/promises';
|
||||
import { release } from 'node:os';
|
||||
import { normalize, sep } from 'node:path';
|
||||
import { platform } from 'node:process';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
class InvalidPathError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'InvalidPathError';
|
||||
// Set the prototype explicitly.
|
||||
Object.setPrototypeOf(this, InvalidPathError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
class NoMatchError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'NoMatchError';
|
||||
// Set the prototype explicitly.
|
||||
Object.setPrototypeOf(this, NoMatchError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if directory exists
|
||||
*
|
||||
* @param directoryPath - The file/folder path
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
async function isDirectoryExisting(directoryPath, dependencies) {
|
||||
try {
|
||||
await dependencies.fsAccess(directoryPath);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first existing parent path
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
async function getFirstExistingParentPath(directoryPath, dependencies) {
|
||||
let parentDirectoryPath = directoryPath;
|
||||
let parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies);
|
||||
while (!parentDirectoryFound) {
|
||||
parentDirectoryPath = dependencies.pathNormalize(parentDirectoryPath + '/..');
|
||||
parentDirectoryFound = await isDirectoryExisting(parentDirectoryPath, dependencies);
|
||||
}
|
||||
return parentDirectoryPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if PowerShell 3 is available based on Windows version
|
||||
*
|
||||
* Note: 6.* is Windows 7
|
||||
* Note: PowerShell 3 is natively available since Windows 8
|
||||
*
|
||||
* @param dependencies - Dependencies Injection Container
|
||||
*/
|
||||
async function hasPowerShell3(dependencies) {
|
||||
const major = parseInt(dependencies.release.split('.')[0], 10);
|
||||
if (major <= 6) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await dependencies.cpExecFile('where', ['powershell'], { windowsHide: true });
|
||||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check disk space
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
* @param dependencies - Dependencies container
|
||||
*/
|
||||
function checkDiskSpace(directoryPath, dependencies = {
|
||||
platform,
|
||||
release: release(),
|
||||
fsAccess: access,
|
||||
pathNormalize: normalize,
|
||||
pathSep: sep,
|
||||
cpExecFile: promisify(execFile),
|
||||
}) {
|
||||
// Note: This function contains other functions in order
|
||||
// to wrap them in a common context and make unit tests easier
|
||||
/**
|
||||
* Maps command output to a normalized object {diskPath, free, size}
|
||||
*
|
||||
* @param stdout - The command output
|
||||
* @param filter - To filter drives (only used for win32)
|
||||
* @param mapping - Map between column index and normalized column name
|
||||
* @param coefficient - The size coefficient to get bytes instead of kB
|
||||
*/
|
||||
function mapOutput(stdout, filter, mapping, coefficient) {
|
||||
const parsed = stdout
|
||||
.split('\n') // Split lines
|
||||
.map(line => line.trim()) // Trim all lines
|
||||
.filter(line => line.length !== 0) // Remove empty lines
|
||||
.slice(1) // Remove header
|
||||
.map(line => line.split(/\s+(?=[\d/])/)); // Split on spaces to get columns
|
||||
const filtered = parsed.filter(filter);
|
||||
if (filtered.length === 0) {
|
||||
throw new NoMatchError();
|
||||
}
|
||||
const diskData = filtered[0];
|
||||
return {
|
||||
diskPath: diskData[mapping.diskPath],
|
||||
free: parseInt(diskData[mapping.free], 10) * coefficient,
|
||||
size: parseInt(diskData[mapping.size], 10) * coefficient,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Run the command and do common things between win32 and unix
|
||||
*
|
||||
* @param cmd - The command to execute
|
||||
* @param filter - To filter drives (only used for win32)
|
||||
* @param mapping - Map between column index and normalized column name
|
||||
* @param coefficient - The size coefficient to get bytes instead of kB
|
||||
*/
|
||||
async function check(cmd, filter, mapping, coefficient = 1) {
|
||||
const [file, ...args] = cmd;
|
||||
/* istanbul ignore if */
|
||||
if (file === undefined) {
|
||||
return Promise.reject(new Error('cmd must contain at least one item'));
|
||||
}
|
||||
try {
|
||||
const { stdout } = await dependencies.cpExecFile(file, args, { windowsHide: true });
|
||||
return mapOutput(stdout, filter, mapping, coefficient);
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Build the check call for win32
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
*/
|
||||
async function checkWin32(directoryPath) {
|
||||
if (directoryPath.charAt(1) !== ':') {
|
||||
return Promise.reject(new InvalidPathError(`The following path is invalid (should be X:\\...): ${directoryPath}`));
|
||||
}
|
||||
const powershellCmd = [
|
||||
'powershell',
|
||||
'Get-CimInstance -ClassName Win32_LogicalDisk | Select-Object Caption, FreeSpace, Size',
|
||||
];
|
||||
const wmicCmd = [
|
||||
'wmic',
|
||||
'logicaldisk',
|
||||
'get',
|
||||
'size,freespace,caption',
|
||||
];
|
||||
const cmd = await hasPowerShell3(dependencies) ? powershellCmd : wmicCmd;
|
||||
return check(cmd, driveData => {
|
||||
// Only get the drive which match the path
|
||||
const driveLetter = driveData[0];
|
||||
return directoryPath.toUpperCase().startsWith(driveLetter.toUpperCase());
|
||||
}, {
|
||||
diskPath: 0,
|
||||
free: 1,
|
||||
size: 2,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Build the check call for unix
|
||||
*
|
||||
* @param directoryPath - The file/folder path from where we want to know disk space
|
||||
*/
|
||||
async function checkUnix(directoryPath) {
|
||||
if (!dependencies.pathNormalize(directoryPath).startsWith(dependencies.pathSep)) {
|
||||
return Promise.reject(new InvalidPathError(`The following path is invalid (should start by ${dependencies.pathSep}): ${directoryPath}`));
|
||||
}
|
||||
const pathToCheck = await getFirstExistingParentPath(directoryPath, dependencies);
|
||||
return check([
|
||||
'df',
|
||||
'-Pk',
|
||||
'--',
|
||||
pathToCheck,
|
||||
], () => true, // We should only get one line, so we did not need to filter
|
||||
{
|
||||
diskPath: 5,
|
||||
free: 3,
|
||||
size: 1,
|
||||
}, 1024);
|
||||
}
|
||||
// Call the right check depending on the OS
|
||||
if (dependencies.platform === 'win32') {
|
||||
return checkWin32(directoryPath);
|
||||
}
|
||||
return checkUnix(directoryPath);
|
||||
}
|
||||
|
||||
export { InvalidPathError, NoMatchError, checkDiskSpace as default, getFirstExistingParentPath };
|
||||
83
node_modules/check-disk-space/package.json
generated
vendored
Normal file
83
node_modules/check-disk-space/package.json
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"name": "check-disk-space",
|
||||
"version": "3.4.0",
|
||||
"description": "Light multi-platform disk space checker without third party for Node.js",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"main": "./dist/check-disk-space.cjs",
|
||||
"module": "./dist/check-disk-space.mjs",
|
||||
"types": "./dist/check-disk-space.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist/check-disk-space.mjs",
|
||||
"require": "./dist/check-disk-space.cjs",
|
||||
"types": "./dist/check-disk-space.d.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build:lib": "rollup --config",
|
||||
"build:dts": "rollup --config rollup.dts.config.mjs",
|
||||
"build": "npm-run-all build:lib build:dts",
|
||||
"lint": "eslint . --cache",
|
||||
"lint:fix": "eslint --fix .",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "npm-run-all test:coverage lint typecheck",
|
||||
"test:unit": "NODE_ENV=test TS_NODE_PROJECT='tsconfig.test.json' ava",
|
||||
"test:coverage": "nyc --reporter=lcov --reporter=text npm run test:unit --silent"
|
||||
},
|
||||
"ava": {
|
||||
"files": [
|
||||
"test/**",
|
||||
"!test/__helpers__/**"
|
||||
],
|
||||
"extensions": [
|
||||
"ts"
|
||||
],
|
||||
"require": [
|
||||
"tsconfig-paths/register",
|
||||
"ts-node/register",
|
||||
"source-map-support/register"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alex-d/eslint-config": "2.2.0",
|
||||
"@istanbuljs/nyc-config-typescript": "1.0.2",
|
||||
"@rollup/plugin-typescript": "11.1.1",
|
||||
"@types/node": "16.11.7",
|
||||
"@typescript-eslint/eslint-plugin": "5.59.6",
|
||||
"@typescript-eslint/parser": "5.59.6",
|
||||
"ava": "5.2.0",
|
||||
"eslint": "8.41.0",
|
||||
"eslint-plugin-ava": "14.0.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-simple-import-sort": "10.0.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"nyc": "15.1.0",
|
||||
"rollup": "3.22.0",
|
||||
"rollup-plugin-dts": "5.3.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"ts-node": "10.9.1",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"tslib": "2.5.2",
|
||||
"typescript": "5.0.4"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Alex-D/check-disk-space.git"
|
||||
},
|
||||
"keywords": [
|
||||
"disk",
|
||||
"space",
|
||||
"hdd",
|
||||
"free"
|
||||
],
|
||||
"author": "Alex-D <contact@alex-d.fr> (https://alex-d.fr)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Alex-D/check-disk-space/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Alex-D/check-disk-space#readme"
|
||||
}
|
||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -22,6 +22,7 @@
|
||||
"@schemastore/package": "0.0.10",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"adm-zip": "^0.5.10",
|
||||
"check-disk-space": "^3.4.0",
|
||||
"console-log-level": "^1.4.1",
|
||||
"del": "^6.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@@ -1807,6 +1808,14 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/check-disk-space": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz",
|
||||
"integrity": "sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@schemastore/package": "0.0.10",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"adm-zip": "^0.5.10",
|
||||
"check-disk-space": "^3.4.0",
|
||||
"console-log-level": "^1.4.1",
|
||||
"del": "^6.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as path from "path";
|
||||
import { performance } from "perf_hooks";
|
||||
|
||||
import * as toolcache from "@actions/tool-cache";
|
||||
import checkDiskSpace from "check-disk-space";
|
||||
import del from "del";
|
||||
import { default as deepEqual } from "fast-deep-equal";
|
||||
import * as semver from "semver";
|
||||
@@ -71,7 +72,7 @@ function tryGetCodeQLCliVersionForRelease(
|
||||
);
|
||||
return undefined;
|
||||
} else if (cliVersionsFromMarkerFiles.length === 0) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Failed to find the CodeQL CLI version for release ${release.tag_name}.`,
|
||||
);
|
||||
return undefined;
|
||||
@@ -84,7 +85,7 @@ export async function tryFindCliVersionDotcomOnly(
|
||||
logger: Logger,
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Fetching the GitHub Release for the CodeQL bundle tagged ${tagName}.`,
|
||||
);
|
||||
const apiClient = api.getApiClient();
|
||||
@@ -96,7 +97,7 @@ export async function tryFindCliVersionDotcomOnly(
|
||||
});
|
||||
return tryGetCodeQLCliVersionForRelease(release.data, logger);
|
||||
} catch (e) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Failed to find the CLI version for the CodeQL bundle tagged ${tagName}. ${
|
||||
wrapError(e).message
|
||||
}`,
|
||||
@@ -200,7 +201,7 @@ function tryGetBundleVersionFromTagName(
|
||||
): string | undefined {
|
||||
const match = tagName.match(/^codeql-bundle-(.*)$/);
|
||||
if (match === null || match.length < 2) {
|
||||
logger.debug(`Could not determine bundle version from tag ${tagName}.`);
|
||||
logger.info(`Could not determine bundle version from tag ${tagName}.`);
|
||||
return undefined;
|
||||
}
|
||||
return match[1];
|
||||
@@ -209,7 +210,7 @@ function tryGetBundleVersionFromTagName(
|
||||
function tryGetTagNameFromUrl(url: string, logger: Logger): string | undefined {
|
||||
const match = url.match(/\/(codeql-bundle-.*)\//);
|
||||
if (match === null || match.length < 2) {
|
||||
logger.debug(`Could not determine tag name for URL ${url}.`);
|
||||
logger.info(`Could not determine tag name for URL ${url}.`);
|
||||
return undefined;
|
||||
}
|
||||
return match[1];
|
||||
@@ -228,7 +229,7 @@ export function tryGetBundleVersionFromUrl(
|
||||
|
||||
export function convertToSemVer(version: string, logger: Logger): string {
|
||||
if (!semver.valid(version)) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`,
|
||||
);
|
||||
version = `0.0.0-${version}`;
|
||||
@@ -284,7 +285,7 @@ async function findOverridingToolsInCache(
|
||||
|
||||
if (candidates.length === 1) {
|
||||
const candidate = candidates[0];
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`CodeQL tools version ${candidate.version} in toolcache overriding version ${humanReadableVersion}.`,
|
||||
);
|
||||
return {
|
||||
@@ -293,11 +294,11 @@ async function findOverridingToolsInCache(
|
||||
toolsVersion: candidate.version,
|
||||
};
|
||||
} else if (candidates.length === 0) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
"Did not find any candidate pinned versions of the CodeQL tools in the toolcache.",
|
||||
);
|
||||
} else {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
"Could not use CodeQL tools from the toolcache since more than one candidate pinned " +
|
||||
"version was found in the toolcache.",
|
||||
);
|
||||
@@ -376,7 +377,7 @@ export async function getCodeQLSource(
|
||||
url ??
|
||||
"unknown";
|
||||
|
||||
logger.debug(
|
||||
logger.info(
|
||||
"Attempting to obtain CodeQL tools. " +
|
||||
`CLI version: ${cliVersion ?? "unknown"}, ` +
|
||||
`bundle tag name: ${tagName ?? "unknown"}, ` +
|
||||
@@ -391,12 +392,12 @@ export async function getCodeQLSource(
|
||||
|
||||
// Fall back to matching `x.y.z-<tagName>`.
|
||||
if (!codeqlFolder) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
"Didn't find a version of the CodeQL tools in the toolcache with a version number " +
|
||||
`exactly matching ${cliVersion}.`,
|
||||
);
|
||||
const allVersions = toolcache.findAllVersions("CodeQL");
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Found the following versions of the CodeQL tools in the toolcache: ${JSON.stringify(
|
||||
allVersions,
|
||||
)}.`,
|
||||
@@ -407,13 +408,13 @@ export async function getCodeQLSource(
|
||||
version.startsWith(`${cliVersion}-`),
|
||||
);
|
||||
if (candidateVersions.length === 1) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Exactly one version of the CodeQL tools starting with ${cliVersion} found in the ` +
|
||||
"toolcache, using that.",
|
||||
);
|
||||
codeqlFolder = toolcache.find("CodeQL", candidateVersions[0]);
|
||||
} else if (candidateVersions.length === 0) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Didn't find any versions of the CodeQL tools starting with ${cliVersion} ` +
|
||||
`in the toolcache. Trying next fallback method.`,
|
||||
);
|
||||
@@ -422,7 +423,7 @@ export async function getCodeQLSource(
|
||||
`Found ${candidateVersions.length} versions of the CodeQL tools starting with ` +
|
||||
`${cliVersion} in the toolcache, but at most one was expected.`,
|
||||
);
|
||||
logger.debug("Trying next fallback method.");
|
||||
logger.info("Trying next fallback method.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,7 +438,7 @@ export async function getCodeQLSource(
|
||||
if (fallbackVersion) {
|
||||
codeqlFolder = toolcache.find("CodeQL", fallbackVersion);
|
||||
} else {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
"Could not determine a fallback toolcache version number for CodeQL tools version " +
|
||||
`${humanReadableVersion}.`,
|
||||
);
|
||||
@@ -511,7 +512,7 @@ export async function tryGetFallbackToolcacheVersion(
|
||||
return undefined;
|
||||
}
|
||||
const fallbackVersion = convertToSemVer(bundleVersion, logger);
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Computed a fallback toolcache version number of ${fallbackVersion} for CodeQL version ` +
|
||||
`${cliVersion ?? tagName}.`,
|
||||
);
|
||||
@@ -542,13 +543,16 @@ export async function downloadCodeQL(
|
||||
// We also don't want to send an authorization header if there's already a token provided in the URL.
|
||||
let authorization: string | undefined = undefined;
|
||||
if (searchParams.has("token")) {
|
||||
logger.debug("CodeQL tools URL contains an authorization token.");
|
||||
logger.info("CodeQL tools URL contains an authorization token.");
|
||||
} else if (codeqlURL.startsWith(`${apiDetails.url}/`)) {
|
||||
logger.debug("Providing an authorization token to download CodeQL tools.");
|
||||
logger.info("Providing an authorization token to download CodeQL tools.");
|
||||
authorization = `token ${apiDetails.auth}`;
|
||||
} else {
|
||||
logger.debug("Downloading CodeQL tools without an authorization token.");
|
||||
logger.info("Downloading CodeQL tools without an authorization token.");
|
||||
}
|
||||
|
||||
await printDiskSpace(logger);
|
||||
|
||||
logger.info(
|
||||
`Downloading CodeQL tools from ${codeqlURL}. This may take a while.`,
|
||||
);
|
||||
@@ -570,26 +574,32 @@ export async function downloadCodeQL(
|
||||
performance.now() - toolsDownloadStart,
|
||||
);
|
||||
|
||||
logger.debug(
|
||||
logger.info(
|
||||
`Finished downloading CodeQL bundle to ${codeqlPath} (${toolsDownloadDurationMs} ms).`,
|
||||
);
|
||||
|
||||
await printDiskSpace(logger);
|
||||
|
||||
const codeqlExtracted = await toolcache.extractTar(codeqlPath);
|
||||
|
||||
logger.debug(`Finished extracting CodeQL bundle to ${codeqlExtracted}.`);
|
||||
logger.info(`Finished extracting CodeQL bundle to ${codeqlExtracted}.`);
|
||||
|
||||
await printDiskSpace(logger);
|
||||
|
||||
try {
|
||||
await del(codeqlPath, { force: true });
|
||||
logger.debug("Deleted CodeQL bundle archive.");
|
||||
logger.info("Deleted CodeQL bundle archive.");
|
||||
} catch (e) {
|
||||
logger.warning("Failed to delete CodeQL bundle archive.");
|
||||
}
|
||||
|
||||
await printDiskSpace(logger);
|
||||
|
||||
const bundleVersion =
|
||||
maybeBundleVersion ?? tryGetBundleVersionFromUrl(codeqlURL, logger);
|
||||
|
||||
if (bundleVersion === undefined) {
|
||||
logger.debug(
|
||||
logger.info(
|
||||
"Could not cache CodeQL tools because we could not determine the bundle version from the " +
|
||||
`URL ${codeqlURL}.`,
|
||||
);
|
||||
@@ -624,13 +634,22 @@ export async function downloadCodeQL(
|
||||
const toolcacheVersion = maybeCliVersion?.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)
|
||||
? `${maybeCliVersion}-${bundleVersion}`
|
||||
: convertToSemVer(bundleVersion, logger);
|
||||
|
||||
const codeqlFolder = await toolcache.cacheDir(
|
||||
codeqlExtracted,
|
||||
"CodeQL",
|
||||
toolcacheVersion,
|
||||
);
|
||||
|
||||
await printDiskSpace(logger);
|
||||
|
||||
await del(codeqlExtracted, { force: true });
|
||||
|
||||
await printDiskSpace(logger);
|
||||
|
||||
return {
|
||||
toolsVersion: maybeCliVersion ?? toolcacheVersion,
|
||||
codeqlFolder: await toolcache.cacheDir(
|
||||
codeqlExtracted,
|
||||
"CodeQL",
|
||||
toolcacheVersion,
|
||||
),
|
||||
codeqlFolder,
|
||||
toolsDownloadDurationMs,
|
||||
};
|
||||
}
|
||||
@@ -690,7 +709,7 @@ export async function setupCodeQLBundle(
|
||||
break;
|
||||
case "toolcache":
|
||||
codeqlFolder = source.codeqlFolder;
|
||||
logger.debug(`CodeQL found in cache ${codeqlFolder}`);
|
||||
logger.info(`CodeQL found in cache ${codeqlFolder}`);
|
||||
toolsSource = ToolsSource.Toolcache;
|
||||
break;
|
||||
case "download": {
|
||||
@@ -714,3 +733,14 @@ export async function setupCodeQLBundle(
|
||||
}
|
||||
return { codeqlFolder, toolsDownloadDurationMs, toolsSource, toolsVersion };
|
||||
}
|
||||
|
||||
async function printDiskSpace(logger: Logger) {
|
||||
const diskSpaceInfo = await checkDiskSpace(
|
||||
process.platform === "win32" ? path.parse(process.cwd()).root : "/",
|
||||
);
|
||||
logger.info(
|
||||
`Disk space info: ${diskSpaceInfo.free / (1024 * 1024 * 1024)} GB free of ${
|
||||
diskSpaceInfo.size / (1024 * 1024 * 1024)
|
||||
} GB`,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user