@regressionproof/snapshotter 0.6.2 → 0.6.4

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,2 +1,2 @@
1
1
  import { SnapshotOptions } from './snapshotter.types.js';
2
- export declare function snapshot(options: SnapshotOptions): Promise<boolean>;
2
+ export declare function snapshot(options: SnapshotOptions): void;
@@ -7,16 +7,52 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { mkdirSync, writeFileSync } from 'fs';
10
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from 'fs';
11
11
  import path from 'path';
12
12
  import { buildLog } from '@sprucelabs/spruce-skill-utils';
13
13
  import { gitCommit, gitPush } from './git.js.js';
14
14
  import { syncFiles } from './sync.js.js';
15
+ const ERROR_FILE_NAME = 'lastError.json';
15
16
  class Snapshotter {
16
17
  constructor() {
17
18
  this.log = buildLog('Snapshotter');
19
+ this.queue = [];
20
+ this.isProcessing = false;
18
21
  }
19
22
  snapshot(options) {
23
+ this.checkForPreviousFailure(options.mirrorPath);
24
+ this.enqueue(options);
25
+ }
26
+ checkForPreviousFailure(mirrorPath) {
27
+ const errorPath = this.getErrorFilePath(mirrorPath);
28
+ if (existsSync(errorPath)) {
29
+ const errorData = JSON.parse(readFileSync(errorPath, 'utf-8'));
30
+ unlinkSync(errorPath);
31
+ throw new Error(`Previous snapshot failed: ${errorData.message}\n` +
32
+ `Timestamp: ${errorData.timestamp}\n` +
33
+ `This error was from a background snapshot that failed. ` +
34
+ `The snapshot has been retried - if this error persists, check your configuration.`);
35
+ }
36
+ }
37
+ enqueue(options) {
38
+ this.queue.push(options);
39
+ this.log.info('Snapshot queued', options.mirrorPath);
40
+ void this.processQueue();
41
+ }
42
+ processQueue() {
43
+ return __awaiter(this, void 0, void 0, function* () {
44
+ if (this.isProcessing || this.queue.length === 0) {
45
+ return;
46
+ }
47
+ this.isProcessing = true;
48
+ while (this.queue.length > 0) {
49
+ const options = this.queue.shift();
50
+ yield this.executeSnapshot(options);
51
+ }
52
+ this.isProcessing = false;
53
+ });
54
+ }
55
+ executeSnapshot(options) {
20
56
  return __awaiter(this, void 0, void 0, function* () {
21
57
  var _a;
22
58
  const sourcePath = (_a = options.sourcePath) !== null && _a !== void 0 ? _a : process.cwd();
@@ -32,25 +68,45 @@ class Snapshotter {
32
68
  const committed = yield gitCommit(mirrorPath, this.log);
33
69
  if (!committed) {
34
70
  this.log.info('No changes to commit', mirrorPath);
35
- return false;
71
+ this.clearError(mirrorPath);
72
+ return;
36
73
  }
37
74
  this.log.info('Commit created, pushing', remote.url);
38
75
  yield gitPush(mirrorPath, remote, this.log);
39
76
  this.log.info('Push completed', remote.url);
40
- return true;
77
+ this.clearError(mirrorPath);
41
78
  }
42
79
  catch (err) {
43
80
  const message = err instanceof Error ? err.message : String(err);
44
- this.log.error('Snapshot failed', message);
45
- throw err;
81
+ this.log.error('Snapshot failed (will surface on next test run)', message);
82
+ this.persistError(mirrorPath, err);
46
83
  }
47
84
  });
48
85
  }
86
+ persistError(mirrorPath, err) {
87
+ const snapshotterDir = path.join(mirrorPath, '.snapshotter');
88
+ mkdirSync(snapshotterDir, { recursive: true });
89
+ const errorPath = this.getErrorFilePath(mirrorPath);
90
+ const errorData = {
91
+ message: err instanceof Error ? err.message : String(err),
92
+ stack: err instanceof Error ? err.stack : undefined,
93
+ timestamp: new Date().toISOString(),
94
+ };
95
+ writeFileSync(errorPath, JSON.stringify(errorData, null, 2));
96
+ }
97
+ clearError(mirrorPath) {
98
+ const errorPath = this.getErrorFilePath(mirrorPath);
99
+ if (existsSync(errorPath)) {
100
+ unlinkSync(errorPath);
101
+ }
102
+ }
103
+ getErrorFilePath(mirrorPath) {
104
+ return path.join(mirrorPath, '.snapshotter', ERROR_FILE_NAME);
105
+ }
49
106
  }
107
+ const snapshotter = new Snapshotter();
50
108
  export function snapshot(options) {
51
- return __awaiter(this, void 0, void 0, function* () {
52
- return new Snapshotter().snapshot(options);
53
- });
109
+ snapshotter.snapshot(options);
54
110
  }
