From be7c0cdefbbef599e29885e766a0e2c13ed1a2ac Mon Sep 17 00:00:00 2001 From: Winston Liu Date: Mon, 27 May 2024 23:42:54 -0700 Subject: [PATCH 1/2] Switch back to official Gallery APIs --- app/exec/extension/_lib/publish.ts | 95 ++---------------------------- app/exec/extension/share.ts | 11 +--- 2 files changed, 9 insertions(+), 97 deletions(-) diff --git a/app/exec/extension/_lib/publish.ts b/app/exec/extension/_lib/publish.ts index 7c81f2f3..32c7bdb8 100644 --- a/app/exec/extension/_lib/publish.ts +++ b/app/exec/extension/_lib/publish.ts @@ -231,16 +231,13 @@ export class PublisherManager extends GalleryBase { } export class SharingManager extends GalleryBase { - private id: Promise; - private publisher: Promise; public shareWith(accounts: string[]): Promise { return this.getExtInfo().then(extInfo => { return Promise.all( accounts.map(account => { trace.info("Sharing extension with %s.", account); - return SharingManager.shareExtension(this.galleryClient, extInfo.publisher, extInfo.id, account).catch(errHandler.httpErr); - // return this.galleryClient.shareExtension(extInfo.publisher, extInfo.id, account).catch(errHandler.httpErr); + return this.galleryClient.shareExtension(extInfo.publisher, extInfo.id, account).catch(errHandler.httpErr); }), ); }); @@ -267,48 +264,6 @@ export class SharingManager extends GalleryBase { return ext.sharedWith.map(acct => acct.name); }); } - - /******** TEMPORARY UNTIL REST CLIENT UPDATED ********/ - public static async shareExtension( - client: IGalleryApi, - publisherName: string, - extensionName: string, - accountName: string - ): Promise { - - return new Promise(async (resolve, reject) => { - let routeValues: any = { - publisherName: publisherName, - extensionName: extensionName, - accountName: accountName - }; - - try { - let verData = await client.vsoClient.getVersioningData( - "6.1-preview.1", - "gallery", - "a1e66d8f-f5de-4d16-8309-91a4e015ee46", - routeValues); - - let url: string = verData.requestUrl; - let options = client.createRequestOptions('application/json', - verData.apiVersion); - - const res = await client.rest.create(url, null, options); - - let ret = client.formatResponse(res.result, - null, - false); - - resolve(ret); - - } - catch (err) { - reject(err); - } - }); - } - /******** /TEMPORARY UNTIL REST CLIENT UPDATED ********/ } export class PackagePublisher extends GalleryBase { @@ -338,9 +293,7 @@ export class PackagePublisher extends GalleryBase { * @return Q.Promise that is resolved when publish is complete */ public publish(): Promise { - const extPackage: GalleryInterfaces.ExtensionPackage = { - extensionManifest: fs.readFileSync(this.settings.vsixPath, "base64"), - }; + const extPackage = fs.createReadStream(this.settings.vsixPath) trace.debug("Publishing %s", this.settings.vsixPath); // Check if the app is already published. If so, call the update endpoint. Otherwise, create. @@ -402,18 +355,16 @@ export class PackagePublisher extends GalleryBase { } private createOrUpdateExtension( - extPackage: GalleryInterfaces.ExtensionPackage, + extPackage: fs.ReadStream, ): Promise { return this.checkVsixPublished().then(extInfo => { - let publishPromise; + let publishPromise: Promise; if (extInfo && extInfo.published) { trace.info("It is, %s the extension", colors.cyan("update").toString()); - publishPromise = this - .updateExtension(extPackage as any, extInfo.publisher, extInfo.id, false) - .catch(errHandler.httpErr); + publishPromise = this.galleryClient.updateExtension(null, extPackage, extInfo.publisher, extInfo.id).catch(errHandler.httpErr); } else { trace.info("It isn't, %s a new extension.", colors.cyan("create").toString()); - publishPromise = this.updateExtension(extPackage as any, extInfo.publisher, extInfo.id, true).catch(errHandler.httpErr); + publishPromise = this.galleryClient.createExtension(null, extPackage).catch(errHandler.httpErr); } return publishPromise.then(() => { return this.galleryClient.getExtension( @@ -427,40 +378,6 @@ export class PackagePublisher extends GalleryBase { }); } - /******** TEMPORARY UNTIL REST CLIENT UPDATED ********/ - private async updateExtension( - content: any, - publisherName: string, - extensionName: string, - create: boolean, - ): Promise { - - let routeValues: any = { - publisherName: publisherName, - extensionName: extensionName - }; - - const queryValues: any = { - bypassScopeCheck: undefined - }; - - const verData = await this.galleryClient.vsoClient.getVersioningData( - "6.1-preview.2", - "gallery", - "e11ea35a-16fe-4b80-ab11-c4cab88a0966", - routeValues, - queryValues - ); - - const url = verData.requestUrl; - const options = this.galleryClient.createRequestOptions("application/json", verData.apiVersion); - options.additionalHeaders = { "Content-Type": "application/json" }; - - const response = await (create ? this.galleryClient.rest.create(url, content, options) : this.galleryClient.rest.replace(url, content, options)); - return this.galleryClient.formatResponse(response.result, GalleryInterfaces.TypeInfo.PublishedExtension, false); - } - /******** /TEMPORARY UNTIL REST CLIENT UPDATED ********/ - public waitForValidation( interval: number, maxInterval: number, diff --git a/app/exec/extension/share.ts b/app/exec/extension/share.ts index 7ba485d9..afc9af15 100644 --- a/app/exec/extension/share.ts +++ b/app/exec/extension/share.ts @@ -52,14 +52,9 @@ export class ExtensionShare extends extBase.ExtensionBase { }); } return extInfoPromise.then(extInfo => { - return this.commandArgs.shareWith.val().then(shareWith => { - let sharePromises: Promise[] = []; - shareWith.forEach(account => { - sharePromises.push(SharingManager.shareExtension(galleryApi, extInfo.publisher, extInfo.id, account)); - }); - return Promise.all(sharePromises).then(() => { - return shareWith; - }); + return this.commandArgs.shareWith.val().then(accounts => { + const sharingMgr = new SharingManager({}, galleryApi, extInfo); + return sharingMgr.shareWith(accounts).then(() => accounts); }); }); }); From fa5f7e48a548701368d1cc7eae3bd56bbaab276b Mon Sep 17 00:00:00 2001 From: Nathan Hammond Date: Tue, 18 Feb 2025 09:56:14 +0800 Subject: [PATCH 2/2] Plumb through bypassScopeCheck --- app/exec/extension/_lib/interfaces.ts | 5 +++++ app/exec/extension/_lib/publish.ts | 2 +- app/exec/extension/default.ts | 6 +++++- app/exec/extension/publish.ts | 2 ++ app/exec/extension/resources/create.ts | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/exec/extension/_lib/interfaces.ts b/app/exec/extension/_lib/interfaces.ts index 84d2efa0..eff30f3c 100644 --- a/app/exec/extension/_lib/interfaces.ts +++ b/app/exec/extension/_lib/interfaces.ts @@ -232,6 +232,11 @@ export interface PublishSettings { * If true, command will not wait for extension to be validated. */ noWaitValidation?: boolean; + + /** + * If true, publish will not halt in the event of requiring new scopes. + */ + bypassScopeCheck?: boolean; } /*** Types related to localized resources ***/ diff --git a/app/exec/extension/_lib/publish.ts b/app/exec/extension/_lib/publish.ts index 32c7bdb8..3063111a 100644 --- a/app/exec/extension/_lib/publish.ts +++ b/app/exec/extension/_lib/publish.ts @@ -361,7 +361,7 @@ export class PackagePublisher extends GalleryBase { let publishPromise: Promise; if (extInfo && extInfo.published) { trace.info("It is, %s the extension", colors.cyan("update").toString()); - publishPromise = this.galleryClient.updateExtension(null, extPackage, extInfo.publisher, extInfo.id).catch(errHandler.httpErr); + publishPromise = this.galleryClient.updateExtension(null, extPackage, extInfo.publisher, extInfo.id, this.settings.bypassScopeCheck).catch(errHandler.httpErr); } else { trace.info("It isn't, %s a new extension.", colors.cyan("create").toString()); publishPromise = this.galleryClient.createExtension(null, extPackage).catch(errHandler.httpErr); diff --git a/app/exec/extension/default.ts b/app/exec/extension/default.ts index bfc01fc2..3d1ff135 100644 --- a/app/exec/extension/default.ts +++ b/app/exec/extension/default.ts @@ -23,6 +23,7 @@ export class ManifestJsonArgument extends args.JsonArgument {} export interface ExtensionArguments extends CoreArguments { accounts: args.ArrayArgument; branch: args.StringArgument; + bypassScopeCheck: args.BooleanArgument; bypassValidation: args.BooleanArgument; description: args.StringArgument; displayName: args.StringArgument; @@ -148,6 +149,7 @@ export class ExtensionBase extends TfCommand { "Path to an existing VSIX (to publish or query for).", args.ReadableFilePathsArgument, ); + this.registerCommandArgument("bypassScopeCheck", "Bypass scope check", null, args.BooleanArgument, "false"); this.registerCommandArgument("bypassValidation", "Bypass local validation", null, args.BooleanArgument, "false"); this.registerCommandArgument( "locRoot", @@ -300,8 +302,9 @@ export class ExtensionBase extends TfCommand { this.commandArgs.extensionId.val(true), this.commandArgs.shareWith.val(), this.commandArgs.noWaitValidation.val(), + this.commandArgs.bypassScopeCheck.val(), ]).then(values => { - const [marketUrl, vsix, publisher, extensionId, shareWith, noWaitValidation] = values; + const [marketUrl, vsix, publisher, extensionId, shareWith, noWaitValidation, bypassScopeCheck] = values; let vsixPath: string = _.isArray(vsix) ? vsix[0] : null; return { galleryUrl: marketUrl, @@ -310,6 +313,7 @@ export class ExtensionBase extends TfCommand { extensionId: extensionId, shareWith: shareWith, noWaitValidation: noWaitValidation, + bypassScopeCheck: bypassScopeCheck, }; }); } diff --git a/app/exec/extension/publish.ts b/app/exec/extension/publish.ts index 9af49d49..f499dca9 100644 --- a/app/exec/extension/publish.ts +++ b/app/exec/extension/publish.ts @@ -20,6 +20,7 @@ export interface ExtensionCreateArguments { override?: any; publisher?: string; extensionid?: string; + bypassscopecheck?: boolean; bypassvalidation?: boolean; } @@ -45,6 +46,7 @@ export class ExtensionPublish extends extBase.ExtensionBase