@pd4castr/cli 0.0.11 → 0.0.12
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 +20 -27
- package/dist/index.js +72 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pd4castr CLI
|
|
2
2
|
|
|
3
|
-
CLI tool for creating, testing, and publishing pd4castr models.
|
|
3
|
+
CLI tool for creating, testing, and publishing [pd4castr](https://pdview.com.au/services/pd4castr/) models.
|
|
4
4
|
|
|
5
5
|
Install via:
|
|
6
6
|
|
|
@@ -8,41 +8,34 @@ Install via:
|
|
|
8
8
|
npm install -g @pd4castr/cli
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Read the [full documentation here](https://github.com/pipelabs/pd4castr-model-examples/)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Quick Usage
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
# set this repository up for linking during develpment
|
|
17
|
-
yarn link
|
|
15
|
+
Authenticate with the pd4castr API
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
```sh
|
|
18
|
+
pd4castr login
|
|
19
|
+
```
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
# ex. https://github.com/pipelabs/pd4castr-model-examples/tree/main/examples/python-demo
|
|
24
|
-
yarn link @pd4castr/cli
|
|
21
|
+
Run model input data fetchers and generate test input data
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
```sh
|
|
24
|
+
pd4castr fetch
|
|
28
25
|
```
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
Run your model locally and verify it reads inputs & uploads output as expected
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- `yarn test` - Run tests once
|
|
36
|
-
- `yarn test:watch` - Run tests in watch mode
|
|
37
|
-
- `yarn lint` - Check for linting issues
|
|
38
|
-
- `yarn format` - Format code with Prettier
|
|
39
|
-
- `yarn type-check` - TypeScript type checking
|
|
29
|
+
```sh
|
|
30
|
+
pd4castr test
|
|
31
|
+
```
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
Publish your model to the pd4castr platform
|
|
42
34
|
|
|
43
|
-
|
|
35
|
+
```sh
|
|
36
|
+
pd4castr publish
|
|
37
|
+
```
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
- disk I/O (`fs`) is mocked using [`memfs`](https://github.com/streamich/memfs) which is handled by Vitest in our [`__mocks__/`](./src/__mocks__) folder
|
|
39
|
+
## Contributing
|
|
47
40
|
|
|
48
|
-
|
|
41
|
+
For development docs, check [CONTRIBUTING.MD](./CONTRIBUTING.md)
|
package/dist/index.js
CHANGED
|
@@ -626,7 +626,7 @@ async function startWebServer(app, port) {
|
|
|
626
626
|
|
|
627
627
|
// src/commands/publish/handle-create-model-flow.ts
|
|
628
628
|
import * as inquirer2 from "@inquirer/prompts";
|
|
629
|
-
import
|
|
629
|
+
import chalk3 from "chalk";
|
|
630
630
|
|
|
631
631
|
// src/api/create-model.ts
|
|
632
632
|
async function createModel(config, authCtx) {
|
|
@@ -667,10 +667,14 @@ async function updateProjectConfig(updateFn) {
|
|
|
667
667
|
import { execa } from "execa";
|
|
668
668
|
async function buildDockerImage(dockerImage, ctx) {
|
|
669
669
|
try {
|
|
670
|
-
await execa(
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
670
|
+
await execa(
|
|
671
|
+
"docker",
|
|
672
|
+
["build", "--platform=linux/amd64", "-t", dockerImage, "."],
|
|
673
|
+
{
|
|
674
|
+
cwd: ctx.projectRoot,
|
|
675
|
+
stdio: "pipe"
|
|
676
|
+
}
|
|
677
|
+
);
|
|
674
678
|
} catch (error) {
|
|
675
679
|
throw new Error("Failed to build docker image", { cause: error });
|
|
676
680
|
}
|
|
@@ -771,19 +775,27 @@ function logEmptyLine() {
|
|
|
771
775
|
console.log("");
|
|
772
776
|
}
|
|
773
777
|
|
|
774
|
-
// src/commands/publish/
|
|
778
|
+
// src/commands/publish/constants.ts
|
|
775
779
|
import chalk from "chalk";
|
|
780
|
+
var MODEL_RUN_TRIGGER_MESSAGE = `${chalk.whiteBright.bold("NOTE!")} If you do not see your model output in the pd4castr UI:
|
|
781
|
+
|
|
782
|
+
\u2022 If you are using static inputs - check you have uploaded your input data to your input bucket
|
|
783
|
+
\u2022 If you are using inputs with data fetchers - wait a few minutes and check again
|
|
784
|
+
`;
|
|
785
|
+
|
|
786
|
+
// src/commands/publish/utils/get-model-summary-lines.ts
|
|
787
|
+
import chalk2 from "chalk";
|
|
776
788
|
function getModelSummaryLines(ctx) {
|
|
777
789
|
return [
|
|
778
|
-
` ${
|
|
779
|
-
` ${
|
|
780
|
-
` ${
|
|
781
|
-
` ${
|
|
782
|
-
` ${
|
|
790
|
+
` ${chalk2.bold("Model name:")} ${ctx.config.name}`,
|
|
791
|
+
` ${chalk2.bold("Revision:")} ${ctx.config.$$revision}`,
|
|
792
|
+
` ${chalk2.bold("Forecast variable:")} ${ctx.config.forecastVariable}`,
|
|
793
|
+
` ${chalk2.bold("Time horizon:")} ${ctx.config.timeHorizon}`,
|
|
794
|
+
` ${chalk2.bold("Inputs:")}`,
|
|
783
795
|
...ctx.config.inputs.map(
|
|
784
796
|
(input2) => ` \u2022 ${input2.key} - ${getInputType(input2)}`
|
|
785
797
|
),
|
|
786
|
-
` ${
|
|
798
|
+
` ${chalk2.bold("Outputs:")}`,
|
|
787
799
|
...ctx.config.outputs.map((output) => ` \u2022 ${output.name} - ${output.type}`),
|
|
788
800
|
""
|
|
789
801
|
];
|
|
@@ -973,7 +985,7 @@ async function runModelIOTests(dockerImage, options, app, ctx) {
|
|
|
973
985
|
|
|
974
986
|
// src/commands/publish/handle-create-model-flow.ts
|
|
975
987
|
async function handleCreateModelFlow(options, app, spinner, ctx, authCtx) {
|
|
976
|
-
spinner.info(`You are publishing a ${
|
|
988
|
+
spinner.info(`You are publishing a ${chalk3.bold("new")} model:
|
|
977
989
|
`);
|
|
978
990
|
getModelSummaryLines(ctx).map((line) => console.log(line));
|
|
979
991
|
const confirm4 = await inquirer2.confirm({
|
|
@@ -1009,29 +1021,34 @@ async function handleCreateModelFlow(options, app, spinner, ctx, authCtx) {
|
|
|
1009
1021
|
await pushDockerImage(dockerImage, model.dockerImage);
|
|
1010
1022
|
spinner.succeed("Model image pushed to reogistry successfully");
|
|
1011
1023
|
spinner.start("Triggering model run...");
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1024
|
+
let modelRunTriggered = false;
|
|
1025
|
+
if (!options.skipTrigger) {
|
|
1026
|
+
try {
|
|
1027
|
+
await triggerModelRun(model.id, authCtx);
|
|
1028
|
+
spinner.succeed("Model run triggered successfully");
|
|
1029
|
+
modelRunTriggered = true;
|
|
1030
|
+
} catch {
|
|
1031
|
+
spinner.info("Model run did not trigger");
|
|
1032
|
+
}
|
|
1019
1033
|
}
|
|
1020
1034
|
spinner.stopAndPersist({
|
|
1021
1035
|
symbol: "\u{1F680} ",
|
|
1022
1036
|
prefixText: "\n",
|
|
1023
1037
|
suffixText: "\n",
|
|
1024
|
-
text:
|
|
1038
|
+
text: chalk3.bold(`${model.name} r${model.revision} published successfully`)
|
|
1025
1039
|
});
|
|
1040
|
+
if (!modelRunTriggered && !options.skipTrigger) {
|
|
1041
|
+
console.log(MODEL_RUN_TRIGGER_MESSAGE);
|
|
1042
|
+
}
|
|
1026
1043
|
}
|
|
1027
1044
|
|
|
1028
1045
|
// src/commands/publish/handle-update-existing-model-flow.ts
|
|
1029
1046
|
import * as inquirer5 from "@inquirer/prompts";
|
|
1030
|
-
import
|
|
1047
|
+
import chalk6 from "chalk";
|
|
1031
1048
|
|
|
1032
1049
|
// src/commands/publish/handle-model-revision-create-flow.ts
|
|
1033
1050
|
import * as inquirer3 from "@inquirer/prompts";
|
|
1034
|
-
import
|
|
1051
|
+
import chalk4 from "chalk";
|
|
1035
1052
|
|
|
1036
1053
|
// src/commands/publish/utils/validate-local-model-state.ts
|
|
1037
1054
|
import invariant2 from "tiny-invariant";
|
|
@@ -1060,7 +1077,7 @@ async function validateLocalModelState(ctx, authCtx) {
|
|
|
1060
1077
|
}
|
|
1061
1078
|
|
|
1062
1079
|
// src/commands/publish/handle-model-revision-create-flow.ts
|
|
1063
|
-
var WARNING_LABEL =
|
|
1080
|
+
var WARNING_LABEL = chalk4.yellowBright.bold("WARNING!");
|
|
1064
1081
|
var CONFIRMATION_MESSAGE = `${WARNING_LABEL} Creating a new revision will preserve existing revisions.
|
|
1065
1082
|
Previous revisions will still be available in the pd4castr UI.
|
|
1066
1083
|
`;
|
|
@@ -1102,27 +1119,32 @@ async function handleModelRevisionCreateFlow(options, app, spinner, ctx, authCtx
|
|
|
1102
1119
|
await pushDockerImage(dockerImage, model.dockerImage);
|
|
1103
1120
|
spinner.succeed("New model revision image pushed to registry successfully");
|
|
1104
1121
|
spinner.start("Triggering model run...");
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1122
|
+
let modelRunTriggered = false;
|
|
1123
|
+
if (!options.skipTrigger) {
|
|
1124
|
+
try {
|
|
1125
|
+
await triggerModelRun(model.id, authCtx);
|
|
1126
|
+
spinner.succeed("Model run triggered successfully");
|
|
1127
|
+
modelRunTriggered = true;
|
|
1128
|
+
} catch {
|
|
1129
|
+
spinner.info("Model run did not trigger");
|
|
1130
|
+
}
|
|
1112
1131
|
}
|
|
1113
1132
|
spinner.stopAndPersist({
|
|
1114
1133
|
symbol: "\u{1F680} ",
|
|
1115
1134
|
prefixText: "\n",
|
|
1116
1135
|
suffixText: "\n",
|
|
1117
|
-
text:
|
|
1136
|
+
text: chalk4.bold(
|
|
1118
1137
|
`New model revision (r${model.revision}) published successfully`
|
|
1119
1138
|
)
|
|
1120
1139
|
});
|
|
1140
|
+
if (!modelRunTriggered && !options.skipTrigger) {
|
|
1141
|
+
console.log(MODEL_RUN_TRIGGER_MESSAGE);
|
|
1142
|
+
}
|
|
1121
1143
|
}
|
|
1122
1144
|
|
|
1123
1145
|
// src/commands/publish/handle-model-revision-update-flow.ts
|
|
1124
1146
|
import * as inquirer4 from "@inquirer/prompts";
|
|
1125
|
-
import
|
|
1147
|
+
import chalk5 from "chalk";
|
|
1126
1148
|
|
|
1127
1149
|
// src/api/update-model.ts
|
|
1128
1150
|
async function updateModel(config, authCtx) {
|
|
@@ -1132,7 +1154,7 @@ async function updateModel(config, authCtx) {
|
|
|
1132
1154
|
}
|
|
1133
1155
|
|
|
1134
1156
|
// src/commands/publish/handle-model-revision-update-flow.ts
|
|
1135
|
-
var WARNING_LABEL2 =
|
|
1157
|
+
var WARNING_LABEL2 = chalk5.yellowBright.bold("WARNING!");
|
|
1136
1158
|
var CONFIRMATION_MESSAGE2 = `${WARNING_LABEL2} Updating a model revision recreates the associated inputs and outputs.
|
|
1137
1159
|
Historical data is preserved, but it will no longer be displayed in the pd4castr UI.
|
|
1138
1160
|
`;
|
|
@@ -1174,25 +1196,30 @@ async function handleModelRevisionUpdateFlow(options, app, spinner, ctx, authCtx
|
|
|
1174
1196
|
await pushDockerImage(dockerImage, model.dockerImage);
|
|
1175
1197
|
spinner.succeed("Updated model image pushed to registry successfully");
|
|
1176
1198
|
spinner.start("Triggering model run...");
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1199
|
+
let modelRunTriggered = false;
|
|
1200
|
+
if (!options.skipTrigger) {
|
|
1201
|
+
try {
|
|
1202
|
+
await triggerModelRun(model.id, authCtx);
|
|
1203
|
+
spinner.succeed("Model run triggered successfully");
|
|
1204
|
+
modelRunTriggered = true;
|
|
1205
|
+
} catch {
|
|
1206
|
+
spinner.info("Model run did not trigger");
|
|
1207
|
+
}
|
|
1184
1208
|
}
|
|
1185
1209
|
spinner.stopAndPersist({
|
|
1186
1210
|
symbol: "\u{1F680} ",
|
|
1187
1211
|
prefixText: "\n",
|
|
1188
1212
|
suffixText: "\n",
|
|
1189
|
-
text:
|
|
1213
|
+
text: chalk5.bold(`${model.name} (r${model.revision}) updated successfully`)
|
|
1190
1214
|
});
|
|
1215
|
+
if (!modelRunTriggered && !options.skipTrigger) {
|
|
1216
|
+
console.log(MODEL_RUN_TRIGGER_MESSAGE);
|
|
1217
|
+
}
|
|
1191
1218
|
}
|
|
1192
1219
|
|
|
1193
1220
|
// src/commands/publish/handle-update-existing-model-flow.ts
|
|
1194
1221
|
async function handleUpdateExistingModelFlow(options, app, spinner, ctx, authCtx) {
|
|
1195
|
-
spinner.info(`You are publishing an ${
|
|
1222
|
+
spinner.info(`You are publishing an ${chalk6.bold("existing")} model:
|
|
1196
1223
|
`);
|
|
1197
1224
|
getModelSummaryLines(ctx).map((line) => console.log(line));
|
|
1198
1225
|
const revision = ctx.config.$$revision ?? 0;
|
|
@@ -1266,7 +1293,7 @@ function registerPublishCommand(program2) {
|
|
|
1266
1293
|
"-p, --port <port>",
|
|
1267
1294
|
"The port to run the IO testing webserver on",
|
|
1268
1295
|
TEST_WEBSERVER_PORT.toString()
|
|
1269
|
-
).option("
|
|
1296
|
+
).option("--sc, --skip-checks", "Skip the model I/O checks", false).option("--st, --skip-trigger", "Skip the model trigger", false).action(handleAction5);
|
|
1270
1297
|
}
|
|
1271
1298
|
|
|
1272
1299
|
// src/commands/test/handle-action.ts
|
|
@@ -1367,7 +1394,7 @@ import { Command } from "commander";
|
|
|
1367
1394
|
// package.json
|
|
1368
1395
|
var package_default = {
|
|
1369
1396
|
name: "@pd4castr/cli",
|
|
1370
|
-
version: "0.0.
|
|
1397
|
+
version: "0.0.12",
|
|
1371
1398
|
description: "CLI tool for creating, testing, and publishing pd4castr models",
|
|
1372
1399
|
main: "dist/index.js",
|
|
1373
1400
|
type: "module",
|