@pd4castr/cli 0.0.11 → 0.0.13

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.
Files changed (3) hide show
  1. package/README.md +20 -27
  2. package/dist/index.js +78 -46
  3. 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
- ## Contributing
11
+ Read the [full documentation here](https://github.com/pipelabs/pd4castr-model-examples/)
12
12
 
13
- ### Quick Start
13
+ ## Quick Usage
14
14
 
15
- ```bash
16
- # set this repository up for linking during develpment
17
- yarn link
15
+ Authenticate with the pd4castr API
18
16
 
19
- # run the project in watch mode
20
- yarn dev
17
+ ```sh
18
+ pd4castr login
19
+ ```
21
20
 
22
- # from a model project, link the module
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
- # from that project, execute a command
27
- yarn pd4castr <command>
23
+ ```sh
24
+ pd4castr fetch
28
25
  ```
29
26
 
30
- ### Scripts
27
+ Run your model locally and verify it reads inputs & uploads output as expected
31
28
 
32
- - `yarn build` - Build the project
33
- - `yarn dev` - Watch mode for development
34
- - `yarn cli <command>` - Run CLI commands against local build
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
- ### Testing
33
+ Publish your model to the pd4castr platform
42
34
 
43
- As this project requires a lot of disk I/O and network reqeuests, we opt for 2 mocking solutions that keep us as close to the metal as possible:
35
+ ```sh
36
+ pd4castr publish
37
+ ```
44
38
 
45
- - network requests are mocked uses [msw](https://mswjs.io/) - request handlers live in the [mocks/handlers](./src/mocks/handlers/) folder
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
- Both of these mocks are initialised globally via our [setup script](./vitest.setup.ts).
41
+ For development docs, check [CONTRIBUTING.MD](./CONTRIBUTING.md)
package/dist/index.js CHANGED
@@ -317,9 +317,14 @@ async function handleAction(options) {
317
317
  try {
318
318
  const authCtx = await getAuth();
319
319
  const ctx = await loadProjectContext();
320
+ const inputsWithFetchers = ctx.config.inputs.filter((input2) => input2.fetcher);
321
+ if (inputsWithFetchers.length === 0) {
322
+ spinner.info("No inputs with data fetchers found, skipping");
323
+ return;
324
+ }
320
325
  for (const input2 of ctx.config.inputs) {
321
326
  if (!input2.fetcher) {
322
- spinner.warn(`\`${input2.key}\` - no data fetcher defined, skipping`);
327
+ spinner.info(`\`${input2.key}\` - no data fetcher defined, skipping`);
323
328
  continue;
324
329
  }
