@xano/cli 0.0.95-beta.16 → 0.0.95-beta.19
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
CHANGED
|
@@ -145,6 +145,8 @@ xano workspace git pull ./output -r https://github.com/owner/repo --path subdir
|
|
|
145
145
|
|
|
146
146
|
All branch commands use **branch labels** (e.g., `v1`, `dev`), not IDs.
|
|
147
147
|
|
|
148
|
+
The `v1` branch is the default branch and always exists. It cannot be created, edited, or deleted.
|
|
149
|
+
|
|
148
150
|
```bash
|
|
149
151
|
# List branches
|
|
150
152
|
xano branch list
|
|
@@ -153,9 +155,9 @@ xano branch list
|
|
|
153
155
|
xano branch get <branch_label>
|
|
154
156
|
|
|
155
157
|
# Create a branch
|
|
156
|
-
xano branch create
|
|
157
|
-
xano branch create
|
|
158
|
-
xano branch create
|
|
158
|
+
xano branch create dev
|
|
159
|
+
xano branch create feature-auth -s dev -d "Auth feature"
|
|
160
|
+
xano branch create staging --color "#ebc346"
|
|
159
161
|
|
|
160
162
|
# Edit a branch
|
|
161
163
|
xano branch edit <branch_label> --label "new-label"
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import BaseCommand from '../../../base-command.js';
|
|
2
2
|
export default class BranchCreate extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
label: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
4
7
|
static examples: string[];
|
|
5
8
|
static flags: {
|
|
6
9
|
color: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
10
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
label: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
11
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
12
|
source: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
13
|
workspace: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import * as yaml from 'js-yaml';
|
|
3
3
|
import * as fs from 'node:fs';
|
|
4
4
|
import * as os from 'node:os';
|
|
@@ -6,17 +6,23 @@ import * as path from 'node:path';
|
|
|
6
6
|
import BaseCommand from '../../../base-command.js';
|
|
7
7
|
export default class BranchCreate extends BaseCommand {
|
|
8
8
|
static description = 'Create a new branch by cloning from an existing branch';
|
|
9
|
+
static args = {
|
|
10
|
+
label: Args.string({
|
|
11
|
+
description: 'Label for the new branch',
|
|
12
|
+
required: true,
|
|
13
|
+
}),
|
|
14
|
+
};
|
|
9
15
|
static examples = [
|
|
10
|
-
`$ xano branch create
|
|
16
|
+
`$ xano branch create dev
|
|
11
17
|
Created branch: dev
|
|
12
18
|
Cloned from: v1
|
|
13
19
|
`,
|
|
14
|
-
`$ xano branch create
|
|
20
|
+
`$ xano branch create feature-auth -s dev -d "Authentication feature"
|
|
15
21
|
Created branch: feature-auth
|
|
16
22
|
Cloned from: dev
|
|
17
23
|
Description: Authentication feature
|
|
18
24
|
`,
|
|
19
|
-
`$ xano branch create
|
|
25
|
+
`$ xano branch create staging --color "#ebc346" --output json
|
|
20
26
|
{
|
|
21
27
|
"created_at": "2024-02-11T10:00:00Z",
|
|
22
28
|
"label": "staging",
|
|
@@ -37,11 +43,6 @@ Created branch: feature-auth
|
|
|
37
43
|
description: 'Description for the new branch',
|
|
38
44
|
required: false,
|
|
39
45
|
}),
|
|
40
|
-
label: Flags.string({
|
|
41
|
-
char: 'l',
|
|
42
|
-
description: 'Label for the new branch',
|
|
43
|
-
required: true,
|
|
44
|
-
}),
|
|
45
46
|
output: Flags.string({
|
|
46
47
|
char: 'o',
|
|
47
48
|
default: 'summary',
|
|
@@ -62,7 +63,7 @@ Created branch: feature-auth
|
|
|
62
63
|
}),
|
|
63
64
|
};
|
|
64
65
|
async run() {
|
|
65
|
-
const { flags } = await this.parse(BranchCreate);
|
|
66
|
+
const { args, flags } = await this.parse(BranchCreate);
|
|
66
67
|
// Get profile name (default or from flag/env)
|
|
67
68
|
const profileName = flags.profile || this.getDefaultProfile();
|
|
68
69
|
// Load credentials
|
|
@@ -84,11 +85,15 @@ Created branch: feature-auth
|
|
|
84
85
|
const workspaceId = flags.workspace || profile.workspace;
|
|
85
86
|
if (!workspaceId) {
|
|
86
87
|
this.error('No workspace ID provided. Either use --workspace flag or set one in your profile.\n' +
|
|
87
|
-
'Usage: xano branch create
|
|
88
|
+
'Usage: xano branch create <label> [--workspace <workspace_id>]');
|
|
89
|
+
}
|
|
90
|
+
// Validate reserved branch names
|
|
91
|
+
if (args.label.toLowerCase() === 'v1') {
|
|
92
|
+
this.error("Cannot create a branch named 'v1'. This is the default branch and always exists.");
|
|
88
93
|
}
|
|
89
94
|
// Build request body
|
|
90
95
|
const body = {
|
|
91
|
-
label:
|
|
96
|
+
label: args.label,
|
|
92
97
|
source_branch: flags.source,
|
|
93
98
|
};
|
|
94
99
|
if (flags.description) {
|
|
@@ -104,8 +109,8 @@ Created branch: feature-auth
|
|
|
104
109
|
const response = await this.verboseFetch(apiUrl, {
|
|
105
110
|
body: JSON.stringify(body),
|
|
106
111
|
headers: {
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
accept: 'application/json',
|
|
113
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
109
114
|
'Content-Type': 'application/json',
|
|
110
115
|
},
|
|
111
116
|
method: 'POST',
|
|
@@ -114,7 +119,7 @@ Created branch: feature-auth
|
|
|
114
119
|
const errorText = await response.text();
|
|
115
120
|
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
116
121
|
}
|
|
117
|
-
const branch = await response.json();
|
|
122
|
+
const branch = (await response.json());
|
|
118
123
|
// Output results
|
|
119
124
|
if (flags.output === 'json') {
|
|
120
125
|
this.log(JSON.stringify(branch, null, 2));
|
|
@@ -145,8 +150,7 @@ Created branch: feature-auth
|
|
|
145
150
|
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
146
151
|
// Check if credentials file exists
|
|
147
152
|
if (!fs.existsSync(credentialsPath)) {
|
|
148
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
149
|
-
`Create a profile using 'xano profile create'`);
|
|
153
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
|
|
150
154
|
}
|
|
151
155
|
// Read credentials file
|
|
152
156
|
try {
|
|
@@ -159,8 +159,7 @@ Pushed 42 documents to sandbox environment from ./my-workspace
|
|
|
159
159
|
this.log('');
|
|
160
160
|
this.log(ux.colorize('red', ux.colorize('bold', '=== CRITICAL: Invalid Indexes ===')));
|
|
161
161
|
this.log('');
|
|
162
|
-
this.log(ux.colorize('red', 'The following tables have
|
|
163
|
-
this.log(ux.colorize('red', 'These will cause the import to fail.'));
|
|
162
|
+
this.log(ux.colorize('red', 'The following tables have indexed referencing fields that do not exist in the schema, which may cause related issues.'));
|
|
164
163
|
this.log('');
|
|
165
164
|
for (const idx of badIndexes) {
|
|
166
165
|
this.log(` ${ux.colorize('red', 'CRITICAL'.padEnd(16))} ${'table'.padEnd(18)} ${idx.table}`);
|
|
@@ -288,13 +288,16 @@ Push functions but exclude test files
|
|
|
288
288
|
const errorJson = JSON.parse(errorText);
|
|
289
289
|
if (errorJson.message?.includes('Push is disabled')) {
|
|
290
290
|
this.log('');
|
|
291
|
-
this.log(ux.colorize('red', ux.colorize('bold', 'Direct push to
|
|
291
|
+
this.log(ux.colorize('red', ux.colorize('bold', 'Direct push is disabled to protect your production workspace from unintended changes.')));
|
|
292
|
+
this.log(ux.colorize('dim', 'Use your sandbox environment to test and review changes before applying them to your production workspace.'));
|
|
293
|
+
this.log('');
|
|
292
294
|
this.log(ux.colorize('dim', 'To apply changes to the workspace, use the sandbox review flow:'));
|
|
293
295
|
this.log(` ${ux.colorize('cyan', 'xano sandbox push')} ${ux.colorize('dim', '— push changes to your sandbox')}`);
|
|
294
296
|
this.log(` ${ux.colorize('cyan', 'xano sandbox review')} ${ux.colorize('dim', '— edit any logic, inspect the snapshot diff, and promote changes to the workspace')}`);
|
|
295
297
|
this.log('');
|
|
296
298
|
this.log(ux.colorize('dim', 'To enable direct push, go to Workspace Settings → CLI → Allow Direct Workspace Push.'));
|
|
297
|
-
this.log(
|
|
299
|
+
this.log('');
|
|
300
|
+
this.log(ux.colorize('dim', "Note: Free plan instances don't include sandbox environments, so direct push is always enabled."));
|
|
298
301
|
this.log('');
|
|
299
302
|
return;
|
|
300
303
|
}
|
|
@@ -505,12 +508,13 @@ Push functions but exclude test files
|
|
|
505
508
|
}
|
|
506
509
|
// Provide clear guidance when push is disabled
|
|
507
510
|
if (errorJson.message?.includes('Push is disabled')) {
|
|
508
|
-
this.error(`
|
|
509
|
-
`
|
|
510
|
-
`Note: This setting does not apply to Free plan instances.\n\n` +
|
|
511
|
+
this.error(`Direct push is disabled to protect your production workspace from unintended changes.\n` +
|
|
512
|
+
`Use your sandbox environment to test and review changes before applying them to your production workspace.\n\n` +
|
|
511
513
|
`Alternatively, use sandbox commands:\n` +
|
|
512
514
|
` xano sandbox push ${args.directory}\n` +
|
|
513
|
-
` xano sandbox
|
|
515
|
+
` xano sandbox review\n\n` +
|
|
516
|
+
`To enable direct push, go to Workspace Settings → CLI → Allow Direct Workspace Push.\n\n` +
|
|
517
|
+
`Note: Free plan instances don't include sandbox environments, so direct push is always enabled.`);
|
|
514
518
|
}
|
|
515
519
|
}
|
|
516
520
|
catch {
|
|
@@ -760,8 +764,7 @@ Push functions but exclude test files
|
|
|
760
764
|
this.log('');
|
|
761
765
|
this.log(ux.colorize('red', ux.colorize('bold', '=== CRITICAL: Invalid Indexes ===')));
|
|
762
766
|
this.log('');
|
|
763
|
-
this.log(ux.colorize('red', 'The following tables have
|
|
764
|
-
this.log(ux.colorize('red', 'These will cause the import to fail.'));
|
|
767
|
+
this.log(ux.colorize('red', 'The following tables have indexed referencing fields that do not exist in the schema, which may cause related issues.'));
|
|
765
768
|
this.log('');
|
|
766
769
|
for (const idx of badIndexes) {
|
|
767
770
|
this.log(` ${ux.colorize('red', 'CRITICAL'.padEnd(16))} ${'table'.padEnd(18)} ${idx.table}`);
|