- override extension type of extensions under dev from existing extensions

- validate after updating the type
This commit is contained in:
Sandeep Somavarapu 2022-05-02 14:05:30 +02:00
parent 1cca784e1f
commit 05b9eddd4b
No known key found for this signature in database
GPG key ID: DD41CAAC8081CC7D
8 changed files with 61 additions and 48 deletions

View file

@ -74,7 +74,7 @@ if %errorlevel% neq 0 exit /b %errorlevel%
echo.
echo ### TypeScript tests
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\typescript-language-features --extensionTestsPath=%~dp0\..\extensions\typescript-language-features\out\test\unit --enable-proposed-api=vscode.typescript-language-features %API_TESTS_EXTRA_ARGS%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\typescript-language-features --extensionTestsPath=%~dp0\..\extensions\typescript-language-features\out\test\unit %API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
echo.
@ -92,7 +92,7 @@ echo ### Git tests
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
mkdir %GITWORKSPACE%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test --enable-proposed-api=vscode.git %API_TESTS_EXTRA_ARGS%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test %API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
echo.

View file

@ -93,7 +93,7 @@ kill_app
echo
echo "### TypeScript tests"
echo
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/typescript-language-features/test-workspace --enable-proposed-api=vscode.typescript-language-features --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS
kill_app
echo
@ -111,7 +111,7 @@ kill_app
echo
echo "### Git tests"
echo
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test $API_TESTS_EXTRA_ARGS
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test $API_TESTS_EXTRA_ARGS
kill_app
echo

View file

@ -64,10 +64,10 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
set ELECTRON_ENABLE_STACK_DUMPING=1
:: Tests in the extension host running from built version (both client and server)
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_VSCODE%/vscode-api-tests/testWorkspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/singlefolder-tests %API_TESTS_EXTRA_ARGS% --extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests --enable-proposed-api=vscode.image-preview
call "%INTEGRATION_TEST_ELECTRON_PATH%" --folder-uri=%REMOTE_VSCODE%/vscode-api-tests/testWorkspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/singlefolder-tests %API_TESTS_EXTRA_ARGS% --extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests
if %errorlevel% neq 0 exit /b %errorlevel%
call "%INTEGRATION_TEST_ELECTRON_PATH%" --file-uri=%REMOTE_VSCODE%/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/workspace-tests %API_TESTS_EXTRA_ARGS% --extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests --enable-proposed-api=vscode.image-preview
call "%INTEGRATION_TEST_ELECTRON_PATH%" --file-uri=%REMOTE_VSCODE%/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=%REMOTE_VSCODE%/vscode-api-tests --extensionTestsPath=%REMOTE_VSCODE%/vscode-api-tests/out/workspace-tests %API_TESTS_EXTRA_ARGS% --extensions-dir=%EXT_PATH% --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests
if %errorlevel% neq 0 exit /b %errorlevel%
)

View file

@ -63,7 +63,7 @@ else
export ELECTRON_ENABLE_LOGGING=1
# Running from a build, we need to enable the vscode-test-resolver extension
EXTRA_INTEGRATION_TEST_ARGUMENTS="--extensions-dir=$EXT_PATH --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests --enable-proposed-api=vscode.image-preview --enable-proposed-api=vscode.git --enable-proposed-api=vscode.markdown-language-features"
EXTRA_INTEGRATION_TEST_ARGUMENTS="--extensions-dir=$EXT_PATH --enable-proposed-api=vscode.vscode-test-resolver --enable-proposed-api=vscode.vscode-api-tests"
echo "Storing crash reports into '$VSCODECRASHDIR'."
echo "Storing log files into '$VSCODELOGSDIR'."
@ -105,7 +105,7 @@ kill_app
echo
echo "### TypeScript tests"
echo
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$REMOTE_VSCODE/typescript-language-features/test-workspace --enable-proposed-api=vscode.typescript-language-features --extensionDevelopmentPath=$REMOTE_VSCODE/typescript-language-features --extensionTestsPath=$REMOTE_VSCODE/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS --folder-uri=$REMOTE_VSCODE/typescript-language-features/test-workspace --extensionDevelopmentPath=$REMOTE_VSCODE/typescript-language-features --extensionTestsPath=$REMOTE_VSCODE/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS $EXTRA_INTEGRATION_TEST_ARGUMENTS
kill_app
echo

