@datatruck/cli 0.24.0 → 0.25.0

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.
@@ -1,7 +1,6 @@
1
1
  import type { ConfigType } from "../Config/Config";
2
2
  import { PackageConfigType } from "../Config/PackageConfig";
3
3
  import { RepositoryConfigType } from "../Config/RepositoryConfig";
4
- import { AppError } from "../Error/AppError";
5
4
  import { SnapshotResultType } from "../Repository/RepositoryAbstract";
6
5
  import { RestoreSessionManager } from "../SessionManager/RestoreSessionManager";
7
6
  import { TaskAbstract } from "../Task/TaskAbstract";
@@ -38,7 +37,7 @@ export declare class RestoreAction<TRequired extends boolean = true> {
38
37
  error: boolean;
39
38
  tmpDirs: string[];
40
39
  }>;
41
- protected getError(pkg: PackageConfigType): AppError | null;
40
+ protected getError(pkg: PackageConfigType): Error | undefined;
42
41
  exec(session: RestoreSessionManager): Promise<{
43
42
  errors: Error[];
44
43
  }>;
@@ -190,20 +190,16 @@ class RestoreAction {
190
190
  };
191
191
  }
192
192
  getError(pkg) {
193
- const taskErrors = this.taskErrors[pkg.name]?.length;
194
- const repoErrors = this.repoErrors[pkg.name]?.length;
195
- if (taskErrors && repoErrors) {
196
- return new AppError_1.AppError("Task and repository failed");
197
- }
198
- else if (taskErrors && !repoErrors) {
199
- return new AppError_1.AppError("Task failed");
200
- }
201
- else if (!taskErrors && repoErrors) {
202
- return new AppError_1.AppError("Repository failed");
203
- }
204
- else {
205
- return null;
206
- }
193
+ const taskErrors = this.taskErrors[pkg.name] || [];
194
+ const repoErrors = this.repoErrors[pkg.name] || [];
195
+ const errors = [...taskErrors, ...repoErrors];
196
+ if (!errors.length)
197
+ return;
198
+ return AppError_1.AppError.create(taskErrors.length && repoErrors.length
199
+ ? "Task and repository failed"
200
+ : taskErrors.length && !repoErrors.length
201
+ ? "Task failed"
202
+ : "Repository failed", errors);
207
203
  }
