Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Run "pa app remove" as admin. Closes #5519 #5610

Closed
Closed
Show file tree
Hide file tree
Changes from 2 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
14 changes: 14 additions & 0 deletions docs/docs/cmd/pa/app/app-remove.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ m365 pa app remove [options]

`-f, --force`
: Don't prompt for confirmation

`-e, --environmentName [environmentName]`
: The name of the environment for which to remove the specified app.
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved

`--asAdmin`
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
: Set, to remove the Power App as admin. Otherwise will remove only your own app.
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
```

<Global />
Expand All @@ -26,6 +32,8 @@ m365 pa app remove [options]

By default, the command will try to remove a Power App. As maker, you are able to delete the Power Apps you own. As administrator, you are also able to delete Power Apps from other users.

To remove the app from other user, use the `asAdmin` option and make sure to specify the `environment` option. You cannot specify only one of the options, when specifying the `environment` option the `asAdmin` option has to be present as well.
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved

To remove a model-driven Power App you need administrator permissions.

If the Power App with the name you specified doesn't exist, you will get the `Error: App 'abc' does not exist` error.
Expand All @@ -44,6 +52,12 @@ Removes the specified Power App without confirmation
m365 pa app remove --name 3989cb59-ce1a-4a5c-bb78-257c5c39381d --force
```

Removes the specified Power App from a given environment
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved

```sh
m365 pa app remove --name 3989cb59-ce1a-4a5c-bb78-257c5c39381d --environmentName Default-d87a7535-dd31-4437-bfe1-95340acd55c5 --asAdmin
```

## Response

The command won't return a response on success.
45 changes: 42 additions & 3 deletions src/m365/pa/commands/app/app-remove.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ describe(commands.APP_REMOVE, () => {
assert(loggerLogToStderrSpy.called);
});

it('removes the specified Microsoft Power App from other user when prompt confirmed (debug)', async () => {
it('removes the specified Microsoft Power App from other user as admin when prompt confirmed (debug)', async () => {
sinon.stub(request, 'delete').callsFake(async (opts) => {
if (opts.url === `https://api.powerapps.com/providers/Microsoft.PowerApps/apps/e0c89645-7f00-4877-a290-cbaf6e060da1?api-version=2017-08-01`) {
if (opts.url === `https://api.powerapps.com/providers/Microsoft.PowerApps/scopes/admin/environments/4ce50206-9576-4237-8b17-38d8aadfaa35/apps/e0c89645-7f00-4877-a290-cbaf6e060da1?api-version=2017-08-01`) {
return { statusCode: 200 };
}

Expand All @@ -152,7 +152,9 @@ describe(commands.APP_REMOVE, () => {
await command.action(logger, {
options: {
debug: true,
name: 'e0c89645-7f00-4877-a290-cbaf6e060da1'
name: 'e0c89645-7f00-4877-a290-cbaf6e060da1',
environmentName: '4ce50206-9576-4237-8b17-38d8aadfaa35',
asAdmin: true
}
});
assert(loggerLogToStderrSpy.called);
Expand Down Expand Up @@ -270,6 +272,28 @@ describe(commands.APP_REMOVE, () => {
assert(containsOption);
});

it('supports specifying environment', () => {
const options = command.options;
let containsOption = false;
options.forEach(o => {
if (o.option.indexOf('--environment') > -1) {
containsOption = true;
}
});
assert(containsOption);
});

it('supports specifying asAdmin', () => {
const options = command.options;
let containsOption = false;
options.forEach(o => {
if (o.option.indexOf('--asAdmin') > -1) {
containsOption = true;
}
});
assert(containsOption);
});

MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
it('correctly handles random api error', async () => {
sinon.stub(request, 'delete').rejects(new Error("Something went wrong"));

Expand All @@ -283,4 +307,19 @@ describe(commands.APP_REMOVE, () => {
}
} as any), new CommandError("Something went wrong"));
});

it('fails validation if asAdmin specified without environment', async () => {
const actual = await command.validate({ options: { name: "5369f386-e380-46cb-82a4-4e18f9e4f3a7", asAdmin: true } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('fails validation if environment specified without admin', async () => {
const actual = await command.validate({ options: { name: "5369f386-e380-46cb-82a4-4e18f9e4f3a7", environmentName: 'Default-d87a7535-dd31-4437-bfe1-95340acd55c6' } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('passes validation if asAdmin specified with environment', async () => {
const actual = await command.validate({ options: { name: "5369f386-e380-46cb-82a4-4e18f9e4f3a7", asAdmin: true, environmentName: 'Default-d87a7535-dd31-4437-bfe1-95340acd55c6' } }, commandInfo);
assert.strictEqual(actual, true);
});
});
22 changes: 20 additions & 2 deletions src/m365/pa/commands/app/app-remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ interface CommandArgs {
interface Options extends GlobalOptions {
name: string;
force?: boolean;
environmentName?: string;
asAdmin: boolean;
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
}

class PaAppRemoveCommand extends PowerAppsCommand {
Expand All @@ -37,7 +39,9 @@ class PaAppRemoveCommand extends PowerAppsCommand {
#initTelemetry(): void {
this.telemetry.push((args: CommandArgs) => {
Object.assign(this.telemetryProperties, {
force: typeof args.options.force !== 'undefined'
force: typeof args.options.force !== 'undefined',
asAdmin: args.options.asAdmin === true,
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
environmentName: typeof args.options.environmentName !== 'undefined'
});
});
}
Expand All @@ -49,6 +53,12 @@ class PaAppRemoveCommand extends PowerAppsCommand {
},
{
option: '-f, --force'
},
{
option: '-e, --environmentName [environmentName]'
},
{
option: '--asAdmin'
}
);
}
Expand All @@ -60,6 +70,14 @@ class PaAppRemoveCommand extends PowerAppsCommand {
return `${args.options.name} is not a valid GUID`;
}

if (args.options.asAdmin && !args.options.environmentName) {
return 'When specifying the asAdmin option the environment option is required as well';
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
}

if (args.options.environmentName && !args.options.asAdmin) {
return 'When specifying the environment option the asAdmin option is required as well';
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
}

return true;
}
);
Expand All @@ -72,7 +90,7 @@ class PaAppRemoveCommand extends PowerAppsCommand {

const removePaApp = async (): Promise<void> => {
const requestOptions: CliRequestOptions = {
url: `${this.resource}/providers/Microsoft.PowerApps/apps/${formatting.encodeQueryParameter(args.options.name)}?api-version=2017-08-01`,
url: `${this.resource}/providers/Microsoft.PowerApps${args.options.asAdmin ? '/scopes/admin' : ''}${args.options.environmentName ? '/environments/' + formatting.encodeQueryParameter(args.options.environmentName) : ''}/apps/${formatting.encodeQueryParameter(args.options.name)}?api-version=2017-08-01`,
MartinM85 marked this conversation as resolved.
Show resolved Hide resolved
fullResponse: true,
headers: {
accept: 'application/json'
Expand Down