View file

@ -68,5 +68,5 @@ echo ### Git tests
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
mkdir %GITWORKSPACE%
call node .\test\integration\browser\out\index.js --workspacePath=%GITWORKSPACE% --extensionDevelopmentPath=.\extensions\git --extensionTestsPath=.\extensions\git\out\test --enable-proposed-api=vscode.git %*
call node .\test\integration\browser\out\index.js --workspacePath=%GITWORKSPACE% --extensionDevelopmentPath=.\extensions\git --extensionTestsPath=.\extensions\git\out\test %*
if %errorlevel% neq 0 exit /b %errorlevel%

View file

@ -63,10 +63,10 @@ node test/integration/browser/out/index.js --workspacePath $ROOT/extensions/emme
echo
echo "### Git tests"
echo
node test/integration/browser/out/index.js --workspacePath $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test "$@"
node test/integration/browser/out/index.js --workspacePath $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test "$@"
echo
echo "### Ipynb tests"
echo
node test/integration/browser/out/index.js --workspacePath $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.ipynb --extensionDevelopmentPath=$ROOT/extensions/ipynb --extensionTestsPath=$ROOT/extensions/ipynb/out/test "$@"
node test/integration/browser/out/index.js --workspacePath $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/ipynb --extensionTestsPath=$ROOT/extensions/ipynb/out/test "$@"

View file

