@vscode/test-electron
Advanced tools
Comparing version 2.3.10 to 2.4.0
# Changelog | ||
### 2.3.10 | 2024-01-19 | ||
### 2.4.0 | 2024-05-24 | ||
- Allow installing unreleased builds using an `-unreleased` suffix, such as `insiders-unreleased`. | ||
- Allow passing different data directories in `runVSCodeCommand`, using it for extension development. | ||
- Improve the appearance progress reporting. | ||
### 2.3.10 | 2024-05-13 | ||
- Add `runVSCodeCommand` method and workaround for Node CVE-2024-27980 | ||
@@ -6,0 +12,0 @@ |
@@ -1,2 +0,3 @@ | ||
import { ProgressReporter } from './progress'; | ||
import { ProgressReporter } from './progress.js'; | ||
import { Version } from './util'; | ||
interface IFetchStableOptions { | ||
@@ -10,5 +11,5 @@ timeout: number; | ||
} | ||
export declare const fetchStableVersions: (timeout: number) => Promise<string[]>; | ||
export declare const fetchInsiderVersions: (timeout: number) => Promise<string[]>; | ||
export declare function fetchTargetInferredVersion(options: IFetchInferredOptions): Promise<string>; | ||
export declare const fetchStableVersions: (released: boolean, timeout: number) => Promise<string[]>; | ||
export declare const fetchInsiderVersions: (released: boolean, timeout: number) => Promise<string[]>; | ||
export declare function fetchTargetInferredVersion(options: IFetchInferredOptions): Promise<Version>; | ||
/** | ||
@@ -18,5 +19,5 @@ * Adapted from https://github.com/microsoft/TypeScript/issues/29729 | ||
*/ | ||
declare type StringLiteralUnion<T extends string> = T | (string & {}); | ||
export declare type DownloadVersion = StringLiteralUnion<'insiders' | 'stable'>; | ||
export declare type DownloadPlatform = StringLiteralUnion<'darwin' | 'darwin-arm64' | 'win32-x64-archive' | 'win32-arm64-archive' | 'linux-x64' | 'linux-arm64' | 'linux-armhf'>; | ||
type StringLiteralUnion<T extends string> = T | (string & {}); | ||
export type DownloadVersion = StringLiteralUnion<'insiders' | 'stable'>; | ||
export type DownloadPlatform = StringLiteralUnion<'darwin' | 'darwin-arm64' | 'win32-x64-archive' | 'win32-arm64-archive' | 'linux-x64' | 'linux-arm64' | 'linux-armhf'>; | ||
export interface DownloadOptions { | ||
@@ -23,0 +24,0 @@ /** |
@@ -6,23 +6,46 @@ "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; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.downloadAndUnzipVSCode = exports.download = exports.defaultCachePath = exports.fetchTargetInferredVersion = exports.fetchInsiderVersions = exports.fetchStableVersions = void 0; | ||
const cp = require("child_process"); | ||
const fs = require("fs"); | ||
const cp = __importStar(require("child_process")); | ||
const fs = __importStar(require("fs")); | ||
const os_1 = require("os"); | ||
const path = require("path"); | ||
const semver = require("semver"); | ||
const path = __importStar(require("path")); | ||
const semver = __importStar(require("semver")); | ||
const stream_1 = require("stream"); | ||
const util_1 = require("util"); | ||
const progress_1 = require("./progress"); | ||
const request = require("./request"); | ||
const progress_js_1 = require("./progress.js"); | ||
const request = __importStar(require("./request")); | ||
const util_2 = require("./util"); | ||
const extensionRoot = process.cwd(); | ||
const pipelineAsync = util_1.promisify(stream_1.pipeline); | ||
const pipelineAsync = (0, util_1.promisify)(stream_1.pipeline); | ||
const vscodeStableReleasesAPI = `https://update.code.visualstudio.com/api/releases/stable`; | ||
const vscodeInsiderReleasesAPI = `https://update.code.visualstudio.com/api/releases/insider`; | ||
const downloadDirNameFormat = /^vscode-(?<platform>[a-z]+)-(?<version>[0-9.]+)$/; | ||
const makeDownloadDirName = (platform, version) => `vscode-${platform}-${version}`; | ||
const makeDownloadDirName = (platform, version) => `vscode-${platform}-${version.id}`; | ||
const DOWNLOAD_ATTEMPTS = 3; | ||
exports.fetchStableVersions = util_2.onceWithoutRejections((timeout) => request.getJSON(vscodeStableReleasesAPI, timeout)); | ||
exports.fetchInsiderVersions = util_2.onceWithoutRejections((timeout) => request.getJSON(vscodeInsiderReleasesAPI, timeout)); | ||
exports.fetchStableVersions = (0, util_2.onceWithoutRejections)((released, timeout) => request.getJSON(`${vscodeStableReleasesAPI}?released=${released}`, timeout)); | ||
exports.fetchInsiderVersions = (0, util_2.onceWithoutRejections)((released, timeout) => request.getJSON(`${vscodeInsiderReleasesAPI}?released=${released}`, timeout)); | ||
/** | ||
@@ -35,4 +58,4 @@ * Returns the stable version to run tests against. Attempts to get the latest | ||
try { | ||
const versions = await exports.fetchStableVersions(timeout); | ||
return versions[0]; | ||
const versions = await (0, exports.fetchStableVersions)(true, timeout); | ||
return new util_2.Version(versions[0]); | ||
} | ||
@@ -57,15 +80,15 @@ catch (e) { | ||
try { | ||
const stable = await exports.fetchStableVersions(options.timeout); | ||
const stable = await (0, exports.fetchStableVersions)(true, options.timeout); | ||
const found1 = stable.find(matches); | ||
if (found1) { | ||
return found1; | ||
return new util_2.Version(found1); | ||
} | ||
const insiders = await exports.fetchInsiderVersions(options.timeout); | ||
const insiders = await (0, exports.fetchInsiderVersions)(true, options.timeout); | ||
const found2 = insiders.find(matches); | ||
if (found2) { | ||
return found2; | ||
return new util_2.Version(found2); | ||
} | ||
const v = extVersions.join(', '); | ||
console.warn(`No version of VS Code satisfies all extension engine constraints (${v}). Falling back to stable.`); | ||
return stable[0]; // 🤷 | ||
return new util_2.Version(stable[0]); // 🤷 | ||
} | ||
@@ -78,7 +101,6 @@ catch (e) { | ||
async function getEngineVersionFromExtension(extensionPath) { | ||
var _a; | ||
try { | ||
const packageContents = await fs.promises.readFile(path.join(extensionPath, 'package.json'), 'utf8'); | ||
const packageJson = JSON.parse(packageContents); | ||
return (_a = packageJson === null || packageJson === void 0 ? void 0 : packageJson.engines) === null || _a === void 0 ? void 0 : _a.vscode; | ||
return packageJson?.engines?.vscode; | ||
} | ||
@@ -99,25 +121,22 @@ catch { | ||
console.warn(`Error retrieving VS Code versions, using already-installed version ${fallbackTo}`, fromError); | ||
return fallbackTo; | ||
return new util_2.Version(fallbackTo); | ||
} | ||
throw fromError; | ||
} | ||
async function isValidVersion(version, platform, timeout) { | ||
if (version === 'insiders' || version === 'stable') { | ||
async function isValidVersion(version, timeout) { | ||
if (version.id === 'insiders' || version.id === 'stable' || version.isCommit) { | ||
return true; | ||
} | ||
if (util_2.isStableVersionIdentifier(version)) { | ||
const stableVersionNumbers = await exports.fetchStableVersions(timeout); | ||
if (stableVersionNumbers.includes(version)) { | ||
if (version.isStable) { | ||
const stableVersionNumbers = await (0, exports.fetchStableVersions)(version.isReleased, timeout); | ||
if (stableVersionNumbers.includes(version.id)) { | ||
return true; | ||
} | ||
} | ||
if (util_2.isInsiderVersionIdentifier(version)) { | ||
const insiderVersionNumbers = await exports.fetchInsiderVersions(timeout); | ||
if (insiderVersionNumbers.includes(version)) { | ||
if (version.isInsiders) { | ||
const insiderVersionNumbers = await (0, exports.fetchInsiderVersions)(version.isReleased, timeout); | ||
if (insiderVersionNumbers.includes(version.id)) { | ||
return true; | ||
} | ||
} | ||
if (/^[0-9a-f]{40}$/.test(version)) { | ||
return true; | ||
} | ||
return false; | ||
@@ -143,3 +162,2 @@ } | ||
async function downloadVSCodeArchive(options) { | ||
var _a, _b, _c; | ||
if (!fs.existsSync(options.cachePath)) { | ||
@@ -149,4 +167,5 @@ fs.mkdirSync(options.cachePath); | ||
const timeout = options.timeout; | ||
const downloadUrl = util_2.getVSCodeDownloadUrl(options.version, options.platform); | ||
(_a = options.reporter) === null || _a === void 0 ? void 0 : _a.report({ stage: progress_1.ProgressReportStage.ResolvingCDNLocation, url: downloadUrl }); | ||
const version = util_2.Version.parse(options.version); | ||
const downloadUrl = (0, util_2.getVSCodeDownloadUrl)(version, options.platform); | ||
options.reporter?.report({ stage: progress_js_1.ProgressReportStage.ResolvingCDNLocation, url: downloadUrl }); | ||
const res = await request.getStream(downloadUrl, timeout); | ||
@@ -166,6 +185,6 @@ if (res.statusCode !== 302) { | ||
const fileName = contentDisposition ? getFilename(contentDisposition) : undefined; | ||
const isZip = (_b = fileName === null || fileName === void 0 ? void 0 : fileName.endsWith('zip')) !== null && _b !== void 0 ? _b : url.endsWith('.zip'); | ||
const isZip = fileName?.endsWith('zip') ?? url.endsWith('.zip'); | ||
const timeoutCtrl = new request.TimeoutController(timeout); | ||
(_c = options.reporter) === null || _c === void 0 ? void 0 : _c.report({ | ||
stage: progress_1.ProgressReportStage.Downloading, | ||
options.reporter?.report({ | ||
stage: progress_js_1.ProgressReportStage.Downloading, | ||
url, | ||
@@ -177,7 +196,6 @@ bytesSoFar: 0, | ||
download.on('data', (chunk) => { | ||
var _a; | ||
bytesSoFar += chunk.length; | ||
timeoutCtrl.touch(); | ||
(_a = options.reporter) === null || _a === void 0 ? void 0 : _a.report({ | ||
stage: progress_1.ProgressReportStage.Downloading, | ||
options.reporter?.report({ | ||
stage: progress_js_1.ProgressReportStage.Downloading, | ||
url, | ||
@@ -189,6 +207,5 @@ bytesSoFar, | ||
download.on('end', () => { | ||
var _a; | ||
timeoutCtrl.dispose(); | ||
(_a = options.reporter) === null || _a === void 0 ? void 0 : _a.report({ | ||
stage: progress_1.ProgressReportStage.Downloading, | ||
options.reporter?.report({ | ||
stage: progress_js_1.ProgressReportStage.Downloading, | ||
url, | ||
@@ -214,7 +231,7 @@ bytesSoFar: totalBytes, | ||
async function unzipVSCode(reporter, extractDir, platform, { format, stream, length, sha256 }) { | ||
const stagingFile = path.join(os_1.tmpdir(), `vscode-test-${Date.now()}.zip`); | ||
const checksum = util_2.validateStream(stream, length, sha256); | ||
const stagingFile = path.join((0, os_1.tmpdir)(), `vscode-test-${Date.now()}.zip`); | ||
const checksum = (0, util_2.validateStream)(stream, length, sha256); | ||
if (format === 'zip') { | ||
try { | ||
reporter.report({ stage: progress_1.ProgressReportStage.ExtractingSynchonrously }); | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.ExtractingSynchonrously }); | ||
// note: this used to use Expand-Archive, but this caused a failure | ||
@@ -226,3 +243,3 @@ // on longer file paths on windows. And we used to use the streaming | ||
if (process.platform === 'win32') { | ||
const [buffer, JSZip] = await Promise.all([util_2.streamToBuffer(stream), Promise.resolve().then(() => require('jszip'))]); | ||
const [buffer, JSZip] = await Promise.all([(0, util_2.streamToBuffer)(stream), import('jszip')]); | ||
await checksum; | ||
@@ -235,3 +252,3 @@ // Turn off Electron's special handling of .asar files, otherwise | ||
process.noAsar = true; | ||
const content = await JSZip.loadAsync(buffer); | ||
const content = await JSZip.default.loadAsync(buffer); | ||
// extract file with jszip | ||
@@ -245,3 +262,3 @@ for (const filename of Object.keys(content.files)) { | ||
// vscode update zips are trusted, but check for zip slip anyway. | ||
if (!util_2.isSubdirectory(extractDir, filepath)) { | ||
if (!(0, util_2.isSubdirectory)(extractDir, filepath)) { | ||
throw new Error(`Invalid zip file: ${filename}`); | ||
@@ -295,16 +312,18 @@ } | ||
async function download(options = {}) { | ||
let version = options === null || options === void 0 ? void 0 : options.version; | ||
const { platform = util_2.systemDefaultPlatform, cachePath = exports.defaultCachePath, reporter = new progress_1.ConsoleReporter(process.stdout.isTTY), timeout = 15000, } = options; | ||
if (version === 'stable') { | ||
const inputVersion = options?.version ? util_2.Version.parse(options.version) : undefined; | ||
const { platform = util_2.systemDefaultPlatform, cachePath = exports.defaultCachePath, reporter = await (0, progress_js_1.makeConsoleReporter)(), timeout = 15_000, } = options; | ||
let version; | ||
if (inputVersion?.id === 'stable') { | ||
version = await fetchTargetStableVersion({ timeout, cachePath, platform }); | ||
} | ||
else if (version) { | ||
else if (inputVersion) { | ||
/** | ||
* Only validate version against server when no local download that matches version exists | ||
*/ | ||
if (!fs.existsSync(path.resolve(cachePath, `vscode-${platform}-${version}`))) { | ||
if (!(await isValidVersion(version, platform, timeout))) { | ||
throw Error(`Invalid version ${version}`); | ||
if (!fs.existsSync(path.resolve(cachePath, makeDownloadDirName(platform, inputVersion)))) { | ||
if (!(await isValidVersion(inputVersion, timeout))) { | ||
throw Error(`Invalid version ${inputVersion.id}`); | ||
} | ||
} | ||
version = inputVersion; | ||
} | ||
@@ -319,17 +338,17 @@ else { | ||
} | ||
if (platform === 'win32-archive' && semver.satisfies(version, '>= 1.85.0', { includePrerelease: true })) { | ||
if (platform === 'win32-archive' && semver.satisfies(version.id, '>= 1.85.0', { includePrerelease: true })) { | ||
throw new Error('Windows 32-bit is no longer supported from v1.85 onwards'); | ||
} | ||
reporter.report({ stage: progress_1.ProgressReportStage.ResolvedVersion, version }); | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.ResolvedVersion, version: version.toString() }); | ||
const downloadedPath = path.resolve(cachePath, makeDownloadDirName(platform, version)); | ||
if (fs.existsSync(path.join(downloadedPath, COMPLETE_FILE_NAME))) { | ||
if (util_2.isInsiderVersionIdentifier(version)) { | ||
reporter.report({ stage: progress_1.ProgressReportStage.FetchingInsidersMetadata }); | ||
const { version: currentHash, date: currentDate } = util_2.insidersDownloadDirMetadata(downloadedPath, platform); | ||
const { version: latestHash, timestamp: latestTimestamp } = version === 'insiders' | ||
? await util_2.getLatestInsidersMetadata(util_2.systemDefaultPlatform) | ||
: await util_2.getInsidersVersionMetadata(util_2.systemDefaultPlatform, version); | ||
if (version.isInsiders) { | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.FetchingInsidersMetadata }); | ||
const { version: currentHash, date: currentDate } = (0, util_2.insidersDownloadDirMetadata)(downloadedPath, platform); | ||
const { version: latestHash, timestamp: latestTimestamp } = version.id === 'insiders' // not qualified with a date | ||
? await (0, util_2.getLatestInsidersMetadata)(util_2.systemDefaultPlatform, version.isReleased) | ||
: await (0, util_2.getInsidersVersionMetadata)(util_2.systemDefaultPlatform, version.id, version.isReleased); | ||
if (currentHash === latestHash) { | ||
reporter.report({ stage: progress_1.ProgressReportStage.FoundMatchingInstall, downloadedPath }); | ||
return Promise.resolve(util_2.insidersDownloadDirToExecutablePath(downloadedPath, platform)); | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.FoundMatchingInstall, downloadedPath }); | ||
return Promise.resolve((0, util_2.insidersDownloadDirToExecutablePath)(downloadedPath, platform)); | ||
} | ||
@@ -339,3 +358,3 @@ else { | ||
reporter.report({ | ||
stage: progress_1.ProgressReportStage.ReplacingOldInsiders, | ||
stage: progress_js_1.ProgressReportStage.ReplacingOldInsiders, | ||
downloadedPath, | ||
@@ -355,9 +374,9 @@ oldDate: currentDate, | ||
} | ||
else if (util_2.isStableVersionIdentifier(version)) { | ||
reporter.report({ stage: progress_1.ProgressReportStage.FoundMatchingInstall, downloadedPath }); | ||
return Promise.resolve(util_2.downloadDirToExecutablePath(downloadedPath, platform)); | ||
else if (version.isStable) { | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.FoundMatchingInstall, downloadedPath }); | ||
return Promise.resolve((0, util_2.downloadDirToExecutablePath)(downloadedPath, platform)); | ||
} | ||
else { | ||
reporter.report({ stage: progress_1.ProgressReportStage.FoundMatchingInstall, downloadedPath }); | ||
return Promise.resolve(util_2.insidersDownloadDirToExecutablePath(downloadedPath, platform)); | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.FoundMatchingInstall, downloadedPath }); | ||
return Promise.resolve((0, util_2.insidersDownloadDirToExecutablePath)(downloadedPath, platform)); | ||
} | ||
@@ -369,3 +388,3 @@ } | ||
const download = await downloadVSCodeArchive({ | ||
version, | ||
version: version.toString(), | ||
platform, | ||
@@ -380,3 +399,3 @@ cachePath, | ||
await fs.promises.writeFile(path.join(downloadedPath, COMPLETE_FILE_NAME), ''); | ||
reporter.report({ stage: progress_1.ProgressReportStage.NewInstallComplete, downloadedPath }); | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.NewInstallComplete, downloadedPath }); | ||
break; | ||
@@ -387,3 +406,3 @@ } | ||
reporter.report({ | ||
stage: progress_1.ProgressReportStage.Retrying, | ||
stage: progress_js_1.ProgressReportStage.Retrying, | ||
attempt: i, | ||
@@ -400,8 +419,8 @@ error: error, | ||
} | ||
reporter.report({ stage: progress_1.ProgressReportStage.NewInstallComplete, downloadedPath }); | ||
if (util_2.isStableVersionIdentifier(version)) { | ||
return util_2.downloadDirToExecutablePath(downloadedPath, platform); | ||
reporter.report({ stage: progress_js_1.ProgressReportStage.NewInstallComplete, downloadedPath }); | ||
if (version.isStable) { | ||
return (0, util_2.downloadDirToExecutablePath)(downloadedPath, platform); | ||
} | ||
else { | ||
return util_2.insidersDownloadDirToExecutablePath(downloadedPath, platform); | ||
return (0, util_2.insidersDownloadDirToExecutablePath)(downloadedPath, platform); | ||
} | ||
@@ -408,0 +427,0 @@ } |
export { download, downloadAndUnzipVSCode, DownloadOptions } from './download'; | ||
export { runTests, TestOptions } from './runTest'; | ||
export { resolveCliPathFromVSCodeExecutablePath, resolveCliArgsFromVSCodeExecutablePath, runVSCodeCommand, VSCodeCommandError, RunVSCodeCommandOptions, } from './util'; | ||
export * from './progress'; | ||
export * from './progress.js'; |
@@ -8,3 +8,7 @@ "use strict"; | ||
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) { | ||
@@ -29,2 +33,2 @@ if (k2 === undefined) k2 = k; | ||
Object.defineProperty(exports, "VSCodeCommandError", { enumerable: true, get: function () { return util_1.VSCodeCommandError; } }); | ||
__exportStar(require("./progress"), exports); | ||
__exportStar(require("./progress.js"), exports); |
@@ -24,3 +24,3 @@ /** Stages of progress while downloading VS Code */ | ||
} | ||
export declare type ProgressReport = { | ||
export type ProgressReport = { | ||
stage: ProgressReportStage.FetchingVersion; | ||
@@ -71,11 +71,2 @@ } | { | ||
/** Default progress reporter that logs VS Code download progress to console */ | ||
export declare class ConsoleReporter implements ProgressReporter { | ||
private readonly showDownloadProgress; | ||
private version?; | ||
private downloadReport?; | ||
constructor(showDownloadProgress: boolean); | ||
report(report: ProgressReport): void; | ||
error(err: unknown): void; | ||
private flushDownloadReport; | ||
private reportDownload; | ||
} | ||
export declare const makeConsoleReporter: () => Promise<ProgressReporter>; |
@@ -7,3 +7,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ConsoleReporter = exports.SilentReporter = exports.ProgressReportStage = void 0; | ||
exports.makeConsoleReporter = exports.SilentReporter = exports.ProgressReportStage = void 0; | ||
/** Stages of progress while downloading VS Code */ | ||
@@ -32,3 +32,3 @@ var ProgressReportStage; | ||
ProgressReportStage["NewInstallComplete"] = "newInstallComplete"; | ||
})(ProgressReportStage = exports.ProgressReportStage || (exports.ProgressReportStage = {})); | ||
})(ProgressReportStage || (exports.ProgressReportStage = ProgressReportStage = {})); | ||
/** Silent progress reporter */ | ||
@@ -45,65 +45,68 @@ class SilentReporter { | ||
/** Default progress reporter that logs VS Code download progress to console */ | ||
class ConsoleReporter { | ||
constructor(showDownloadProgress) { | ||
this.showDownloadProgress = showDownloadProgress; | ||
const makeConsoleReporter = async () => { | ||
// needs to be async targeting Node 16 because ora is an es module that cannot be required | ||
const { default: ora } = await import('ora'); | ||
let version; | ||
let spinner = ora('Resolving version...').start(); | ||
function toMB(bytes) { | ||
return (bytes / 1024 / 1024).toFixed(2); | ||
} | ||
report(report) { | ||
switch (report.stage) { | ||
case ProgressReportStage.ResolvedVersion: | ||
this.version = report.version; | ||
break; | ||
case ProgressReportStage.ReplacingOldInsiders: | ||
console.log(`Removing outdated Insiders at ${report.downloadedPath} and re-downloading.`); | ||
console.log(`Old: ${report.oldHash} | ${report.oldDate.toISOString()}`); | ||
console.log(`New: ${report.newHash} | ${report.newDate.toISOString()}`); | ||
break; | ||
case ProgressReportStage.FoundMatchingInstall: | ||
console.log(`Found existing install in ${report.downloadedPath}. Skipping download`); | ||
break; | ||
case ProgressReportStage.ResolvingCDNLocation: | ||
console.log(`Downloading VS Code ${this.version} from ${report.url}`); | ||
break; | ||
case ProgressReportStage.Downloading: | ||
if (!this.showDownloadProgress && report.bytesSoFar === 0) { | ||
console.log(`Downloading VS Code (${report.totalBytes}B)`); | ||
} | ||
else if (!this.downloadReport) { | ||
this.downloadReport = { timeout: setTimeout(() => this.reportDownload(), 100), report }; | ||
} | ||
else { | ||
this.downloadReport.report = report; | ||
} | ||
break; | ||
case ProgressReportStage.Retrying: | ||
this.flushDownloadReport(); | ||
console.log(`Error downloading, retrying (attempt ${report.attempt} of ${report.totalAttempts}): ${report.error.message}`); | ||
break; | ||
case ProgressReportStage.NewInstallComplete: | ||
this.flushDownloadReport(); | ||
console.log(`Downloaded VS Code into ${report.downloadedPath}`); | ||
break; | ||
} | ||
} | ||
error(err) { | ||
console.error(err); | ||
} | ||
flushDownloadReport() { | ||
if (this.showDownloadProgress) { | ||
this.reportDownload(); | ||
console.log(''); | ||
} | ||
} | ||
reportDownload() { | ||
if (!this.downloadReport) { | ||
return; | ||
} | ||
const { totalBytes, bytesSoFar } = this.downloadReport.report; | ||
this.downloadReport = undefined; | ||
const percent = Math.max(0, Math.min(1, bytesSoFar / totalBytes)); | ||
const progressBarSize = 30; | ||
const barTicks = Math.floor(percent * progressBarSize); | ||
const progressBar = '='.repeat(barTicks) + '-'.repeat(progressBarSize - barTicks); | ||
process.stdout.write(`\x1b[G\x1b[0KDownloading VS Code [${progressBar}] ${(percent * 100).toFixed()}%`); | ||
} | ||
} | ||
exports.ConsoleReporter = ConsoleReporter; | ||
return { | ||
error(err) { | ||
if (spinner) { | ||
spinner?.fail(`Error: ${err}`); | ||
spinner = undefined; | ||
} | ||
else { | ||
console.error(err); | ||
} | ||
}, | ||
report(report) { | ||
switch (report.stage) { | ||
case ProgressReportStage.ResolvedVersion: | ||
version = report.version; | ||
spinner?.succeed(`Validated version: ${version}`); | ||
spinner = undefined; | ||
break; | ||
case ProgressReportStage.ReplacingOldInsiders: | ||
spinner?.succeed(); | ||
spinner = ora(`Updating Insiders ${report.oldHash} (${report.oldDate.toISOString()}) -> ${report.newHash}`).start(); | ||
break; | ||
case ProgressReportStage.FoundMatchingInstall: | ||
spinner?.succeed(); | ||
spinner = undefined; | ||
ora(`Found existing install in ${report.downloadedPath}`).succeed(); | ||
break; | ||
case ProgressReportStage.ResolvingCDNLocation: | ||
spinner?.succeed(); | ||
spinner = ora(`Found at ${report.url}`).start(); | ||
break; | ||
case ProgressReportStage.Downloading: | ||
if (report.bytesSoFar === 0) { | ||
spinner?.succeed(); | ||
spinner = ora(`Downloading (${toMB(report.totalBytes)} MB)`).start(); | ||
} | ||
else if (spinner) { | ||
if (report.bytesSoFar === report.totalBytes) { | ||
spinner.text = 'Extracting...'; | ||
} | ||
else { | ||
const percent = Math.max(0, Math.min(1, report.bytesSoFar / report.totalBytes)); | ||
const size = `${toMB(report.bytesSoFar)}/${toMB(report.totalBytes)}MB`; | ||
spinner.text = `Downloading VS Code: ${size} (${(percent * 100).toFixed()}%)`; | ||
} | ||
} | ||
break; | ||
case ProgressReportStage.Retrying: | ||
spinner?.fail(`Error downloading, retrying (attempt ${report.attempt} of ${report.totalAttempts}): ${report.error.message}`); | ||
spinner = undefined; | ||
break; | ||
case ProgressReportStage.NewInstallComplete: | ||
spinner?.succeed(`Downloaded VS Code into ${report.downloadedPath}`); | ||
spinner = undefined; | ||
break; | ||
} | ||
}, | ||
}; | ||
}; | ||
exports.makeConsoleReporter = makeConsoleReporter; |
@@ -1,2 +0,2 @@ | ||
/// <reference types="node" /> | ||
/// <reference types="node" resolution-mode="import"/> | ||
import { IncomingMessage } from 'http'; | ||
@@ -3,0 +3,0 @@ export declare function getStream(api: string, timeout: number): Promise<IncomingMessage>; |
@@ -6,5 +6,28 @@ "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; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TimeoutError = exports.TimeoutController = exports.getJSON = exports.getStream = void 0; | ||
const https = require("https"); | ||
const https = __importStar(require("https")); | ||
const util_1 = require("./util"); | ||
@@ -18,3 +41,3 @@ async function getStream(api, timeout) { | ||
}); | ||
const req = https.get(api, util_1.urlToOptions(api), (res) => resolve(res)).on('error', reject); | ||
const req = https.get(api, (0, util_1.urlToOptions)(api), (res) => resolve(res)).on('error', reject); | ||
}).finally(() => ctrl.dispose()); | ||
@@ -31,3 +54,3 @@ } | ||
const req = https | ||
.get(api, util_1.urlToOptions(api), (res) => { | ||
.get(api, (0, util_1.urlToOptions)(api), (res) => { | ||
if (res.statusCode !== 200) { | ||
@@ -59,2 +82,5 @@ reject('Failed to get JSON'); | ||
class TimeoutController { | ||
get signal() { | ||
return this.ctrl.signal; | ||
} | ||
constructor(timeout) { | ||
@@ -68,5 +94,2 @@ this.timeout = timeout; | ||
} | ||
get signal() { | ||
return this.ctrl.signal; | ||
} | ||
touch() { | ||
@@ -73,0 +96,0 @@ clearTimeout(this.handle); |
@@ -63,3 +63,1 @@ import { DownloadOptions } from './download'; | ||
export declare function runTests(options: TestOptions): Promise<number>; | ||
/** Adds the extensions and user data dir to the arguments for the VS Code CLI */ | ||
export declare function getProfileArguments(args: readonly string[]): string[]; |
@@ -6,6 +6,28 @@ "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; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getProfileArguments = exports.runTests = void 0; | ||
const cp = require("child_process"); | ||
const path = require("path"); | ||
exports.runTests = void 0; | ||
const cp = __importStar(require("child_process")); | ||
const download_1 = require("./download"); | ||
@@ -20,3 +42,3 @@ const util_1 = require("./util"); | ||
if (!options.vscodeExecutablePath) { | ||
options.vscodeExecutablePath = await download_1.downloadAndUnzipVSCode(options); | ||
options.vscodeExecutablePath = await (0, download_1.downloadAndUnzipVSCode)(options); | ||
} | ||
@@ -45,3 +67,3 @@ let args = [ | ||
if (!options.reuseMachineInstall) { | ||
args.push(...getProfileArguments(args)); | ||
args.push(...(0, util_1.getProfileArguments)(args)); | ||
} | ||
@@ -51,17 +73,2 @@ return innerRunTests(options.vscodeExecutablePath, args, options.extensionTestsEnv); | ||
exports.runTests = runTests; | ||
/** Adds the extensions and user data dir to the arguments for the VS Code CLI */ | ||
function getProfileArguments(args) { | ||
const out = []; | ||
if (!hasArg('extensions-dir', args)) { | ||
out.push(`--extensions-dir=${path.join(download_1.defaultCachePath, 'extensions')}`); | ||
} | ||
if (!hasArg('user-data-dir', args)) { | ||
out.push(`--user-data-dir=${path.join(download_1.defaultCachePath, 'user-data')}`); | ||
} | ||
return out; | ||
} | ||
exports.getProfileArguments = getProfileArguments; | ||
function hasArg(argName, argList) { | ||
return argList.some((a) => a === `--${argName}` || a.startsWith(`--${argName}=`)); | ||
} | ||
const SIGINT = 'SIGINT'; | ||
@@ -84,3 +91,3 @@ async function innerRunTests(executable, args, testRunnerEnv) { | ||
exitRequested = true; | ||
util_1.killTree(cmd.pid, true); | ||
(0, util_1.killTree)(cmd.pid, true); | ||
}; | ||
@@ -102,3 +109,3 @@ const prom = new Promise((resolve, reject) => { | ||
finished = true; | ||
console.log(`Exit code: ${code !== null && code !== void 0 ? code : signal}`); | ||
console.log(`Exit code: ${code ?? signal}`); | ||
// fix: on windows, it seems like these descriptors can linger for an | ||
@@ -116,3 +123,3 @@ // indeterminate amount of time, causing the process to hang. | ||
console.log('Done\n'); | ||
resolve(code !== null && code !== void 0 ? code : -1); | ||
resolve(code ?? -1); | ||
} | ||
@@ -119,0 +126,0 @@ } |
@@ -1,2 +0,5 @@ | ||
/// <reference types="node" /> | ||
/// <reference types="node" resolution-mode="import"/> | ||
/// <reference types="node" resolution-mode="import"/> | ||
/// <reference types="node" resolution-mode="import"/> | ||
/// <reference types="node" resolution-mode="import"/> | ||
import { SpawnOptions } from 'child_process'; | ||
@@ -7,5 +10,13 @@ import * as https from 'https'; | ||
export declare let systemDefaultPlatform: DownloadPlatform; | ||
export declare function isInsiderVersionIdentifier(version: string): boolean; | ||
export declare function isStableVersionIdentifier(version: string): boolean; | ||
export declare function getVSCodeDownloadUrl(version: string, platform?: DownloadPlatform): string; | ||
export declare class Version { | ||
readonly id: string; | ||
readonly isReleased: boolean; | ||
static parse(version: string): Version; | ||
constructor(id: string, isReleased?: boolean); | ||
get isCommit(): boolean; | ||
get isInsiders(): boolean; | ||
get isStable(): boolean; | ||
toString(): string; | ||
} | ||
export declare function getVSCodeDownloadUrl(version: Version, platform: string): string; | ||
export declare function urlToOptions(url: string): https.RequestOptions; | ||
@@ -28,4 +39,4 @@ export declare function downloadDirToExecutablePath(dir: string, platform: DownloadPlatform): string; | ||
} | ||
export declare function getInsidersVersionMetadata(platform: string, version: string): Promise<IUpdateMetadata>; | ||
export declare function getLatestInsidersMetadata(platform: string): Promise<IUpdateMetadata>; | ||
export declare function getInsidersVersionMetadata(platform: string, version: string, released: boolean): Promise<IUpdateMetadata>; | ||
export declare function getLatestInsidersMetadata(platform: string, released: boolean): Promise<IUpdateMetadata>; | ||
/** | ||
@@ -56,5 +67,19 @@ * Resolve the VS Code cli path from executable path returned from `downloadAndUnzipVSCode`. | ||
export declare function resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath: string, options?: Pick<TestOptions, 'reuseMachineInstall' | 'platform'>): string[]; | ||
export declare type RunVSCodeCommandOptions = Partial<DownloadOptions> & { | ||
export interface RunVSCodeCommandOptions extends Partial<DownloadOptions> { | ||
/** | ||
* Additional options to pass to `child_process.spawn` | ||
*/ | ||
spawn?: SpawnOptions; | ||
}; | ||
/** | ||
* Whether VS Code should be launched using default settings and extensions | ||
* installed on this machine. If `false`, then separate directories will be | ||
* used inside the `.vscode-test` folder within the project. | ||
* | ||
* Defaults to `false`. | ||
*/ | ||
reuseMachineInstall?: boolean; | ||
} | ||
/** Adds the extensions and user data dir to the arguments for the VS Code CLI */ | ||
export declare function getProfileArguments(args: readonly string[]): string[]; | ||
export declare function hasArg(argName: string, argList: readonly string[]): boolean; | ||
export declare class VSCodeCommandError extends Error { | ||
@@ -67,6 +92,7 @@ readonly exitCode: number | null; | ||
/** | ||
* Runs a VS Code command, and returns its output | ||
* Runs a VS Code command, and returns its output. | ||
* | ||
* @throws a {@link VSCodeCommandError} if the command fails | ||
*/ | ||
export declare function runVSCodeCommand(args: string[], options?: RunVSCodeCommandOptions): Promise<{ | ||
export declare function runVSCodeCommand(_args: readonly string[], options?: RunVSCodeCommandOptions): Promise<{ | ||
stdout: string; | ||
@@ -73,0 +99,0 @@ stderr: string; |
162
out/util.js
@@ -6,14 +6,36 @@ "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; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.killTree = exports.onceWithoutRejections = exports.isSubdirectory = exports.streamToBuffer = exports.validateStream = exports.isDefined = exports.runVSCodeCommand = exports.VSCodeCommandError = exports.resolveCliArgsFromVSCodeExecutablePath = exports.resolveCliPathFromVSCodeExecutablePath = exports.getLatestInsidersMetadata = exports.getInsidersVersionMetadata = exports.insidersDownloadDirMetadata = exports.insidersDownloadDirToExecutablePath = exports.downloadDirToExecutablePath = exports.urlToOptions = exports.getVSCodeDownloadUrl = exports.isStableVersionIdentifier = exports.isInsiderVersionIdentifier = exports.systemDefaultPlatform = void 0; | ||
exports.killTree = exports.onceWithoutRejections = exports.isSubdirectory = exports.streamToBuffer = exports.validateStream = exports.isDefined = exports.runVSCodeCommand = exports.VSCodeCommandError = exports.hasArg = exports.getProfileArguments = exports.resolveCliArgsFromVSCodeExecutablePath = exports.resolveCliPathFromVSCodeExecutablePath = exports.getLatestInsidersMetadata = exports.getInsidersVersionMetadata = exports.insidersDownloadDirMetadata = exports.insidersDownloadDirToExecutablePath = exports.downloadDirToExecutablePath = exports.urlToOptions = exports.getVSCodeDownloadUrl = exports.Version = exports.systemDefaultPlatform = void 0; | ||
const child_process_1 = require("child_process"); | ||
const crypto_1 = require("crypto"); | ||
const fs_1 = require("fs"); | ||
const createHttpProxyAgent = require("http-proxy-agent"); | ||
const createHttpsProxyAgent = require("https-proxy-agent"); | ||
const path = require("path"); | ||
const http_proxy_agent_1 = require("http-proxy-agent"); | ||
const https_proxy_agent_1 = require("https-proxy-agent"); | ||
const path = __importStar(require("path")); | ||
const url_1 = require("url"); | ||
const download_1 = require("./download"); | ||
const request = require("./request"); | ||
const runTest_1 = require("./runTest"); | ||
const request = __importStar(require("./request")); | ||
const windowsPlatforms = new Set(['win32-x64-archive', 'win32-arm64-archive']); | ||
@@ -32,23 +54,42 @@ const darwinPlatforms = new Set(['darwin-arm64', 'darwin']); | ||
} | ||
function isInsiderVersionIdentifier(version) { | ||
return version === 'insiders' || version.endsWith('-insider'); // insider or 1.2.3-insider version string | ||
const UNRELEASED_SUFFIX = '-unreleased'; | ||
class Version { | ||
static parse(version) { | ||
const unreleased = version.endsWith(UNRELEASED_SUFFIX); | ||
if (unreleased) { | ||
version = version.slice(0, -UNRELEASED_SUFFIX.length); | ||
} | ||
return new Version(version, !unreleased); | ||
} | ||
constructor(id, isReleased = true) { | ||
this.id = id; | ||
this.isReleased = isReleased; | ||
} | ||
get isCommit() { | ||
return /^[0-9a-f]{40}$/.test(this.id); | ||
} | ||
get isInsiders() { | ||
return this.id === 'insiders' || this.id.endsWith('-insider'); | ||
} | ||
get isStable() { | ||
return this.id === 'stable' || /^[0-9]+\.[0-9]+\.[0-9]$/.test(this.id); | ||
} | ||
toString() { | ||
return this.id + (this.isReleased ? '' : UNRELEASED_SUFFIX); | ||
} | ||
} | ||
exports.isInsiderVersionIdentifier = isInsiderVersionIdentifier; | ||
function isStableVersionIdentifier(version) { | ||
return version === 'stable' || /^[0-9]+\.[0-9]+\.[0-9]$/.test(version); // stable or 1.2.3 version string | ||
} | ||
exports.isStableVersionIdentifier = isStableVersionIdentifier; | ||
function getVSCodeDownloadUrl(version, platform = exports.systemDefaultPlatform) { | ||
if (version === 'insiders') { | ||
return `https://update.code.visualstudio.com/latest/${platform}/insider`; | ||
exports.Version = Version; | ||
function getVSCodeDownloadUrl(version, platform) { | ||
if (version.id === 'insiders') { | ||
return `https://update.code.visualstudio.com/latest/${platform}/insider?released=${version.isReleased}`; | ||
} | ||
else if (isInsiderVersionIdentifier(version)) { | ||
return `https://update.code.visualstudio.com/${version}/${platform}/insider`; | ||
else if (version.isInsiders) { | ||
return `https://update.code.visualstudio.com/${version.id}/${platform}/insider?released=${version.isReleased}`; | ||
} | ||
else if (isStableVersionIdentifier(version)) { | ||
return `https://update.code.visualstudio.com/${version}/${platform}/stable`; | ||
else if (version.isStable) { | ||
return `https://update.code.visualstudio.com/${version.id}/${platform}/stable?released=${version.isReleased}`; | ||
} | ||
else { | ||
// insiders commit hash | ||
return `https://update.code.visualstudio.com/commit:${version}/${platform}/insider`; | ||
return `https://update.code.visualstudio.com/commit:${version.id}/${platform}/insider`; | ||
} | ||
@@ -60,7 +101,7 @@ } | ||
if (process.env.npm_config_proxy) { | ||
PROXY_AGENT = createHttpProxyAgent(process.env.npm_config_proxy); | ||
HTTPS_PROXY_AGENT = createHttpsProxyAgent(process.env.npm_config_proxy); | ||
PROXY_AGENT = new http_proxy_agent_1.HttpProxyAgent(process.env.npm_config_proxy); | ||
HTTPS_PROXY_AGENT = new https_proxy_agent_1.HttpsProxyAgent(process.env.npm_config_proxy); | ||
} | ||
if (process.env.npm_config_https_proxy) { | ||
HTTPS_PROXY_AGENT = createHttpsProxyAgent(process.env.npm_config_https_proxy); | ||
HTTPS_PROXY_AGENT = new https_proxy_agent_1.HttpsProxyAgent(process.env.npm_config_https_proxy); | ||
} | ||
@@ -114,3 +155,3 @@ function urlToOptions(url) { | ||
} | ||
const productJson = JSON.parse(fs_1.readFileSync(productJsonPath, 'utf-8')); | ||
const productJson = JSON.parse((0, fs_1.readFileSync)(productJsonPath, 'utf-8')); | ||
return { | ||
@@ -122,10 +163,10 @@ version: productJson.commit, | ||
exports.insidersDownloadDirMetadata = insidersDownloadDirMetadata; | ||
async function getInsidersVersionMetadata(platform, version) { | ||
const remoteUrl = `https://update.code.visualstudio.com/api/versions/${version}/${platform}/insider`; | ||
return await request.getJSON(remoteUrl, 30000); | ||
async function getInsidersVersionMetadata(platform, version, released) { | ||
const remoteUrl = `https://update.code.visualstudio.com/api/versions/${version}/${platform}/insider?released=${released}`; | ||
return await request.getJSON(remoteUrl, 30_000); | ||
} | ||
exports.getInsidersVersionMetadata = getInsidersVersionMetadata; | ||
async function getLatestInsidersMetadata(platform) { | ||
const remoteUrl = `https://update.code.visualstudio.com/api/update/${platform}/insider/latest`; | ||
return await request.getJSON(remoteUrl, 30000); | ||
async function getLatestInsidersMetadata(platform, released) { | ||
const remoteUrl = `https://update.code.visualstudio.com/api/update/${platform}/insider/latest?released=${released}`; | ||
return await request.getJSON(remoteUrl, 30_000); | ||
} | ||
@@ -182,8 +223,7 @@ exports.getLatestInsidersMetadata = getLatestInsidersMetadata; | ||
function resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath, options) { | ||
var _a; | ||
const args = [ | ||
resolveCliPathFromVSCodeExecutablePath(vscodeExecutablePath, (_a = options === null || options === void 0 ? void 0 : options.platform) !== null && _a !== void 0 ? _a : exports.systemDefaultPlatform), | ||
resolveCliPathFromVSCodeExecutablePath(vscodeExecutablePath, options?.platform ?? exports.systemDefaultPlatform), | ||
]; | ||
if (!(options === null || options === void 0 ? void 0 : options.reuseMachineInstall)) { | ||
args.push(...runTest_1.getProfileArguments(args)); | ||
if (!options?.reuseMachineInstall) { | ||
args.push(...getProfileArguments(args)); | ||
} | ||
@@ -193,2 +233,18 @@ return args; | ||
exports.resolveCliArgsFromVSCodeExecutablePath = resolveCliArgsFromVSCodeExecutablePath; | ||
/** Adds the extensions and user data dir to the arguments for the VS Code CLI */ | ||
function getProfileArguments(args) { | ||
const out = []; | ||
if (!hasArg('extensions-dir', args)) { | ||
out.push(`--extensions-dir=${path.join(download_1.defaultCachePath, 'extensions')}`); | ||
} | ||
if (!hasArg('user-data-dir', args)) { | ||
out.push(`--user-data-dir=${path.join(download_1.defaultCachePath, 'user-data')}`); | ||
} | ||
return out; | ||
} | ||
exports.getProfileArguments = getProfileArguments; | ||
function hasArg(argName, argList) { | ||
return argList.some((a) => a === `--${argName}` || a.startsWith(`--${argName}=`)); | ||
} | ||
exports.hasArg = hasArg; | ||
class VSCodeCommandError extends Error { | ||
@@ -204,14 +260,22 @@ constructor(args, exitCode, stderr, stdout) { | ||
/** | ||
* Runs a VS Code command, and returns its output | ||
* Runs a VS Code command, and returns its output. | ||
* | ||
* @throws a {@link VSCodeCommandError} if the command fails | ||
*/ | ||
async function runVSCodeCommand(args, options = {}) { | ||
const vscodeExecutablePath = await download_1.downloadAndUnzipVSCode(options); | ||
const [cli, ...baseArgs] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); | ||
const shell = process.platform === 'win32'; | ||
async function runVSCodeCommand(_args, options = {}) { | ||
const args = _args.slice(); | ||
let executable = await (0, download_1.downloadAndUnzipVSCode)(options); | ||
let shell = false; | ||
if (!options.reuseMachineInstall) { | ||
args.push(...getProfileArguments(args)); | ||
} | ||
// Unless the user is manually running tests or extension development, then resolve to the CLI script | ||
if (!hasArg('extensionTestsPath', args) && !hasArg('extensionDevelopmentPath', args)) { | ||
executable = resolveCliPathFromVSCodeExecutablePath(executable, options?.platform ?? exports.systemDefaultPlatform); | ||
shell = process.platform === 'win32'; // CVE-2024-27980 | ||
} | ||
return new Promise((resolve, reject) => { | ||
var _a, _b; | ||
let stdout = ''; | ||
let stderr = ''; | ||
const child = child_process_1.spawn(shell ? `"${cli}"` : cli, [...baseArgs, ...args], { | ||
const child = (0, child_process_1.spawn)(shell ? `"${executable}"` : executable, args, { | ||
stdio: 'pipe', | ||
@@ -222,4 +286,4 @@ shell, | ||
}); | ||
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.setEncoding('utf-8').on('data', (data) => (stdout += data)); | ||
(_b = child.stderr) === null || _b === void 0 ? void 0 : _b.setEncoding('utf-8').on('data', (data) => (stderr += data)); | ||
child.stdout?.setEncoding('utf-8').on('data', (data) => (stdout += data)); | ||
child.stderr?.setEncoding('utf-8').on('data', (data) => (stderr += data)); | ||
child.on('error', reject); | ||
@@ -250,6 +314,6 @@ child.on('exit', (code) => { | ||
let actualLen = 0; | ||
const checksum = sha256 ? crypto_1.createHash('sha256') : undefined; | ||
const checksum = sha256 ? (0, crypto_1.createHash)('sha256') : undefined; | ||
return new Promise((resolve, reject) => { | ||
readable.on('data', (chunk) => { | ||
checksum === null || checksum === void 0 ? void 0 : checksum.update(chunk); | ||
checksum?.update(chunk); | ||
actualLen += chunk.length; | ||
@@ -262,3 +326,3 @@ }); | ||
} | ||
const digest = checksum === null || checksum === void 0 ? void 0 : checksum.digest('hex'); | ||
const digest = checksum?.digest('hex'); | ||
if (digest && digest !== sha256) { | ||
@@ -311,7 +375,7 @@ return reject(new Error(`Downloaded file checksum ${digest} does not match expected checksum ${sha256}`)); | ||
// Therefore we use TASKKILL.EXE | ||
cp = child_process_1.spawn(path.join(windir, 'System32', 'taskkill.exe'), [...(force ? ['/F'] : []), '/T', '/PID', processId.toString()], { stdio: 'inherit' }); | ||
cp = (0, child_process_1.spawn)(path.join(windir, 'System32', 'taskkill.exe'), [...(force ? ['/F'] : []), '/T', '/PID', processId.toString()], { stdio: 'inherit' }); | ||
} | ||
else { | ||
// on linux and OS X we kill all direct and indirect child processes as well | ||
cp = child_process_1.spawn('sh', [path.resolve(__dirname, '../killTree.sh'), processId.toString(), force ? '9' : '15'], { | ||
cp = (0, child_process_1.spawn)('sh', [path.resolve(__dirname, '../killTree.sh'), processId.toString(), force ? '9' : '15'], { | ||
stdio: 'inherit', | ||
@@ -318,0 +382,0 @@ }); |
{ | ||
"name": "@vscode/test-electron", | ||
"version": "2.3.10", | ||
"version": "2.4.0", | ||
"scripts": { | ||
@@ -8,4 +8,4 @@ "compile": "tsc -p ./", | ||
"prepack": "tsc -p ./", | ||
"fmt": "prettier --write \"lib/**/*.ts\" \"*.md\"", | ||
"test": "eslint lib --ext ts && vitest && tsc --noEmit", | ||
"fmt": "prettier --write \"lib/**/*.{ts,mts}\" \"*.md\"", | ||
"test": "eslint \"lib/**/*.{ts,mts}\" && vitest && tsc --noEmit", | ||
"prepare": "husky install" | ||
@@ -27,20 +27,20 @@ }, | ||
"dependencies": { | ||
"http-proxy-agent": "^4.0.1", | ||
"https-proxy-agent": "^5.0.0", | ||
"http-proxy-agent": "^7.0.2", | ||
"https-proxy-agent": "^7.0.4", | ||
"jszip": "^3.10.1", | ||
"semver": "^7.5.2" | ||
"ora": "^7.0.1", | ||
"semver": "^7.6.2" | ||
}, | ||
"devDependencies": { | ||
"@eslint/js": "^9.3.0", | ||
"@types/node": "^18", | ||
"@types/rimraf": "^3.0.0", | ||
"@types/semver": "^7.3.13", | ||
"@typescript-eslint/eslint-plugin": "^4.13.0", | ||
"@typescript-eslint/parser": "^4.13.0", | ||
"eslint": "^7.17.0", | ||
"eslint-plugin-header": "^3.1.0", | ||
"eslint": "^9.3.0", | ||
"husky": "^8.0.3", | ||
"lint-staged": "^13.1.2", | ||
"prettier": "^2.8.4", | ||
"typescript": "^4.3.5", | ||
"vitest": "^0.10.2" | ||
"typescript": "^5.4.5", | ||
"typescript-eslint": "^7.10.0", | ||
"vitest": "^1.6.0" | ||
}, | ||
@@ -47,0 +47,0 @@ "license": "MIT", |
@@ -9,6 +9,6 @@ /*--------------------------------------------------------------------------------------------- | ||
export default defineConfig({ | ||
test: { | ||
include: ['lib/**/*.test.ts'], | ||
test: { | ||
include: ['lib/**/*.test.{ts,mts}'], | ||
testTimeout: 120_000, | ||
}, | ||
}, | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
93756
11
1672
5
+ Addedora@^7.0.1
+ Addedagent-base@7.1.1(transitive)
+ Addedansi-regex@6.1.0(transitive)
+ Addedbase64-js@1.5.1(transitive)
+ Addedbl@5.1.0(transitive)
+ Addedbuffer@6.0.3(transitive)
+ Addedchalk@5.3.0(transitive)
+ Addedcli-cursor@4.0.0(transitive)
+ Addedcli-spinners@2.9.2(transitive)
+ Addedeastasianwidth@0.2.0(transitive)
+ Addedemoji-regex@10.4.0(transitive)
+ Addedhttp-proxy-agent@7.0.2(transitive)
+ Addedhttps-proxy-agent@7.0.5(transitive)
+ Addedieee754@1.2.1(transitive)
+ Addedis-interactive@2.0.0(transitive)
+ Addedis-unicode-supported@1.3.0(transitive)
+ Addedlog-symbols@5.1.0(transitive)
+ Addedmimic-fn@2.1.0(transitive)
+ Addedonetime@5.1.2(transitive)
+ Addedora@7.0.1(transitive)
+ Addedreadable-stream@3.6.2(transitive)
+ Addedrestore-cursor@4.0.0(transitive)
+ Addedsignal-exit@3.0.7(transitive)
+ Addedstdin-discarder@0.1.0(transitive)
+ Addedstring-width@6.1.0(transitive)
+ Addedstrip-ansi@7.1.0(transitive)
- Removed@tootallnate/once@1.1.2(transitive)
- Removedagent-base@6.0.2(transitive)
- Removedhttp-proxy-agent@4.0.1(transitive)
- Removedhttps-proxy-agent@5.0.1(transitive)
Updatedhttp-proxy-agent@^7.0.2
Updatedhttps-proxy-agent@^7.0.4
Updatedsemver@^7.6.2