@xano/cli 0.0.20 → 0.0.22
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/dist/base-command.d.ts +1 -1
- package/dist/base-command.js +6 -6
- package/dist/commands/branch/create/index.d.ts +17 -0
- package/dist/commands/branch/create/index.js +164 -0
- package/dist/commands/branch/delete/index.d.ts +18 -0
- package/dist/commands/branch/delete/index.js +156 -0
- package/dist/commands/branch/edit/index.d.ts +19 -0
- package/dist/commands/branch/edit/index.js +166 -0
- package/dist/commands/branch/get/index.d.ts +16 -0
- package/dist/commands/branch/get/index.js +135 -0
- package/dist/commands/branch/list/index.d.ts +18 -0
- package/dist/commands/branch/list/index.js +138 -0
- package/dist/commands/branch/set-live/index.d.ts +18 -0
- package/dist/commands/branch/set-live/index.js +155 -0
- package/dist/commands/function/create/index.d.ts +6 -6
- package/dist/commands/function/create/index.js +55 -55
- package/dist/commands/function/edit/index.d.ts +10 -10
- package/dist/commands/function/edit/index.js +155 -162
- package/dist/commands/function/get/index.d.ts +5 -5
- package/dist/commands/function/get/index.js +55 -60
- package/dist/commands/function/list/index.d.ts +5 -5
- package/dist/commands/function/list/index.js +52 -52
- package/dist/commands/profile/create/index.d.ts +6 -6
- package/dist/commands/profile/create/index.js +37 -37
- package/dist/commands/profile/delete/index.d.ts +2 -2
- package/dist/commands/profile/delete/index.js +9 -9
- package/dist/commands/profile/edit/index.d.ts +7 -7
- package/dist/commands/profile/edit/index.js +47 -47
- package/dist/commands/profile/get-default/index.js +1 -1
- package/dist/commands/profile/list/index.d.ts +2 -2
- package/dist/commands/profile/list/index.js +9 -9
- package/dist/commands/profile/me/index.d.ts +3 -3
- package/dist/commands/profile/me/index.js +21 -21
- package/dist/commands/profile/project/index.js +1 -1
- package/dist/commands/profile/set-default/index.js +1 -1
- package/dist/commands/profile/token/index.js +1 -1
- package/dist/commands/profile/wizard/index.d.ts +4 -4
- package/dist/commands/profile/wizard/index.js +118 -122
- package/dist/commands/run/env/delete/index.d.ts +2 -2
- package/dist/commands/run/env/delete/index.js +9 -9
- package/dist/commands/run/env/get/index.d.ts +2 -2
- package/dist/commands/run/env/get/index.js +10 -10
- package/dist/commands/run/env/list/index.d.ts +2 -2
- package/dist/commands/run/env/list/index.js +16 -18
- package/dist/commands/run/env/set/index.d.ts +2 -2
- package/dist/commands/run/env/set/index.js +4 -4
- package/dist/commands/run/exec/index.d.ts +11 -11
- package/dist/commands/run/exec/index.js +109 -109
- package/dist/commands/run/info/index.d.ts +4 -4
- package/dist/commands/run/info/index.js +26 -26
- package/dist/commands/run/projects/create/index.d.ts +3 -3
- package/dist/commands/run/projects/create/index.js +22 -22
- package/dist/commands/run/projects/delete/index.d.ts +2 -2
- package/dist/commands/run/projects/delete/index.js +9 -9
- package/dist/commands/run/projects/list/index.d.ts +2 -2
- package/dist/commands/run/projects/list/index.js +11 -11
- package/dist/commands/run/projects/update/index.d.ts +3 -3
- package/dist/commands/run/projects/update/index.js +20 -20
- package/dist/commands/run/secrets/delete/index.d.ts +2 -2
- package/dist/commands/run/secrets/delete/index.js +9 -9
- package/dist/commands/run/secrets/get/index.d.ts +2 -2
- package/dist/commands/run/secrets/get/index.js +10 -10
- package/dist/commands/run/secrets/list/index.d.ts +2 -2
- package/dist/commands/run/secrets/list/index.js +21 -23
- package/dist/commands/run/secrets/set/index.d.ts +3 -3
- package/dist/commands/run/secrets/set/index.js +15 -15
- package/dist/commands/run/sessions/delete/index.d.ts +2 -2
- package/dist/commands/run/sessions/delete/index.js +9 -9
- package/dist/commands/run/sessions/get/index.d.ts +2 -2
- package/dist/commands/run/sessions/get/index.js +10 -10
- package/dist/commands/run/sessions/list/index.d.ts +2 -2
- package/dist/commands/run/sessions/list/index.js +10 -10
- package/dist/commands/run/sessions/start/index.d.ts +2 -2
- package/dist/commands/run/sessions/start/index.js +10 -10
- package/dist/commands/run/sessions/stop/index.d.ts +2 -2
- package/dist/commands/run/sessions/stop/index.js +10 -10
- package/dist/commands/run/sink/get/index.d.ts +2 -2
- package/dist/commands/run/sink/get/index.js +10 -10
- package/dist/commands/static_host/build/create/index.d.ts +4 -4
- package/dist/commands/static_host/build/create/index.js +33 -33
- package/dist/commands/static_host/build/get/index.d.ts +4 -4
- package/dist/commands/static_host/build/get/index.js +20 -20
- package/dist/commands/static_host/build/list/index.d.ts +3 -3
- package/dist/commands/static_host/build/list/index.js +31 -31
- package/dist/commands/static_host/list/index.d.ts +3 -3
- package/dist/commands/static_host/list/index.js +31 -31
- package/dist/commands/workspace/create/index.d.ts +14 -0
- package/dist/commands/workspace/create/index.js +131 -0
- package/dist/commands/workspace/delete/index.d.ts +20 -0
- package/dist/commands/workspace/delete/index.js +141 -0
- package/dist/commands/workspace/edit/index.d.ts +22 -0
- package/dist/commands/workspace/edit/index.js +176 -0
- package/dist/commands/workspace/get/index.d.ts +18 -0
- package/dist/commands/workspace/get/index.js +136 -0
- package/dist/commands/workspace/list/index.d.ts +2 -2
- package/dist/commands/workspace/list/index.js +15 -15
- package/dist/commands/workspace/pull/index.d.ts +4 -4
- package/dist/commands/workspace/pull/index.js +46 -51
- package/dist/commands/workspace/push/index.js +3 -3
- package/dist/help.d.ts +1 -1
- package/dist/lib/base-run-command.d.ts +4 -4
- package/dist/lib/base-run-command.js +3 -3
- package/dist/lib/run-http-client.d.ts +21 -21
- package/dist/lib/run-http-client.js +72 -72
- package/dist/lib/run-types.d.ts +80 -80
- package/oclif.manifest.json +1633 -791
- package/package.json +1 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import BaseCommand from '../../../base-command.js';
|
|
7
|
+
export default class BranchGet extends BaseCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
branch_label: Args.string({
|
|
10
|
+
description: 'Branch label (e.g., "v1", "dev")',
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static description = 'Get details for a specific branch';
|
|
15
|
+
static examples = [
|
|
16
|
+
`$ xano branch get v1
|
|
17
|
+
Branch: v1 (live)
|
|
18
|
+
Created: 2024-01-15
|
|
19
|
+
`,
|
|
20
|
+
`$ xano branch get dev -w 123
|
|
21
|
+
Branch: dev
|
|
22
|
+
Created: 2024-02-01
|
|
23
|
+
`,
|
|
24
|
+
`$ xano branch get staging --output json
|
|
25
|
+
{
|
|
26
|
+
"created_at": "2024-02-10T09:15:00Z",
|
|
27
|
+
"label": "staging",
|
|
28
|
+
"backup": false,
|
|
29
|
+
"live": false
|
|
30
|
+
}
|
|
31
|
+
`,
|
|
32
|
+
];
|
|
33
|
+
static flags = {
|
|
34
|
+
...BaseCommand.baseFlags,
|
|
35
|
+
output: Flags.string({
|
|
36
|
+
char: 'o',
|
|
37
|
+
default: 'summary',
|
|
38
|
+
description: 'Output format',
|
|
39
|
+
options: ['summary', 'json'],
|
|
40
|
+
required: false,
|
|
41
|
+
}),
|
|
42
|
+
workspace: Flags.integer({
|
|
43
|
+
char: 'w',
|
|
44
|
+
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
45
|
+
required: false,
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
async run() {
|
|
49
|
+
const { args, flags } = await this.parse(BranchGet);
|
|
50
|
+
// Get profile name (default or from flag/env)
|
|
51
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
52
|
+
// Load credentials
|
|
53
|
+
const credentials = this.loadCredentials();
|
|
54
|
+
// Get the profile configuration
|
|
55
|
+
if (!(profileName in credentials.profiles)) {
|
|
56
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
57
|
+
`Create a profile using 'xano profile create'`);
|
|
58
|
+
}
|
|
59
|
+
const profile = credentials.profiles[profileName];
|
|
60
|
+
// Validate required fields
|
|
61
|
+
if (!profile.instance_origin) {
|
|
62
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
63
|
+
}
|
|
64
|
+
if (!profile.access_token) {
|
|
65
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
66
|
+
}
|
|
67
|
+
// Get workspace ID from flag or profile
|
|
68
|
+
const workspaceId = flags.workspace || profile.workspace;
|
|
69
|
+
if (!workspaceId) {
|
|
70
|
+
this.error('No workspace ID provided. Either use --workspace flag or set one in your profile.\n' +
|
|
71
|
+
'Usage: xano branch get <branch_label> --workspace <workspace_id>');
|
|
72
|
+
}
|
|
73
|
+
const branchLabel = args.branch_label;
|
|
74
|
+
// Construct the API URL
|
|
75
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch/${encodeURIComponent(branchLabel)}`;
|
|
76
|
+
// Fetch branch from the API
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetch(apiUrl, {
|
|
79
|
+
headers: {
|
|
80
|
+
'accept': 'application/json',
|
|
81
|
+
'Authorization': `Bearer ${profile.access_token}`,
|
|
82
|
+
},
|
|
83
|
+
method: 'GET',
|
|
84
|
+
});
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
const errorText = await response.text();
|
|
87
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
88
|
+
}
|
|
89
|
+
const branch = await response.json();
|
|
90
|
+
// Output results
|
|
91
|
+
if (flags.output === 'json') {
|
|
92
|
+
this.log(JSON.stringify(branch, null, 2));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// summary format
|
|
96
|
+
const liveIndicator = branch.live ? ' (live)' : '';
|
|
97
|
+
const backupIndicator = branch.backup ? ' (backup)' : '';
|
|
98
|
+
this.log(`Branch: ${branch.label}${liveIndicator}${backupIndicator}`);
|
|
99
|
+
if (branch.created_at) {
|
|
100
|
+
const createdDate = branch.created_at.split('T')[0];
|
|
101
|
+
this.log(` Created: ${createdDate}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (error instanceof Error) {
|
|
107
|
+
this.error(`Failed to fetch branch: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.error(`Failed to fetch branch: ${String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
loadCredentials() {
|
|
115
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
116
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
117
|
+
// Check if credentials file exists
|
|
118
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
119
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
120
|
+
`Create a profile using 'xano profile create'`);
|
|
121
|
+
}
|
|
122
|
+
// Read credentials file
|
|
123
|
+
try {
|
|
124
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
125
|
+
const parsed = yaml.load(fileContent);
|
|
126
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
127
|
+
this.error('Credentials file has invalid format.');
|
|
128
|
+
}
|
|
129
|
+
return parsed;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import BaseCommand from '../../../base-command.js';
|
|
2
|
+
export default class BranchList extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
workspace_id: import("@oclif/core/interfaces").Arg<number | undefined, {
|
|
5
|
+
max?: number;
|
|
6
|
+
min?: number;
|
|
7
|
+
}>;
|
|
8
|
+
};
|
|
9
|
+
static description: string;
|
|
10
|
+
static examples: string[];
|
|
11
|
+
static flags: {
|
|
12
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<void>;
|
|
17
|
+
private loadCredentials;
|
|
18
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import BaseCommand from '../../../base-command.js';
|
|
7
|
+
export default class BranchList extends BaseCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
workspace_id: Args.integer({
|
|
10
|
+
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
11
|
+
required: false,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static description = 'List all branches in a workspace';
|
|
15
|
+
static examples = [
|
|
16
|
+
`$ xano branch list
|
|
17
|
+
Available branches:
|
|
18
|
+
- v1 (live)
|
|
19
|
+
- dev
|
|
20
|
+
- staging
|
|
21
|
+
`,
|
|
22
|
+
`$ xano branch list 123
|
|
23
|
+
Available branches:
|
|
24
|
+
- v1 (live)
|
|
25
|
+
- feature-auth
|
|
26
|
+
`,
|
|
27
|
+
`$ xano branch list --output json
|
|
28
|
+
[
|
|
29
|
+
{
|
|
30
|
+
"created_at": "2024-01-15T10:30:00Z",
|
|
31
|
+
"label": "v1",
|
|
32
|
+
"backup": false,
|
|
33
|
+
"live": true
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
`,
|
|
37
|
+
];
|
|
38
|
+
static flags = {
|
|
39
|
+
...BaseCommand.baseFlags,
|
|
40
|
+
output: Flags.string({
|
|
41
|
+
char: 'o',
|
|
42
|
+
default: 'summary',
|
|
43
|
+
description: 'Output format',
|
|
44
|
+
options: ['summary', 'json'],
|
|
45
|
+
required: false,
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
async run() {
|
|
49
|
+
const { args, flags } = await this.parse(BranchList);
|
|
50
|
+
// Get profile name (default or from flag/env)
|
|
51
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
52
|
+
// Load credentials
|
|
53
|
+
const credentials = this.loadCredentials();
|
|
54
|
+
// Get the profile configuration
|
|
55
|
+
if (!(profileName in credentials.profiles)) {
|
|
56
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
57
|
+
`Create a profile using 'xano profile create'`);
|
|
58
|
+
}
|
|
59
|
+
const profile = credentials.profiles[profileName];
|
|
60
|
+
// Validate required fields
|
|
61
|
+
if (!profile.instance_origin) {
|
|
62
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
63
|
+
}
|
|
64
|
+
if (!profile.access_token) {
|
|
65
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
66
|
+
}
|
|
67
|
+
// Get workspace ID from args or profile
|
|
68
|
+
const workspaceId = args.workspace_id || profile.workspace;
|
|
69
|
+
if (!workspaceId) {
|
|
70
|
+
this.error('No workspace ID provided. Either pass a workspace ID as an argument or set one in your profile.\n' +
|
|
71
|
+
'Usage: xano branch list [workspace_id]');
|
|
72
|
+
}
|
|
73
|
+
// Construct the API URL
|
|
74
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch`;
|
|
75
|
+
// Fetch branches from the API
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(apiUrl, {
|
|
78
|
+
headers: {
|
|
79
|
+
'accept': 'application/json',
|
|
80
|
+
'Authorization': `Bearer ${profile.access_token}`,
|
|
81
|
+
},
|
|
82
|
+
method: 'GET',
|
|
83
|
+
});
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
const errorText = await response.text();
|
|
86
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
87
|
+
}
|
|
88
|
+
const branches = await response.json();
|
|
89
|
+
// Output results
|
|
90
|
+
if (flags.output === 'json') {
|
|
91
|
+
this.log(JSON.stringify(branches, null, 2));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// summary format
|
|
95
|
+
if (branches.length === 0) {
|
|
96
|
+
this.log('No branches found');
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
this.log('Available branches:');
|
|
100
|
+
for (const branch of branches) {
|
|
101
|
+
const liveIndicator = branch.live ? ' (live)' : '';
|
|
102
|
+
const backupIndicator = branch.backup ? ' (backup)' : '';
|
|
103
|
+
this.log(` - ${branch.label}${liveIndicator}${backupIndicator}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (error instanceof Error) {
|
|
110
|
+
this.error(`Failed to fetch branches: ${error.message}`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
this.error(`Failed to fetch branches: ${String(error)}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
loadCredentials() {
|
|
118
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
119
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
120
|
+
// Check if credentials file exists
|
|
121
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
122
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
123
|
+
`Create a profile using 'xano profile create'`);
|
|
124
|
+
}
|
|
125
|
+
// Read credentials file
|
|
126
|
+
try {
|
|
127
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
128
|
+
const parsed = yaml.load(fileContent);
|
|
129
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
130
|
+
this.error('Credentials file has invalid format.');
|
|
131
|
+
}
|
|
132
|
+
return parsed;
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import BaseCommand from '../../../base-command.js';
|
|
2
|
+
export default class BranchSetLive extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
branch_label: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
private confirm;
|
|
17
|
+
private loadCredentials;
|
|
18
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import BaseCommand from '../../../base-command.js';
|
|
7
|
+
export default class BranchSetLive extends BaseCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
branch_label: Args.string({
|
|
10
|
+
description: 'Branch label to set as live (use "v1" for default branch)',
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static description = 'Set a branch as the live (active) branch for API requests';
|
|
15
|
+
static examples = [
|
|
16
|
+
`$ xano branch set-live staging
|
|
17
|
+
Are you sure you want to set 'staging' as the live branch? (y/N) y
|
|
18
|
+
Branch 'staging' is now live
|
|
19
|
+
`,
|
|
20
|
+
`$ xano branch set-live v1 --force
|
|
21
|
+
Branch 'v1' is now live
|
|
22
|
+
`,
|
|
23
|
+
`$ xano branch set-live production -f -o json
|
|
24
|
+
{
|
|
25
|
+
"created_at": "2024-02-10T09:15:00Z",
|
|
26
|
+
"label": "production",
|
|
27
|
+
"backup": false,
|
|
28
|
+
"live": true
|
|
29
|
+
}
|
|
30
|
+
`,
|
|
31
|
+
];
|
|
32
|
+
static flags = {
|
|
33
|
+
...BaseCommand.baseFlags,
|
|
34
|
+
force: Flags.boolean({
|
|
35
|
+
char: 'f',
|
|
36
|
+
default: false,
|
|
37
|
+
description: 'Skip confirmation prompt',
|
|
38
|
+
required: false,
|
|
39
|
+
}),
|
|
40
|
+
output: Flags.string({
|
|
41
|
+
char: 'o',
|
|
42
|
+
default: 'summary',
|
|
43
|
+
description: 'Output format',
|
|
44
|
+
options: ['summary', 'json'],
|
|
45
|
+
required: false,
|
|
46
|
+
}),
|
|
47
|
+
workspace: Flags.integer({
|
|
48
|
+
char: 'w',
|
|
49
|
+
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
50
|
+
required: false,
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
async run() {
|
|
54
|
+
const { args, flags } = await this.parse(BranchSetLive);
|
|
55
|
+
// Get profile name (default or from flag/env)
|
|
56
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
57
|
+
// Load credentials
|
|
58
|
+
const credentials = this.loadCredentials();
|
|
59
|
+
// Get the profile configuration
|
|
60
|
+
if (!(profileName in credentials.profiles)) {
|
|
61
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
62
|
+
`Create a profile using 'xano profile create'`);
|
|
63
|
+
}
|
|
64
|
+
const profile = credentials.profiles[profileName];
|
|
65
|
+
// Validate required fields
|
|
66
|
+
if (!profile.instance_origin) {
|
|
67
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
68
|
+
}
|
|
69
|
+
if (!profile.access_token) {
|
|
70
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
71
|
+
}
|
|
72
|
+
// Get workspace ID from flag or profile
|
|
73
|
+
const workspaceId = flags.workspace || profile.workspace;
|
|
74
|
+
if (!workspaceId) {
|
|
75
|
+
this.error('No workspace ID provided. Either use --workspace flag or set one in your profile.\n' +
|
|
76
|
+
'Usage: xano branch set-live <branch_label> [--workspace <workspace_id>]');
|
|
77
|
+
}
|
|
78
|
+
const branchLabel = args.branch_label;
|
|
79
|
+
// Confirmation prompt unless --force is used
|
|
80
|
+
if (!flags.force) {
|
|
81
|
+
const confirmed = await this.confirm(`Are you sure you want to set '${branchLabel}' as the live branch?`);
|
|
82
|
+
if (!confirmed) {
|
|
83
|
+
this.log('Operation cancelled.');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Construct the API URL
|
|
88
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch/${encodeURIComponent(branchLabel)}/live`;
|
|
89
|
+
// Set branch as live via the API
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(apiUrl, {
|
|
92
|
+
headers: {
|
|
93
|
+
'accept': 'application/json',
|
|
94
|
+
'Authorization': `Bearer ${profile.access_token}`,
|
|
95
|
+
},
|
|
96
|
+
method: 'POST',
|
|
97
|
+
});
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const errorText = await response.text();
|
|
100
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
101
|
+
}
|
|
102
|
+
const branch = await response.json();
|
|
103
|
+
// Output results
|
|
104
|
+
if (flags.output === 'json') {
|
|
105
|
+
this.log(JSON.stringify(branch, null, 2));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this.log(`Branch '${branch.label}' is now live`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error instanceof Error) {
|
|
113
|
+
this.error(`Failed to set branch as live: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.error(`Failed to set branch as live: ${String(error)}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async confirm(message) {
|
|
121
|
+
// Use readline for simple yes/no confirmation
|
|
122
|
+
const readline = await import('node:readline');
|
|
123
|
+
const rl = readline.createInterface({
|
|
124
|
+
input: process.stdin,
|
|
125
|
+
output: process.stdout,
|
|
126
|
+
});
|
|
127
|
+
return new Promise((resolve) => {
|
|
128
|
+
rl.question(`${message} (y/N) `, (answer) => {
|
|
129
|
+
rl.close();
|
|
130
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
loadCredentials() {
|
|
135
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
136
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
137
|
+
// Check if credentials file exists
|
|
138
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
139
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
140
|
+
`Create a profile using 'xano profile create'`);
|
|
141
|
+
}
|
|
142
|
+
// Read credentials file
|
|
143
|
+
try {
|
|
144
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
145
|
+
const parsed = yaml.load(fileContent);
|
|
146
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
147
|
+
this.error('Credentials file has invalid format.');
|
|
148
|
+
}
|
|
149
|
+
return parsed;
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import BaseCommand from '../../../base-command.js';
|
|
2
2
|
export default class FunctionCreate extends BaseCommand {
|
|
3
3
|
static args: {};
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
4
6
|
static flags: {
|
|
5
|
-
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
-
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
-
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
7
|
edit: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
12
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
13
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
14
|
};
|
|
13
|
-
static description: string;
|
|
14
|
-
static examples: string[];
|
|
15
15
|
run(): Promise<void>;
|
|
16
16
|
private editFile;
|
|
17
|
-
private readStdin;
|
|
18
17
|
private loadCredentials;
|
|
18
|
+
private readStdin;
|
|
19
19
|
}
|
|
@@ -1,47 +1,12 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
2
3
|
import { execSync } from 'node:child_process';
|
|
3
4
|
import * as fs from 'node:fs';
|
|
4
5
|
import * as os from 'node:os';
|
|
5
6
|
import * as path from 'node:path';
|
|
6
|
-
import * as yaml from 'js-yaml';
|
|
7
7
|
import BaseCommand from '../../../base-command.js';
|
|
8
8
|
export default class FunctionCreate extends BaseCommand {
|
|
9
9
|
static args = {};
|
|
10
|
-
static flags = {
|
|
11
|
-
...BaseCommand.baseFlags,
|
|
12
|
-
workspace: Flags.string({
|
|
13
|
-
char: 'w',
|
|
14
|
-
description: 'Workspace ID (optional if set in profile)',
|
|
15
|
-
required: false,
|
|
16
|
-
}),
|
|
17
|
-
file: Flags.string({
|
|
18
|
-
char: 'f',
|
|
19
|
-
description: 'Path to file containing XanoScript code',
|
|
20
|
-
required: false,
|
|
21
|
-
exclusive: ['stdin'],
|
|
22
|
-
}),
|
|
23
|
-
stdin: Flags.boolean({
|
|
24
|
-
char: 's',
|
|
25
|
-
description: 'Read XanoScript code from stdin',
|
|
26
|
-
required: false,
|
|
27
|
-
default: false,
|
|
28
|
-
exclusive: ['file'],
|
|
29
|
-
}),
|
|
30
|
-
edit: Flags.boolean({
|
|
31
|
-
char: 'e',
|
|
32
|
-
description: 'Open file in editor before creating function (requires --file)',
|
|
33
|
-
required: false,
|
|
34
|
-
default: false,
|
|
35
|
-
dependsOn: ['file'],
|
|
36
|
-
}),
|
|
37
|
-
output: Flags.string({
|
|
38
|
-
char: 'o',
|
|
39
|
-
description: 'Output format',
|
|
40
|
-
required: false,
|
|
41
|
-
default: 'summary',
|
|
42
|
-
options: ['summary', 'json'],
|
|
43
|
-
}),
|
|
44
|
-
};
|
|
45
10
|
static description = 'Create a new function in a workspace';
|
|
46
11
|
static examples = [
|
|
47
12
|
`$ xano function:create -w 40 -f function.xs
|
|
@@ -73,6 +38,41 @@ Name: my_function
|
|
|
73
38
|
}
|
|
74
39
|
`,
|
|
75
40
|
];
|
|
41
|
+
static flags = {
|
|
42
|
+
...BaseCommand.baseFlags,
|
|
43
|
+
edit: Flags.boolean({
|
|
44
|
+
char: 'e',
|
|
45
|
+
default: false,
|
|
46
|
+
dependsOn: ['file'],
|
|
47
|
+
description: 'Open file in editor before creating function (requires --file)',
|
|
48
|
+
required: false,
|
|
49
|
+
}),
|
|
50
|
+
file: Flags.string({
|
|
51
|
+
char: 'f',
|
|
52
|
+
description: 'Path to file containing XanoScript code',
|
|
53
|
+
exclusive: ['stdin'],
|
|
54
|
+
required: false,
|
|
55
|
+
}),
|
|
56
|
+
output: Flags.string({
|
|
57
|
+
char: 'o',
|
|
58
|
+
default: 'summary',
|
|
59
|
+
description: 'Output format',
|
|
60
|
+
options: ['summary', 'json'],
|
|
61
|
+
required: false,
|
|
62
|
+
}),
|
|
63
|
+
stdin: Flags.boolean({
|
|
64
|
+
char: 's',
|
|
65
|
+
default: false,
|
|
66
|
+
description: 'Read XanoScript code from stdin',
|
|
67
|
+
exclusive: ['file'],
|
|
68
|
+
required: false,
|
|
69
|
+
}),
|
|
70
|
+
workspace: Flags.string({
|
|
71
|
+
char: 'w',
|
|
72
|
+
description: 'Workspace ID (optional if set in profile)',
|
|
73
|
+
required: false,
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
76
|
async run() {
|
|
77
77
|
const { flags } = await this.parse(FunctionCreate);
|
|
78
78
|
// Get profile name (default or from flag/env)
|
|
@@ -154,13 +154,13 @@ Name: my_function
|
|
|
154
154
|
// Create function via API
|
|
155
155
|
try {
|
|
156
156
|
const response = await fetch(apiUrl, {
|
|
157
|
-
|
|
157
|
+
body: xanoscript,
|
|
158
158
|
headers: {
|
|
159
159
|
'accept': 'application/json',
|
|
160
|
-
'Content-Type': 'text/x-xanoscript',
|
|
161
160
|
'Authorization': `Bearer ${profile.access_token}`,
|
|
161
|
+
'Content-Type': 'text/x-xanoscript',
|
|
162
162
|
},
|
|
163
|
-
|
|
163
|
+
method: 'POST',
|
|
164
164
|
});
|
|
165
165
|
if (!response.ok) {
|
|
166
166
|
const errorText = await response.text();
|
|
@@ -240,22 +240,6 @@ Name: my_function
|
|
|
240
240
|
}
|
|
241
241
|
return tmpFile;
|
|
242
242
|
}
|
|
243
|
-
async readStdin() {
|
|
244
|
-
return new Promise((resolve, reject) => {
|
|
245
|
-
const chunks = [];
|
|
246
|
-
process.stdin.on('data', (chunk) => {
|
|
247
|
-
chunks.push(chunk);
|
|
248
|
-
});
|
|
249
|
-
process.stdin.on('end', () => {
|
|
250
|
-
resolve(Buffer.concat(chunks).toString('utf8'));
|
|
251
|
-
});
|
|
252
|
-
process.stdin.on('error', (error) => {
|
|
253
|
-
reject(error);
|
|
254
|
-
});
|
|
255
|
-
// Resume stdin if it was paused
|
|
256
|
-
process.stdin.resume();
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
243
|
loadCredentials() {
|
|
260
244
|
const configDir = path.join(os.homedir(), '.xano');
|
|
261
245
|
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
@@ -277,4 +261,20 @@ Name: my_function
|
|
|
277
261
|
this.error(`Failed to parse credentials file: ${error}`);
|
|
278
262
|
}
|
|
279
263
|
}
|
|
264
|
+
async readStdin() {
|
|
265
|
+
return new Promise((resolve, reject) => {
|
|
266
|
+
const chunks = [];
|
|
267
|
+
process.stdin.on('data', (chunk) => {
|
|
268
|
+
chunks.push(chunk);
|
|
269
|
+
});
|
|
270
|
+
process.stdin.on('end', () => {
|
|
271
|
+
resolve(Buffer.concat(chunks).toString('utf8'));
|
|
272
|
+
});
|
|
273
|
+
process.stdin.on('error', (error) => {
|
|
274
|
+
reject(error);
|
|
275
|
+
});
|
|
276
|
+
// Resume stdin if it was paused
|
|
277
|
+
process.stdin.resume();
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
280
|
}
|
|
@@ -3,23 +3,23 @@ export default class FunctionEdit extends BaseCommand {
|
|
|
3
3
|
static args: {
|
|
4
4
|
function_id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
5
|
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
6
8
|
static flags: {
|
|
7
|
-
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
9
|
edit: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
-
|
|
10
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
11
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
publish: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
15
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
16
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
17
|
};
|
|
16
|
-
static description: string;
|
|
17
|
-
static examples: string[];
|
|
18
18
|
run(): Promise<void>;
|
|
19
|
-
private fetchFunctionCode;
|
|
20
|
-
private editFunctionContent;
|
|
21
19
|
private editFile;
|
|
22
|
-
private
|
|
23
|
-
private
|
|
20
|
+
private editFunctionContent;
|
|
21
|
+
private fetchFunctionCode;
|
|
24
22
|
private loadCredentials;
|
|
23
|
+
private promptForFunctionId;
|
|
24
|
+
private readStdin;
|
|
25
25
|
}
|