@pipelab/core-node 1.0.1-beta.25 → 1.0.1-beta.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipelab/core-node",
3
- "version": "1.0.1-beta.25",
3
+ "version": "1.0.1-beta.27",
4
4
  "private": false,
5
5
  "description": "The Pipelab automation engine for Node.js",
6
6
  "license": "FSL-1.1-MIT",
@@ -28,6 +28,7 @@
28
28
  "dependencies": {
29
29
  "adm-zip": "0.5.16",
30
30
  "archiver": "7.0.1",
31
+ "check-disk-space": "3.4.0",
31
32
  "es-toolkit": "1.25.2",
32
33
  "execa": "9.5.2",
33
34
  "nanoid": "5.0.7",
@@ -38,8 +39,8 @@
38
39
  "type-fest": "4.39.0",
39
40
  "ws": "8.18.3",
40
41
  "yauzl": "2.10.0",
41
- "@pipelab/constants": "1.0.1-beta.21",
42
- "@pipelab/shared": "2.0.1-beta.22"
42
+ "@pipelab/constants": "1.0.1-beta.23",
43
+ "@pipelab/shared": "2.0.1-beta.24"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@types/adm-zip": "0.5.7",
@@ -52,7 +53,7 @@
52
53
  "@types/yauzl": "2.10.3",
53
54
  "tsdown": "0.21.2",
54
55
  "typescript": "^5.0.0",
55
- "@pipelab/tsconfig": "1.0.1-beta.21"
56
+ "@pipelab/tsconfig": "1.0.1-beta.23"
56
57
  },
57
58
  "scripts": {
58
59
  "build": "tsdown",
@@ -2,9 +2,10 @@ import { PipelabContext } from "../context";
2
2
  import { join } from "node:path";
3
3
  import { writeFile, readFile, unlink, mkdir, stat, readdir } from "node:fs/promises";
4
4
  import { tmpdir } from "node:os";
5
- import { BuildHistoryEntry, IBuildHistoryStorage, AppConfig } from "@pipelab/shared";
6
- import { useLogger } from "@pipelab/shared";
5
+ import { useLogger, BuildHistoryEntry, IBuildHistoryStorage, AppConfig } from "@pipelab/shared";
7
6
  import { setupConfigFile } from "../config";
7
+ import checkDiskSpace from "check-disk-space";
8
+ import { getFolderSize } from "../utils/fs-extras";
8
9
 
9
10
  // Simplified storage - one file per pipeline containing array of build entries
10
11
 
@@ -128,6 +129,11 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
128
129
  this.logger
129
130
  .logger()
130
131
  .info(`Saved build history entry: ${entry.id} for pipeline: ${entry.pipelineId}`);
132
+
133
+ // Apply retention policy after each save
134
+ this.applyRetentionPolicy().catch((err) => {
135
+ this.logger.logger().error("Failed to apply retention policy after save:", err);
136
+ });
131
137
  } catch (error) {
132
138
  this.logger.logger().error("Failed to save build history entry:", error);
133
139
  throw new Error(`Failed to save build history entry: ${error}`);
@@ -280,24 +286,31 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
280
286
  oldestEntry?: number;
281
287
  newestEntry?: number;
282
288
  numberOfPipelines: number;
283
- cachePath: string;
284
289
  userDataPath: string;
285
290
  retentionPolicy: {
286
291
  enabled: boolean;
287
292
  maxEntries: number;
288
293
  maxAge: number;
289
294
  };
295
+ disk: {
296
+ total: number;
297
+ free: number;
298
+ pipelab: number;
299
+ };
290
300
  }> {
291
301
  try {
292
302
  const allEntries = await this.getAll();
293
303
  const files = await this.getAllPipelineFiles();
294
304
 
305
+ const diskSpace = await checkDiskSpace(this.context.userDataPath);
306
+ const pipelabSize = await getFolderSize(this.context.userDataPath);
307
+
295
308
  const settings = await setupConfigFile<AppConfig>("settings", { context: this.context });
296
309
  const config = await settings.getConfig();
297
310
  const policy = config?.buildHistory?.retentionPolicy || {
298
311
  enabled: false,
299
- maxEntries: 0,
300
- maxAge: 0,
312
+ maxEntries: 50,
313
+ maxAge: 30,
301
314
  };
302
315
 
303
316
  if (allEntries.length === 0) {
@@ -305,13 +318,17 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
305
318
  totalEntries: 0,
306
319
  totalSize: 0,
307
320
  numberOfPipelines: files.length,
308
- cachePath: config?.cacheFolder || tmpdir(),
309
321
  userDataPath: this.context.userDataPath,
310
322
  retentionPolicy: {
311
323
  enabled: policy.enabled,
312
324
  maxEntries: policy.maxEntries,
313
325
  maxAge: policy.maxAge,
314
326
  },
327
+ disk: {
328
+ total: diskSpace.size,
329
+ free: diskSpace.free,
330
+ pipelab: pipelabSize,
331
+ },
315
332
  };
316
333
  }
317
334
 
@@ -334,13 +351,17 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
334
351
  oldestEntry: sortedEntries[0]?.createdAt,
335
352
  newestEntry: sortedEntries[sortedEntries.length - 1]?.createdAt,
336
353
  numberOfPipelines: files.length,
337
- cachePath: config?.cacheFolder || tmpdir(),
338
354
  userDataPath: this.context.userDataPath,
339
355
  retentionPolicy: {
340
356
  enabled: policy.enabled,
341
357
  maxEntries: policy.maxEntries,
342
358
  maxAge: policy.maxAge,
343
359
  },
360
+ disk: {
361
+ total: diskSpace.size,
362
+ free: diskSpace.free,
363
+ pipelab: pipelabSize,
364
+ },
344
365
  };
