zephyr-cli 0.0.2 → 0.1.3-next.6
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/.eslintignore +3 -0
- package/.eslintrc.json +22 -0
- package/LICENSE +40 -21
- package/README.md +91 -18
- package/dist/cli.d.ts +25 -0
- package/dist/cli.js +141 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/deploy.d.ts +12 -0
- package/dist/commands/deploy.js +60 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/run.d.ts +9 -0
- package/dist/commands/run.js +161 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/index.js +48 -60
- package/dist/index.js.map +1 -0
- package/dist/lib/build-stats.d.ts +7 -0
- package/dist/lib/build-stats.js +12 -0
- package/dist/lib/build-stats.js.map +1 -0
- package/dist/lib/command-detector.d.ts +38 -0
- package/dist/lib/command-detector.js +453 -0
- package/dist/lib/command-detector.js.map +1 -0
- package/dist/lib/config-readers.d.ts +37 -0
- package/dist/lib/config-readers.js +239 -0
- package/dist/lib/config-readers.js.map +1 -0
- package/dist/lib/extract-assets.d.ts +6 -0
- package/dist/lib/extract-assets.js +95 -0
- package/dist/lib/extract-assets.js.map +1 -0
- package/dist/lib/shell-parser.d.ts +40 -0
- package/dist/lib/shell-parser.js +190 -0
- package/dist/lib/shell-parser.js.map +1 -0
- package/dist/lib/spawn-helper.d.ts +14 -0
- package/dist/lib/spawn-helper.js +36 -0
- package/dist/lib/spawn-helper.js.map +1 -0
- package/dist/lib/upload.d.ts +14 -0
- package/dist/lib/upload.js +32 -0
- package/dist/lib/upload.js.map +1 -0
- package/dist/package.json +48 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/jest.config.ts +10 -0
- package/package.json +39 -22
- package/project.json +34 -0
- package/src/cli.ts +150 -0
- package/src/commands/deploy.ts +74 -0
- package/src/commands/run.ts +196 -0
- package/src/index.ts +58 -0
- package/src/lib/build-stats.ts +13 -0
- package/src/lib/command-detector.ts +600 -0
- package/src/lib/config-readers.ts +269 -0
- package/src/lib/extract-assets.ts +111 -0
- package/src/lib/shell-parser.ts +229 -0
- package/src/lib/spawn-helper.ts +49 -0
- package/src/lib/upload.ts +39 -0
- package/tsconfig.json +22 -0
- package/tsconfig.lib.json +10 -0
- package/tsconfig.spec.json +14 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeCommand = executeCommand;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
/**
|
|
6
|
+
* Execute a command with full stdio passthrough. All stdin, stdout, and stderr are
|
|
7
|
+
* proxied between the parent and child process.
|
|
8
|
+
*
|
|
9
|
+
* @param parsed - The parsed command to execute
|
|
10
|
+
* @param cwd - The working directory
|
|
11
|
+
* @returns Promise that resolves with exit code and signal
|
|
12
|
+
*/
|
|
13
|
+
async function executeCommand(parsed, cwd) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const { command, args, envVars } = parsed;
|
|
16
|
+
// Merge environment variables
|
|
17
|
+
const env = Object.assign(Object.assign({}, process.env), envVars);
|
|
18
|
+
// Spawn the command
|
|
19
|
+
const child = (0, node_child_process_1.spawn)(command, args, {
|
|
20
|
+
cwd,
|
|
21
|
+
env,
|
|
22
|
+
stdio: 'inherit', // This passes stdin, stdout, and stderr through
|
|
23
|
+
shell: true, // Use shell to handle complex commands
|
|
24
|
+
});
|
|
25
|
+
child.on('error', (error) => {
|
|
26
|
+
reject(error);
|
|
27
|
+
});
|
|
28
|
+
child.on('close', (code, signal) => {
|
|
29
|
+
resolve({
|
|
30
|
+
exitCode: code !== null && code !== void 0 ? code : 1,
|
|
31
|
+
signal,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=spawn-helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-helper.js","sourceRoot":"","sources":["../../src/lib/spawn-helper.ts"],"names":[],"mappings":";;AAgBA,wCAgCC;AAhDD,2DAA2C;AAQ3C;;;;;;;GAOG;AACI,KAAK,UAAU,cAAc,CAClC,MAAqB,EACrB,GAAW;IAEX,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAE1C,8BAA8B;QAC9B,MAAM,GAAG,mCACJ,OAAO,CAAC,GAAG,GACX,OAAO,CACX,CAAC;QAEF,oBAAoB;QACpB,MAAM,KAAK,GAAG,IAAA,0BAAK,EAAC,OAAO,EAAE,IAAI,EAAE;YACjC,GAAG;YACH,GAAG;YACH,KAAK,EAAE,SAAS,EAAE,gDAAgD;YAClE,KAAK,EAAE,IAAI,EAAE,uCAAuC;SACrD,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YACjC,OAAO,CAAC;gBACN,QAAQ,EAAE,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,CAAC;gBACnB,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ZeBuildAssetsMap } from 'zephyr-edge-contract';
|
|
2
|
+
import type { ZephyrEngine } from 'zephyr-agent';
|
|
3
|
+
export interface UploadOptions {
|
|
4
|
+
zephyr_engine: ZephyrEngine;
|
|
5
|
+
assetsMap: ZeBuildAssetsMap;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Orchestrate the upload process:
|
|
9
|
+
*
|
|
10
|
+
* 1. Start a new build
|
|
11
|
+
* 2. Upload assets with build stats
|
|
12
|
+
* 3. Finish the build
|
|
13
|
+
*/
|
|
14
|
+
export declare function uploadAssets(options: UploadOptions): Promise<void>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uploadAssets = uploadAssets;
|
|
4
|
+
const zephyr_agent_1 = require("zephyr-agent");
|
|
5
|
+
const build_stats_1 = require("./build-stats");
|
|
6
|
+
/**
|
|
7
|
+
* Orchestrate the upload process:
|
|
8
|
+
*
|
|
9
|
+
* 1. Start a new build
|
|
10
|
+
* 2. Upload assets with build stats
|
|
11
|
+
* 3. Finish the build
|
|
12
|
+
*/
|
|
13
|
+
async function uploadAssets(options) {
|
|
14
|
+
const { zephyr_engine, assetsMap } = options;
|
|
15
|
+
try {
|
|
16
|
+
// Start a new build
|
|
17
|
+
await zephyr_engine.start_new_build();
|
|
18
|
+
// Generate build stats
|
|
19
|
+
const buildStats = await (0, build_stats_1.getBuildStats)(zephyr_engine);
|
|
20
|
+
// Upload assets and finish the build
|
|
21
|
+
await zephyr_engine.upload_assets({
|
|
22
|
+
assetsMap,
|
|
23
|
+
buildStats,
|
|
24
|
+
});
|
|
25
|
+
await zephyr_engine.build_finished();
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
(0, zephyr_agent_1.logFn)('error', zephyr_agent_1.ZephyrError.format(error));
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/lib/upload.ts"],"names":[],"mappings":";;AAiBA,oCAqBC;AApCD,+CAAkD;AAClD,+CAA8C;AAO9C;;;;;;GAMG;AACI,KAAK,UAAU,YAAY,CAAC,OAAsB;IACvD,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE7C,IAAI,CAAC;QACH,oBAAoB;QACpB,MAAM,aAAa,CAAC,eAAe,EAAE,CAAC;QAEtC,uBAAuB;QACvB,MAAM,UAAU,GAAG,MAAM,IAAA,2BAAa,EAAC,aAAa,CAAC,CAAC;QAEtD,qCAAqC;QACrC,MAAM,aAAa,CAAC,aAAa,CAAC;YAChC,SAAS;YACT,UAAU;SACX,CAAC,CAAC;QAEH,MAAM,aAAa,CAAC,cAAc,EAAE,CAAC;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAA,oBAAK,EAAC,OAAO,EAAE,0BAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zephyr-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tool for running build commands and uploading assets to Zephyr",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"zephyr",
|
|
7
|
+
"cli",
|
|
8
|
+
"deploy",
|
|
9
|
+
"build",
|
|
10
|
+
"runner"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/ZephyrCloudIO/zephyr-packages.git",
|
|
15
|
+
"directory": "libs/zephyr-cli"
|
|
16
|
+
},
|
|
17
|
+
"license": "Apache-2.0",
|
|
18
|
+
"author": {
|
|
19
|
+
"name": "ZephyrCloudIO",
|
|
20
|
+
"url": "https://github.com/ZephyrCloudIO"
|
|
21
|
+
},
|
|
22
|
+
"type": "commonjs",
|
|
23
|
+
"main": "dist/index.js",
|
|
24
|
+
"types": "dist/index.d.ts",
|
|
25
|
+
"bin": {
|
|
26
|
+
"ze-cli": "dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "nx run zephyr-cli:build",
|
|
30
|
+
"patch-version": "pnpm version"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"cosmiconfig": "^9.0.0",
|
|
34
|
+
"jsonc-parser": "^3.3.1",
|
|
35
|
+
"tslib": "catalog:typescript",
|
|
36
|
+
"zephyr-agent": "workspace:*"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/jest": "catalog:typescript",
|
|
40
|
+
"@types/node": "catalog:typescript",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "catalog:eslint",
|
|
42
|
+
"ts-jest": "catalog:typescript"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"provenance": true
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"5.9.3"}
|
package/jest.config.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
displayName: 'zephyr-cli',
|
|
3
|
+
preset: '../../jest.preset.js',
|
|
4
|
+
testEnvironment: 'node',
|
|
5
|
+
transform: {
|
|
6
|
+
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
7
|
+
},
|
|
8
|
+
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
9
|
+
coverageDirectory: '../../coverage/libs/zephyr-cli',
|
|
10
|
+
};
|
package/package.json
CHANGED
|
@@ -1,31 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zephyr-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"zephyr": "dist/index.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "tsc",
|
|
11
|
-
"prepare": "npm run build",
|
|
12
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
|
-
},
|
|
3
|
+
"version": "0.1.3-next.6",
|
|
4
|
+
"description": "CLI tool for running build commands and uploading assets to Zephyr",
|
|
14
5
|
"keywords": [
|
|
15
|
-
"cli",
|
|
16
6
|
"zephyr",
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"files": [
|
|
22
|
-
"dist"
|
|
7
|
+
"cli",
|
|
8
|
+
"deploy",
|
|
9
|
+
"build",
|
|
10
|
+
"runner"
|
|
23
11
|
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/ZephyrCloudIO/zephyr-packages.git",
|
|
15
|
+
"directory": "libs/zephyr-cli"
|
|
16
|
+
},
|
|
17
|
+
"license": "Apache-2.0",
|
|
18
|
+
"author": {
|
|
19
|
+
"name": "ZephyrCloudIO",
|
|
20
|
+
"url": "https://github.com/ZephyrCloudIO"
|
|
21
|
+
},
|
|
22
|
+
"type": "commonjs",
|
|
23
|
+
"main": "dist/index.js",
|
|
24
|
+
"types": "dist/index.d.ts",
|
|
25
|
+
"bin": {
|
|
26
|
+
"ze-cli": "dist/index.js"
|
|
27
|
+
},
|
|
24
28
|
"dependencies": {
|
|
25
|
-
"
|
|
29
|
+
"cosmiconfig": "^9.0.0",
|
|
30
|
+
"jsonc-parser": "^3.3.1",
|
|
31
|
+
"tslib": "^2.8.1",
|
|
32
|
+
"zephyr-agent": "0.1.3-next.6"
|
|
26
33
|
},
|
|
27
34
|
"devDependencies": {
|
|
28
|
-
"@types/
|
|
29
|
-
"
|
|
35
|
+
"@types/jest": "29.5.14",
|
|
36
|
+
"@types/node": "^22.13.11",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^8.27.0",
|
|
38
|
+
"ts-jest": "^29.2.6"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public",
|
|
42
|
+
"provenance": true
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "nx run zephyr-cli:build",
|
|
46
|
+
"patch-version": "pnpm version"
|
|
30
47
|
}
|
|
31
|
-
}
|
|
48
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zephyr-cli",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "libs/zephyr-cli/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "@nx/js:tsc",
|
|
10
|
+
"outputs": ["{options.outputPath}"],
|
|
11
|
+
"options": {
|
|
12
|
+
"rootDir": "libs/zephyr-cli/src",
|
|
13
|
+
"outputPath": "libs/zephyr-cli/dist",
|
|
14
|
+
"tsConfig": "libs/zephyr-cli/tsconfig.lib.json",
|
|
15
|
+
"main": "libs/zephyr-cli/src/index.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"nx-release-publish": {
|
|
19
|
+
"options": {
|
|
20
|
+
"packageRoot": "dist\\{projectRoot}"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"lint": {
|
|
24
|
+
"executor": "@nx/eslint:lint"
|
|
25
|
+
},
|
|
26
|
+
"test": {
|
|
27
|
+
"executor": "@nx/jest:jest",
|
|
28
|
+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
29
|
+
"options": {
|
|
30
|
+
"jestConfig": "libs/zephyr-cli/jest.config.ts"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export interface CliOptions {
|
|
2
|
+
command: 'run' | 'deploy';
|
|
3
|
+
commandLine?: string; // For 'run' command
|
|
4
|
+
directory?: string; // For 'deploy' command
|
|
5
|
+
target?: 'web' | 'ios' | 'android';
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
ssr?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse command line arguments.
|
|
12
|
+
*
|
|
13
|
+
* Syntax:
|
|
14
|
+
*
|
|
15
|
+
* - Ze-cli [options] <command> [args...] - run command (default)
|
|
16
|
+
* - Ze-cli deploy <directory> [options] - deploy command
|
|
17
|
+
*
|
|
18
|
+
* Examples:
|
|
19
|
+
*
|
|
20
|
+
* - Ze-cli --ssr pnpm build
|
|
21
|
+
* - Ze-cli tsc
|
|
22
|
+
* - Ze-cli NODE_ENV=production webpack
|
|
23
|
+
* - Ze-cli deploy ./dist
|
|
24
|
+
* - Ze-cli deploy ./dist --ssr
|
|
25
|
+
*/
|
|
26
|
+
export function parseArgs(args: string[]): CliOptions {
|
|
27
|
+
const options: CliOptions = {
|
|
28
|
+
command: 'run', // Default to 'run'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Find where flags end and the command/subcommand begins
|
|
32
|
+
let commandStartIndex = -1;
|
|
33
|
+
const flags: string[] = [];
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < args.length; i++) {
|
|
36
|
+
const arg = args[i];
|
|
37
|
+
|
|
38
|
+
if (arg === '--help' || arg === '-h') {
|
|
39
|
+
printHelp();
|
|
40
|
+
process.exit(0);
|
|
41
|
+
} else if (arg === '--version' || arg === '-v') {
|
|
42
|
+
// Version is handled by the caller
|
|
43
|
+
options.verbose = true;
|
|
44
|
+
} else if (arg === '--ssr') {
|
|
45
|
+
options.ssr = true;
|
|
46
|
+
flags.push(arg);
|
|
47
|
+
} else if (arg === '--target' || arg === '-t') {
|
|
48
|
+
const value = args[++i];
|
|
49
|
+
if (value && ['web', 'ios', 'android'].includes(value)) {
|
|
50
|
+
options.target = value as 'web' | 'ios' | 'android';
|
|
51
|
+
}
|
|
52
|
+
flags.push(arg, value);
|
|
53
|
+
} else if (arg === '--verbose') {
|
|
54
|
+
options.verbose = true;
|
|
55
|
+
flags.push(arg);
|
|
56
|
+
} else if (!arg.startsWith('-')) {
|
|
57
|
+
// First non-flag argument
|
|
58
|
+
commandStartIndex = i;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (commandStartIndex === -1) {
|
|
64
|
+
printHelp();
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const firstArg = args[commandStartIndex];
|
|
69
|
+
|
|
70
|
+
// Check if it's a subcommand
|
|
71
|
+
if (firstArg === 'deploy') {
|
|
72
|
+
options.command = 'deploy';
|
|
73
|
+
const directory = args[commandStartIndex + 1];
|
|
74
|
+
|
|
75
|
+
if (!directory) {
|
|
76
|
+
console.error('Error: deploy command requires a directory argument');
|
|
77
|
+
console.error('Usage: ze-cli deploy <directory> [options]');
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
options.directory = directory;
|
|
82
|
+
|
|
83
|
+
// Parse any additional flags after the directory
|
|
84
|
+
for (let i = commandStartIndex + 2; i < args.length; i++) {
|
|
85
|
+
const arg = args[i];
|
|
86
|
+
|
|
87
|
+
if (arg === '--ssr') {
|
|
88
|
+
options.ssr = true;
|
|
89
|
+
} else if (arg === '--target' || arg === '-t') {
|
|
90
|
+
const value = args[++i];
|
|
91
|
+
if (value && ['web', 'ios', 'android'].includes(value)) {
|
|
92
|
+
options.target = value as 'web' | 'ios' | 'android';
|
|
93
|
+
}
|
|
94
|
+
} else if (arg === '--verbose') {
|
|
95
|
+
options.verbose = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
// It's a run command - everything from commandStartIndex onwards is the command
|
|
100
|
+
options.command = 'run';
|
|
101
|
+
options.commandLine = args.slice(commandStartIndex).join(' ');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return options;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function printHelp(): void {
|
|
108
|
+
console.log(`
|
|
109
|
+
Usage: ze-cli [options] <command> [args...]
|
|
110
|
+
ze-cli deploy <directory> [options]
|
|
111
|
+
|
|
112
|
+
Run a build command and automatically upload assets to Zephyr, or deploy
|
|
113
|
+
pre-built assets from a directory.
|
|
114
|
+
|
|
115
|
+
Commands:
|
|
116
|
+
<command> [args...] Run a build command and upload (default)
|
|
117
|
+
deploy <directory> Upload pre-built assets from a directory
|
|
118
|
+
|
|
119
|
+
Options:
|
|
120
|
+
--ssr Mark this snapshot as server-side rendered
|
|
121
|
+
--target, -t <target> Build target: web, ios, or android (default: web)
|
|
122
|
+
--verbose Enable verbose output
|
|
123
|
+
--help, -h Show this help message
|
|
124
|
+
|
|
125
|
+
Examples:
|
|
126
|
+
# Run build commands
|
|
127
|
+
ze-cli pnpm build
|
|
128
|
+
ze-cli yarn build
|
|
129
|
+
ze-cli tsc
|
|
130
|
+
ze-cli NODE_ENV=production webpack
|
|
131
|
+
ze-cli --ssr pnpm build
|
|
132
|
+
|
|
133
|
+
# Deploy pre-built assets
|
|
134
|
+
ze-cli deploy ./dist
|
|
135
|
+
ze-cli deploy ./dist --ssr
|
|
136
|
+
ze-cli deploy ./build --target ios
|
|
137
|
+
|
|
138
|
+
How it works:
|
|
139
|
+
- For run commands, ze-cli executes your build command and automatically
|
|
140
|
+
detects the output directory to upload assets.
|
|
141
|
+
- For deploy commands, ze-cli uploads assets from the specified directory.
|
|
142
|
+
- All stdout/stderr from build commands are passed through.
|
|
143
|
+
- ze-cli logs are written to stderr only.
|
|
144
|
+
|
|
145
|
+
Note: No configuration file is needed. Zephyr will automatically detect
|
|
146
|
+
application information from your package.json and git repository.
|
|
147
|
+
|
|
148
|
+
For more information: https://docs.zephyr-cloud.io/cli
|
|
149
|
+
`);
|
|
150
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { access, constants } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { ZephyrEngine, logFn, ZephyrError, ZeErrors } from 'zephyr-agent';
|
|
4
|
+
import { extractAssetsFromDirectory } from '../lib/extract-assets';
|
|
5
|
+
import { uploadAssets } from '../lib/upload';
|
|
6
|
+
|
|
7
|
+
export interface DeployOptions {
|
|
8
|
+
directory: string;
|
|
9
|
+
target?: 'web' | 'ios' | 'android';
|
|
10
|
+
verbose?: boolean;
|
|
11
|
+
ssr?: boolean;
|
|
12
|
+
cwd: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Deploy command: Upload pre-built assets from a directory to Zephyr. This is similar to
|
|
17
|
+
* the standalone zephyr-cli tool.
|
|
18
|
+
*/
|
|
19
|
+
export async function deployCommand(options: DeployOptions): Promise<void> {
|
|
20
|
+
const { directory, target, verbose, ssr, cwd } = options;
|
|
21
|
+
|
|
22
|
+
// Resolve the directory path
|
|
23
|
+
const directoryPath = resolve(cwd, directory);
|
|
24
|
+
|
|
25
|
+
// Check if directory exists
|
|
26
|
+
try {
|
|
27
|
+
await access(directoryPath, constants.F_OK);
|
|
28
|
+
} catch {
|
|
29
|
+
throw new ZephyrError(ZeErrors.ERR_UNKNOWN, {
|
|
30
|
+
message: `Directory does not exist: ${directoryPath}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (verbose) {
|
|
35
|
+
logFn('info', `Uploading assets from: ${directoryPath}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Initialize ZephyrEngine with project root context
|
|
39
|
+
const zephyr_engine = await ZephyrEngine.create({
|
|
40
|
+
builder: 'unknown',
|
|
41
|
+
context: cwd,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Set build target if specified
|
|
45
|
+
if (target) {
|
|
46
|
+
zephyr_engine.env.target = target;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Set SSR flag if specified
|
|
50
|
+
if (ssr) {
|
|
51
|
+
zephyr_engine.env.ssr = true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Extract assets from the directory
|
|
55
|
+
if (verbose) {
|
|
56
|
+
logFn('info', 'Extracting assets from directory...');
|
|
57
|
+
}
|
|
58
|
+
const assetsMap = await extractAssetsFromDirectory(directoryPath);
|
|
59
|
+
|
|
60
|
+
if (verbose) {
|
|
61
|
+
const assetCount = Object.keys(assetsMap).length;
|
|
62
|
+
logFn('info', `Found ${assetCount} assets to upload`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Upload assets
|
|
66
|
+
await uploadAssets({
|
|
67
|
+
zephyr_engine,
|
|
68
|
+
assetsMap,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (verbose) {
|
|
72
|
+
logFn('info', 'Upload completed successfully');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { relative, resolve } from 'node:path';
|
|
3
|
+
import { ZeErrors, ZephyrEngine, ZephyrError } from 'zephyr-agent';
|
|
4
|
+
import { detectMultipleCommands } from '../lib/command-detector';
|
|
5
|
+
import { extractAssetsFromDirectory } from '../lib/extract-assets';
|
|
6
|
+
import { parseShellCommand, splitCommands } from '../lib/shell-parser';
|
|
7
|
+
import { executeCommand } from '../lib/spawn-helper';
|
|
8
|
+
import { uploadAssets } from '../lib/upload';
|
|
9
|
+
|
|
10
|
+
export interface RunOptions {
|
|
11
|
+
commandLine: string;
|
|
12
|
+
target?: 'web' | 'ios' | 'android';
|
|
13
|
+
verbose?: boolean;
|
|
14
|
+
ssr?: boolean;
|
|
15
|
+
cwd: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Run command: Execute a build command and automatically upload the resulting assets. */
|
|
19
|
+
export async function runCommand(options: RunOptions): Promise<void> {
|
|
20
|
+
const { commandLine, target, verbose, ssr, cwd } = options;
|
|
21
|
+
|
|
22
|
+
// Log to stderr so it doesn't interfere with command output
|
|
23
|
+
const log = (level: 'info' | 'warn' | 'error', message: string) => {
|
|
24
|
+
if (level === 'info' && !verbose) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// All ze-cli logs go to stderr
|
|
28
|
+
console.error(`[ze-cli] ${message}`);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Parse the shell command - check if there are multiple commands
|
|
32
|
+
log('info', `Parsing command: ${commandLine}`);
|
|
33
|
+
const individualCommands = splitCommands(commandLine);
|
|
34
|
+
|
|
35
|
+
if (individualCommands.length > 1) {
|
|
36
|
+
log('info', `Detected ${individualCommands.length} commands to execute`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Detect multiple commands and their output directories
|
|
40
|
+
const multiDetection = await detectMultipleCommands(commandLine, cwd);
|
|
41
|
+
const { commands: detectedCommands, outputDirs, commonOutputDir } = multiDetection;
|
|
42
|
+
|
|
43
|
+
// Log detected tools
|
|
44
|
+
// Flatten commands if there are sub-commands
|
|
45
|
+
const allCommands: typeof detectedCommands = [];
|
|
46
|
+
for (const detected of detectedCommands) {
|
|
47
|
+
if (detected.subCommands && detected.subCommands.length > 0) {
|
|
48
|
+
// If there are sub-commands, log them instead of the parent
|
|
49
|
+
allCommands.push(...detected.subCommands);
|
|
50
|
+
} else {
|
|
51
|
+
allCommands.push(detected);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < allCommands.length; i++) {
|
|
56
|
+
const detected = allCommands[i];
|
|
57
|
+
log('info', `Command ${i + 1}: ${detected.tool}`);
|
|
58
|
+
|
|
59
|
+
if (detected.configFile) {
|
|
60
|
+
log('info', ` Config file: ${detected.configFile}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (detected.outputDir) {
|
|
64
|
+
const absoluteOutputDir = resolve(cwd, detected.outputDir);
|
|
65
|
+
log('info', ` Output directory: ${relative(cwd, absoluteOutputDir) || '.'}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If multiple output directories detected, show common ancestor
|
|
70
|
+
if (outputDirs.length > 1 && commonOutputDir) {
|
|
71
|
+
log(
|
|
72
|
+
'info',
|
|
73
|
+
`Multiple output directories detected, using common ancestor: ${relative(cwd, commonOutputDir) || '.'}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Warn about dynamic configs
|
|
78
|
+
if (!outputDirs.length) {
|
|
79
|
+
console.error('[ze-cli] WARNING: Configuration is too dynamic to analyze!');
|
|
80
|
+
console.error('[ze-cli] ');
|
|
81
|
+
console.error(
|
|
82
|
+
'[ze-cli] Your build tool uses a JavaScript configuration file that cannot be'
|
|
83
|
+
);
|
|
84
|
+
console.error('[ze-cli] statically analyzed. This means ze-cli cannot automatically');
|
|
85
|
+
console.error('[ze-cli] detect the output directory.');
|
|
86
|
+
console.error('[ze-cli] ');
|
|
87
|
+
console.error('[ze-cli] Recommendations:');
|
|
88
|
+
console.error('[ze-cli] 1. Use a Zephyr bundler plugin:');
|
|
89
|
+
console.error('[ze-cli] - @zephyrcloud/webpack-plugin');
|
|
90
|
+
console.error('[ze-cli] - @zephyrcloud/rollup-plugin');
|
|
91
|
+
console.error('[ze-cli] - @zephyrcloud/vite-plugin');
|
|
92
|
+
console.error('[ze-cli] - etc.');
|
|
93
|
+
console.error('[ze-cli] 2. Or use "ze-cli deploy <dir>" after building');
|
|
94
|
+
console.error('[ze-cli] ');
|
|
95
|
+
console.error('[ze-cli] For more info: https://docs.zephyr-cloud.io/integrations');
|
|
96
|
+
console.error('[ze-cli] ');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Display warnings from all commands
|
|
100
|
+
for (const detected of detectedCommands) {
|
|
101
|
+
if (detected.warnings.length > 0 && !detected.isDynamicConfig) {
|
|
102
|
+
for (const warning of detected.warnings) {
|
|
103
|
+
console.error(`[ze-cli] Warning: ${warning}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Execute all build commands sequentially
|
|
109
|
+
for (let i = 0; i < individualCommands.length; i++) {
|
|
110
|
+
const cmd = individualCommands[i];
|
|
111
|
+
log('info', `Executing command ${i + 1}/${individualCommands.length}: ${cmd}`);
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const parsed = parseShellCommand(cmd);
|
|
115
|
+
const result = await executeCommand(parsed, cwd);
|
|
116
|
+
|
|
117
|
+
if (result.exitCode !== 0) {
|
|
118
|
+
throw new ZephyrError(ZeErrors.ERR_UNKNOWN, {
|
|
119
|
+
message: `Build command failed with exit code ${result.exitCode}`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
log('info', `Command ${i + 1} completed successfully`);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
throw new ZephyrError(ZeErrors.ERR_UNKNOWN, {
|
|
126
|
+
message: `Failed to execute command: ${cmd}\n${(error as Error).message}`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
log('info', 'All build commands completed successfully');
|
|
132
|
+
|
|
133
|
+
// Determine which output directory to use
|
|
134
|
+
let outputDir: string | null = null;
|
|
135
|
+
|
|
136
|
+
if (commonOutputDir) {
|
|
137
|
+
outputDir = commonOutputDir;
|
|
138
|
+
} else if (detectedCommands.length === 1 && detectedCommands[0].outputDir) {
|
|
139
|
+
outputDir = resolve(cwd, detectedCommands[0].outputDir);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// If we couldn't detect the output directory, stop here
|
|
143
|
+
if (!outputDir) {
|
|
144
|
+
console.error('[ze-cli] ');
|
|
145
|
+
console.error('[ze-cli] Could not detect output directory. Skipping upload.');
|
|
146
|
+
console.error('[ze-cli] Please use "ze-cli deploy <dir>" to upload manually.');
|
|
147
|
+
console.error('[ze-cli] ');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
log('info', `Using output directory: ${relative(cwd, outputDir) || '.'}`);
|
|
152
|
+
|
|
153
|
+
// Check if output directory exists
|
|
154
|
+
if (!existsSync(outputDir)) {
|
|
155
|
+
throw new ZephyrError(ZeErrors.ERR_UNKNOWN, {
|
|
156
|
+
message: `Output directory does not exist: ${outputDir}`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Determine the primary build tool for ZephyrEngine
|
|
161
|
+
const primaryTool = detectedCommands[0]?.tool || 'unknown';
|
|
162
|
+
|
|
163
|
+
// Initialize ZephyrEngine with project root context
|
|
164
|
+
log('info', 'Initializing Zephyr Engine...');
|
|
165
|
+
const zephyr_engine = await ZephyrEngine.create({
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
|
+
builder: primaryTool as any,
|
|
168
|
+
context: cwd,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Set build target if specified
|
|
172
|
+
if (target) {
|
|
173
|
+
zephyr_engine.env.target = target;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Set SSR flag if specified
|
|
177
|
+
if (ssr) {
|
|
178
|
+
zephyr_engine.env.ssr = true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Extract assets from the output directory
|
|
182
|
+
log('info', 'Extracting assets from output directory...');
|
|
183
|
+
const assetsMap = await extractAssetsFromDirectory(outputDir);
|
|
184
|
+
|
|
185
|
+
const assetCount = Object.keys(assetsMap).length;
|
|
186
|
+
log('info', `Found ${assetCount} assets to upload`);
|
|
187
|
+
|
|
188
|
+
// Upload assets
|
|
189
|
+
log('info', 'Uploading assets to Zephyr...');
|
|
190
|
+
await uploadAssets({
|
|
191
|
+
zephyr_engine,
|
|
192
|
+
assetsMap,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
log('info', 'Upload completed successfully');
|
|
196
|
+
}
|