@ -23,7 +23,7 @@ import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { Metadata } from 'vs/platform/extensionManagement/common/extensionManagement';
import { computeTargetPlatform, ExtensionKey, getExtensionId, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { areSameExtensions, computeTargetPlatform, ExtensionKey, getExtensionId, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionType, ExtensionIdentifier, IExtensionManifest, TargetPlatform, IExtensionIdentifier, IRelaxedExtensionManifest, UNDEFINED_PUBLISHER, IExtensionDescription, BUILTIN_MANIFEST_CACHE_FILE, USER_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER } from 'vs/platform/extensions/common/extensions';
import { validateExtensionManifest } from 'vs/platform/extensions/common/extensionValidator';
import { FileOperationResult, IFileService, toFileOperationResult } from 'vs/platform/files/common/files';
@ -118,7 +118,7 @@ export interface IExtensionsScannerService {
scanAllExtensions(scanOptions: ScanOptions): Promise<IScannedExtension[]>;
scanSystemExtensions(scanOptions: ScanOptions): Promise<IScannedExtension[]>;
scanUserExtensions(scanOptions: ScanOptions): Promise<IScannedExtension[]>;
scanExtensionsUnderDevelopment(scanOptions: ScanOptions): Promise<IScannedExtension[]>;
scanExtensionsUnderDevelopment(scanOptions: ScanOptions, existingExtensions: IScannedExtension[]): Promise<IScannedExtension[]>;
scanExistingExtension(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension | null>;
scanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise<IScannedExtension[]>;
@ -163,11 +163,11 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
}
async scanAllExtensions(scanOptions: ScanOptions): Promise<IScannedExtension[]> {
const [system, user, development] = await Promise.all([
const [system, user] = await Promise.all([
this.scanSystemExtensions(scanOptions),
this.scanUserExtensions(scanOptions),
this.scanExtensionsUnderDevelopment(scanOptions),
]);
const development = await this.scanExtensionsUnderDevelopment(scanOptions, [...system, ...user]);
return this.dedupExtensions([...system, ...user, ...development], await this.getTargetPlatform(), true);
}
@ -189,10 +189,19 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
return extensions;
}
async scanExtensionsUnderDevelopment(scanOptions: ScanOptions): Promise<IScannedExtension[]> {
async scanExtensionsUnderDevelopment(scanOptions: ScanOptions, existingExtensions: IScannedExtension[]): Promise<IScannedExtension[]> {
if (this.environmentService.isExtensionDevelopment && this.environmentService.extensionDevelopmentLocationURI) {
const extensions = (await Promise.all(this.environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file)
.map(async extensionDevelopmentLocationURI => this.extensionsScanner.scanOneOrMultipleExtensions((await this.createExtensionScannerInput(extensionDevelopmentLocationURI, ExtensionType.User, true, scanOptions.language))))))
.map(async extensionDevelopmentLocationURI => {
const input = await this.createExtensionScannerInput(extensionDevelopmentLocationURI, ExtensionType.User, true, scanOptions.language, false /* do not validate */);
const extensions = await this.extensionsScanner.scanOneOrMultipleExtensions(input);
return extensions.map(extension => {
// Override the extension type from the existing extensions
extension.type = existingExtensions.find(e => areSameExtensions(e.identifier, extension.identifier))?.type ?? extension.type;
// Validate the extension
return this.extensionsScanner.validate(extension, input);
});
})))
.flat();
return this.applyScanOptions(extensions, scanOptions, true);
}
@ -327,7 +336,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
}
}
private async createExtensionScannerInput(location: URI, type: ExtensionType, excludeObsolete: boolean, language: string | undefined): Promise<ExtensionScannerInput> {
private async createExtensionScannerInput(location: URI, type: ExtensionType, excludeObsolete: boolean, language: string | undefined, validate: boolean = true): Promise<ExtensionScannerInput> {
const translations = await this.getTranslations(language ?? platform.language);
let mtime: number | undefined;
try {
@ -343,6 +352,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
mtime,
type,
excludeObsolete,
validate,
this.productService.version,
this.productService.date,
this.productService.commit,
@ -361,6 +371,7 @@ class ExtensionScannerInput {
public readonly mtime: number | undefined,
public readonly type: ExtensionType,
public readonly excludeObsolete: boolean,
public readonly validate: boolean,
public readonly productVersion: string,
public readonly productDate: string | undefined,
public readonly productCommit: string | undefined,
@ -386,6 +397,7 @@ class ExtensionScannerInput {
&& a.mtime === b.mtime
&& a.type === b.type
&& a.excludeObsolete === b.excludeObsolete
&& a.validate === b.validate
&& a.productVersion === b.productVersion
&& a.productDate === b.productDate
&& a.productCommit === b.productCommit
@ -431,7 +443,7 @@ class ExtensionsScanner extends Disposable {
if (input.type === ExtensionType.User && basename(c.resource).indexOf('.') === 0) {
return null;
}
const extensionScannerInput = new ExtensionScannerInput(c.resource, input.mtime, input.type, input.excludeObsolete, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations);
const extensionScannerInput = new ExtensionScannerInput(c.resource, input.mtime, input.type, input.excludeObsolete, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations);
const extension = await this.scanExtension(extensionScannerInput);
return extension && !obsolete[ExtensionKey.create(extension).toString()] ? extension : null;
}));
@ -440,7 +452,7 @@ class ExtensionsScanner extends Disposable {
return [];
}
async scanOneOrMultipleExtensions(input: ExtensionScannerInput): Promise<IScannedExtension[]> {
async scanOneOrMultipleExtensions(input: ExtensionScannerInput): Promise<IRelaxedScannedExtension[]> {
try {
if (await this.fileService.exists(joinPath(input.location, 'package.json'))) {
const extension = await this.scanExtension(input);
@ -468,16 +480,8 @@ class ExtensionsScanner extends Disposable {
const identifier = metadata?.id ? { id, uuid: metadata.id } : { id };
const type = metadata?.isSystem ? ExtensionType.System : input.type;
const isBuiltin = type === ExtensionType.System || !!metadata?.isBuiltin;
const validations = validateExtensionManifest(input.productVersion, input.productDate, input.location, manifest, isBuiltin);
let isValid = true;
for (const [severity, message] of validations) {
if (severity === Severity.Error) {
isValid = false;
this.logService.error(this.formatMessage(input.location, message));
}
}
manifest = await this.translateManifest(input.location, manifest, ExtensionScannerInput.createNlsConfiguration(input));
return {
const extension = {
type,
identifier,
manifest,
@ -485,9 +489,10 @@ class ExtensionsScanner extends Disposable {
isBuiltin,
targetPlatform: metadata?.targetPlatform ?? TargetPlatform.UNDEFINED,
metadata,
isValid,
validations
isValid: true,
validations: []
};
return input.validate ? this.validate(extension, input) : extension;
}
} catch (e) {
if (input.type !== ExtensionType.System) {
@ -497,6 +502,20 @@ class ExtensionsScanner extends Disposable {
return null;
}
validate(extension: IRelaxedScannedExtension, input: ExtensionScannerInput): IRelaxedScannedExtension {
let isValid = true;
const validations = validateExtensionManifest(input.productVersion, input.productDate, input.location, extension.manifest, extension.isBuiltin);
for (const [severity, message] of validations) {
if (severity === Severity.Error) {
isValid = false;
this.logService.error(this.formatMessage(input.location, message));
}
}
extension.isValid = isValid;
extension.validations = validations;
return extension;
}
private async scanExtensionManifest(extensionLocation: URI): Promise<IScannedExtensionManifest | null> {
const manifestLocation = joinPath(extensionLocation, 'package.json');
let content;

View file

@ -50,21 +50,15 @@ export class CachedExtensionScanner {
}
private async _scanInstalledExtensions(): Promise<{ system: IExtensionDescription[]; user: IExtensionDescription[]; development: IExtensionDescription[] }> {
const language = platform.language;
const builtinExtensions = this._extensionsScannerService.scanSystemExtensions({ language, useCache: true, checkControlFile: true })
.then(scannedExtensions => scannedExtensions.map(e => toExtensionDescription(e, false)));
const userExtensions = this._extensionsScannerService.scanUserExtensions({ language, useCache: true })
.then(scannedExtensions => scannedExtensions.map(e => toExtensionDescription(e, false)));
const developedExtensions = this._extensionsScannerService.scanExtensionsUnderDevelopment({ language })
.then(scannedExtensions => scannedExtensions.map(e => toExtensionDescription(e, true)));
return Promise.all([builtinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => {
const system = extensionDescriptions[0];
const user = extensionDescriptions[1];
const development = extensionDescriptions[2];
try {
const language = platform.language;
const [scannedSystemExtensions, scannedUserExtensions] = await Promise.all([
this._extensionsScannerService.scanSystemExtensions({ language, useCache: true, checkControlFile: true }),
this._extensionsScannerService.scanUserExtensions({ language, useCache: true })]);
const scannedDevelopedExtensions = await this._extensionsScannerService.scanExtensionsUnderDevelopment({ language }, [...scannedSystemExtensions, ...scannedUserExtensions]);
const system = scannedSystemExtensions.map(e => toExtensionDescription(e, false));
const user = scannedUserExtensions.map(e => toExtensionDescription(e, false));
const development = scannedDevelopedExtensions.map(e => toExtensionDescription(e, true));
const disposable = this._extensionsScannerService.onDidChangeCache(() => {
disposable.dispose();
this._notificationService.prompt(
@ -78,11 +72,11 @@ export class CachedExtensionScanner {
});
timeout(5000).then(() => disposable.dispose());
return { system, user, development };
}).then(undefined, err => {
} catch (err) {
this._logService.error(`Error scanning installed extensions:`);
this._logService.error(err);
return { system: [], user: [], development: [] };
});
}
}
}