208
204
  async exec(session) {
209
205
  if (!this.options.snapshotId)
@@ -12,5 +12,5 @@ export type BackupCommandOptionsType<TResolved = false> = {
12
12
  };
13
13
  export declare class BackupCommand extends CommandAbstract<BackupCommandOptionsType<false>, BackupCommandOptionsType<true>> {
14
14
  onOptions(): import("../utils/cli").OptionsType<BackupCommandOptionsType<false>, BackupCommandOptionsType<true>>;
15
- onExec(): Promise<1 | 0>;
15
+ onExec(): Promise<0 | 1>;
16
16
  }
@@ -12,5 +12,5 @@ export type RestoreCommandOptionsType<TResolved = false> = {
12
12
  };
13
13
  export declare class RestoreCommand extends CommandAbstract<RestoreCommandOptionsType<false>, RestoreCommandOptionsType<true>> {
14
14
  onOptions(): import("../utils/cli").OptionsType<RestoreCommandOptionsType<false>, RestoreCommandOptionsType<true>>;
15
- onExec(): Promise<1 | 0>;
15
+ onExec(): Promise<0 | 1>;
16
16
  }
@@ -1,14 +1,9 @@
1
+ import { Step } from "../utils/steps";
1
2
  import { PackageRepositoryConfigType } from "./PackageRepositoryConfig";
2
3
  import { PrunePolicyConfigType } from "./PrunePolicyConfig";
3
4
  import type { TaskConfigType } from "./TaskConfig";
4
5
  import { JSONSchema7 } from "json-schema";
5
6
  export declare const packageConfigDefinition: JSONSchema7;
6
- export declare const pathsObjectDefinition: JSONSchema7;
7
- export type PathsObjectType = {
8
- type: "spawn";
9
- command: string;
10
- args?: string[];
11
- };
12
7
  export type PackageConfigType = {
13
8
  name: string;
14
9
  enabled?: boolean;
@@ -19,8 +14,8 @@ export type PackageConfigType = {
19
14
  uid: string | number;
20
15
  gid: string | number;
21
16
  };
22
- include?: (string | PathsObjectType)[];
23
- exclude?: (string | PathsObjectType)[];
17
+ include?: (string | Step)[];
18
+ exclude?: (string | Step)[];
24
19
  repositoryNames?: string[];
25
20
  prunePolicy?: PrunePolicyConfigType;
26
21
  repositoryConfigs?: PackageRepositoryConfigType[];
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pathsObjectDefinition = exports.packageConfigDefinition = void 0;
3
+ exports.packageConfigDefinition = void 0;
4
4
  const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
5
+ const ScriptTask_1 = require("../Task/ScriptTask");
5
6
  exports.packageConfigDefinition = {
6
7
  type: "object",
7
8
  required: ["name"],
@@ -24,13 +25,19 @@ exports.packageConfigDefinition = {
24
25
  include: {
25
26
  type: "array",
26
27
  items: {
27
- anyOf: [{ type: "string" }, (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.pathsObject)],
28
+ anyOf: [
29
+ { type: "string" },
30
+ (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.scriptTask, ScriptTask_1.ScriptTaskDefinitionEnum.step),
31
+ ],
28
32
  },
29
33
  },
30
34
  exclude: {
31
35
  type: "array",
32
36
  items: {
33
- anyOf: [{ type: "string" }, (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.pathsObject)],
37
+ anyOf: [
38
+ { type: "string" },
39
+ (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.scriptTask, ScriptTask_1.ScriptTaskDefinitionEnum.step),
40
+ ],
34
41
  },
35
42
  },
36
43
  repositoryNames: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
@@ -41,29 +48,3 @@ exports.packageConfigDefinition = {
41
48
  prunePolicy: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.prunePolicy),
42
49
  },
43
50
  };
44
- exports.pathsObjectDefinition = {
45
- type: "object",
46
- required: ["type"],
47
- properties: {
48
- type: { type: "string" },
49
- },
50
- anyOf: [
51
- {
52
- if: {
53
- type: "object",
54
- properties: {
55
- type: { const: "spawn" },
56
- },
57
- },
58
- then: {
59
- type: "object",
60
- required: ["command"],
61
- properties: {
62
- command: { type: "string" },
63
- args: (0, DefinitionEnum_1.makeRef)(DefinitionEnum_1.DefinitionEnum.stringListUtil),
64
- },
65
- },
66
- else: false,
67
- },
68
- ],
69
- };
@@ -19,7 +19,6 @@ export declare enum DefinitionEnum {
19
19
  sqlDumpTask = "sqldump-task",
20
20
  stringListUtil = "stringlist-util",
21
21
  prunePolicy = "prune-policy",
22
- pathsObject = "paths-object",
23
22
  compressUtil = "compress-util"
24
23
  }
25
24
  export declare function makeRef(type: DefinitionEnum, subType?: string): {
@@ -23,7 +23,6 @@ var DefinitionEnum;
23
23
  DefinitionEnum["sqlDumpTask"] = "sqldump-task";
24
24
  DefinitionEnum["stringListUtil"] = "stringlist-util";
25
25
  DefinitionEnum["prunePolicy"] = "prune-policy";
26
- DefinitionEnum["pathsObject"] = "paths-object";
27
26
  DefinitionEnum["compressUtil"] = "compress-util";
28
27
  })(DefinitionEnum || (exports.DefinitionEnum = DefinitionEnum = {}));
29
28
  function makeRef(type, subType) {
@@ -45,7 +45,6 @@ exports.definitions = {
45
45
  [DefinitionEnum_1.DefinitionEnum.postgresqlDumpTask]: PostgresqlDumpTask_1.postgresqlDumpTaskDefinition,
46
46
  [DefinitionEnum_1.DefinitionEnum.config]: Config_1.configDefinition,
47
47
  [DefinitionEnum_1.DefinitionEnum.prunePolicy]: PrunePolicyConfig_1.prunePolicyConfigDefinition,
48
- [DefinitionEnum_1.DefinitionEnum.pathsObject]: PackageConfig_1.pathsObjectDefinition,
49
48
  [DefinitionEnum_1.DefinitionEnum.compressUtil]: tar_1.compressDefinition,
50
49
  };
51
50
  for (const key in exports.definitions) {
@@ -159,20 +159,20 @@ class DatatruckRepository extends RepositoryAbstract_1.RepositoryAbstract {
159
159
  const sourcePath = data.targetPath ?? pkg.path;
160
160
  (0, assert_1.ok)(sourcePath);
161
161
  await (0, promises_1.mkdir)(outPath, { recursive: true });
162
+ const backupPathsOptions = {
163
+ package: data.package,
164
+ snapshot: data.snapshot,
165
+ targetPath: sourcePath,
166
+ verbose: data.options.verbose,
167
+ };
162
168
  const scanner = await (0, fs_1.createFileScanner)({
163
169
  onProgress: data.onProgress,
164
170
  glob: {
165
171
  cwd: sourcePath,
166
172
  onlyFiles: false,
167
- include: await (0, paths_1.parsePaths)(pkg.include ?? ["**"], {
168
- cwd: sourcePath,
169
- verbose: data.options.verbose,
170
- }),
173
+ include: await (0, paths_1.parseBackupPaths)(pkg.include ?? ["**"], backupPathsOptions),
171
174
  ignore: pkg.exclude
172
- ? await (0, paths_1.parsePaths)(pkg.exclude, {
173
- cwd: sourcePath,
174
- verbose: data.options.verbose,
175
- })
175
+ ? await (0, paths_1.parseBackupPaths)(pkg.exclude, backupPathsOptions)
176
176
  : undefined,
177
177
  },
178
178
  });
@@ -166,15 +166,15 @@ class GitRepository extends RepositoryAbstract_1.RepositoryAbstract {
166
166
  });
167
167
  await git.removeAll();
168
168
  const createdPaths = [];
169
- const include = await (0, paths_1.parsePaths)(pkg.include ?? ["**"], {
170
- cwd: sourcePath,
169
+ const backupPathsOptions = {
170
+ package: data.package,
171
+ snapshot: data.snapshot,
172
+ targetPath: sourcePath,
171
173
  verbose: data.options.verbose,
172
- });
174
+ };
175
+ const include = await (0, paths_1.parseBackupPaths)(pkg.include ?? ["**"], backupPathsOptions);
173
176
  const exclude = pkg.exclude
174
- ? await (0, paths_1.parsePaths)(pkg.exclude, {
175
- cwd: sourcePath,
176
- verbose: data.options.verbose,
177
- })
177
+ ? await (0, paths_1.parseBackupPaths)(pkg.exclude, backupPathsOptions)
178
178
  : undefined;
179
179
  const stream = await (0, fast_glob_1.default)(include, {
180
180
  cwd: sourcePath,
@@ -191,11 +191,14 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
191
191
  const sourcePath = data.targetPath ?? data.package.path;
192
192
  (0, assert_1.ok)(sourcePath);
193
193
  let gitignorePath;
194
+ const backupPathsOptions = {
195
+ package: data.package,
196
+ snapshot: data.snapshot,
197
+ targetPath: sourcePath,
198
+ verbose: data.options.verbose,
199
+ };
194
200
  if (!pkg.include && pkg.exclude) {
195
- const exclude = await (0, paths_1.parsePaths)(pkg.exclude, {
196
- cwd: sourcePath,
197
- verbose: data.options.verbose,
198
- });
201
+ const exclude = await (0, paths_1.parseBackupPaths)(pkg.exclude, backupPathsOptions);
199
202
  await data.onProgress({
200
203
  relative: {
201
204
  description: "Writing excluded paths list",
@@ -207,15 +210,9 @@ class ResticRepository extends RepositoryAbstract_1.RepositoryAbstract {
207
210
  await (0, promises_1.writeFile)(gitignorePath, ignoredContents);
208
211
  }
209
212
  else if (pkg.include || pkg.exclude) {
210
- const include = await (0, paths_1.parsePaths)(pkg.include ?? ["**"], {
211
- cwd: sourcePath,
212
- verbose: data.options.verbose,
213
- });
213
+ const include = await (0, paths_1.parseBackupPaths)(pkg.include ?? ["**"], backupPathsOptions);
214
214
  const exclude = pkg.exclude
215
- ? await (0, paths_1.parsePaths)(pkg.exclude, {
216
- cwd: sourcePath,
217
- verbose: data.options.verbose,
218
- })
215
+ ? await (0, paths_1.parseBackupPaths)(pkg.exclude, backupPathsOptions)
219
216
  : undefined;
220
217
  const stream = fast_glob_1.default.stream(include, {
221
218
  cwd: sourcePath,
@@ -6,6 +6,11 @@ export type ScriptTaskConfigType = {
6
6
  backupSteps: Step[];
7
7
  restoreSteps: Step[];
8
8
  };
9
+ export declare enum ScriptTaskDefinitionEnum {
10
+ step = "step",
11
+ processStepConfig = "processStepConfig",
12
+ nodeStepConfig = "nodeStepConfig"
13
+ }
9
14
  export declare const scriptTaskName = "script";
10
15
  export declare const scriptTaskDefinition: JSONSchema7;
11
16
  export declare class ScriptTask extends TaskAbstract<ScriptTaskConfigType> {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ScriptTask = exports.scriptTaskDefinition = exports.scriptTaskName = void 0;
3
+ exports.ScriptTask = exports.scriptTaskDefinition = exports.scriptTaskName = exports.ScriptTaskDefinitionEnum = void 0;
4
4
  const DefinitionEnum_1 = require("../JsonSchema/DefinitionEnum");
5
5
  const fs_1 = require("../utils/fs");
6
6
  const steps_1 = require("../utils/steps");
@@ -11,7 +11,7 @@ var ScriptTaskDefinitionEnum;
11
11
  ScriptTaskDefinitionEnum["step"] = "step";
12
12
  ScriptTaskDefinitionEnum["processStepConfig"] = "processStepConfig";
13
13
  ScriptTaskDefinitionEnum["nodeStepConfig"] = "nodeStepConfig";
14
- })(ScriptTaskDefinitionEnum || (ScriptTaskDefinitionEnum = {}));
14
+ })(ScriptTaskDefinitionEnum || (exports.ScriptTaskDefinitionEnum = ScriptTaskDefinitionEnum = {}));
15
15
  const stepTypes = {
16
16
  process: ScriptTaskDefinitionEnum.processStepConfig,
17
17
  node: ScriptTaskDefinitionEnum.nodeStepConfig,
@@ -176,7 +176,7 @@
176
176
  "type": "string"
177
177
  },
178
178
  {
179
- "$ref": "#/definitions/paths-object"
179
+ "$ref": "#/definitions/script-task_step"
180
180
  }
181
181
  ]
182
182
  }
@@ -189,7 +189,7 @@
189
189
  "type": "string"
190
190
  },
191
191
  {
192
- "$ref": "#/definitions/paths-object"
192
+ "$ref": "#/definitions/script-task_step"
193
193
  }
194
194
  ]
195
195
  }
@@ -1036,44 +1036,6 @@
1036
1036
  }
1037
1037
  }
1038
1038
  },
1039
- "paths-object": {
1040
- "type": "object",
1041
- "required": [
1042
- "type"
1043
- ],
1044
- "properties": {
1045
- "type": {
1046
- "type": "string"
1047
- }
1048
- },
1049
- "anyOf": [
1050
- {
1051
- "if": {
1052
- "type": "object",
1053
- "properties": {
1054
- "type": {
1055
- "const": "spawn"
1056
- }
1057
- }
1058
- },
1059
- "then": {
1060
- "type": "object",
1061
- "required": [
1062
- "command"
1063
- ],
1064
- "properties": {
1065
- "command": {
1066
- "type": "string"
1067
- },
1068
- "args": {
1069
- "$ref": "#/definitions/stringlist-util"
1070
- }
1071
- }
1072
- },
1073
- "else": false
1074
- }
1075
- ]
1076
- },
1077
1039
  "compress-util": {
1078
1040
  "type": "object",
1079
1041
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datatruck/cli",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "dependencies": {
5
5
  "@supercharge/promise-pool": "^3.1.0",
6
6
  "ajv": "^8.12.0",
@@ -32,15 +32,15 @@ export declare const pkgPathParams: {
32
32
  };
33
33
  export declare const pkgIncludeParams: {
34
34
  packageName: string;
35
- snapshotId: string;
36
35
  temp: string;
36
+ snapshotId: string;
37
37
  snapshotDate: string;
38
38
  action: string;
39
39
  };
40
40
  export declare const pkgExcludeParams: {
41
41
  packageName: string;
42
- snapshotId: string;
43
42
  temp: string;
43
+ snapshotId: string;
44
44
  snapshotDate: string;
45
45
  action: string;
46
46
  };
@@ -53,30 +53,30 @@ export declare const dbNameParams: {
53
53
  export declare const params: {
54
54
  pkgPath: {
55
55
  packageName: string;
56
- snapshotId: string;
57
56
  temp: string;
57
+ snapshotId: string;
58
58
  snapshotDate: string;
59
59
  action: string;
60
60
  };
61
61
  pkgRestorePath: {
62
62
  path: string;
63
63
  packageName: string;
64
- snapshotId: string;
65
64
  temp: string;
65
+ snapshotId: string;
66
66
  snapshotDate: string;
67
67
  action: string;
68
68
  };
69
69
  pkgInclude: {
70
70
  packageName: string;
71
- snapshotId: string;
72
71
  temp: string;
72
+ snapshotId: string;
73
73
  snapshotDate: string;
74
74
  action: string;
75
75
  };
76
76
  pkgExclude: {
77
77
  packageName: string;
78
- snapshotId: string;
79
78
  temp: string;
79
+ snapshotId: string;
80
80
  snapshotDate: string;
81
81
  action: string;
82
82
  };
@@ -1,5 +1,21 @@
1
- import { PathsObjectType } from "../../Config/PackageConfig";
2
- export declare function parsePaths(values: (string | PathsObjectType)[], options: {
1
+ import { PackageConfigType } from "../../Config/PackageConfig";
2
+ import { SnapshotType } from "../../Repository/RepositoryAbstract";
3
+ import { Step } from "../steps";
4
+ export type ParsePathsOptions = {
3
5
  cwd?: string;
4
6
  verbose?: boolean;
7
+ vars?: Record<string, any>;
8
+ };
9
+ export declare function parsePaths(values: (string | Step)[], options: {
10
+ cwd?: string;
11
+ verbose?: boolean;
12
+ vars?: Record<string, any>;
13
+ tempDir?: () => Promise<string>;
5
14
  }): Promise<string[]>;
15
+ export type BackupPathsOptions = {
16
+ package: PackageConfigType;
17
+ snapshot: SnapshotType;
18
+ targetPath: string;
19
+ verbose?: boolean;
20
+ };
21
+ export declare function parseBackupPaths(paths: (string | Step)[], options: BackupPathsOptions): Promise<string[]>;
@@ -1,26 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parsePaths = void 0;
4
- const process_1 = require("../process");
3
+ exports.parseBackupPaths = exports.parsePaths = void 0;
4
+ const steps_1 = require("../steps");
5
5
  async function parsePaths(values, options) {
6
6
  let paths = [];
7
7
  for (const value of values) {
8
8
  if (typeof value === "string") {
9
9
  paths.push(value);
10
10
  }
11
- else if (value.type === "spawn") {
12
- const spawnResult = await (0, process_1.exec)(value.command, value.args, { cwd: options.cwd }, {
13
- log: options.verbose,
14
- stderr: { save: true },
15
- stdout: { save: true },
11
+ else {
12
+ await (0, steps_1.runSteps)(value, {
13
+ node: { tempDir: options.tempDir },
14
+ verbose: options.verbose,
15
+ onLine: (path) => paths.push(path),
16
16
  });
17
- const spawnFiles = [spawnResult.stderr, spawnResult.stdout].flatMap((text) => text
18
- .split(/\r?\n/)
19
- .map((v) => v.trim())
20
- .filter((v) => !!v.length));
21
- paths.push(...spawnFiles);
22
17
  }
23
18
  }
24
19
  return paths;
25
20
  }
26
21
  exports.parsePaths = parsePaths;
22
+ async function parseBackupPaths(paths, options) {
23
+ return parsePaths(paths, {
24
+ cwd: options.targetPath,
25
+ verbose: options.verbose,
26
+ vars: {
27
+ dtt: {
28
+ package: options.package,
29
+ snapshot: options.snapshot,
30
+ targetPath: options.targetPath,
31
+ },
32
+ },
33
+ });
34
+ }
35
+ exports.parseBackupPaths = parseBackupPaths;
package/utils/steps.d.ts CHANGED
@@ -25,6 +25,8 @@ export type StepOptions = {
25
25
  vars?: Record<string, any>;
26
26
  tempDir?: () => Promise<string>;
27
27
  };
28
+ cwd?: string;
29
+ onLine?: (p: string) => any;
28
30
  verbose?: boolean;
29
31
  };
30
32
  export declare function runSteps(input: Step[] | Step, options: StepOptions): Promise<void>;
package/utils/steps.js CHANGED
@@ -1,17 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runSteps = void 0;
4
+ const fs_1 = require("./fs");
4
5
  const process_1 = require("./process");
5
6
  const string_1 = require("./string");
6
- const crypto_1 = require("crypto");
7
7
  const promises_1 = require("fs/promises");
8
- const os_1 = require("os");
9
8
  const path_1 = require("path");
10
9
  async function runSteps(input, options) {
11
10
  const steps = Array.isArray(input) ? input : [input];
12
11
  for (const step of steps) {
13
12
  if (step.type === "process") {
14
13
  await (0, process_1.exec)(step.config.command, (step.config.args || []).map((v) => (0, string_1.render)(v, options.process?.vars || {})), {
14
+ cwd: options.cwd,
15
15
  env: {
16
16
  ...process.env,
17
17
  ...options.env,
@@ -19,6 +19,12 @@ async function runSteps(input, options) {
19
19
  },
20
20
  }, {
21
21
  log: options.verbose,
22
+ ...(options.onLine && {
23
+ stdout: {
24
+ parseLines: "skip-empty",
25
+ onData: (line) => options.onLine(line),
26
+ },
27
+ }),
22
28
  });
23
29
  }
24
30
  else if (step.type === "node") {
@@ -27,8 +33,7 @@ async function runSteps(input, options) {
27
33
  tempDir = await options.node.tempDir();
28
34
  }
29
35
  else {
30
- tempDir = (0, path_1.join)((0, os_1.tmpdir)(), (0, crypto_1.randomBytes)(8).toString("hex"));
31
- await (0, promises_1.mkdir)(tempDir, { recursive: true });
36
+ tempDir = await (0, fs_1.mkTmpDir)("node-step");
32
37
  }
33
38
  const scriptPath = (0, path_1.join)(tempDir, "script.js");
34
39
  const vars = Object.entries({
@@ -42,6 +47,7 @@ async function runSteps(input, options) {
42
47
  ? [...vars, ...step.config.code].join(";\n")
43
48
  : `${vars.join(";\n")}\n${step.config.code}`);
44
49
  await (0, process_1.exec)("node", [scriptPath], {
50
+ cwd: options.cwd,
45
51
  env: {
46
52
  ...process.env,
47
53
  ...options.env,
@@ -49,6 +55,12 @@ async function runSteps(input, options) {
49
55
  },
50
56
  }, {
51
57
  log: options.verbose,
58
+ ...(options.onLine && {
59
+ stdout: {
60
+ parseLines: "skip-empty",
61
+ onData: (line) => options.onLine(line),
62
+ },
63
+ }),
52
64
  });
53
65
  }
54
66
  else {