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
1 change: 1 addition & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This change log covers only the command line interface (CLI) of Open VSX.

#### Added

- Add `show` command to print an extension's metadata, mirroring `vsce show`: identity, publisher, rating, notices and a version history listing each version's target platforms ([#2149](https://github.com/eclipse-openvsx/openvsx/issues/2149)). `namespace.extension@version` reports a single version, `--target` scopes the report to one target platform, `--all-versions` lists every published version instead of the most recent few, and `--json` prints the registry's raw metadata
- Add `unpublish` command to delete an extension or some of its versions, mirroring `vsce unpublish` ([#1958](https://github.com/eclipse-openvsx/openvsx/issues/1958)); requires a registry running version 1.2.0 or later, which `unpublish` checks for before deleting
- `publish` checks the packaged extension's size against the limit reported by the registry's `/api/version` endpoint before uploading, instead of failing only after the upload completes ([#1953](https://github.com/eclipse-openvsx/openvsx/issues/1953))
- Add `verify` command to check a downloaded `.vsix` package's signature against the registry's public key, mirroring `vsce verify-signature` ([#993](https://github.com/eclipse-openvsx/openvsx/issues/993))
Expand Down
2 changes: 1 addition & 1 deletion cli/src/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function getExtension(options: GetOptions): Promise<void> {
const registry = new Registry(options);
const match = matchExtensionId(options.extensionId);
if (!match) {
throw new Error('The extension identifier must have the form `namespace.extension`.');
throw new Error('The extension identifier must have the form `namespace.extension` or `namespace/extension`.');
}

const extension = await registry.getMetadata(match[1], match[2], options.target);
Expand Down
11 changes: 11 additions & 0 deletions cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { publish } from './publish';
import { unpublish } from './unpublish';
import { handleError } from './util';
import { getExtension } from './get';
import { show } from './show';
import { verify } from './verify';
import { verifySignature } from './verify-signature';
import login from './login';
Expand Down Expand Up @@ -116,6 +117,16 @@ module.exports = function (argv: string[]): void {
}).catch(handleError(program.debug));
});

const showCmd = program.command('show <namespace.extension[@version]>');
showCmd.description('Show an extension\'s metadata.')
.option('-t, --target <target>', 'Only report on the given target architecture.')
.option('--all-versions', 'List every published version instead of the most recent few.')
.option('--json', 'Print the raw metadata as JSON.')
.action((extensionId: string, { target, allVersions, json }) => {
const { registryUrl } = program.opts();
show({ extensionId, target, allVersions, json, registryUrl }).catch(handleError(program.debug));
});

const getCmd = program.command('get <namespace.extension>');
getCmd.description('Download an extension or its metadata.')
.option('-t, --target <target>', 'Target architecture')
Expand Down
61 changes: 60 additions & 1 deletion cli/src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,48 @@ export class Registry {
}
}

getMetadata(namespace: string, extension: string, target?: string): Promise<Extension> {
getMetadata(namespace: string, extension: string, target?: string, version?: string): Promise<Extension> {
try {
const segments = ['api', namespace, extension];
if (target) {
segments.push(target);
}
if (version) {
segments.push(version);
}
return this.getJson(this.getUrl(segments));
} catch (err) {
return rejectError(err);
}
}

/**
* Returns a page of an extension's published versions, newest first, one entry per version and
* target platform. `allVersions` on the metadata response carries version numbers and links
* only, so this is what makes the target platforms of each version available.
*/
getVersionReferences(
namespace: string,
extension: string,
target: string | undefined,
size: number,
offset: number
): Promise<VersionReferences> {
try {
const segments = ['api', namespace, extension];
if (target) {
segments.push(target);
}
segments.push('version-references');
return this.getJson(this.getUrl(segments, {
size: String(size),
offset: String(offset)
}));
} catch (err) {
return rejectError(err);
}
}

download(file: string, url: URL): Promise<void> {
return new Promise((resolve, reject) => {
const stream = fs.createWriteStream(file);
Expand Down Expand Up @@ -293,8 +323,18 @@ export interface Extension extends Response {
versionAlias: string[];
timestamp: string;
preview?: boolean;
preRelease?: boolean;
displayName?: string;
namespaceDisplayName?: string;
description?: string;
deprecated?: boolean;
replacement?: ExtensionReplacement;
downloadable?: boolean;
publishedWithTrustedPublishing?: boolean;
namespaceOwnershipConflict?: boolean;
extensionKind?: string[];
localizedLanguages?: string[];
sponsorLink?: string;

// key: engine, value: version constraint
engines?: { [engine: string]: string };
Expand Down Expand Up @@ -346,6 +386,25 @@ export interface Badge {
description: string;
}

export interface ExtensionReplacement {
url: string;
displayName?: string;
}

export interface VersionReference {
url: string;
files: { [type: string]: string };
version: string;
targetPlatform?: string;
engines?: { [engine: string]: string };
}

export interface VersionReferences extends Response {
offset: number;
totalSize: number;
versions?: VersionReference[];
}

export interface ExtensionReference {
url: string;
namespace: string;
Expand Down
34 changes: 34 additions & 0 deletions cli/src/show-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/******************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*****************************************************************************/

import { RegistryOptions } from './registry-options';

export interface ShowOptions extends RegistryOptions {
/**
* Identifier in the form `namespace.extension` or `namespace/extension`, optionally suffixed
* with `@<version>` - an exact version, or one of the `latest` / `pre-release` aliases.
*/
extensionId: string;
/**
* Target platform to report on. Defaults to whichever the registry considers current.
*/
target?: string;
/**
* Print the raw metadata as JSON instead of a readable summary.
*/
json?: boolean;
/**
* List every published version rather than the most recent few.
*/
allVersions?: boolean;
}
Loading