55
111
  function sortTestResults(testResults) {
56
112
  const suites = [...testResults.suites].map((suite) => (Object.assign(Object.assign({}, suite), { tests: [...suite.tests].sort((left, right) => left.name.localeCompare(right.name)) })));
@@ -1,2 +1,2 @@
1
1
  import { SnapshotOptions } from './snapshotter.types.js';
2
- export declare function snapshot(options: SnapshotOptions): Promise<boolean>;
2
+ export declare function snapshot(options: SnapshotOptions): void;
package/build/snapshot.js CHANGED
@@ -9,11 +9,45 @@ const path_1 = __importDefault(require("path"));
9
9
  const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
10
10
  const git_js_1 = require("./git.js");
11
11
  const sync_js_1 = require("./sync.js");
12
+ const ERROR_FILE_NAME = 'lastError.json';
12
13
  class Snapshotter {
13
14
  constructor() {
14
15
  this.log = (0, spruce_skill_utils_1.buildLog)('Snapshotter');
16
+ this.queue = [];
17
+ this.isProcessing = false;
15
18
  }
16
- async snapshot(options) {
19
+ snapshot(options) {
20
+ this.checkForPreviousFailure(options.mirrorPath);
21
+ this.enqueue(options);
22
+ }
23
+ checkForPreviousFailure(mirrorPath) {
24
+ const errorPath = this.getErrorFilePath(mirrorPath);
25
+ if ((0, fs_1.existsSync)(errorPath)) {
26
+ const errorData = JSON.parse((0, fs_1.readFileSync)(errorPath, 'utf-8'));
27
+ (0, fs_1.unlinkSync)(errorPath);
28
+ throw new Error(`Previous snapshot failed: ${errorData.message}\n` +
29
+ `Timestamp: ${errorData.timestamp}\n` +
30
+ `This error was from a background snapshot that failed. ` +
31
+ `The snapshot has been retried - if this error persists, check your configuration.`);
32
+ }
33
+ }
34
+ enqueue(options) {
35
+ this.queue.push(options);
36
+ this.log.info('Snapshot queued', options.mirrorPath);
37
+ void this.processQueue();
38
+ }
39
+ async processQueue() {
40
+ if (this.isProcessing || this.queue.length === 0) {
41
+ return;
42
+ }
43
+ this.isProcessing = true;
44
+ while (this.queue.length > 0) {
45
+ const options = this.queue.shift();
46
+ await this.executeSnapshot(options);
47
+ }
48
+ this.isProcessing = false;
49
+ }
50
+ async executeSnapshot(options) {
17
51
  const sourcePath = options.sourcePath ?? process.cwd();
18
52
  const { mirrorPath, testResults, remote } = options;
19
53
  this.log.info('Starting snapshot', sourcePath, mirrorPath);
@@ -27,22 +61,44 @@ class Snapshotter {
27
61
  const committed = await (0, git_js_1.gitCommit)(mirrorPath, this.log);
28
62
  if (!committed) {
29
63
  this.log.info('No changes to commit', mirrorPath);
30
- return false;
64
+ this.clearError(mirrorPath);
65
+ return;
31
66
  }
32
67
  this.log.info('Commit created, pushing', remote.url);
33
68
  await (0, git_js_1.gitPush)(mirrorPath, remote, this.log);
34
69
  this.log.info('Push completed', remote.url);
35
- return true;
70
+ this.clearError(mirrorPath);
36
71
  }
37
72
  catch (err) {
38
73
  const message = err instanceof Error ? err.message : String(err);
39
- this.log.error('Snapshot failed', message);
40
- throw err;
74
+ this.log.error('Snapshot failed (will surface on next test run)', message);
75
+ this.persistError(mirrorPath, err);
41
76
  }
42
77
  }
78
+ persistError(mirrorPath, err) {
79
+ const snapshotterDir = path_1.default.join(mirrorPath, '.snapshotter');
80
+ (0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
81
+ const errorPath = this.getErrorFilePath(mirrorPath);
82
+ const errorData = {
83
+ message: err instanceof Error ? err.message : String(err),
84
+ stack: err instanceof Error ? err.stack : undefined,
85
+ timestamp: new Date().toISOString(),
86
+ };
87
+ (0, fs_1.writeFileSync)(errorPath, JSON.stringify(errorData, null, 2));
88
+ }
89
+ clearError(mirrorPath) {
90
+ const errorPath = this.getErrorFilePath(mirrorPath);
91
+ if ((0, fs_1.existsSync)(errorPath)) {
92
+ (0, fs_1.unlinkSync)(errorPath);
93
+ }
94
+ }
95
+ getErrorFilePath(mirrorPath) {
96
+ return path_1.default.join(mirrorPath, '.snapshotter', ERROR_FILE_NAME);
97
+ }
43
98
  }
44
- async function snapshot(options) {
45
- return new Snapshotter().snapshot(options);
99
+ const snapshotter = new Snapshotter();
100
+ function snapshot(options) {
101
+ snapshotter.snapshot(options);
46
102
  }
47
103
  function sortTestResults(testResults) {
48
104
  const suites = [...testResults.suites].map((suite) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@regressionproof/snapshotter",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -94,5 +94,5 @@
94
94
  "@sprucelabs/spruce-core-schemas": "^42.1.3",
95
95
  "@sprucelabs/spruce-skill-utils": "^34.0.3"
96
96
  },
97
- "gitHead": "97dd0de8de268600fd4727669c045cef16f82d8c"
97
+ "gitHead": "d2f31ff2ccfed75b6b5638510b4bbeebcbe0ec1b"
98
98
  }