325
330
  if (!FETCHABLE_DATA_FETCHER_TYPES.has(input2.fetcher.type)) {
@@ -626,7 +631,7 @@ async function startWebServer(app, port) {
626
631
 
627
632
  // src/commands/publish/handle-create-model-flow.ts
628
633
  import * as inquirer2 from "@inquirer/prompts";
629
- import chalk2 from "chalk";
634
+ import chalk3 from "chalk";
630
635
 
631
636
  // src/api/create-model.ts
632
637
  async function createModel(config, authCtx) {
@@ -667,10 +672,14 @@ async function updateProjectConfig(updateFn) {
667
672
  import { execa } from "execa";
668
673
  async function buildDockerImage(dockerImage, ctx) {
669
674
  try {
670
- await execa("docker", ["build", "-t", dockerImage, "."], {
671
- cwd: ctx.projectRoot,
672
- stdio: "pipe"
673
- });
675
+ await execa(
676
+ "docker",
677
+ ["build", "--platform=linux/amd64", "-t", dockerImage, "."],
678
+ {
679
+ cwd: ctx.projectRoot,
680
+ stdio: "pipe"
681
+ }
682
+ );
674
683
  } catch (error) {
675
684
  throw new Error("Failed to build docker image", { cause: error });
676
685
  }
@@ -771,19 +780,27 @@ function logEmptyLine() {
771
780
  console.log("");
772
781
  }
773
782
 
774
- // src/commands/publish/utils/get-model-summary-lines.ts
783
+ // src/commands/publish/constants.ts
775
784
  import chalk from "chalk";
785
+ var MODEL_RUN_TRIGGER_MESSAGE = `${chalk.whiteBright.bold("NOTE!")} If you do not see your model output in the pd4castr UI:
786
+
787
+ \u2022 If you are using static inputs - check you have uploaded your input data to your input bucket
788
+ \u2022 If you are using inputs with data fetchers - wait a few minutes and check again
789
+ `;
790
+
791
+ // src/commands/publish/utils/get-model-summary-lines.ts
792
+ import chalk2 from "chalk";
776
793
  function getModelSummaryLines(ctx) {
777
794
  return [
778
- ` ${chalk.bold("Model name:")} ${ctx.config.name}`,
779
- ` ${chalk.bold("Revision:")} ${ctx.config.$$revision}`,
780
- ` ${chalk.bold("Forecast variable:")} ${ctx.config.forecastVariable}`,
781
- ` ${chalk.bold("Time horizon:")} ${ctx.config.timeHorizon}`,
782
- ` ${chalk.bold("Inputs:")}`,
795
+ ` ${chalk2.bold("Model name:")} ${ctx.config.name}`,
796
+ ` ${chalk2.bold("Revision:")} ${ctx.config.$$revision}`,
797
+ ` ${chalk2.bold("Forecast variable:")} ${ctx.config.forecastVariable}`,
798
+ ` ${chalk2.bold("Time horizon:")} ${ctx.config.timeHorizon}`,
799
+ ` ${chalk2.bold("Inputs:")}`,
783
800
  ...ctx.config.inputs.map(
784
801
  (input2) => ` \u2022 ${input2.key} - ${getInputType(input2)}`
785
802
  ),
786
- ` ${chalk.bold("Outputs:")}`,
803
+ ` ${chalk2.bold("Outputs:")}`,
787
804
  ...ctx.config.outputs.map((output) => ` \u2022 ${output.name} - ${output.type}`),
788
805
  ""
789
806
  ];
@@ -973,7 +990,7 @@ async function runModelIOTests(dockerImage, options, app, ctx) {
973
990
 
974
991
  // src/commands/publish/handle-create-model-flow.ts
975
992
  async function handleCreateModelFlow(options, app, spinner, ctx, authCtx) {
976
- spinner.info(`You are publishing a ${chalk2.bold("new")} model:
993
+ spinner.info(`You are publishing a ${chalk3.bold("new")} model:
977
994
  `);
978
995
  getModelSummaryLines(ctx).map((line) => console.log(line));
979
996
  const confirm4 = await inquirer2.confirm({
@@ -1009,29 +1026,34 @@ async function handleCreateModelFlow(options, app, spinner, ctx, authCtx) {
1009
1026
  await pushDockerImage(dockerImage, model.dockerImage);
1010
1027
  spinner.succeed("Model image pushed to reogistry successfully");
1011
1028
  spinner.start("Triggering model run...");
1012
- try {
1013
- await triggerModelRun(model.id, authCtx);
1014
- spinner.succeed("Model run triggered successfully");
1015
- } catch {
1016
- spinner.warn(`Failed to trigger model run
1017
- If you use static inputs, make sure you have uploaded it to your input bucket
1018
- If you use inputs with data fetchers, your model will run when they have fetched new data`);
1029
+ let modelRunTriggered = false;
1030
+ if (!options.skipTrigger) {
1031
+ try {
1032
+ await triggerModelRun(model.id, authCtx);
1033
+ spinner.succeed("Model run triggered successfully");
1034
+ modelRunTriggered = true;
1035
+ } catch {
1036
+ spinner.info("Model run did not trigger");
1037
+ }
1019
1038
  }
1020
1039
  spinner.stopAndPersist({
1021
1040
  symbol: "\u{1F680} ",
1022
1041
  prefixText: "\n",
1023
1042
  suffixText: "\n",
1024
- text: chalk2.bold(`${model.name} r${model.revision} published successfully`)
1043
+ text: chalk3.bold(`${model.name} r${model.revision} published successfully`)
1025
1044
  });
1045
+ if (!modelRunTriggered && !options.skipTrigger) {
1046
+ console.log(MODEL_RUN_TRIGGER_MESSAGE);
1047
+ }
1026
1048
  }
1027
1049
 
1028
1050
  // src/commands/publish/handle-update-existing-model-flow.ts
1029
1051
  import * as inquirer5 from "@inquirer/prompts";
1030
- import chalk5 from "chalk";
1052
+ import chalk6 from "chalk";
1031
1053
 
1032
1054
  // src/commands/publish/handle-model-revision-create-flow.ts
1033
1055
  import * as inquirer3 from "@inquirer/prompts";
1034
- import chalk3 from "chalk";
1056
+ import chalk4 from "chalk";
1035
1057
 
1036
1058
  // src/commands/publish/utils/validate-local-model-state.ts
1037
1059
  import invariant2 from "tiny-invariant";
@@ -1060,7 +1082,7 @@ async function validateLocalModelState(ctx, authCtx) {
1060
1082
  }
1061
1083
 
1062
1084
  // src/commands/publish/handle-model-revision-create-flow.ts
1063
- var WARNING_LABEL = chalk3.yellowBright.bold("WARNING!");
1085
+ var WARNING_LABEL = chalk4.yellowBright.bold("WARNING!");
1064
1086
  var CONFIRMATION_MESSAGE = `${WARNING_LABEL} Creating a new revision will preserve existing revisions.
1065
1087
  Previous revisions will still be available in the pd4castr UI.
1066
1088
  `;
@@ -1102,27 +1124,32 @@ async function handleModelRevisionCreateFlow(options, app, spinner, ctx, authCtx
1102
1124
  await pushDockerImage(dockerImage, model.dockerImage);
1103
1125
  spinner.succeed("New model revision image pushed to registry successfully");
1104
1126
  spinner.start("Triggering model run...");
1105
- try {
1106
- await triggerModelRun(model.id, authCtx);
1107
- spinner.succeed("Model run triggered successfully");
1108
- } catch {
1109
- spinner.warn(`Failed to trigger model run
1110
- If you use static inputs, make sure you have uploaded it to your input bucket
1111
- If you use inputs with data fetchers, your model will run when they have fetched new data`);
1127
+ let modelRunTriggered = false;
1128
+ if (!options.skipTrigger) {
1129
+ try {
1130
+ await triggerModelRun(model.id, authCtx);
1131
+ spinner.succeed("Model run triggered successfully");
1132
+ modelRunTriggered = true;
1133
+ } catch {
1134
+ spinner.info("Model run did not trigger");
1135
+ }
1112
1136
  }
1113
1137
  spinner.stopAndPersist({
1114
1138
  symbol: "\u{1F680} ",
1115
1139
  prefixText: "\n",
1116
1140
  suffixText: "\n",
1117
- text: chalk3.bold(
1141
+ text: chalk4.bold(
1118
1142
  `New model revision (r${model.revision}) published successfully`
1119
1143
  )
1120
1144
  });
1145
+ if (!modelRunTriggered && !options.skipTrigger) {
1146
+ console.log(MODEL_RUN_TRIGGER_MESSAGE);
1147
+ }
1121
1148
  }
1122
1149
 
1123
1150
  // src/commands/publish/handle-model-revision-update-flow.ts
1124
1151
  import * as inquirer4 from "@inquirer/prompts";
1125
- import chalk4 from "chalk";
1152
+ import chalk5 from "chalk";
1126
1153
 
1127
1154
  // src/api/update-model.ts
1128
1155
  async function updateModel(config, authCtx) {
@@ -1132,7 +1159,7 @@ async function updateModel(config, authCtx) {
1132
1159
  }
1133
1160
 
1134
1161
  // src/commands/publish/handle-model-revision-update-flow.ts
1135
- var WARNING_LABEL2 = chalk4.yellowBright.bold("WARNING!");
1162
+ var WARNING_LABEL2 = chalk5.yellowBright.bold("WARNING!");
1136
1163
  var CONFIRMATION_MESSAGE2 = `${WARNING_LABEL2} Updating a model revision recreates the associated inputs and outputs.
1137
1164
  Historical data is preserved, but it will no longer be displayed in the pd4castr UI.
1138
1165
  `;
@@ -1174,25 +1201,30 @@ async function handleModelRevisionUpdateFlow(options, app, spinner, ctx, authCtx
1174
1201
  await pushDockerImage(dockerImage, model.dockerImage);
1175
1202
  spinner.succeed("Updated model image pushed to registry successfully");
1176
1203
  spinner.start("Triggering model run...");
1177
- try {
1178
- await triggerModelRun(model.id, authCtx);
1179
- spinner.succeed("Model run triggered successfully");
1180
- } catch {
1181
- spinner.warn(`Failed to trigger model run
1182
- If you use static inputs, make sure you have uploaded it to your input bucket
1183
- If you use inputs with data fetchers, your model will run when they have fetched new data`);
1204
+ let modelRunTriggered = false;
1205
+ if (!options.skipTrigger) {
1206
+ try {
1207
+ await triggerModelRun(model.id, authCtx);
1208
+ spinner.succeed("Model run triggered successfully");
1209
+ modelRunTriggered = true;
1210
+ } catch {
1211
+ spinner.info("Model run did not trigger");
1212
+ }
1184
1213
  }
1185
1214
  spinner.stopAndPersist({
1186
1215
  symbol: "\u{1F680} ",
1187
1216
  prefixText: "\n",
1188
1217
  suffixText: "\n",
1189
- text: chalk4.bold(`${model.name} (r${model.revision}) updated successfully`)
1218
+ text: chalk5.bold(`${model.name} (r${model.revision}) updated successfully`)
1190
1219
  });
1220
+ if (!modelRunTriggered && !options.skipTrigger) {
1221
+ console.log(MODEL_RUN_TRIGGER_MESSAGE);
1222
+ }
1191
1223
  }
1192
1224
 
1193
1225
  // src/commands/publish/handle-update-existing-model-flow.ts
1194
1226
  async function handleUpdateExistingModelFlow(options, app, spinner, ctx, authCtx) {
1195
- spinner.info(`You are publishing an ${chalk5.bold("existing")} model:
1227
+ spinner.info(`You are publishing an ${chalk6.bold("existing")} model:
1196
1228
  `);
1197
1229
  getModelSummaryLines(ctx).map((line) => console.log(line));
1198
1230
  const revision = ctx.config.$$revision ?? 0;
@@ -1266,7 +1298,7 @@ function registerPublishCommand(program2) {
1266
1298
  "-p, --port <port>",
1267
1299
  "The port to run the IO testing webserver on",
1268
1300
  TEST_WEBSERVER_PORT.toString()
1269
- ).option("-s, --skip-checks", "Skip the model I/O checks", false).action(handleAction5);
1301
+ ).option("--sc, --skip-checks", "Skip the model I/O checks", false).option("--st, --skip-trigger", "Skip the model trigger", false).action(handleAction5);
1270
1302
  }
1271
1303
 
1272
1304
  // src/commands/test/handle-action.ts
@@ -1367,7 +1399,7 @@ import { Command } from "commander";
1367
1399
  // package.json
1368
1400
  var package_default = {
1369
1401
  name: "@pd4castr/cli",
1370
- version: "0.0.11",
1402
+ version: "0.0.13",
1371
1403
  description: "CLI tool for creating, testing, and publishing pd4castr models",
1372
1404
  main: "dist/index.js",
1373
1405
  type: "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pd4castr/cli",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "CLI tool for creating, testing, and publishing pd4castr models",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",