Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions build/hygiene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,7 @@ export function hygiene(some: NodeJS.ReadWriteStream | string[] | undefined, run
let errorCount = 0;

const productJson = es.through(function (file: VinylFile) {
const product = JSON.parse(file.contents!.toString('utf8'));

if (product.extensionsGallery) {
console.error(`product.json: Contains 'extensionsGallery'`);
errorCount++;
}
JSON.parse(file.contents!.toString('utf8'));

this.emit('data', file);
});
Expand Down
35 changes: 35 additions & 0 deletions product.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"nameShort": "BlockIDE",
"nameLong": "BlockIDE",
"applicationName": "blockide",
"extensionCompatibilityVersion": "1.145.2",
"dataFolderName": ".blockide",
"sharedDataFolderName": ".blockide-shared",
"win32MutexName": "blockide",
Expand Down Expand Up @@ -245,6 +246,40 @@
"builtInExtensionsEnabledWithAutoUpdates": [
"GitHub.copilot-chat"
],
"extensionsGallery": {
"nlsBaseUrl": "https://www.vscode-unpkg.net/_lp/",
"serviceUrl": "https://marketplace.visualstudio.com/_apis/public/gallery",
"itemUrl": "https://marketplace.visualstudio.com/items",
"publisherUrl": "https://marketplace.visualstudio.com/publishers",
"resourceUrlTemplate": "https://{publisher}.vscode-unpkg.net/{publisher}/{name}/{version}/{path}",
"extensionUrlTemplate": "https://www.vscode-unpkg.net/_gallery/{publisher}/{name}/latest",
"controlUrl": "https://main.vscode-cdn.net/extensions/marketplace.json",
"mcpUrl": "https://main.vscode-cdn.net/mcp/servers.json",
"accessSKUs": [
"copilot_enterprise_seat",
"copilot_enterprise_seat_quota",
"copilot_enterprise_seat_multi_quota",
"copilot_enterprise_seat_assignment",
"copilot_enterprise_seat_assignment_quota",
"copilot_enterprise_seat_assignment_multi_quota",
"copilot_enterprise_trial_seat",
"copilot_enterprise_trial_seat_quota",
"copilot_for_business_seat",
"copilot_for_business_seat_quota",
"copilot_for_business_seat_multi_quota",
"copilot_for_business_seat_assignment",
"copilot_for_business_seat_assignment_quota",
"copilot_for_business_seat_assignment_multi_quota",
"copilot_for_business_trial_seat",
"copilot_for_business_trial_seat_quota"
],
"accessScopes": [
"openid",
"profile",
"email",
"offline_access"
]
},
"sessionsWindowAllowedExtensions": [],
"voiceWsUrl": "wss://falcon-caas.mai.microsoft.com/voice-code/api/v1/realtime/voice"
}
6 changes: 6 additions & 0 deletions src/vs/base/common/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ export interface IDictationRuntimeProductConfig {

export interface IProductConfiguration {
readonly version: string;
/**
* Version reported to the extension Marketplace and used for `engines.vscode`
* compatibility checks. Forks that use their own release numbering can keep
* {@link version} for branding while reporting an upstream VS Code version here.
*/
readonly extensionCompatibilityVersion?: string;
readonly date?: string;
readonly quality?: string;
readonly commit?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode,
InstallOptions, UninstallOptions, Metadata, InstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent, IExtensionManagementService, InstallExtensionInfo, EXTENSION_INSTALL_DEP_PACK_CONTEXT, ExtensionGalleryError,
IProductVersion, ExtensionGalleryErrorCode,
getCompatibilityProductVersion,
EXTENSION_INSTALL_SOURCE_CONTEXT,
DidUpdateExtensionMetadata,
UninstallExtensionInfo,
Expand Down Expand Up @@ -200,7 +201,7 @@ export abstract class AbstractExtensionManagementService extends CommontExtensio

await Promise.allSettled(extensions.map(async ({ extension, options }) => {
try {
const compatible = await this.checkAndGetCompatibleVersion(extension, !!options?.installGivenVersion, !!options?.installPreReleaseVersion, options.productVersion ?? { version: this.productService.version, date: this.productService.date });
const compatible = await this.checkAndGetCompatibleVersion(extension, !!options?.installGivenVersion, !!options?.installPreReleaseVersion, options.productVersion ?? getCompatibilityProductVersion(this.productService));
installableExtensions.push({ ...compatible, options });
} catch (error) {
results.push({ identifier: extension.identifier, operation: InstallOperation.Install, source: extension, error, profileLocation: options.profileLocation ?? this.getCurrentExtensionsManifestLocation() });
Expand Down Expand Up @@ -351,7 +352,7 @@ export abstract class AbstractExtensionManagementService extends CommontExtensio
isBuiltin,
isApplicationScoped,
profileLocation: isApplicationScoped ? this.userDataProfilesService.defaultProfile.extensionsResource : options.profileLocation ?? this.getCurrentExtensionsManifestLocation(),
productVersion: options.productVersion ?? { version: this.productService.version, date: this.productService.date }
productVersion: options.productVersion ?? getCompatibilityProductVersion(this.productService)
};

const existingInstallExtensionTask = !URI.isUri(extension) ? this.installingExtensions.get(getInstallExtensionTaskKey(extension, installExtensionTaskOptions.profileLocation)) : undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { URI } from '../../../base/common/uri.js';
import { IHeaders, IRequestContext, IRequestOptions, isOfflineError } from '../../../base/parts/request/common/request.js';
import { IConfigurationService } from '../../configuration/common/configuration.js';
import { IEnvironmentService } from '../../environment/common/environment.js';
import { getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo, ISearchPrefferedResults, ExtensionGalleryError, ExtensionGalleryErrorCode, IProductVersion, IAllowedExtensionsService, EXTENSION_IDENTIFIER_REGEX, SortBy, FilterType, MaliciousExtensionInfo, ExtensionRequestsTimeoutConfigKey, IExtensionBlockingInfo, ExtensionBlockingOrigin } from './extensionManagement.js';
import { getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo, ISearchPrefferedResults, ExtensionGalleryError, ExtensionGalleryErrorCode, IProductVersion, IAllowedExtensionsService, EXTENSION_IDENTIFIER_REGEX, SortBy, FilterType, MaliciousExtensionInfo, ExtensionRequestsTimeoutConfigKey, IExtensionBlockingInfo, ExtensionBlockingOrigin, getCompatibilityProductVersion } from './extensionManagement.js';
import { adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, getGalleryExtensionTelemetryData } from './extensionManagementUtil.js';
import { IExtensionManifest, TargetPlatform } from '../../extensions/common/extensions.js';
import { isEngineValid } from '../../extensions/common/extensionValidator.js';
Expand Down Expand Up @@ -676,7 +676,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
this.extensionsControlUrl = productService.extensionsGallery?.controlUrl;
this.unpkgResourceApi = productService.extensionsGallery?.extensionUrlTemplate;
this.commonHeadersPromise = resolveMarketplaceHeaders(
productService.version,
getCompatibilityProductVersion(productService).version,
productService,
this.environmentService,
this.configurationService,
Expand Down Expand Up @@ -789,7 +789,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
includePreRelease,
versions,
compatible: !!options.compatible,
productVersion: options.productVersion ?? { version: this.productService.version, date: this.productService.date },
productVersion: options.productVersion ?? getCompatibilityProductVersion(this.productService),
includeBlockedVersions: options.includeBlockedVersions,
isQueryForReleaseVersionFromPreReleaseVersion
},
Expand Down Expand Up @@ -937,10 +937,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
{
targetPlatform,
compatible: !!options.compatible,
productVersion: options.productVersion ?? {
version: this.productService.version,
date: this.productService.date
},
productVersion: options.productVersion ?? getCompatibilityProductVersion(this.productService),
version: extensionInfo.preRelease ? VersionKind.Prerelease : VersionKind.Release
}, allTargetPlatforms);

Expand All @@ -957,10 +954,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
{
targetPlatform,
compatible: !!options.compatible,
productVersion: options.productVersion ?? {
version: this.productService.version,
date: this.productService.date
},
productVersion: options.productVersion ?? getCompatibilityProductVersion(this.productService),
version: VersionKind.Release
}, allTargetPlatforms);

Expand All @@ -980,10 +974,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
{
targetPlatform,
compatible: false,
productVersion: options.productVersion ?? {
version: this.productService.version,
date: this.productService.date
},
productVersion: options.productVersion ?? getCompatibilityProductVersion(this.productService),
version: VersionKind.Prerelease
}, allTargetPlatforms);

Expand All @@ -1000,7 +991,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
return prereleaseVersion ?? releaseVersion ?? null;
}

async getCompatibleExtension(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion: IProductVersion = { version: this.productService.version, date: this.productService.date }): Promise<IGalleryExtension | null> {
async getCompatibleExtension(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion: IProductVersion = getCompatibilityProductVersion(this.productService)): Promise<IGalleryExtension | null> {
if (isNotWebExtensionInWebTargetPlatform(extension.allTargetPlatforms, targetPlatform)) {
return null;
}
Expand All @@ -1024,7 +1015,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
return result[0] ?? null;
}

async isExtensionCompatible(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion: IProductVersion = { version: this.productService.version, date: this.productService.date }): Promise<boolean> {
async isExtensionCompatible(extension: IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform, productVersion: IProductVersion = getCompatibilityProductVersion(this.productService)): Promise<boolean> {
return this.isValidVersion(
{
id: extension.identifier.id,
Expand Down Expand Up @@ -1213,7 +1204,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
}

const runQuery = async (query: Query, token: CancellationToken) => {
const { extensions, total } = await this.queryGalleryExtensions(query, { targetPlatform: CURRENT_TARGET_PLATFORM, compatible: false, includePreRelease: !!options.includePreRelease, productVersion: options.productVersion ?? { version: this.productService.version, date: this.productService.date } }, extensionGalleryManifest, token);
const { extensions, total } = await this.queryGalleryExtensions(query, { targetPlatform: CURRENT_TARGET_PLATFORM, compatible: false, includePreRelease: !!options.includePreRelease, productVersion: options.productVersion ?? getCompatibilityProductVersion(this.productService) }, extensionGalleryManifest, token);

const result: IGalleryExtension[] = [];
let defaultChatAgentExtension: IGalleryExtension | undefined;
Expand Down Expand Up @@ -1871,7 +1862,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
}

const versions: IRawGalleryExtensionVersion[] = [];
const productVersion = { version: this.productService.version, date: this.productService.date };
const productVersion = getCompatibilityProductVersion(this.productService);
await Promise.all(galleryExtensions[0].versions.map(async (version) => {
try {
if (
Expand Down Expand Up @@ -2017,7 +2008,7 @@ export abstract class AbstractExtensionGalleryService implements IExtensionGalle
}
if (result.migrateToPreRelease) {
for (const [unsupportedPreReleaseExtensionId, preReleaseExtensionInfo] of Object.entries(result.migrateToPreRelease)) {
if (!preReleaseExtensionInfo.engine || isEngineValid(preReleaseExtensionInfo.engine, this.productService.version, this.productService.date)) {
if (!preReleaseExtensionInfo.engine || isEngineValid(preReleaseExtensionInfo.engine, getCompatibilityProductVersion(this.productService).version, this.productService.date)) {
deprecated[unsupportedPreReleaseExtensionId.toLowerCase()] = {
disallowInstall: true,
extension: {
Expand Down
13 changes: 13 additions & 0 deletions src/vs/platform/extensionManagement/common/extensionManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ConfigurationScope, Extensions, IConfigurationRegistry } from '../../co
import { ExtensionType, IExtension, IExtensionManifest, TargetPlatform } from '../../extensions/common/extensions.js';
import { FileOperationError, FileOperationResult, IFileService, IFileStat } from '../../files/common/files.js';
import { createDecorator } from '../../instantiation/common/instantiation.js';
import { IProductService } from '../../product/common/productService.js';
import { Registry } from '../../registry/common/platform.js';
import { IExtensionGalleryManifest } from './extensionGalleryManifest.js';

Expand All @@ -40,6 +41,18 @@ export interface IProductVersion {
readonly date?: string;
}

/**
* Product version used for extension compatibility checks and Marketplace queries.
* Uses {@link IProductConfiguration.extensionCompatibilityVersion} when a product
* ships with its own version numbering.
*/
export function getCompatibilityProductVersion(productService: IProductService): IProductVersion {
return {
version: productService.extensionCompatibilityVersion ?? productService.version,
date: productService.date
};
}

export function TargetPlatformToString(targetPlatform: TargetPlatform) {
switch (targetPlatform) {
case TargetPlatform.WIN32_X64: return 'Windows 64 bit';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Severity from '../../../base/common/severity.js';
import { URI } from '../../../base/common/uri.js';
import { localize } from '../../../nls.js';
import { IEnvironmentService } from '../../environment/common/environment.js';
import { IProductVersion, Metadata } from './extensionManagement.js';
import { getCompatibilityProductVersion, IProductVersion, Metadata } from './extensionManagement.js';
import { areSameExtensions, computeTargetPlatform, getExtensionId, getGalleryExtensionId } from './extensionManagementUtil.js';
import { ExtensionType, ExtensionIdentifier, IExtensionManifest, TargetPlatform, IExtensionIdentifier, IRelaxedExtensionManifest, UNDEFINED_PUBLISHER, IExtensionDescription, getManifestCacheFileName, ExtensionIdentifierMap, parseEnabledApiProposalNames } from '../../extensions/common/extensions.js';
import { validateExtensionManifest } from '../../extensions/common/extensionValidator.js';
Expand Down Expand Up @@ -521,10 +521,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem
}

private getProductVersion(): IProductVersion {
return {
version: this.productService.version,
date: this.productService.date,
};
return getCompatibilityProductVersion(this.productService);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
ExtensionManagementError, ExtensionManagementErrorCode, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService, IGalleryExtension, ILocalExtension, InstallOperation,
Metadata, InstallOptions,
IProductVersion,
getCompatibilityProductVersion,
EXTENSION_INSTALL_CLIENT_TARGET_PLATFORM_CONTEXT,
ExtensionSignatureVerificationCode,
computeSize,
Expand Down Expand Up @@ -130,7 +131,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
}
}

getInstalled(type?: ExtensionType, profileLocation: URI = this.userDataProfilesService.defaultProfile.extensionsResource, productVersion: IProductVersion = { version: this.productService.version, date: this.productService.date }, language?: string): Promise<ILocalExtension[]> {
getInstalled(type?: ExtensionType, profileLocation: URI = this.userDataProfilesService.defaultProfile.extensionsResource, productVersion: IProductVersion = getCompatibilityProductVersion(this.productService), language?: string): Promise<ILocalExtension[]> {
return this.extensionsScanner.scanExtensions(type ?? null, profileLocation, productVersion, language);
}

Expand All @@ -150,7 +151,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
try {
const manifest = await getManifest(path.resolve(location.fsPath));
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode, this.productService.version, this.productService.date)) {
if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode, getCompatibilityProductVersion(this.productService).version, this.productService.date)) {
throw new Error(nls.localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", extensionId, this.productService.version));
}

Expand Down Expand Up @@ -234,7 +235,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
}

copyExtensions(fromProfileLocation: URI, toProfileLocation: URI): Promise<void> {
return this.extensionsScanner.copyExtensions(fromProfileLocation, toProfileLocation, { version: this.productService.version, date: this.productService.date });
return this.extensionsScanner.copyExtensions(fromProfileLocation, toProfileLocation, getCompatibilityProductVersion(this.productService));
}

deleteExtensions(...extensions: IExtension[]): Promise<void> {
Expand Down
Loading
Loading