@xano/cli 0.0.88 → 0.0.90
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.
|
@@ -16,6 +16,8 @@ export default class Push extends BaseCommand {
|
|
|
16
16
|
transaction: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
17
|
truncate: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
18
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
exclude: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
filter: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
21
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
20
22
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
23
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Args, Flags, ux } from '@oclif/core';
|
|
2
2
|
import * as yaml from 'js-yaml';
|
|
3
|
+
import { minimatch } from 'minimatch';
|
|
3
4
|
import * as fs from 'node:fs';
|
|
4
5
|
import * as os from 'node:os';
|
|
5
6
|
import * as path from 'node:path';
|
|
@@ -46,6 +47,18 @@ Push without overwriting environment variables
|
|
|
46
47
|
`,
|
|
47
48
|
`$ xano workspace push ./my-workspace --truncate
|
|
48
49
|
Truncate all table records before importing
|
|
50
|
+
`,
|
|
51
|
+
`$ xano workspace push ./my-workspace -f "**/func*"
|
|
52
|
+
Push only files matching the glob pattern
|
|
53
|
+
`,
|
|
54
|
+
`$ xano workspace push ./my-workspace -f "function/*" -f "table/*"
|
|
55
|
+
Push files matching multiple patterns
|
|
56
|
+
`,
|
|
57
|
+
`$ xano workspace push ./my-workspace -e "table/*"
|
|
58
|
+
Push all files except tables
|
|
59
|
+
`,
|
|
60
|
+
`$ xano workspace push ./my-workspace -f "function/*" -e "**/test*"
|
|
61
|
+
Push functions but exclude test files
|
|
49
62
|
`,
|
|
50
63
|
];
|
|
51
64
|
static flags = {
|
|
@@ -102,6 +115,18 @@ Truncate all table records before importing
|
|
|
102
115
|
description: 'Workspace ID (optional if set in profile)',
|
|
103
116
|
required: false,
|
|
104
117
|
}),
|
|
118
|
+
exclude: Flags.string({
|
|
119
|
+
char: 'e',
|
|
120
|
+
description: 'Glob pattern to exclude files (e.g. "table/*", "**/test*"). Matched against relative paths from the push directory.',
|
|
121
|
+
multiple: true,
|
|
122
|
+
required: false,
|
|
123
|
+
}),
|
|
124
|
+
filter: Flags.string({
|
|
125
|
+
char: 'f',
|
|
126
|
+
description: 'Glob pattern to filter files (e.g. "**/func*", "table/*.xs"). Matched against relative paths from the push directory.',
|
|
127
|
+
multiple: true,
|
|
128
|
+
required: false,
|
|
129
|
+
}),
|
|
105
130
|
force: Flags.boolean({
|
|
106
131
|
default: false,
|
|
107
132
|
description: 'Skip preview and confirmation prompt (for CI/CD pipelines)',
|
|
@@ -149,9 +174,33 @@ Truncate all table records before importing
|
|
|
149
174
|
this.error(`Not a directory: ${inputDir}`);
|
|
150
175
|
}
|
|
151
176
|
// Collect all .xs files from the directory tree
|
|
152
|
-
const
|
|
177
|
+
const allFiles = this.collectFiles(inputDir);
|
|
178
|
+
let files = allFiles;
|
|
179
|
+
// Apply glob filter(s) if specified
|
|
180
|
+
if (flags.filter && flags.filter.length > 0) {
|
|
181
|
+
files = files.filter((f) => {
|
|
182
|
+
const rel = path.relative(inputDir, f);
|
|
183
|
+
return flags.filter.some((pattern) => minimatch(rel, pattern, { matchBase: true }));
|
|
184
|
+
});
|
|
185
|
+
this.log('');
|
|
186
|
+
this.log(` ${ux.colorize('dim', 'Filter:')} ${flags.filter.map((p) => ux.colorize('cyan', p)).join(', ')}`);
|
|
187
|
+
this.log(` ${ux.colorize('dim', 'Matched:')} ${ux.colorize('bold', String(files.length))} of ${allFiles.length} files`);
|
|
188
|
+
}
|
|
189
|
+
// Apply glob exclude(s) if specified
|
|
190
|
+
if (flags.exclude && flags.exclude.length > 0) {
|
|
191
|
+
const beforeCount = files.length;
|
|
192
|
+
files = files.filter((f) => {
|
|
193
|
+
const rel = path.relative(inputDir, f);
|
|
194
|
+
return !flags.exclude.some((pattern) => minimatch(rel, pattern, { matchBase: true }));
|
|
195
|
+
});
|
|
196
|
+
this.log('');
|
|
197
|
+
this.log(` ${ux.colorize('dim', 'Exclude:')} ${flags.exclude.map((p) => ux.colorize('cyan', p)).join(', ')}`);
|
|
198
|
+
this.log(` ${ux.colorize('dim', 'Kept:')} ${ux.colorize('bold', String(files.length))} of ${beforeCount} files (excluded ${beforeCount - files.length})`);
|
|
199
|
+
}
|
|
153
200
|
if (files.length === 0) {
|
|
154
|
-
this.error(
|
|
201
|
+
this.error(flags.filter || flags.exclude
|
|
202
|
+
? `No .xs files remain after ${[flags.filter ? `filter ${flags.filter.join(', ')}` : '', flags.exclude ? `exclude ${flags.exclude.join(', ')}` : ''].filter(Boolean).join(' and ')} in ${args.directory}`
|
|
203
|
+
: `No .xs files found in ${args.directory}`);
|
|
155
204
|
}
|
|
156
205
|
// Read each file and track file path alongside content
|
|
157
206
|
const documentEntries = [];
|
|
@@ -385,7 +434,12 @@ Truncate all table records before importing
|
|
|
385
434
|
return true;
|
|
386
435
|
// For queries, operation name includes verb (e.g., "path/{id} DELETE")
|
|
387
436
|
const opName = parsed.verb ? `${parsed.name} ${parsed.verb}` : parsed.name;
|
|
388
|
-
|
|
437
|
+
if (changedKeys.has(`${parsed.type}:${opName}`))
|
|
438
|
+
return true;
|
|
439
|
+
// Keep table documents that contain records when --records is active
|
|
440
|
+
if (flags.records && parsed.type === 'table' && /\bitems\s*=\s*\[/m.test(entry.content))
|
|
441
|
+
return true;
|
|
442
|
+
return false;
|
|
389
443
|
});
|
|
390
444
|
if (filteredEntries.length === 0) {
|
|
391
445
|
this.log('No changes to push.');
|