@capawesome/cli 4.1.0-dev.f5ef8ba.1771047437 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/commands/apps/builds/cancel.js +6 -41
- package/dist/commands/apps/builds/create.js +10 -55
- package/dist/commands/apps/builds/download.js +6 -41
- package/dist/commands/apps/builds/logs.js +6 -41
- package/dist/commands/apps/channels/create.js +6 -36
- package/dist/commands/apps/channels/create.test.js +5 -15
- package/dist/commands/apps/channels/delete.js +6 -36
- package/dist/commands/apps/channels/delete.test.js +6 -18
- package/dist/commands/apps/channels/get.js +3 -7
- package/dist/commands/apps/channels/list.js +6 -36
- package/dist/commands/apps/channels/list.test.js +4 -1
- package/dist/commands/apps/channels/pause.js +6 -40
- package/dist/commands/apps/channels/resume.js +6 -40
- package/dist/commands/apps/channels/update.js +6 -36
- package/dist/commands/apps/channels/update.test.js +14 -31
- package/dist/commands/apps/create.js +5 -23
- package/dist/commands/apps/create.test.js +13 -31
- package/dist/commands/apps/delete.js +6 -35
- package/dist/commands/apps/delete.test.js +11 -35
- package/dist/commands/apps/deployments/cancel.js +6 -41
- package/dist/commands/apps/deployments/create.js +6 -41
- package/dist/commands/apps/deployments/logs.js +6 -41
- package/dist/commands/apps/devices/delete.js +6 -36
- package/dist/commands/apps/devices/delete.test.js +14 -36
- package/dist/commands/apps/environments/create.js +6 -36
- package/dist/commands/apps/environments/delete.js +6 -36
- package/dist/commands/apps/environments/list.js +6 -36
- package/dist/commands/apps/environments/set.js +6 -36
- package/dist/commands/apps/environments/unset.js +6 -36
- package/dist/commands/apps/liveupdates/register.js +6 -40
- package/dist/commands/apps/liveupdates/register.test.js +2 -1
- package/dist/commands/apps/liveupdates/rollback.js +6 -41
- package/dist/commands/apps/liveupdates/rollout.js +6 -41
- package/dist/commands/apps/liveupdates/set-native-versions.js +3 -7
- package/dist/commands/apps/liveupdates/upload.js +6 -40
- package/dist/commands/apps/liveupdates/upload.test.js +2 -1
- package/dist/commands/organizations/create.js +3 -7
- package/dist/commands/organizations/create.test.js +3 -1
- package/dist/utils/auth.js +27 -0
- package/dist/utils/prompt.js +56 -11
- package/dist/utils/signature.js +2 -1
- package/package.json +6 -2
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import appChannelsService from '../../../services/app-channels.js';
|
|
2
|
-
import
|
|
3
|
-
import authorizationService from '../../../services/authorization-service.js';
|
|
4
|
-
import organizationsService from '../../../services/organizations.js';
|
|
2
|
+
import { withAuth } from '../../../utils/auth.js';
|
|
5
3
|
import { isInteractive } from '../../../utils/environment.js';
|
|
6
|
-
import {
|
|
4
|
+
import { promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
|
|
7
5
|
import { defineCommand, defineOptions } from '@robingenz/zli';
|
|
8
6
|
import consola from 'consola';
|
|
9
7
|
import { z } from 'zod';
|
|
@@ -15,43 +13,15 @@ export default defineCommand({
|
|
|
15
13
|
limit: z.coerce.number().optional().describe('Limit for pagination.'),
|
|
16
14
|
offset: z.coerce.number().optional().describe('Offset for pagination.'),
|
|
17
15
|
})),
|
|
18
|
-
action: async (options, args) => {
|
|
16
|
+
action: withAuth(async (options, args) => {
|
|
19
17
|
let { appId, json, limit, offset } = options;
|
|
20
|
-
if (!authorizationService.hasAuthorizationToken()) {
|
|
21
|
-
consola.error('You must be logged in to run this command. Please run the `login` command first.');
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
18
|
if (!appId) {
|
|
25
19
|
if (!isInteractive()) {
|
|
26
20
|
consola.error('You must provide an app ID when running in non-interactive environment.');
|
|
27
21
|
process.exit(1);
|
|
28
22
|
}
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
consola.error('You must create an organization before listing channels.');
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
35
|
-
const organizationId = await prompt('Select the organization of the app for which you want to list channels.', {
|
|
36
|
-
type: 'select',
|
|
37
|
-
options: organizations.map((organization) => ({ label: organization.name, value: organization.id })),
|
|
38
|
-
});
|
|
39
|
-
if (!organizationId) {
|
|
40
|
-
consola.error('You must select the organization of an app for which you want to list channels.');
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
const apps = await appsService.findAll({
|
|
44
|
-
organizationId,
|
|
45
|
-
});
|
|
46
|
-
if (!apps.length) {
|
|
47
|
-
consola.error('You must create an app before listing channels.');
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
51
|
-
appId = await prompt('Which app do you want to list the channels for?', {
|
|
52
|
-
type: 'select',
|
|
53
|
-
options: apps.map((app) => ({ label: app.name, value: app.id })),
|
|
54
|
-
});
|
|
23
|
+
const organizationId = await promptOrganizationSelection();
|
|
24
|
+
appId = await promptAppSelection(organizationId);
|
|
55
25
|
}
|
|
56
26
|
const foundChannels = await appChannelsService.findAll({
|
|
57
27
|
appId,
|
|
@@ -65,5 +35,5 @@ export default defineCommand({
|
|
|
65
35
|
console.table(foundChannels);
|
|
66
36
|
consola.success('Channels retrieved successfully.');
|
|
67
37
|
}
|
|
68
|
-
},
|
|
38
|
+
}),
|
|
69
39
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_API_BASE_URL } from '../../../config/consts.js';
|
|
2
2
|
import authorizationService from '../../../services/authorization-service.js';
|
|
3
|
+
import { prompt } from '../../../utils/prompt.js';
|
|
3
4
|
import userConfig from '../../../utils/user-config.js';
|
|
4
5
|
import consola from 'consola';
|
|
5
6
|
import nock from 'nock';
|
|
@@ -7,10 +8,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
7
8
|
import listChannelsCommand from './list.js';
|
|
8
9
|
// Mock dependencies
|
|
9
10
|
vi.mock('@/utils/user-config.js');
|
|
11
|
+
vi.mock('@/utils/prompt.js');
|
|
10
12
|
vi.mock('@/services/authorization-service.js');
|
|
11
13
|
vi.mock('consola');
|
|
12
14
|
describe('apps-channels-list', () => {
|
|
13
15
|
const mockUserConfig = vi.mocked(userConfig);
|
|
16
|
+
const mockPrompt = vi.mocked(prompt);
|
|
14
17
|
const mockConsola = vi.mocked(consola);
|
|
15
18
|
const mockAuthorizationService = vi.mocked(authorizationService);
|
|
16
19
|
beforeEach(() => {
|
|
@@ -33,7 +36,7 @@ describe('apps-channels-list', () => {
|
|
|
33
36
|
const options = { appId };
|
|
34
37
|
mockAuthorizationService.hasAuthorizationToken.mockReturnValue(false);
|
|
35
38
|
await expect(listChannelsCommand.action(options, undefined)).rejects.toThrow('Process exited with code 1');
|
|
36
|
-
expect(mockConsola.error).toHaveBeenCalledWith('You must be logged in to run this command.
|
|
39
|
+
expect(mockConsola.error).toHaveBeenCalledWith('You must be logged in to run this command. Set the `CAPAWESOME_TOKEN` environment variable or use the `--token` option.');
|
|
37
40
|
});
|
|
38
41
|
it('should require appId', async () => {
|
|
39
42
|
const options = { appId: undefined };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import appChannelsService from '../../../services/app-channels.js';
|
|
2
|
-
import
|
|
3
|
-
import authorizationService from '../../../services/authorization-service.js';
|
|
4
|
-
import organizationsService from '../../../services/organizations.js';
|
|
2
|
+
import { withAuth } from '../../../utils/auth.js';
|
|
5
3
|
import { isInteractive } from '../../../utils/environment.js';
|
|
6
|
-
import { prompt } from '../../../utils/prompt.js';
|
|
4
|
+
import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
|
|
7
5
|
import { defineCommand, defineOptions } from '@robingenz/zli';
|
|
8
6
|
import consola from 'consola';
|
|
9
7
|
import { z } from 'zod';
|
|
@@ -13,47 +11,15 @@ export default defineCommand({
|
|
|
13
11
|
appId: z.string().uuid({ message: 'App ID must be a UUID.' }).optional().describe('ID of the app.'),
|
|
14
12
|
channel: z.string().optional().describe('Name of the channel to pause.'),
|
|
15
13
|
})),
|
|
16
|
-
action: async (options, args) => {
|
|
14
|
+
action: withAuth(async (options, args) => {
|
|
17
15
|
let { appId, channel } = options;
|
|
18
|
-
if (!authorizationService.hasAuthorizationToken()) {
|
|
19
|
-
consola.error('You must be logged in to run this command. Please run the `login` command first.');
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
16
|
if (!appId) {
|
|
23
17
|
if (!isInteractive()) {
|
|
24
18
|
consola.error('You must provide an app ID when running in non-interactive environment.');
|
|
25
19
|
process.exit(1);
|
|
26
20
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
consola.error('You must create an organization before pausing a channel.');
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
33
|
-
const organizationId = await prompt('Select the organization of the app.', {
|
|
34
|
-
type: 'select',
|
|
35
|
-
options: organizations.map((organization) => ({ label: organization.name, value: organization.id })),
|
|
36
|
-
});
|
|
37
|
-
if (!organizationId) {
|
|
38
|
-
consola.error('You must select the organization of the app.');
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
const apps = await appsService.findAll({
|
|
42
|
-
organizationId,
|
|
43
|
-
});
|
|
44
|
-
if (!apps.length) {
|
|
45
|
-
consola.error('You must create an app before pausing a channel.');
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
49
|
-
appId = await prompt('Which app do you want to pause the channel in?', {
|
|
50
|
-
type: 'select',
|
|
51
|
-
options: apps.map((app) => ({ label: app.name, value: app.id })),
|
|
52
|
-
});
|
|
53
|
-
if (!appId) {
|
|
54
|
-
consola.error('You must select an app.');
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
21
|
+
const organizationId = await promptOrganizationSelection();
|
|
22
|
+
appId = await promptAppSelection(organizationId);
|
|
57
23
|
}
|
|
58
24
|
if (!channel) {
|
|
59
25
|
if (!isInteractive()) {
|
|
@@ -81,5 +47,5 @@ export default defineCommand({
|
|
|
81
47
|
}
|
|
82
48
|
await appChannelsService.pause({ appId, channelId });
|
|
83
49
|
consola.success('Channel paused successfully.');
|
|
84
|
-
},
|
|
50
|
+
}),
|
|
85
51
|
});
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import appChannelsService from '../../../services/app-channels.js';
|
|
2
|
-
import
|
|
3
|
-
import authorizationService from '../../../services/authorization-service.js';
|
|
4
|
-
import organizationsService from '../../../services/organizations.js';
|
|
2
|
+
import { withAuth } from '../../../utils/auth.js';
|
|
5
3
|
import { isInteractive } from '../../../utils/environment.js';
|
|
6
|
-
import { prompt } from '../../../utils/prompt.js';
|
|
4
|
+
import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
|
|
7
5
|
import { defineCommand, defineOptions } from '@robingenz/zli';
|
|
8
6
|
import consola from 'consola';
|
|
9
7
|
import { z } from 'zod';
|
|
@@ -13,47 +11,15 @@ export default defineCommand({
|
|
|
13
11
|
appId: z.string().uuid({ message: 'App ID must be a UUID.' }).optional().describe('ID of the app.'),
|
|
14
12
|
channel: z.string().optional().describe('Name of the channel to resume.'),
|
|
15
13
|
})),
|
|
16
|
-
action: async (options, args) => {
|
|
14
|
+
action: withAuth(async (options, args) => {
|
|
17
15
|
let { appId, channel } = options;
|
|
18
|
-
if (!authorizationService.hasAuthorizationToken()) {
|
|
19
|
-
consola.error('You must be logged in to run this command. Please run the `login` command first.');
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
16
|
if (!appId) {
|
|
23
17
|
if (!isInteractive()) {
|
|
24
18
|
consola.error('You must provide an app ID when running in non-interactive environment.');
|
|
25
19
|
process.exit(1);
|
|
26
20
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
consola.error('You must create an organization before resuming a channel.');
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
33
|
-
const organizationId = await prompt('Select the organization of the app.', {
|
|
34
|
-
type: 'select',
|
|
35
|
-
options: organizations.map((organization) => ({ label: organization.name, value: organization.id })),
|
|
36
|
-
});
|
|
37
|
-
if (!organizationId) {
|
|
38
|
-
consola.error('You must select the organization of the app.');
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
const apps = await appsService.findAll({
|
|
42
|
-
organizationId,
|
|
43
|
-
});
|
|
44
|
-
if (!apps.length) {
|
|
45
|
-
consola.error('You must create an app before resuming a channel.');
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
49
|
-
appId = await prompt('Which app do you want to resume the channel in?', {
|
|
50
|
-
type: 'select',
|
|
51
|
-
options: apps.map((app) => ({ label: app.name, value: app.id })),
|
|
52
|
-
});
|
|
53
|
-
if (!appId) {
|
|
54
|
-
consola.error('You must select an app.');
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
21
|
+
const organizationId = await promptOrganizationSelection();
|
|
22
|
+
appId = await promptAppSelection(organizationId);
|
|
57
23
|
}
|
|
58
24
|
if (!channel) {
|
|
59
25
|
if (!isInteractive()) {
|
|
@@ -81,5 +47,5 @@ export default defineCommand({
|
|
|
81
47
|
}
|
|
82
48
|
await appChannelsService.resume({ appId, channelId });
|
|
83
49
|
consola.success('Channel resumed successfully.');
|
|
84
|
-
},
|
|
50
|
+
}),
|
|
85
51
|
});
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import appChannelsService from '../../../services/app-channels.js';
|
|
2
|
-
import
|
|
3
|
-
import authorizationService from '../../../services/authorization-service.js';
|
|
4
|
-
import organizationsService from '../../../services/organizations.js';
|
|
2
|
+
import { withAuth } from '../../../utils/auth.js';
|
|
5
3
|
import { isInteractive } from '../../../utils/environment.js';
|
|
6
|
-
import { prompt } from '../../../utils/prompt.js';
|
|
4
|
+
import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
|
|
7
5
|
import { defineCommand, defineOptions } from '@robingenz/zli';
|
|
8
6
|
import consola from 'consola';
|
|
9
7
|
import { z } from 'zod';
|
|
@@ -15,44 +13,16 @@ export default defineCommand({
|
|
|
15
13
|
name: z.string().optional().describe('Name of the channel.'),
|
|
16
14
|
protected: z.boolean().optional().describe('Whether to protect the channel or not.'),
|
|
17
15
|
})),
|
|
18
|
-
action: async (options, args) => {
|
|
16
|
+
action: withAuth(async (options, args) => {
|
|
19
17
|
let { appId, channelId, name, protected: _protected } = options;
|
|
20
|
-
if (!authorizationService.hasAuthorizationToken()) {
|
|
21
|
-
consola.error('You must be logged in to run this command. Please run the `login` command first.');
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
18
|
// Prompt app ID if not provided
|
|
25
19
|
if (!appId) {
|
|
26
20
|
if (!isInteractive()) {
|
|
27
21
|
consola.error('You must provide an app ID when running in non-interactive environment.');
|
|
28
22
|
process.exit(1);
|
|
29
23
|
}
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
consola.error('You must create an organization before updating a channel.');
|
|
33
|
-
process.exit(1);
|
|
34
|
-
}
|
|
35
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
36
|
-
const organizationId = await prompt('Select the organization of the app for which you want to update a channel.', {
|
|
37
|
-
type: 'select',
|
|
38
|
-
options: organizations.map((organization) => ({ label: organization.name, value: organization.id })),
|
|
39
|
-
});
|
|
40
|
-
if (!organizationId) {
|
|
41
|
-
consola.error('You must select the organization of an app for which you want to update a channel.');
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
const apps = await appsService.findAll({
|
|
45
|
-
organizationId,
|
|
46
|
-
});
|
|
47
|
-
if (!apps.length) {
|
|
48
|
-
consola.error('You must create an app before updating a channel.');
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
52
|
-
appId = await prompt('Which app do you want to update the channel for?', {
|
|
53
|
-
type: 'select',
|
|
54
|
-
options: apps.map((app) => ({ label: app.name, value: app.id })),
|
|
55
|
-
});
|
|
24
|
+
const organizationId = await promptOrganizationSelection();
|
|
25
|
+
appId = await promptAppSelection(organizationId);
|
|
56
26
|
}
|
|
57
27
|
// Prompt for channel ID if not provided
|
|
58
28
|
if (!channelId) {
|
|
@@ -72,5 +42,5 @@ export default defineCommand({
|
|
|
72
42
|
protected: _protected,
|
|
73
43
|
});
|
|
74
44
|
consola.success('Channel updated successfully.');
|
|
75
|
-
},
|
|
45
|
+
}),
|
|
76
46
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_API_BASE_URL } from '../../../config/consts.js';
|
|
2
2
|
import authorizationService from '../../../services/authorization-service.js';
|
|
3
|
-
import { prompt } from '../../../utils/prompt.js';
|
|
3
|
+
import { prompt, promptAppSelection, promptOrganizationSelection } from '../../../utils/prompt.js';
|
|
4
4
|
import userConfig from '../../../utils/user-config.js';
|
|
5
5
|
import consola from 'consola';
|
|
6
6
|
import nock from 'nock';
|
|
@@ -17,6 +17,8 @@ vi.mock('@/utils/environment.js', () => ({
|
|
|
17
17
|
describe('apps-channels-update', () => {
|
|
18
18
|
const mockUserConfig = vi.mocked(userConfig);
|
|
19
19
|
const mockPrompt = vi.mocked(prompt);
|
|
20
|
+
const mockPromptOrganizationSelection = vi.mocked(promptOrganizationSelection);
|
|
21
|
+
const mockPromptAppSelection = vi.mocked(promptAppSelection);
|
|
20
22
|
const mockConsola = vi.mocked(consola);
|
|
21
23
|
const mockAuthorizationService = vi.mocked(authorizationService);
|
|
22
24
|
beforeEach(() => {
|
|
@@ -37,8 +39,10 @@ describe('apps-channels-update', () => {
|
|
|
37
39
|
const channelId = 'channel-456';
|
|
38
40
|
const options = { appId, channelId };
|
|
39
41
|
mockAuthorizationService.hasAuthorizationToken.mockReturnValue(false);
|
|
42
|
+
mockPrompt.mockResolvedValueOnce(false);
|
|
40
43
|
await expect(updateChannelCommand.action(options, undefined)).rejects.toThrow('Process exited with code 1');
|
|
41
|
-
expect(mockConsola.error).toHaveBeenCalledWith('You must be logged in to run this command.
|
|
44
|
+
expect(mockConsola.error).toHaveBeenCalledWith('You must be logged in to run this command.');
|
|
45
|
+
expect(mockConsola.error).toHaveBeenCalledWith('Please run the `login` command first.');
|
|
42
46
|
});
|
|
43
47
|
it('should update channel with provided options', async () => {
|
|
44
48
|
const appId = 'app-123';
|
|
@@ -63,29 +67,15 @@ describe('apps-channels-update', () => {
|
|
|
63
67
|
const appId = 'app-1';
|
|
64
68
|
const channelId = 'channel-456';
|
|
65
69
|
const testToken = 'test-token';
|
|
66
|
-
const organization = { id: orgId, name: 'Org 1' };
|
|
67
|
-
const app = { id: appId, name: 'App 1' };
|
|
68
70
|
const options = { channelId };
|
|
69
|
-
const orgsScope = nock(DEFAULT_API_BASE_URL)
|
|
70
|
-
.get('/v1/organizations')
|
|
71
|
-
.matchHeader('Authorization', `Bearer ${testToken}`)
|
|
72
|
-
.reply(200, [organization]);
|
|
73
|
-
const appsScope = nock(DEFAULT_API_BASE_URL)
|
|
74
|
-
.get('/v1/apps')
|
|
75
|
-
.query({ organizationId: orgId })
|
|
76
|
-
.matchHeader('Authorization', `Bearer ${testToken}`)
|
|
77
|
-
.reply(200, [app]);
|
|
78
71
|
const updateScope = nock(DEFAULT_API_BASE_URL)
|
|
79
72
|
.patch(`/v1/apps/${appId}/channels/${channelId}`)
|
|
80
73
|
.matchHeader('Authorization', `Bearer ${testToken}`)
|
|
81
74
|
.reply(200, { id: channelId });
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.mockResolvedValueOnce(channelId); // channel ID input
|
|
75
|
+
mockPromptOrganizationSelection.mockResolvedValueOnce(orgId);
|
|
76
|
+
mockPromptAppSelection.mockResolvedValueOnce(appId);
|
|
77
|
+
mockPrompt.mockResolvedValueOnce(channelId); // channel ID input
|
|
86
78
|
await updateChannelCommand.action(options, undefined);
|
|
87
|
-
expect(orgsScope.isDone()).toBe(true);
|
|
88
|
-
expect(appsScope.isDone()).toBe(true);
|
|
89
79
|
expect(updateScope.isDone()).toBe(true);
|
|
90
80
|
expect(mockConsola.success).toHaveBeenCalledWith('Channel updated successfully.');
|
|
91
81
|
});
|
|
@@ -116,24 +106,17 @@ describe('apps-channels-update', () => {
|
|
|
116
106
|
await expect(updateChannelCommand.action(options, undefined)).rejects.toThrow();
|
|
117
107
|
expect(scope.isDone()).toBe(true);
|
|
118
108
|
});
|
|
119
|
-
it('should
|
|
120
|
-
const testToken = 'test-token';
|
|
109
|
+
it('should exit when promptOrganizationSelection exits', async () => {
|
|
121
110
|
const options = { name: 'new-name' };
|
|
122
|
-
|
|
123
|
-
.
|
|
124
|
-
.
|
|
125
|
-
.reply(200, []);
|
|
126
|
-
const exitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => {
|
|
127
|
-
throw new Error(`process.exit called with code ${code}`);
|
|
111
|
+
mockPromptOrganizationSelection.mockImplementation(() => {
|
|
112
|
+
process.exit(1);
|
|
113
|
+
return Promise.resolve('');
|
|
128
114
|
});
|
|
129
115
|
try {
|
|
130
116
|
await updateChannelCommand.action(options, undefined);
|
|
131
117
|
}
|
|
132
118
|
catch (error) {
|
|
133
|
-
expect(error.message).toBe('
|
|
119
|
+
expect(error.message).toBe('Process exited with code 1');
|
|
134
120
|
}
|
|
135
|
-
expect(scope.isDone()).toBe(true);
|
|
136
|
-
expect(mockConsola.error).toHaveBeenCalledWith('You must create an organization before updating a channel.');
|
|
137
|
-
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
138
121
|
});
|
|
139
122
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import appsService from '../../services/apps.js';
|
|
2
|
-
import
|
|
3
|
-
import organizationsService from '../../services/organizations.js';
|
|
2
|
+
import { withAuth } from '../../utils/auth.js';
|
|
4
3
|
import { isInteractive } from '../../utils/environment.js';
|
|
5
|
-
import { prompt } from '../../utils/prompt.js';
|
|
4
|
+
import { prompt, promptOrganizationSelection } from '../../utils/prompt.js';
|
|
6
5
|
import { defineCommand, defineOptions } from '@robingenz/zli';
|
|
7
6
|
import consola from 'consola';
|
|
8
7
|
import { z } from 'zod';
|
|
@@ -12,31 +11,14 @@ export default defineCommand({
|
|
|
12
11
|
name: z.string().optional().describe('Name of the app.'),
|
|
13
12
|
organizationId: z.string().optional().describe('ID of the organization to create the app in.'),
|
|
14
13
|
})),
|
|
15
|
-
action: async (options, args) => {
|
|
14
|
+
action: withAuth(async (options, args) => {
|
|
16
15
|
let { name, organizationId } = options;
|
|
17
|
-
if (!authorizationService.hasAuthorizationToken()) {
|
|
18
|
-
consola.error('You must be logged in to run this command. Please run the `login` command first.');
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
16
|
if (!organizationId) {
|
|
22
17
|
if (!isInteractive()) {
|
|
23
18
|
consola.error('You must provide the organization ID when running in non-interactive environment.');
|
|
24
19
|
process.exit(1);
|
|
25
20
|
}
|
|
26
|
-
|
|
27
|
-
if (organizations.length === 0) {
|
|
28
|
-
consola.error('You must create an organization before creating an app.');
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
32
|
-
organizationId = await prompt('Which organization do you want to create the app in?', {
|
|
33
|
-
type: 'select',
|
|
34
|
-
options: organizations.map((organization) => ({ label: organization.name, value: organization.id })),
|
|
35
|
-
});
|
|
36
|
-
if (!organizationId) {
|
|
37
|
-
consola.error('You must select an organization to create the app in.');
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
21
|
+
organizationId = await promptOrganizationSelection({ allowCreate: true });
|
|
40
22
|
}
|
|
41
23
|
if (!name) {
|
|
42
24
|
if (!isInteractive()) {
|
|
@@ -48,5 +30,5 @@ export default defineCommand({
|
|
|
48
30
|
const response = await appsService.create({ name, organizationId });
|
|
49
31
|
consola.info(`App ID: ${response.id}`);
|
|
50
32
|
consola.success('App created successfully.');
|
|
51
|
-
},
|
|
33
|
+
}),
|
|
52
34
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_API_BASE_URL } from '../../config/consts.js';
|
|
2
2
|
import authorizationService from '../../services/authorization-service.js';
|
|
3
|
-
import { prompt } from '../../utils/prompt.js';
|
|
3
|
+
import { prompt, promptOrganizationSelection } from '../../utils/prompt.js';
|
|
4
4
|
import userConfig from '../../utils/user-config.js';
|
|
5
5
|
import consola from 'consola';
|
|
6
6
|
import nock from 'nock';
|
|
@@ -17,6 +17,7 @@ vi.mock('@/utils/environment.js', () => ({
|
|
|
17
17
|
describe('apps-create', () => {
|
|
18
18
|
const mockUserConfig = vi.mocked(userConfig);
|
|
19
19
|
const mockPrompt = vi.mocked(prompt);
|
|
20
|
+
const mockPromptOrganizationSelection = vi.mocked(promptOrganizationSelection);
|
|
20
21
|
const mockConsola = vi.mocked(consola);
|
|
21
22
|
const mockAuthorizationService = vi.mocked(authorizationService);
|
|
22
23
|
beforeEach(() => {
|
|
@@ -49,34 +50,19 @@ describe('apps-create', () => {
|
|
|
49
50
|
});
|
|
50
51
|
it('should prompt for organization when not provided', async () => {
|
|
51
52
|
const appName = 'Test App';
|
|
52
|
-
const
|
|
53
|
-
const orgId2 = 'org-2';
|
|
53
|
+
const orgId = 'org-1';
|
|
54
54
|
const appId = 'app-456';
|
|
55
55
|
const testToken = 'test-token';
|
|
56
|
-
const organizations = [
|
|
57
|
-
{ id: orgId1, name: 'Org 1' },
|
|
58
|
-
{ id: orgId2, name: 'Org 2' },
|
|
59
|
-
];
|
|
60
56
|
const options = { name: appName };
|
|
61
|
-
const orgsScope = nock(DEFAULT_API_BASE_URL)
|
|
62
|
-
.get('/v1/organizations')
|
|
63
|
-
.matchHeader('Authorization', `Bearer ${testToken}`)
|
|
64
|
-
.reply(200, organizations);
|
|
65
57
|
const createScope = nock(DEFAULT_API_BASE_URL)
|
|
66
|
-
.post(`/v1/apps?organizationId=${
|
|
58
|
+
.post(`/v1/apps?organizationId=${orgId}`, { name: appName })
|
|
67
59
|
.matchHeader('Authorization', `Bearer ${testToken}`)
|
|
68
60
|
.reply(201, { id: appId, name: appName });
|
|
69
|
-
|
|
61
|
+
mockPromptOrganizationSelection.mockResolvedValueOnce(orgId);
|
|
70
62
|
await createAppCommand.action(options, undefined);
|
|
71
|
-
expect(orgsScope.isDone()).toBe(true);
|
|
72
63
|
expect(createScope.isDone()).toBe(true);
|
|
73
|
-
expect(
|
|
74
|
-
|
|
75
|
-
options: [
|
|
76
|
-
{ label: 'Org 1', value: orgId1 },
|
|
77
|
-
{ label: 'Org 2', value: orgId2 },
|
|
78
|
-
],
|
|
79
|
-
});
|
|
64
|
+
expect(mockPromptOrganizationSelection).toHaveBeenCalled();
|
|
65
|
+
expect(mockConsola.success).toHaveBeenCalledWith('App created successfully.');
|
|
80
66
|
});
|
|
81
67
|
it('should prompt for app name when not provided', async () => {
|
|
82
68
|
const organizationId = 'org-123';
|
|
@@ -93,17 +79,13 @@ describe('apps-create', () => {
|
|
|
93
79
|
expect(scope.isDone()).toBe(true);
|
|
94
80
|
expect(mockPrompt).toHaveBeenCalledWith('Enter the name of the app:', { type: 'text' });
|
|
95
81
|
});
|
|
96
|
-
it('should
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
.matchHeader('Authorization', `Bearer ${testToken}`)
|
|
103
|
-
.reply(200, []);
|
|
82
|
+
it('should exit when promptOrganizationSelection exits', async () => {
|
|
83
|
+
const options = { name: 'Test App' };
|
|
84
|
+
mockPromptOrganizationSelection.mockImplementation(() => {
|
|
85
|
+
process.exit(1);
|
|
86
|
+
return Promise.resolve('');
|
|
87
|
+
});
|
|
104
88
|
await expect(createAppCommand.action(options, undefined)).rejects.toThrow('Process exited with code 1');
|
|
105
|
-
expect(scope.isDone()).toBe(true);
|
|
106
|
-
expect(mockConsola.error).toHaveBeenCalledWith('You must create an organization before creating an app.');
|
|
107
89
|
});
|
|
108
90
|
it('should handle API error during creation', async () => {
|
|
109
91
|
const appName = 'Test App';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import appsService from '../../services/apps.js';
|
|
2
|
-
import
|
|
3
|
-
import organizationsService from '../../services/organizations.js';
|
|
2
|
+
import { withAuth } from '../../utils/auth.js';
|
|
4
3
|
import { isInteractive } from '../../utils/environment.js';
|
|
5
|
-
import { prompt } from '../../utils/prompt.js';
|
|
4
|
+
import { prompt, promptAppSelection, promptOrganizationSelection } from '../../utils/prompt.js';
|
|
6
5
|
import { defineCommand, defineOptions } from '@robingenz/zli';
|
|
7
6
|
import consola from 'consola';
|
|
8
7
|
import { z } from 'zod';
|
|
@@ -12,43 +11,15 @@ export default defineCommand({
|
|
|
12
11
|
appId: z.string().optional().describe('ID of the app.'),
|
|
13
12
|
yes: z.boolean().optional().describe('Skip confirmation prompt.'),
|
|
14
13
|
}), { y: 'yes' }),
|
|
15
|
-
action: async (options, args) => {
|
|
14
|
+
action: withAuth(async (options, args) => {
|
|
16
15
|
let { appId } = options;
|
|
17
|
-
if (!authorizationService.hasAuthorizationToken()) {
|
|
18
|
-
consola.error('You must be logged in to run this command. Please run the `login` command first.');
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
16
|
if (!appId) {
|
|
22
17
|
if (!isInteractive()) {
|
|
23
18
|
consola.error('You must provide the app ID when running in non-interactive environment.');
|
|
24
19
|
process.exit(1);
|
|
25
20
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
consola.error('You must create an organization before deleting an app.');
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
32
|
-
const organizationId = await prompt('Which organization do you want to delete the app from?', {
|
|
33
|
-
type: 'select',
|
|
34
|
-
options: organizations.map((organization) => ({ label: organization.name, value: organization.id })),
|
|
35
|
-
});
|
|
36
|
-
if (!organizationId) {
|
|
37
|
-
consola.error('You must select an organization to delete the app from.');
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
const apps = await appsService.findAll({
|
|
41
|
-
organizationId,
|
|
42
|
-
});
|
|
43
|
-
if (!apps.length) {
|
|
44
|
-
consola.error('You must create an app before deleting it.');
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
// @ts-ignore wait till https://github.com/unjs/consola/pull/280 is merged
|
|
48
|
-
appId = await prompt('Which app do you want to delete?', {
|
|
49
|
-
type: 'select',
|
|
50
|
-
options: apps.map((app) => ({ label: app.name, value: app.id })),
|
|
51
|
-
});
|
|
21
|
+
const organizationId = await promptOrganizationSelection();
|
|
22
|
+
appId = await promptAppSelection(organizationId);
|
|
52
23
|
}
|
|
53
24
|
if (!options.yes && isInteractive()) {
|
|
54
25
|
const confirmed = await prompt('Are you sure you want to delete this app?', {
|
|
@@ -60,5 +31,5 @@ export default defineCommand({
|
|
|
60
31
|
}
|
|
61
32
|
await appsService.delete({ id: appId });
|
|
62
33
|
consola.success('App deleted successfully.');
|
|
63
|
-
},
|
|
34
|
+
}),
|
|
64
35
|
});
|