@xano/cli 0.0.95-beta.3 → 0.0.95
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 +2 -27
- package/dist/base-command.d.ts +0 -24
- package/dist/base-command.js +0 -37
- package/dist/commands/tenant/create/index.d.ts +3 -1
- package/dist/commands/tenant/create/index.js +28 -6
- package/dist/commands/tenant/get/index.js +2 -2
- package/dist/commands/tenant/list/index.js +2 -2
- package/dist/commands/tenant/push/index.js +34 -0
- package/dist/commands/workspace/push/index.js +0 -26
- package/dist/help.d.ts +1 -2
- package/dist/help.js +1 -39
- package/oclif.manifest.json +2059 -4455
- package/package.json +1 -16
- package/dist/commands/release/deploy/index.d.ts +0 -17
- package/dist/commands/release/deploy/index.js +0 -107
- package/dist/commands/sandbox/env/delete/index.d.ts +0 -14
- package/dist/commands/sandbox/env/delete/index.js +0 -89
- package/dist/commands/sandbox/env/get/index.d.ts +0 -12
- package/dist/commands/sandbox/env/get/index.js +0 -65
- package/dist/commands/sandbox/env/get_all/index.d.ts +0 -13
- package/dist/commands/sandbox/env/get_all/index.js +0 -78
- package/dist/commands/sandbox/env/list/index.d.ts +0 -11
- package/dist/commands/sandbox/env/list/index.js +0 -67
- package/dist/commands/sandbox/env/set/index.d.ts +0 -13
- package/dist/commands/sandbox/env/set/index.js +0 -74
- package/dist/commands/sandbox/env/set_all/index.d.ts +0 -13
- package/dist/commands/sandbox/env/set_all/index.js +0 -86
- package/dist/commands/sandbox/get/index.d.ts +0 -11
- package/dist/commands/sandbox/get/index.js +0 -48
- package/dist/commands/sandbox/impersonate/index.d.ts +0 -5
- package/dist/commands/sandbox/impersonate/index.js +0 -5
- package/dist/commands/sandbox/license/get/index.d.ts +0 -13
- package/dist/commands/sandbox/license/get/index.js +0 -78
- package/dist/commands/sandbox/license/set/index.d.ts +0 -14
- package/dist/commands/sandbox/license/set/index.js +0 -95
- package/dist/commands/sandbox/pull/index.d.ts +0 -17
- package/dist/commands/sandbox/pull/index.js +0 -182
- package/dist/commands/sandbox/push/index.d.ts +0 -18
- package/dist/commands/sandbox/push/index.js +0 -143
- package/dist/commands/sandbox/reset/index.d.ts +0 -12
- package/dist/commands/sandbox/reset/index.js +0 -71
- package/dist/commands/sandbox/review/index.d.ts +0 -13
- package/dist/commands/sandbox/review/index.js +0 -94
- package/dist/commands/sandbox/unit_test/list/index.d.ts +0 -13
- package/dist/commands/sandbox/unit_test/list/index.js +0 -91
- package/dist/commands/sandbox/unit_test/run/index.d.ts +0 -14
- package/dist/commands/sandbox/unit_test/run/index.js +0 -79
- package/dist/commands/sandbox/unit_test/run_all/index.d.ts +0 -13
- package/dist/commands/sandbox/unit_test/run_all/index.js +0 -169
- package/dist/commands/sandbox/workflow_test/delete/index.d.ts +0 -17
- package/dist/commands/sandbox/workflow_test/delete/index.js +0 -61
- package/dist/commands/sandbox/workflow_test/get/index.d.ts +0 -17
- package/dist/commands/sandbox/workflow_test/get/index.js +0 -60
- package/dist/commands/sandbox/workflow_test/list/index.d.ts +0 -12
- package/dist/commands/sandbox/workflow_test/list/index.js +0 -84
- package/dist/commands/sandbox/workflow_test/run/index.d.ts +0 -17
- package/dist/commands/sandbox/workflow_test/run/index.js +0 -77
- package/dist/commands/sandbox/workflow_test/run_all/index.d.ts +0 -12
- package/dist/commands/sandbox/workflow_test/run_all/index.js +0 -155
- package/dist/commands/tenant/unit_test/list/index.d.ts +0 -15
- package/dist/commands/tenant/unit_test/list/index.js +0 -140
- package/dist/commands/tenant/unit_test/run/index.d.ts +0 -16
- package/dist/commands/tenant/unit_test/run/index.js +0 -128
- package/dist/commands/tenant/unit_test/run_all/index.d.ts +0 -15
- package/dist/commands/tenant/unit_test/run_all/index.js +0 -215
- package/dist/commands/tenant/workflow_test/delete/index.d.ts +0 -19
- package/dist/commands/tenant/workflow_test/delete/index.js +0 -110
- package/dist/commands/tenant/workflow_test/get/index.d.ts +0 -19
- package/dist/commands/tenant/workflow_test/get/index.js +0 -112
- package/dist/commands/tenant/workflow_test/list/index.d.ts +0 -14
- package/dist/commands/tenant/workflow_test/list/index.js +0 -133
- package/dist/commands/tenant/workflow_test/run/index.d.ts +0 -19
- package/dist/commands/tenant/workflow_test/run/index.js +0 -126
- package/dist/commands/tenant/workflow_test/run_all/index.d.ts +0 -14
- package/dist/commands/tenant/workflow_test/run_all/index.js +0 -201
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import BaseCommand from '../../../base-command.js';
|
|
3
|
-
import { findFilesWithGuid } from '../../../utils/document-parser.js';
|
|
4
|
-
import * as fs from 'node:fs';
|
|
5
|
-
import * as path from 'node:path';
|
|
6
|
-
export default class SandboxPush extends BaseCommand {
|
|
7
|
-
static args = {
|
|
8
|
-
directory: Args.string({
|
|
9
|
-
description: 'Directory containing documents to push (as produced by sandbox pull or workspace pull)',
|
|
10
|
-
required: true,
|
|
11
|
-
}),
|
|
12
|
-
};
|
|
13
|
-
static description = 'Push local documents to your sandbox environment via multidoc import';
|
|
14
|
-
static examples = [
|
|
15
|
-
`$ xano sandbox push ./my-workspace
|
|
16
|
-
Pushed 42 documents to sandbox environment tc24-abcd-x1y2 from ./my-workspace
|
|
17
|
-
`,
|
|
18
|
-
`$ xano sandbox push ./backup --records --env`,
|
|
19
|
-
`$ xano sandbox push ./my-workspace --truncate`,
|
|
20
|
-
];
|
|
21
|
-
static flags = {
|
|
22
|
-
...BaseCommand.baseFlags,
|
|
23
|
-
env: Flags.boolean({
|
|
24
|
-
default: false,
|
|
25
|
-
description: 'Include environment variables in import',
|
|
26
|
-
required: false,
|
|
27
|
-
}),
|
|
28
|
-
records: Flags.boolean({
|
|
29
|
-
default: false,
|
|
30
|
-
description: 'Include records in import',
|
|
31
|
-
required: false,
|
|
32
|
-
}),
|
|
33
|
-
transaction: Flags.boolean({
|
|
34
|
-
allowNo: true,
|
|
35
|
-
default: true,
|
|
36
|
-
description: 'Wrap import in a database transaction (use --no-transaction for debugging purposes)',
|
|
37
|
-
required: false,
|
|
38
|
-
}),
|
|
39
|
-
truncate: Flags.boolean({
|
|
40
|
-
default: false,
|
|
41
|
-
description: 'Truncate all table records before importing',
|
|
42
|
-
required: false,
|
|
43
|
-
}),
|
|
44
|
-
};
|
|
45
|
-
async run() {
|
|
46
|
-
const { args, flags } = await this.parse(SandboxPush);
|
|
47
|
-
const { profile } = this.resolveProfile(flags);
|
|
48
|
-
const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
|
|
49
|
-
const tenantName = tenant.name;
|
|
50
|
-
const inputDir = path.resolve(args.directory);
|
|
51
|
-
if (!fs.existsSync(inputDir)) {
|
|
52
|
-
this.error(`Directory not found: ${inputDir}`);
|
|
53
|
-
}
|
|
54
|
-
if (!fs.statSync(inputDir).isDirectory()) {
|
|
55
|
-
this.error(`Not a directory: ${inputDir}`);
|
|
56
|
-
}
|
|
57
|
-
const files = this.collectFiles(inputDir);
|
|
58
|
-
if (files.length === 0) {
|
|
59
|
-
this.error(`No .xs files found in ${args.directory}`);
|
|
60
|
-
}
|
|
61
|
-
const documentEntries = [];
|
|
62
|
-
for (const filePath of files) {
|
|
63
|
-
const content = fs.readFileSync(filePath, 'utf8').trim();
|
|
64
|
-
if (content) {
|
|
65
|
-
documentEntries.push({ content, filePath });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (documentEntries.length === 0) {
|
|
69
|
-
this.error(`All .xs files in ${args.directory} are empty`);
|
|
70
|
-
}
|
|
71
|
-
const multidoc = documentEntries.map((d) => d.content).join('\n---\n');
|
|
72
|
-
const queryParams = new URLSearchParams({
|
|
73
|
-
env: flags.env.toString(),
|
|
74
|
-
records: flags.records.toString(),
|
|
75
|
-
transaction: flags.transaction.toString(),
|
|
76
|
-
truncate: flags.truncate.toString(),
|
|
77
|
-
});
|
|
78
|
-
const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${tenantName}/multidoc?${queryParams.toString()}`;
|
|
79
|
-
const startTime = Date.now();
|
|
80
|
-
try {
|
|
81
|
-
const response = await this.verboseFetch(apiUrl, {
|
|
82
|
-
body: multidoc,
|
|
83
|
-
headers: {
|
|
84
|
-
accept: 'application/json',
|
|
85
|
-
Authorization: `Bearer ${profile.access_token}`,
|
|
86
|
-
'Content-Type': 'text/x-xanoscript',
|
|
87
|
-
},
|
|
88
|
-
method: 'POST',
|
|
89
|
-
}, flags.verbose, profile.access_token);
|
|
90
|
-
if (!response.ok) {
|
|
91
|
-
const errorText = await response.text();
|
|
92
|
-
let errorMessage = `Push failed (${response.status})`;
|
|
93
|
-
try {
|
|
94
|
-
const errorJson = JSON.parse(errorText);
|
|
95
|
-
errorMessage += `: ${errorJson.message}`;
|
|
96
|
-
if (errorJson.payload?.param) {
|
|
97
|
-
errorMessage += `\n Parameter: ${errorJson.payload.param}`;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
errorMessage += `\n${errorText}`;
|
|
102
|
-
}
|
|
103
|
-
const guidMatch = errorMessage.match(/Duplicate \w+ guid: (\S+)/);
|
|
104
|
-
if (guidMatch) {
|
|
105
|
-
const dupeFiles = findFilesWithGuid(documentEntries, guidMatch[1]);
|
|
106
|
-
if (dupeFiles.length > 0) {
|
|
107
|
-
const relPaths = dupeFiles.map((f) => path.relative(inputDir, f));
|
|
108
|
-
errorMessage += `\n Local files with this GUID:\n${relPaths.map((f) => ` ${f}`).join('\n')}`;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
this.error(errorMessage);
|
|
112
|
-
}
|
|
113
|
-
const responseText = await response.text();
|
|
114
|
-
if (responseText && responseText !== 'null' && flags.verbose) {
|
|
115
|
-
this.log(responseText);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
if (error instanceof Error) {
|
|
120
|
-
this.error(`Failed to push multidoc: ${error.message}`);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
this.error(`Failed to push multidoc: ${String(error)}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
127
|
-
this.log(`Pushed ${documentEntries.length} documents to sandbox environment ${tenantName} from ${args.directory} in ${elapsed}s`);
|
|
128
|
-
}
|
|
129
|
-
collectFiles(dir) {
|
|
130
|
-
const files = [];
|
|
131
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
132
|
-
for (const entry of entries) {
|
|
133
|
-
const fullPath = path.join(dir, entry.name);
|
|
134
|
-
if (entry.isDirectory()) {
|
|
135
|
-
files.push(...this.collectFiles(fullPath));
|
|
136
|
-
}
|
|
137
|
-
else if (entry.isFile() && entry.name.endsWith('.xs')) {
|
|
138
|
-
files.push(fullPath);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return files.sort();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import BaseCommand from '../../../base-command.js';
|
|
2
|
-
export default class SandboxReset extends BaseCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
-
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
-
};
|
|
10
|
-
run(): Promise<void>;
|
|
11
|
-
private confirm;
|
|
12
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
|
-
import BaseCommand from '../../../base-command.js';
|
|
3
|
-
export default class SandboxReset extends BaseCommand {
|
|
4
|
-
static description = 'Reset your sandbox environment (clears all workspace data and drafts)';
|
|
5
|
-
static examples = [
|
|
6
|
-
`$ xano sandbox reset
|
|
7
|
-
Are you sure you want to reset your sandbox environment? All workspace data and drafts will be cleared. (y/N) y
|
|
8
|
-
Reset sandbox environment tc24-abcd-x1y2
|
|
9
|
-
`,
|
|
10
|
-
`$ xano sandbox reset --force`,
|
|
11
|
-
];
|
|
12
|
-
static flags = {
|
|
13
|
-
...BaseCommand.baseFlags,
|
|
14
|
-
force: Flags.boolean({
|
|
15
|
-
char: 'f',
|
|
16
|
-
default: false,
|
|
17
|
-
description: 'Skip confirmation prompt',
|
|
18
|
-
required: false,
|
|
19
|
-
}),
|
|
20
|
-
};
|
|
21
|
-
async run() {
|
|
22
|
-
const { flags } = await this.parse(SandboxReset);
|
|
23
|
-
const { profile } = this.resolveProfile(flags);
|
|
24
|
-
const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
|
|
25
|
-
const tenantName = tenant.name;
|
|
26
|
-
if (!flags.force) {
|
|
27
|
-
const confirmed = await this.confirm(`Are you sure you want to reset your sandbox environment? All workspace data and drafts will be cleared.`);
|
|
28
|
-
if (!confirmed) {
|
|
29
|
-
this.log('Reset cancelled.');
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${encodeURIComponent(tenantName)}/reset`;
|
|
34
|
-
try {
|
|
35
|
-
const response = await this.verboseFetch(apiUrl, {
|
|
36
|
-
headers: {
|
|
37
|
-
accept: 'application/json',
|
|
38
|
-
Authorization: `Bearer ${profile.access_token}`,
|
|
39
|
-
'Content-Type': 'application/json',
|
|
40
|
-
},
|
|
41
|
-
method: 'POST',
|
|
42
|
-
}, flags.verbose, profile.access_token);
|
|
43
|
-
if (!response.ok) {
|
|
44
|
-
const errorText = await response.text();
|
|
45
|
-
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
46
|
-
}
|
|
47
|
-
this.log('Sandbox environment has been reset.');
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
if (error instanceof Error) {
|
|
51
|
-
this.error(`Failed to reset sandbox environment: ${error.message}`);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
this.error(`Failed to reset sandbox environment: ${String(error)}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
async confirm(message) {
|
|
59
|
-
const readline = await import('node:readline');
|
|
60
|
-
const rl = readline.createInterface({
|
|
61
|
-
input: process.stdin,
|
|
62
|
-
output: process.stdout,
|
|
63
|
-
});
|
|
64
|
-
return new Promise((resolve) => {
|
|
65
|
-
rl.question(`${message} (y/N) `, (answer) => {
|
|
66
|
-
rl.close();
|
|
67
|
-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import BaseCommand from '../../../base-command.js';
|
|
2
|
-
export default class SandboxReview extends BaseCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
-
'url-only': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
-
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
-
};
|
|
11
|
-
run(): Promise<void>;
|
|
12
|
-
private getFrontendUrl;
|
|
13
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
|
-
import open from 'open';
|
|
3
|
-
import BaseCommand from '../../../base-command.js';
|
|
4
|
-
export default class SandboxReview extends BaseCommand {
|
|
5
|
-
static description = 'Open your sandbox environment in the browser to review and promote changes';
|
|
6
|
-
static examples = [
|
|
7
|
-
`$ xano sandbox review
|
|
8
|
-
Opening browser...
|
|
9
|
-
Review session started!
|
|
10
|
-
`,
|
|
11
|
-
`$ xano sandbox review -u`,
|
|
12
|
-
`$ xano sandbox review -o json`,
|
|
13
|
-
];
|
|
14
|
-
static flags = {
|
|
15
|
-
...BaseCommand.baseFlags,
|
|
16
|
-
output: Flags.string({
|
|
17
|
-
char: 'o',
|
|
18
|
-
default: 'summary',
|
|
19
|
-
description: 'Output format',
|
|
20
|
-
options: ['summary', 'json'],
|
|
21
|
-
required: false,
|
|
22
|
-
}),
|
|
23
|
-
'url-only': Flags.boolean({
|
|
24
|
-
char: 'u',
|
|
25
|
-
default: false,
|
|
26
|
-
description: 'Print the URL without opening the browser',
|
|
27
|
-
required: false,
|
|
28
|
-
}),
|
|
29
|
-
};
|
|
30
|
-
async run() {
|
|
31
|
-
const { flags } = await this.parse(SandboxReview);
|
|
32
|
-
const { profile } = this.resolveProfile(flags);
|
|
33
|
-
const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
|
|
34
|
-
const tenantName = tenant.name;
|
|
35
|
-
const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${encodeURIComponent(tenantName)}/impersonate`;
|
|
36
|
-
try {
|
|
37
|
-
const response = await this.verboseFetch(apiUrl, {
|
|
38
|
-
headers: {
|
|
39
|
-
accept: 'application/json',
|
|
40
|
-
Authorization: `Bearer ${profile.access_token}`,
|
|
41
|
-
},
|
|
42
|
-
method: 'GET',
|
|
43
|
-
}, flags.verbose, profile.access_token);
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
const errorText = await response.text();
|
|
46
|
-
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
47
|
-
}
|
|
48
|
-
const result = (await response.json());
|
|
49
|
-
if (!result._ti) {
|
|
50
|
-
this.error('No one-time token returned from impersonate API');
|
|
51
|
-
}
|
|
52
|
-
if (flags.output === 'json') {
|
|
53
|
-
this.log(JSON.stringify(result, null, 2));
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
const frontendUrl = this.getFrontendUrl(profile.instance_origin);
|
|
57
|
-
const params = new URLSearchParams({
|
|
58
|
-
_ti: result._ti,
|
|
59
|
-
});
|
|
60
|
-
const impersonateUrl = `${frontendUrl}/impersonate?${params.toString()}`;
|
|
61
|
-
if (flags['url-only']) {
|
|
62
|
-
this.log(impersonateUrl);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
this.log('Opening browser...');
|
|
66
|
-
await open(impersonateUrl);
|
|
67
|
-
this.log('Review session started!');
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
process.exit(0);
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
if (error instanceof Error) {
|
|
74
|
-
this.error(`Failed to open sandbox review: ${error.message}`);
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
this.error(`Failed to open sandbox review: ${String(error)}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
getFrontendUrl(instanceOrigin) {
|
|
82
|
-
try {
|
|
83
|
-
const url = new URL(instanceOrigin);
|
|
84
|
-
if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
|
|
85
|
-
url.port = '4200';
|
|
86
|
-
return url.origin;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
// fall through
|
|
91
|
-
}
|
|
92
|
-
return instanceOrigin;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import BaseCommand from '../../../../base-command.js';
|
|
2
|
-
export default class SandboxUnitTestList 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
|
-
'obj-type': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
-
};
|
|
12
|
-
run(): Promise<void>;
|
|
13
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
|
-
import BaseCommand from '../../../../base-command.js';
|
|
3
|
-
export default class SandboxUnitTestList extends BaseCommand {
|
|
4
|
-
static description = 'List all unit tests for a sandbox environment';
|
|
5
|
-
static examples = [
|
|
6
|
-
`$ xano sandbox unit-test list
|
|
7
|
-
Unit tests:
|
|
8
|
-
- my-test (ID: abc-123) [function: math]
|
|
9
|
-
`,
|
|
10
|
-
`$ xano sandbox unit-test list -o json`,
|
|
11
|
-
];
|
|
12
|
-
static flags = {
|
|
13
|
-
...BaseCommand.baseFlags,
|
|
14
|
-
branch: Flags.string({
|
|
15
|
-
char: 'b',
|
|
16
|
-
description: 'Filter by branch name',
|
|
17
|
-
required: false,
|
|
18
|
-
}),
|
|
19
|
-
'obj-type': Flags.string({
|
|
20
|
-
description: 'Filter by object type',
|
|
21
|
-
options: ['function', 'query', 'middleware'],
|
|
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
|
-
};
|
|
32
|
-
async run() {
|
|
33
|
-
const { flags } = await this.parse(SandboxUnitTestList);
|
|
34
|
-
const { profile } = this.resolveProfile(flags);
|
|
35
|
-
const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
|
|
36
|
-
const tenantName = tenant.name;
|
|
37
|
-
const params = new URLSearchParams();
|
|
38
|
-
params.set('per_page', '10000');
|
|
39
|
-
if (flags.branch)
|
|
40
|
-
params.set('branch', flags.branch);
|
|
41
|
-
if (flags['obj-type'])
|
|
42
|
-
params.set('obj_type', flags['obj-type']);
|
|
43
|
-
const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${encodeURIComponent(tenantName)}/unit_test?${params}`;
|
|
44
|
-
try {
|
|
45
|
-
const response = await this.verboseFetch(apiUrl, {
|
|
46
|
-
headers: {
|
|
47
|
-
accept: 'application/json',
|
|
48
|
-
Authorization: `Bearer ${profile.access_token}`,
|
|
49
|
-
},
|
|
50
|
-
method: 'GET',
|
|
51
|
-
}, flags.verbose, profile.access_token);
|
|
52
|
-
if (!response.ok) {
|
|
53
|
-
const errorText = await response.text();
|
|
54
|
-
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
55
|
-
}
|
|
56
|
-
const data = (await response.json());
|
|
57
|
-
let tests;
|
|
58
|
-
if (Array.isArray(data)) {
|
|
59
|
-
tests = data;
|
|
60
|
-
}
|
|
61
|
-
else if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items)) {
|
|
62
|
-
tests = data.items;
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
this.error('Unexpected API response format');
|
|
66
|
-
}
|
|
67
|
-
if (flags.output === 'json') {
|
|
68
|
-
this.log(JSON.stringify(tests, null, 2));
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
if (tests.length === 0) {
|
|
72
|
-
this.log('No unit tests found');
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
this.log(`Unit tests for sandbox environment ${tenantName}:`);
|
|
76
|
-
for (const test of tests) {
|
|
77
|
-
this.log(` - ${test.name} (ID: ${test.id}) [${test.obj_type}: ${test.obj_name}]`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
if (error instanceof Error) {
|
|
84
|
-
this.error(`Failed to list unit tests: ${error.message}`);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
this.error(`Failed to list unit tests: ${String(error)}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import BaseCommand from '../../../../base-command.js';
|
|
2
|
-
export default class SandboxUnitTestRun extends BaseCommand {
|
|
3
|
-
static args: {
|
|
4
|
-
unit_test_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
-
};
|
|
6
|
-
static description: string;
|
|
7
|
-
static examples: string[];
|
|
8
|
-
static flags: {
|
|
9
|
-
output: import("@oclif/core/interfaces").OptionFlag<string, 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
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import BaseCommand from '../../../../base-command.js';
|
|
3
|
-
export default class SandboxUnitTestRun extends BaseCommand {
|
|
4
|
-
static args = {
|
|
5
|
-
unit_test_id: Args.string({
|
|
6
|
-
description: 'ID of the unit test to run',
|
|
7
|
-
required: true,
|
|
8
|
-
}),
|
|
9
|
-
};
|
|
10
|
-
static description = 'Run a unit test for a sandbox environment';
|
|
11
|
-
static examples = [
|
|
12
|
-
`$ xano sandbox unit-test run abc-123
|
|
13
|
-
Running unit test abc-123...
|
|
14
|
-
Result: PASS
|
|
15
|
-
`,
|
|
16
|
-
`$ xano sandbox unit-test run abc-123 -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
|
-
};
|
|
28
|
-
async run() {
|
|
29
|
-
const { args, flags } = await this.parse(SandboxUnitTestRun);
|
|
30
|
-
const { profile } = this.resolveProfile(flags);
|
|
31
|
-
const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
|
|
32
|
-
const tenantName = tenant.name;
|
|
33
|
-
const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${encodeURIComponent(tenantName)}/unit_test/${encodeURIComponent(args.unit_test_id)}/run`;
|
|
34
|
-
try {
|
|
35
|
-
if (flags.output === 'summary') {
|
|
36
|
-
this.log(`Running unit test ${args.unit_test_id}...`);
|
|
37
|
-
}
|
|
38
|
-
const response = await this.verboseFetch(apiUrl, {
|
|
39
|
-
headers: {
|
|
40
|
-
accept: 'application/json',
|
|
41
|
-
Authorization: `Bearer ${profile.access_token}`,
|
|
42
|
-
'Content-Type': 'application/json',
|
|
43
|
-
},
|
|
44
|
-
method: 'POST',
|
|
45
|
-
}, flags.verbose, profile.access_token);
|
|
46
|
-
if (!response.ok) {
|
|
47
|
-
const errorText = await response.text();
|
|
48
|
-
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
49
|
-
}
|
|
50
|
-
const result = (await response.json());
|
|
51
|
-
if (flags.output === 'json') {
|
|
52
|
-
this.log(JSON.stringify(result, null, 2));
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
if (result.status === 'ok') {
|
|
56
|
-
this.log('Result: PASS');
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
this.log('Result: FAIL');
|
|
60
|
-
const failedExpects = result.results?.filter((r) => r.status === 'fail') ?? [];
|
|
61
|
-
for (const expect of failedExpects) {
|
|
62
|
-
if (expect.message) {
|
|
63
|
-
this.log(` Error: ${expect.message}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
this.exit(1);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
if (error instanceof Error) {
|
|
72
|
-
this.error(`Failed to run unit test: ${error.message}`);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
this.error(`Failed to run unit test: ${String(error)}`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import BaseCommand from '../../../../base-command.js';
|
|
2
|
-
export default class SandboxUnitTestRunAll 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
|
-
'obj-type': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
-
};
|
|
12
|
-
run(): Promise<void>;
|
|
13
|
-
}
|