345
366
  } catch (error) {
346
367
  this.logger.logger().error("Failed to get storage info:", error);
@@ -226,6 +226,36 @@ export const registerHistoryHandlers = (context: PipelabContext) => {
226
226
  }
227
227
  });
228
228
 
229
+ handle("build-history:clear-by-pipeline", async (event, { send, value }) => {
230
+ try {
231
+ await checkBuildHistoryAuthorization(event);
232
+
233
+ await buildHistoryStorage.clearByPipeline(value.pipelineId);
234
+ send({
235
+ type: "end",
236
+ data: { type: "success", result: { result: "ok" } },
237
+ });
238
+ } catch (error) {
239
+ logger().error(`Failed to clear build history for pipeline ${value.pipelineId}:`, error);
240
+
241
+ if (error instanceof SubscriptionRequiredError) {
242
+ send({
243
+ type: "end",
244
+ data: { type: "error", ipcError: error.userMessage, code: error.code },
245
+ });
246
+ return;
247
+ }
248
+
249
+ send({
250
+ type: "end",
251
+ data: {
252
+ type: "error",
253
+ ipcError: error instanceof Error ? error.message : "Failed to clear build history for pipeline",
254
+ },
255
+ });
256
+ }
257
+ });
258
+
229
259
  handle("build-history:get-storage-info", async (event, { send }) => {
230
260
  try {
231
261
  await checkBuildHistoryAuthorization(event);
package/src/runner.ts CHANGED
@@ -69,7 +69,8 @@ export async function runPipelineCommand(file: string, options: RunOptions, vers
69
69
 
70
70
  const settings = await setupConfigFile<AppConfig>("settings", { context });
71
71
  const config = await settings.getConfig();
72
- const cachePath = config?.cacheFolder || tmpdir();
72
+ const cachePath = join(context.userDataPath, "cache");
73
+ await mkdir(cachePath, { recursive: true });
73
74
 
74
75
  const abortController = new AbortController();
75
76
 
@@ -1,6 +1,6 @@
1
1
  import { mkdir, createWriteStream, createReadStream } from "node:fs";
2
2
  import { execa, Options, Subprocess } from "execa";
3
- import { mkdir as mkdirP, access, writeFile, realpath, mkdtemp, chmod } from "node:fs/promises";
3
+ import { mkdir as mkdirP, access, writeFile, realpath, mkdtemp, chmod, stat, readdir } from "node:fs/promises";
4
4
  import { join, dirname } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import tar from "tar";
@@ -180,3 +180,32 @@ export const runWithLiveLogs = async (
180
180
  throw new Error(`Command failed with exit code ${code}: ${error.message}`);
181
181
  }
182
182
  };
183
+
184
+ /**
185
+ * Calculates the total size of a directory recursively.
186
+ */
187
+ export async function getFolderSize(dirPath: string): Promise<number> {
188
+ try {
189
+ const files = await readdir(dirPath, { withFileTypes: true });
190
+ const ArrayOfPromises = files.map(async (file) => {
191
+ const path = join(dirPath, file.name);
192
+ if (file.isDirectory()) {
193
+ try {
194
+ return await getFolderSize(path);
195
+ } catch {
196
+ return 0;
197
+ }
198
+ }
199
+ try {
200
+ const { size } = await stat(path);
201
+ return size;
202
+ } catch {
203
+ return 0;
204
+ }
205
+ });
206
+ const results = await Promise.all(ArrayOfPromises);
207
+ return results.reduce((acc, size) => acc + size, 0);
208
+ } catch {
209
+ return 0;
210
+ }
211
+ }
package/src/utils.ts CHANGED
@@ -125,6 +125,9 @@ export const executeGraphWithHistory = async ({
125
125
  const logs: any[] = [];
126
126
  const sandboxPath = await generateTempFolder(cachePath);
127
127
  const { logger } = useLogger();
128
+ let completedSteps = 0;
129
+ let failedSteps = 0;
130
+ let cancelledSteps = 0;
128
131
 
129
132
  // Ensure all plugins used in the graph are downloaded and registered
130
133
  const { registerPlugins, plugins: registeredPlugins } = usePlugins();
@@ -156,7 +159,7 @@ export const executeGraphWithHistory = async ({
156
159
  logger().info(`[Sandbox] Execution sandbox created at: ${sandboxPath}`);
157
160
  const settingsFile = await setupConfigFile<AppConfig>("settings", { context: ctx });
158
161
  const config = await settingsFile.getConfig();
159
- const shouldCleanup = config?.clearTemporaryFoldersOnPipelineEnd ?? true;
162
+ const shouldCleanup = true;
160
163
 
161
164
  try {
162
165
  const result = await processGraph({
@@ -175,7 +178,8 @@ export const executeGraphWithHistory = async ({
175
178
  async (data) => {
176
179
  if (data.type === "log") {
177
180
  const logEntry = {
178
- type: data.type,
181
+ id: nanoid(),
182
+ level: "info",
179
183
  message: data.data.message,
180
184
  timestamp: data.data.time,
181
185
  nodeUid: node?.uid,
@@ -195,7 +199,14 @@ export const executeGraphWithHistory = async ({
195
199
  onNodeEnter: (node) => {
196
200
  onNodeEnter?.(node);
197
201
  },
198
- onNodeExit: (node) => {
202
+ onNodeExit: async (node) => {
203
+ completedSteps++;
204
+ if (!shouldDisableHistory) {
205
+ // Update progress in the background
206
+ buildHistoryStorage.update(buildId, { completedSteps }, pipelineId).catch((err) => {
207
+ logger().error(`Failed to update progress for build ${buildId}:`, err);
208
+ });
209
+ }
199
210
  onNodeExit?.(node);
200
211
  },
201
212
  abortSignal,
@@ -211,6 +222,7 @@ export const executeGraphWithHistory = async ({
211
222
  duration: endTime - startTime,
212
223
  output: result.steps,
213
224
  logs,
225
+ completedSteps,
214
226
  },
215
227
  pipelineId,
216
228
  );
@@ -234,6 +246,9 @@ export const executeGraphWithHistory = async ({
234
246
  timestamp: endTime,
235
247
  },
236
248
  logs,
249
+ completedSteps,
250
+ failedSteps: isCanceled ? 0 : 1,
251
+ cancelledSteps: isCanceled ? 1 : 0,
237
252
  },
238
253
  pipelineId,
239
254
  );