@xano/cli 0.0.94 → 0.0.95-beta.2
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/README.md +19 -0
- package/dist/commands/ephemeral/access/index.d.ts +15 -0
- package/dist/commands/ephemeral/access/index.js +78 -0
- package/dist/commands/ephemeral/create/index.d.ts +17 -0
- package/dist/commands/ephemeral/create/index.js +102 -0
- package/dist/commands/ephemeral/delete/index.d.ts +16 -0
- package/dist/commands/ephemeral/delete/index.js +99 -0
- package/dist/commands/ephemeral/env/delete/index.d.ts +17 -0
- package/dist/commands/ephemeral/env/delete/index.js +105 -0
- package/dist/commands/ephemeral/env/get/index.d.ts +15 -0
- package/dist/commands/ephemeral/env/get/index.js +81 -0
- package/dist/commands/ephemeral/env/get_all/index.d.ts +16 -0
- package/dist/commands/ephemeral/env/get_all/index.js +94 -0
- package/dist/commands/ephemeral/env/list/index.d.ts +14 -0
- package/dist/commands/ephemeral/env/list/index.js +83 -0
- package/dist/commands/ephemeral/env/set/index.d.ts +16 -0
- package/dist/commands/ephemeral/env/set/index.js +90 -0
- package/dist/commands/ephemeral/env/set_all/index.d.ts +16 -0
- package/dist/commands/ephemeral/env/set_all/index.js +102 -0
- package/dist/commands/ephemeral/get/index.d.ts +14 -0
- package/dist/commands/ephemeral/get/index.js +102 -0
- package/dist/commands/ephemeral/impersonate/index.d.ts +16 -0
- package/dist/commands/ephemeral/impersonate/index.js +110 -0
- package/dist/commands/ephemeral/license/get/index.d.ts +16 -0
- package/dist/commands/ephemeral/license/get/index.js +94 -0
- package/dist/commands/ephemeral/license/set/index.d.ts +17 -0
- package/dist/commands/ephemeral/license/set/index.js +111 -0
- package/dist/commands/ephemeral/list/index.d.ts +15 -0
- package/dist/commands/ephemeral/list/index.js +109 -0
- package/dist/commands/ephemeral/pull/index.d.ts +18 -0
- package/dist/commands/ephemeral/pull/index.js +197 -0
- package/dist/commands/ephemeral/push/index.d.ts +19 -0
- package/dist/commands/ephemeral/push/index.js +158 -0
- package/dist/commands/ephemeral/shared/index.d.ts +15 -0
- package/dist/commands/ephemeral/shared/index.js +108 -0
- package/dist/commands/ephemeral/unit_test/list/index.d.ts +14 -0
- package/dist/commands/ephemeral/unit_test/list/index.js +105 -0
- package/dist/commands/ephemeral/unit_test/run/index.d.ts +15 -0
- package/dist/commands/ephemeral/unit_test/run/index.js +93 -0
- package/dist/commands/ephemeral/unit_test/run_all/index.d.ts +14 -0
- package/dist/commands/ephemeral/unit_test/run_all/index.js +183 -0
- package/dist/commands/ephemeral/workflow_test/delete/index.d.ts +18 -0
- package/dist/commands/ephemeral/workflow_test/delete/index.js +75 -0
- package/dist/commands/ephemeral/workflow_test/get/index.d.ts +18 -0
- package/dist/commands/ephemeral/workflow_test/get/index.js +77 -0
- package/dist/commands/ephemeral/workflow_test/list/index.d.ts +13 -0
- package/dist/commands/ephemeral/workflow_test/list/index.js +98 -0
- package/dist/commands/ephemeral/workflow_test/run/index.d.ts +18 -0
- package/dist/commands/ephemeral/workflow_test/run/index.js +91 -0
- package/dist/commands/ephemeral/workflow_test/run_all/index.d.ts +13 -0
- package/dist/commands/ephemeral/workflow_test/run_all/index.js +169 -0
- package/dist/commands/release/deploy/index.d.ts +17 -0
- package/dist/commands/release/deploy/index.js +107 -0
- package/dist/commands/tenant/create/index.d.ts +0 -1
- package/dist/commands/tenant/create/index.js +0 -5
- package/dist/commands/tenant/push/index.js +1 -1
- package/dist/commands/tenant/unit_test/list/index.d.ts +15 -0
- package/dist/commands/tenant/unit_test/list/index.js +140 -0
- package/dist/commands/tenant/unit_test/run/index.d.ts +16 -0
- package/dist/commands/tenant/unit_test/run/index.js +128 -0
- package/dist/commands/tenant/unit_test/run_all/index.d.ts +15 -0
- package/dist/commands/tenant/unit_test/run_all/index.js +215 -0
- package/dist/commands/tenant/workflow_test/delete/index.d.ts +19 -0
- package/dist/commands/tenant/workflow_test/delete/index.js +110 -0
- package/dist/commands/tenant/workflow_test/get/index.d.ts +19 -0
- package/dist/commands/tenant/workflow_test/get/index.js +112 -0
- package/dist/commands/tenant/workflow_test/list/index.d.ts +14 -0
- package/dist/commands/tenant/workflow_test/list/index.js +133 -0
- package/dist/commands/tenant/workflow_test/run/index.d.ts +19 -0
- package/dist/commands/tenant/workflow_test/run/index.js +126 -0
- package/dist/commands/tenant/workflow_test/run_all/index.d.ts +14 -0
- package/dist/commands/tenant/workflow_test/run_all/index.js +201 -0
- package/dist/help.d.ts +2 -1
- package/dist/help.js +39 -1
- package/oclif.manifest.json +5193 -2303
- package/package.json +16 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import BaseCommand from '../../../../base-command.js';
|
|
3
|
+
export default class TenantWorkflowTestRun extends BaseCommand {
|
|
4
|
+
static args = {
|
|
5
|
+
workflow_test_id: Args.integer({
|
|
6
|
+
description: 'ID of the workflow test to run',
|
|
7
|
+
required: true,
|
|
8
|
+
}),
|
|
9
|
+
};
|
|
10
|
+
static description = 'Run a workflow test for a tenant';
|
|
11
|
+
static examples = [
|
|
12
|
+
`$ xano tenant workflow-test run 42 -t my-tenant
|
|
13
|
+
Running workflow test 42...
|
|
14
|
+
Result: PASS (0.25s)
|
|
15
|
+
`,
|
|
16
|
+
`$ xano tenant workflow-test run 42 -t my-tenant -o json`,
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
...BaseCommand.baseFlags,
|
|
20
|
+
output: Flags.string({
|
|
21
|
+
char: 'o',
|
|
22
|
+
default: 'summary',
|
|
23
|
+
description: 'Output format',
|
|
24
|
+
options: ['summary', 'json'],
|
|
25
|
+
required: false,
|
|
26
|
+
}),
|
|
27
|
+
tenant: Flags.string({
|
|
28
|
+
char: 't',
|
|
29
|
+
description: 'Tenant name',
|
|
30
|
+
required: true,
|
|
31
|
+
}),
|
|
32
|
+
workspace: Flags.string({
|
|
33
|
+
char: 'w',
|
|
34
|
+
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
35
|
+
required: false,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
async run() {
|
|
39
|
+
const { args, flags } = await this.parse(TenantWorkflowTestRun);
|
|
40
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
41
|
+
const credentials = this.loadCredentialsFile();
|
|
42
|
+
if (!credentials || !(profileName in credentials.profiles)) {
|
|
43
|
+
this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
|
|
44
|
+
}
|
|
45
|
+
const profile = credentials.profiles[profileName];
|
|
46
|
+
if (!profile.instance_origin) {
|
|
47
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
48
|
+
}
|
|
49
|
+
if (!profile.access_token) {
|
|
50
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
51
|
+
}
|
|
52
|
+
const workspaceId = flags.workspace || profile.workspace;
|
|
53
|
+
if (!workspaceId) {
|
|
54
|
+
this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
|
|
55
|
+
}
|
|
56
|
+
// Resolve tenant to get its workspace
|
|
57
|
+
const tenantUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${encodeURIComponent(flags.tenant)}`;
|
|
58
|
+
let tenantWorkspaceId;
|
|
59
|
+
try {
|
|
60
|
+
const tenantResponse = await this.verboseFetch(tenantUrl, {
|
|
61
|
+
headers: {
|
|
62
|
+
accept: 'application/json',
|
|
63
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
64
|
+
},
|
|
65
|
+
method: 'GET',
|
|
66
|
+
}, flags.verbose, profile.access_token);
|
|
67
|
+
if (!tenantResponse.ok) {
|
|
68
|
+
const errorText = await tenantResponse.text();
|
|
69
|
+
this.error(`Failed to find tenant '${flags.tenant}': ${tenantResponse.status}\n${errorText}`);
|
|
70
|
+
}
|
|
71
|
+
const tenant = (await tenantResponse.json());
|
|
72
|
+
tenantWorkspaceId = String(tenant.workspace?.id || workspaceId);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error instanceof Error) {
|
|
76
|
+
this.error(`Failed to resolve tenant: ${error.message}`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.error(`Failed to resolve tenant: ${String(error)}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${tenantWorkspaceId}/workflow_test/${args.workflow_test_id}/run`;
|
|
83
|
+
try {
|
|
84
|
+
if (flags.output === 'summary') {
|
|
85
|
+
this.log(`Running workflow test ${args.workflow_test_id}...`);
|
|
86
|
+
}
|
|
87
|
+
const response = await this.verboseFetch(apiUrl, {
|
|
88
|
+
headers: {
|
|
89
|
+
accept: 'application/json',
|
|
90
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
91
|
+
'Content-Type': 'application/json',
|
|
92
|
+
},
|
|
93
|
+
method: 'POST',
|
|
94
|
+
}, flags.verbose, profile.access_token);
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
const errorText = await response.text();
|
|
97
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
98
|
+
}
|
|
99
|
+
const result = (await response.json());
|
|
100
|
+
if (flags.output === 'json') {
|
|
101
|
+
this.log(JSON.stringify(result, null, 2));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const timing = result.timing ? ` (${result.timing}s)` : '';
|
|
105
|
+
if (result.status === 'ok') {
|
|
106
|
+
this.log(`Result: PASS${timing}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
this.log(`Result: FAIL${timing}`);
|
|
110
|
+
if (result.message) {
|
|
111
|
+
this.log(` Error: ${result.message}`);
|
|
112
|
+
}
|
|
113
|
+
this.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error instanceof Error) {
|
|
119
|
+
this.error(`Failed to run workflow test: ${error.message}`);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this.error(`Failed to run workflow test: ${String(error)}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import BaseCommand from '../../../../base-command.js';
|
|
2
|
+
export default class TenantWorkflowTestRunAll extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import BaseCommand from '../../../../base-command.js';
|
|
3
|
+
export default class TenantWorkflowTestRunAll extends BaseCommand {
|
|
4
|
+
static description = 'Run all workflow tests for a tenant';
|
|
5
|
+
static examples = [
|
|
6
|
+
`$ xano tenant workflow-test run-all -t my-tenant
|
|
7
|
+
Running 3 workflow tests...
|
|
8
|
+
|
|
9
|
+
PASS my-test (0.25s)
|
|
10
|
+
FAIL data-check (0.10s)
|
|
11
|
+
Error: assertion failed
|
|
12
|
+
|
|
13
|
+
Results: 2 passed, 1 failed
|
|
14
|
+
`,
|
|
15
|
+
`$ xano tenant workflow-test run-all -t my-tenant -o json`,
|
|
16
|
+
];
|
|
17
|
+
static flags = {
|
|
18
|
+
...BaseCommand.baseFlags,
|
|
19
|
+
branch: Flags.string({
|
|
20
|
+
char: 'b',
|
|
21
|
+
description: 'Filter by branch name',
|
|
22
|
+
required: false,
|
|
23
|
+
}),
|
|
24
|
+
output: Flags.string({
|
|
25
|
+
char: 'o',
|
|
26
|
+
default: 'summary',
|
|
27
|
+
description: 'Output format',
|
|
28
|
+
options: ['summary', 'json'],
|
|
29
|
+
required: false,
|
|
30
|
+
}),
|
|
31
|
+
tenant: Flags.string({
|
|
32
|
+
char: 't',
|
|
33
|
+
description: 'Tenant name',
|
|
34
|
+
required: true,
|
|
35
|
+
}),
|
|
36
|
+
workspace: Flags.string({
|
|
37
|
+
char: 'w',
|
|
38
|
+
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
39
|
+
required: false,
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
async run() {
|
|
43
|
+
const { flags } = await this.parse(TenantWorkflowTestRunAll);
|
|
44
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
45
|
+
const credentials = this.loadCredentialsFile();
|
|
46
|
+
if (!credentials || !(profileName in credentials.profiles)) {
|
|
47
|
+
this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
|
|
48
|
+
}
|
|
49
|
+
const profile = credentials.profiles[profileName];
|
|
50
|
+
if (!profile.instance_origin) {
|
|
51
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
52
|
+
}
|
|
53
|
+
if (!profile.access_token) {
|
|
54
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
55
|
+
}
|
|
56
|
+
const workspaceId = flags.workspace || profile.workspace;
|
|
57
|
+
if (!workspaceId) {
|
|
58
|
+
this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
|
|
59
|
+
}
|
|
60
|
+
// Resolve tenant to get its workspace
|
|
61
|
+
const tenantUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${encodeURIComponent(flags.tenant)}`;
|
|
62
|
+
let tenantWorkspaceId;
|
|
63
|
+
try {
|
|
64
|
+
const tenantResponse = await this.verboseFetch(tenantUrl, {
|
|
65
|
+
headers: {
|
|
66
|
+
accept: 'application/json',
|
|
67
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
68
|
+
},
|
|
69
|
+
method: 'GET',
|
|
70
|
+
}, flags.verbose, profile.access_token);
|
|
71
|
+
if (!tenantResponse.ok) {
|
|
72
|
+
const errorText = await tenantResponse.text();
|
|
73
|
+
this.error(`Failed to find tenant '${flags.tenant}': ${tenantResponse.status}\n${errorText}`);
|
|
74
|
+
}
|
|
75
|
+
const tenant = (await tenantResponse.json());
|
|
76
|
+
tenantWorkspaceId = String(tenant.workspace?.id || workspaceId);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof Error) {
|
|
80
|
+
this.error(`Failed to resolve tenant: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.error(`Failed to resolve tenant: ${String(error)}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const baseUrl = `${profile.instance_origin}/api:meta/workspace/${tenantWorkspaceId}/workflow_test`;
|
|
87
|
+
try {
|
|
88
|
+
const listParams = new URLSearchParams();
|
|
89
|
+
listParams.set('per_page', '10000');
|
|
90
|
+
if (flags.branch)
|
|
91
|
+
listParams.set('branch', flags.branch);
|
|
92
|
+
const listResponse = await this.verboseFetch(`${baseUrl}?${listParams}`, {
|
|
93
|
+
headers: {
|
|
94
|
+
accept: 'application/json',
|
|
95
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
96
|
+
},
|
|
97
|
+
method: 'GET',
|
|
98
|
+
}, flags.verbose, profile.access_token);
|
|
99
|
+
if (!listResponse.ok) {
|
|
100
|
+
const errorText = await listResponse.text();
|
|
101
|
+
this.error(`Failed to list workflow tests: ${listResponse.status}: ${listResponse.statusText}\n${errorText}`);
|
|
102
|
+
}
|
|
103
|
+
const data = (await listResponse.json());
|
|
104
|
+
let tests;
|
|
105
|
+
if (Array.isArray(data)) {
|
|
106
|
+
tests = data;
|
|
107
|
+
}
|
|
108
|
+
else if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items)) {
|
|
109
|
+
tests = data.items;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this.error('Unexpected API response format');
|
|
113
|
+
}
|
|
114
|
+
if (tests.length === 0) {
|
|
115
|
+
this.log('No workflow tests found');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (flags.output === 'summary') {
|
|
119
|
+
this.log(`Running ${tests.length} workflow test${tests.length === 1 ? '' : 's'}...\n`);
|
|
120
|
+
}
|
|
121
|
+
const results = [];
|
|
122
|
+
for (const test of tests) {
|
|
123
|
+
const runUrl = `${baseUrl}/${test.id}/run`;
|
|
124
|
+
try {
|
|
125
|
+
const runResponse = await this.verboseFetch(runUrl, {
|
|
126
|
+
headers: {
|
|
127
|
+
accept: 'application/json',
|
|
128
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
},
|
|
131
|
+
method: 'POST',
|
|
132
|
+
}, flags.verbose, profile.access_token);
|
|
133
|
+
if (!runResponse.ok) {
|
|
134
|
+
const errorText = await runResponse.text();
|
|
135
|
+
results.push({
|
|
136
|
+
message: `API error ${runResponse.status}: ${errorText}`,
|
|
137
|
+
name: test.name,
|
|
138
|
+
status: 'fail',
|
|
139
|
+
});
|
|
140
|
+
if (flags.output === 'summary') {
|
|
141
|
+
this.log(`FAIL ${test.name}`);
|
|
142
|
+
this.log(` Error: API error ${runResponse.status}`);
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const runResult = (await runResponse.json());
|
|
147
|
+
const passed = runResult.status === 'ok';
|
|
148
|
+
results.push({
|
|
149
|
+
message: runResult.message,
|
|
150
|
+
name: test.name,
|
|
151
|
+
status: passed ? 'pass' : 'fail',
|
|
152
|
+
timing: runResult.timing,
|
|
153
|
+
});
|
|
154
|
+
if (flags.output === 'summary') {
|
|
155
|
+
const timing = runResult.timing ? ` (${runResult.timing}s)` : '';
|
|
156
|
+
if (passed) {
|
|
157
|
+
this.log(`PASS ${test.name}${timing}`);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
this.log(`FAIL ${test.name}${timing}`);
|
|
161
|
+
if (runResult.message) {
|
|
162
|
+
this.log(` Error: ${runResult.message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
169
|
+
results.push({
|
|
170
|
+
message,
|
|
171
|
+
name: test.name,
|
|
172
|
+
status: 'fail',
|
|
173
|
+
});
|
|
174
|
+
if (flags.output === 'summary') {
|
|
175
|
+
this.log(`FAIL ${test.name}`);
|
|
176
|
+
this.log(` Error: ${message}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const passed = results.filter((r) => r.status === 'pass').length;
|
|
181
|
+
const failed = results.filter((r) => r.status === 'fail').length;
|
|
182
|
+
if (flags.output === 'json') {
|
|
183
|
+
this.log(JSON.stringify({ failed, passed, results }, null, 2));
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
this.log(`\nResults: ${passed} passed, ${failed} failed`);
|
|
187
|
+
}
|
|
188
|
+
if (failed > 0) {
|
|
189
|
+
process.exitCode = 1;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
if (error instanceof Error) {
|
|
194
|
+
this.error(`Failed to run workflow tests: ${error.message}`);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
this.error(`Failed to run workflow tests: ${String(error)}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
package/dist/help.d.ts
CHANGED
|
@@ -12,9 +12,10 @@ declare class CustomCommandHelp extends BaseCommandHelp {
|
|
|
12
12
|
protected flagHelpLabel(flag: Command.Flag.Any, showOptions?: boolean): string;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Custom Help class that
|
|
15
|
+
* Custom Help class that injects promoted commands into the COMMANDS list
|
|
16
16
|
*/
|
|
17
17
|
export default class Help extends BaseHelp {
|
|
18
18
|
protected CommandHelpClass: typeof CustomCommandHelp;
|
|
19
|
+
formatCommands(commands: Command.Loadable[]): string;
|
|
19
20
|
}
|
|
20
21
|
export {};
|
package/dist/help.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { Help as BaseHelp } from '@oclif/core';
|
|
2
2
|
import { CommandHelp as BaseCommandHelp } from '@oclif/core/help';
|
|
3
|
+
/**
|
|
4
|
+
* Extra commands to include in the top-level COMMANDS list.
|
|
5
|
+
* These are nested commands promoted for discoverability.
|
|
6
|
+
*/
|
|
7
|
+
const PROMOTED_COMMANDS = [
|
|
8
|
+
{ description: 'Create a new workspace', label: 'workspace create' },
|
|
9
|
+
{ description: 'List workspaces', label: 'workspace list' },
|
|
10
|
+
{ description: 'Pull a workspace to local files', label: 'workspace pull' },
|
|
11
|
+
{ description: 'Push local documents to a workspace', label: 'workspace push' },
|
|
12
|
+
];
|
|
3
13
|
/**
|
|
4
14
|
* Custom CommandHelp class that extends the default to display environment variables
|
|
5
15
|
* alongside flag descriptions
|
|
@@ -19,8 +29,36 @@ class CustomCommandHelp extends BaseCommandHelp {
|
|
|
19
29
|
}
|
|
20
30
|
}
|
|
21
31
|
/**
|
|
22
|
-
* Custom Help class that
|
|
32
|
+
* Custom Help class that injects promoted commands into the COMMANDS list
|
|
23
33
|
*/
|
|
24
34
|
export default class Help extends BaseHelp {
|
|
25
35
|
CommandHelpClass = CustomCommandHelp;
|
|
36
|
+
formatCommands(commands) {
|
|
37
|
+
if (commands.length === 0 && PROMOTED_COMMANDS.length === 0)
|
|
38
|
+
return '';
|
|
39
|
+
// Check before IDs are mutated: root help has top-level commands (no colons)
|
|
40
|
+
const isRootHelp = commands.some((c) => !c.id.includes(':'));
|
|
41
|
+
const entries = commands
|
|
42
|
+
.filter((c) => (this.opts.hideAliasesFromRoot ? !c.aliases?.includes(c.id) : true))
|
|
43
|
+
.filter((c) => c.id !== 'plugins')
|
|
44
|
+
.map((c) => {
|
|
45
|
+
if (this.config.topicSeparator !== ':')
|
|
46
|
+
c.id = c.id.replaceAll(':', this.config.topicSeparator);
|
|
47
|
+
const summary = this.summary(c);
|
|
48
|
+
return [c.id, summary ? summary.replace(/\u001B\[\d+m/g, '') : ''];
|
|
49
|
+
});
|
|
50
|
+
// Only add promoted commands at the root level, not within a specific topic
|
|
51
|
+
if (isRootHelp) {
|
|
52
|
+
for (const promoted of PROMOTED_COMMANDS) {
|
|
53
|
+
entries.push([promoted.label, promoted.description]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
entries.sort((a, b) => a[0].localeCompare(b[0]));
|
|
57
|
+
const body = this.renderList(entries, {
|
|
58
|
+
indentation: 2,
|
|
59
|
+
spacer: '\n',
|
|
60
|
+
stripAnsi: this.opts.stripAnsi,
|
|
61
|
+
});
|
|
62
|
+
return this.section('COMMANDS', body + `\n\n\x1b[2mSee xano <topic> --help for all commands in a topic.\x1b[0m`);
|
|
63
|
+
}
|
|
26
64
|
}
|