Skip to content

Commit dbcfc0d

Browse files
Vikram KaltaVikram Kalta
authored andcommitted
feat: added support for uninstall all flag
1 parent 7647fa0 commit dbcfc0d

File tree

8 files changed

+88
-18
lines changed

8 files changed

+88
-18
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,13 @@ Uninstall an app
155155

156156
```
157157
USAGE
158-
$ csdx app:uninstall [--org <value>] [--app-uid <value>] [--installation-uid <value>]
158+
$ csdx app:uninstall [--org <value>] [--app-uid <value>] [--installation-uid <value>] [--uninstall-all]
159159
160160
FLAGS
161161
--app-uid=<value> Provide the app UID
162162
--installation-uid=<value> Provide the installation ID of the app that needs to be uninstalled.
163163
--org=<value> Provide the organization UID
164+
--uninstall-all Please select stacks from where the app must be uninstalled.
164165
165166
DESCRIPTION
166167
Uninstall an app

src/commands/app/uninstall.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { BaseCommand } from "./base-command";
22
import { flags } from "@contentstack/cli-utilities";
3-
import { getOrg, getApp, fetchApp, getInstallation, uninstallApp } from "../../util";
3+
import { getOrg, getApp, fetchApp } from "../../util";
44
import { commonMsg, uninstallAppMsg } from "../../messages";
5+
import { UninstallAppFactory } from "../../factories/uninstall-app-factory";
56

67
export default class Uninstall extends BaseCommand<typeof Uninstall> {
78
static description = "Uninstall an app";
@@ -19,6 +20,9 @@ export default class Uninstall extends BaseCommand<typeof Uninstall> {
1920
}),
2021
'installation-uid': flags.string({
2122
description: uninstallAppMsg.INSTALLATION_UID
23+
}),
24+
'uninstall-all': flags.boolean({
25+
description: uninstallAppMsg.UNINSTALL_ALL,
2226
})
2327
}
2428

@@ -34,19 +38,14 @@ export default class Uninstall extends BaseCommand<typeof Uninstall> {
3438
} else {
3539
app = await fetchApp(this.flags, this.sharedConfig.org, {managementSdk: this.managementAppSdk, log: this.log})
3640
}
37-
41+
3842
this.flags['app-uid'] = app?.uid;
3943
appType = app?.['target_type']
4044

41-
// select installation uid to uninstall
42-
if (!this.flags['installation-uid']) {
43-
this.flags['installation-uid'] = await getInstallation(this.flags, this.sharedConfig.org, this.managementSdk, appType, {managementSdk: this.managementAppSdk, log: this.log})
44-
}
45-
46-
// uninstall app
47-
for (const installationUid of this.flags['installation-uid']) {
48-
await uninstallApp(this.flags, this.sharedConfig.org, {managementSdk: this.managementAppSdk, log: this.log}, installationUid)
49-
}
45+
const factory = new UninstallAppFactory()
46+
const strategy = factory.getStrategyInstance(this.flags['uninstall-all'])
47+
await strategy.run(this.flags, this.sharedConfig.org, {managementSdk: this.managementAppSdk, log: this.log}, appType)
48+
5049
this.log(this.$t(uninstallAppMsg.APP_UNINSTALLED, { app: app?.name || this.flags["app-uid"] }), "info")
5150

5251
} catch (error: any) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { UninstallApp } from "../interfaces/uninstall-app";
2+
import { UninstallAll } from "../strategies/uninstall-all";
3+
import { UninstallSelected } from "../strategies/uninstall-selected";
4+
5+
export class UninstallAppFactory {
6+
public getStrategyInstance(uninstallAll: boolean): UninstallApp {
7+
let strategy: UninstallApp;
8+
if (uninstallAll) {
9+
strategy = new UninstallAll()
10+
} else {
11+
strategy = new UninstallSelected()
12+
}
13+
return strategy
14+
}
15+
}

src/interfaces/uninstall-app.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { FlagInput } from "@contentstack/cli-utilities";
2+
import { CommonOptions } from "../util";
3+
import { AppTarget } from "@contentstack/management/types/app/index"
4+
5+
export interface UninstallApp {
6+
run(flags: FlagInput, org: string, options: CommonOptions, appType: AppTarget): Promise<void>;
7+
}

src/messages/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ const uninstallAppMsg = {
9595
INSTALLATION_UID: "Provide the installation ID of the app that needs to be uninstalled.",
9696
NO_INSTALLATIONS_FOUND: "Cannot find any installations for this app.",
9797
APP_UNINSTALLED: "{app} uninstalled successfully.",
98-
UNINSTALLING_APP: "Uninstalling app from {type}..."
98+
UNINSTALLING_APP: "Uninstalling app from {type}...",
99+
UNINSTALL_ALL: "Please select stacks from where the app must be uninstalled.",
99100
}
100101

101102
const messages: typeof errors &

src/strategies/uninstall-all.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { FlagInput } from "@contentstack/cli-utilities";
2+
import { UninstallApp } from "../interfaces/uninstall-app";
3+
import { CommonOptions, getInstallation, uninstallApp } from "../util";
4+
import { AppTarget } from "@contentstack/management/types/app/index"
5+
6+
export class UninstallAll implements UninstallApp {
7+
public async run(flags: FlagInput, org: string, options: CommonOptions, appType: AppTarget): Promise<void> {
8+
// get all installation uids to uninstall
9+
const installationUids = await this.getInstallations(flags, org, options, appType)
10+
for (const installationUid of installationUids) {
11+
await uninstallApp(flags, org, options, installationUid)
12+
}
13+
}
14+
15+
public async getInstallations(flags: FlagInput, org: string, options: CommonOptions, appType: AppTarget): Promise<string[]> {
16+
let installationUids: string = await getInstallation(flags, org, options.managementSdk, appType, options, true)
17+
return installationUids.split(',')
18+
}
19+
}

src/strategies/uninstall-selected.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { FlagInput } from "@contentstack/cli-utilities";
2+
import { UninstallApp } from "../interfaces/uninstall-app";
3+
import { CommonOptions, getInstallation, uninstallApp } from "../util";
4+
import { AppTarget } from "@contentstack/management/types/app/index"
5+
6+
export class UninstallSelected implements UninstallApp {
7+
public async run(flags: FlagInput, org: string, options: CommonOptions, appType: AppTarget): Promise<void> {
8+
// select installation uid to uninstall
9+
const installationUids = await this.getInstallations(flags, org, options, appType)
10+
for (const installationUid of installationUids) {
11+
await uninstallApp(flags, org, options, installationUid)
12+
}
13+
}
14+
15+
public async getInstallations(flags: FlagInput, org: string, options: CommonOptions, appType: AppTarget): Promise<string[]> {
16+
let installationUids: any = flags['installation-uid'];
17+
if (!installationUids) {
18+
installationUids = await getInstallation(flags, org, options.managementSdk, appType, options)
19+
}
20+
return installationUids.split(',')
21+
}
22+
}

src/util/inquirer.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ async function getInstallation(
180180
orgUid: string,
181181
managementSdkForStacks: ContentstackClient,
182182
appType: AppTarget,
183-
options:CommonOptions
183+
options:CommonOptions,
184+
uninstallAll?: boolean,
184185
) : Promise<string> {
185186
const {log} = options;
186187
if (appType === 'stack') {
@@ -201,24 +202,29 @@ async function getInstallation(
201202
cliux.loader("done");
202203
const stacks: Stack[] = await getStacks({managementSdk: managementSdkForStacks, log: options.log}, orgUid);
203204
installations = populateMissingDataInInstallations(installations, stacks)
204-
selectedInstallation = await cliux
205+
// To support uninstall all flag
206+
if (uninstallAll) {
207+
return installations.join(',')
208+
}
209+
let _selectedInstallation = await cliux
205210
.inquire({
206211
type: 'checkbox',
207212
name: 'appInstallation',
208213
choices: installations,
209214
message: messages.CHOOSE_AN_INSTALLATION
210-
}) as string
215+
}) as string[]
216+
selectedInstallation = _selectedInstallation.join(',')
211217
} else {
212218
// as this is an organization app, and it is supposed to only be installed on the source organization
213219
// it will be uninstalled from the selected organization
214-
selectedInstallation = installations.pop()?.uid || "";
220+
selectedInstallation = installations.pop()?.uid || ""
215221
}
216222

217223
log($t(uninstallAppMsg.UNINSTALLING_APP, {
218224
type: appType
219225
}), "info")
220226

221-
return selectedInstallation;
227+
return selectedInstallation
222228
}
223229

224230
function populateMissingDataInInstallations(installations: [Installation], stacks: Stack[]): [Installation] {

0 commit comments

Comments
 (0)