@xano/cli 1.0.4-beta.4 → 1.0.4-beta.5
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 +3 -0
- package/dist/commands/static_host/build/push/index.d.ts +1 -1
- package/dist/commands/static_host/build/push/index.js +20 -17
- package/dist/utils/static-host-files.d.ts +21 -0
- package/dist/utils/static-host-files.js +41 -0
- package/oclif.manifest.json +1187 -1179
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -577,11 +577,14 @@ xano static_host build pull default --env prod -d ./prod-release
|
|
|
577
577
|
|
|
578
578
|
# Push a build (name optional — auto-generated from the timestamp if omitted).
|
|
579
579
|
# Accepts a directory (-d) or a zip file (-f). Defaults to the current directory.
|
|
580
|
+
# When pushing a directory, files matched by its .gitignore are skipped by default
|
|
581
|
+
# (the .git/ folder is always excluded); use --no-gitignore to push everything.
|
|
580
582
|
# For package.json builds, the CLI waits for the build to finish (--no-wait to skip).
|
|
581
583
|
xano static_host build push default -d ./dist -n "v1.0.0"
|
|
582
584
|
xano static_host build push default # current dir, auto-name
|
|
583
585
|
xano static_host build push default -f ./build.zip -n "v1.0.0" # from zip file
|
|
584
586
|
xano static_host build push default -n "release" --description "Production build"
|
|
587
|
+
xano static_host build push default -d ./static --no-gitignore # push gitignored files too
|
|
585
588
|
|
|
586
589
|
# Delete a build (prompts for confirmation; --force to skip)
|
|
587
590
|
xano static_host build delete default --build_id 52
|
|
@@ -10,6 +10,7 @@ export default class StaticHostBuildPush extends BaseCommand {
|
|
|
10
10
|
directory: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
12
|
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
'no-gitignore': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
14
|
'no-wait': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
15
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
16
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -18,6 +19,5 @@ export default class StaticHostBuildPush extends BaseCommand {
|
|
|
18
19
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
19
20
|
};
|
|
20
21
|
run(): Promise<void>;
|
|
21
|
-
private countFiles;
|
|
22
22
|
private createZipBuffer;
|
|
23
23
|
}
|
|
@@ -3,6 +3,7 @@ import archiver from 'archiver';
|
|
|
3
3
|
import * as fs from 'node:fs';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import BaseCommand from '../../../../base-command.js';
|
|
6
|
+
import { collectStaticHostFiles } from '../../../../utils/static-host-files.js';
|
|
6
7
|
import { generateBuildName } from '../create/index.js';
|
|
7
8
|
export default class StaticHostBuildPush extends BaseCommand {
|
|
8
9
|
static args = {
|
|
@@ -27,6 +28,9 @@ ID: 124
|
|
|
27
28
|
`$ xano static_host build push myhost -n "production" --description "Production build" -w 40
|
|
28
29
|
Pushed 22 files as build "production"
|
|
29
30
|
ID: 125
|
|
31
|
+
`,
|
|
32
|
+
`$ xano static_host build push default -d ./static --no-gitignore
|
|
33
|
+
Pushed 30 files as build "20260531-143022"
|
|
30
34
|
`,
|
|
31
35
|
];
|
|
32
36
|
static flags = {
|
|
@@ -52,6 +56,11 @@ ID: 125
|
|
|
52
56
|
description: 'Build name (auto-generated from the current timestamp if omitted)',
|
|
53
57
|
required: false,
|
|
54
58
|
}),
|
|
59
|
+
'no-gitignore': Flags.boolean({
|
|
60
|
+
default: false,
|
|
61
|
+
description: 'Push every file in the directory, including those matched by .gitignore (the .git/ folder is always excluded)',
|
|
62
|
+
required: false,
|
|
63
|
+
}),
|
|
55
64
|
'no-wait': Flags.boolean({
|
|
56
65
|
default: false,
|
|
57
66
|
description: 'Return immediately after upload instead of waiting for the build to finish',
|
|
@@ -113,10 +122,15 @@ ID: 125
|
|
|
113
122
|
if (!dirStats.isDirectory()) {
|
|
114
123
|
this.error(`Path is not a directory: ${sourceDir}`);
|
|
115
124
|
}
|
|
116
|
-
|
|
125
|
+
const files = collectStaticHostFiles(sourceDir, { respectGitignore: !flags['no-gitignore'] });
|
|
126
|
+
if (files.length === 0) {
|
|
127
|
+
this.error(`No files to push from ${sourceDir} — everything is excluded by .gitignore. ` +
|
|
128
|
+
`Use --no-gitignore to push the entire directory.`);
|
|
129
|
+
}
|
|
130
|
+
fileCount = files.length;
|
|
117
131
|
if (animate)
|
|
118
132
|
ux.action.start('Packaging', `${fileCount} files`);
|
|
119
|
-
zipBuffer = await this.createZipBuffer(sourceDir);
|
|
133
|
+
zipBuffer = await this.createZipBuffer(sourceDir, files);
|
|
120
134
|
if (animate) {
|
|
121
135
|
ux.action.stop(`${fileCount} files (${(zipBuffer.length / (1024 * 1024)).toFixed(1)} MB)`);
|
|
122
136
|
ux.action.start('Uploading');
|
|
@@ -192,20 +206,7 @@ ID: 125
|
|
|
192
206
|
}
|
|
193
207
|
}
|
|
194
208
|
}
|
|
195
|
-
|
|
196
|
-
let count = 0;
|
|
197
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
198
|
-
for (const entry of entries) {
|
|
199
|
-
if (entry.isDirectory()) {
|
|
200
|
-
count += this.countFiles(path.join(dir, entry.name));
|
|
201
|
-
}
|
|
202
|
-
else if (entry.isFile()) {
|
|
203
|
-
count++;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return count;
|
|
207
|
-
}
|
|
208
|
-
async createZipBuffer(sourceDir) {
|
|
209
|
+
async createZipBuffer(sourceDir, files) {
|
|
209
210
|
return new Promise((resolve, reject) => {
|
|
210
211
|
const chunks = [];
|
|
211
212
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
@@ -218,7 +219,9 @@ ID: 125
|
|
|
218
219
|
archive.on('error', (err) => {
|
|
219
220
|
reject(err);
|
|
220
221
|
});
|
|
221
|
-
|
|
222
|
+
for (const rel of files) {
|
|
223
|
+
archive.file(path.join(sourceDir, rel), { name: rel });
|
|
224
|
+
}
|
|
222
225
|
archive.finalize();
|
|
223
226
|
});
|
|
224
227
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface CollectStaticHostFilesOptions {
|
|
2
|
+
/**
|
|
3
|
+
* When true, skip files matched by the source directory's `.gitignore`.
|
|
4
|
+
* The `.git/` folder is always excluded regardless of this setting.
|
|
5
|
+
*/
|
|
6
|
+
respectGitignore: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Collect the files to upload for a static-host build, as POSIX-relative paths
|
|
10
|
+
* (sorted, for a deterministic archive).
|
|
11
|
+
*
|
|
12
|
+
* Honours the `.gitignore` at the root of `sourceDir` when `respectGitignore` is
|
|
13
|
+
* set, and always excludes the `.git/` directory — it is repo metadata, never
|
|
14
|
+
* deployable output.
|
|
15
|
+
*
|
|
16
|
+
* Directory rules in `.gitignore` carry a trailing slash (e.g. `node_modules/`),
|
|
17
|
+
* and the `ignore` package only matches those when the tested path also ends in a
|
|
18
|
+
* slash — so directories are tested as `${rel}/` (which also lets us prune the
|
|
19
|
+
* whole subtree) while files are tested as-is.
|
|
20
|
+
*/
|
|
21
|
+
export declare function collectStaticHostFiles(sourceDir: string, options: CollectStaticHostFilesOptions): string[];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import ignore from 'ignore';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { join, relative, sep } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Collect the files to upload for a static-host build, as POSIX-relative paths
|
|
6
|
+
* (sorted, for a deterministic archive).
|
|
7
|
+
*
|
|
8
|
+
* Honours the `.gitignore` at the root of `sourceDir` when `respectGitignore` is
|
|
9
|
+
* set, and always excludes the `.git/` directory — it is repo metadata, never
|
|
10
|
+
* deployable output.
|
|
11
|
+
*
|
|
12
|
+
* Directory rules in `.gitignore` carry a trailing slash (e.g. `node_modules/`),
|
|
13
|
+
* and the `ignore` package only matches those when the tested path also ends in a
|
|
14
|
+
* slash — so directories are tested as `${rel}/` (which also lets us prune the
|
|
15
|
+
* whole subtree) while files are tested as-is.
|
|
16
|
+
*/
|
|
17
|
+
export function collectStaticHostFiles(sourceDir, options) {
|
|
18
|
+
const ig = ignore().add('.git');
|
|
19
|
+
if (options.respectGitignore) {
|
|
20
|
+
const gitignorePath = join(sourceDir, '.gitignore');
|
|
21
|
+
if (fs.existsSync(gitignorePath)) {
|
|
22
|
+
ig.add(fs.readFileSync(gitignorePath, 'utf8'));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const files = [];
|
|
26
|
+
const walk = (dir) => {
|
|
27
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
28
|
+
const abs = join(dir, entry.name);
|
|
29
|
+
const rel = relative(sourceDir, abs).split(sep).join('/');
|
|
30
|
+
if (entry.isDirectory()) {
|
|
31
|
+
if (!ig.ignores(`${rel}/`))
|
|
32
|
+
walk(abs);
|
|
33
|
+
}
|
|
34
|
+
else if (entry.isFile() && !ig.ignores(rel)) {
|
|
35
|
+
files.push(rel);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
walk(sourceDir);
|
|
40
|
+
return files.sort();
|
|
41
|
+
}
|