@regressionproof/snapshotter 0.7.0 → 0.7.2
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/build/Snapshotter.d.ts +11 -0
- package/build/Snapshotter.js +25 -0
- package/build/components/ErrorHandler.d.ts +9 -0
- package/build/components/ErrorHandler.js +46 -0
- package/build/components/FileSyncer.d.ts +8 -0
- package/build/{sync.js → components/FileSyncer.js} +30 -16
- package/build/components/TestResultsWriter.d.ts +7 -0
- package/build/components/TestResultsWriter.js +45 -0
- package/build/esm/Snapshotter.d.ts +11 -0
- package/build/esm/Snapshotter.js +20 -0
- package/build/esm/components/ErrorHandler.d.ts +9 -0
- package/build/esm/components/ErrorHandler.js +41 -0
- package/build/esm/components/FileSyncer.d.ts +8 -0
- package/build/esm/{sync.js → components/FileSyncer.js} +36 -17
- package/build/esm/components/TestResultsWriter.d.ts +7 -0
- package/build/esm/components/TestResultsWriter.js +33 -0
- package/build/esm/index.d.ts +2 -1
- package/build/esm/index.js +1 -1
- package/build/esm/scripts/runPush.d.ts +1 -0
- package/build/esm/scripts/runPush.js +83 -0
- package/build/esm/scripts/runSnapshot.js +5 -64
- package/build/esm/scripts/testManual.js +4 -3
- package/build/esm/strategies/AsyncStrategy.d.ts +11 -0
- package/build/esm/strategies/AsyncStrategy.js +32 -0
- package/build/esm/strategies/SnapshotStrategy.d.ts +4 -0
- package/build/esm/strategies/SnapshotStrategy.js +1 -0
- package/build/esm/strategies/SyncStrategy.d.ts +10 -0
- package/build/esm/strategies/SyncStrategy.js +61 -0
- package/build/index.d.ts +2 -1
- package/build/index.js +6 -4
- package/build/scripts/runPush.d.ts +1 -0
- package/build/scripts/runPush.js +75 -0
- package/build/scripts/runSnapshot.js +4 -68
- package/build/scripts/testManual.js +3 -2
- package/build/strategies/AsyncStrategy.d.ts +11 -0
- package/build/strategies/AsyncStrategy.js +38 -0
- package/build/strategies/SnapshotStrategy.d.ts +4 -0
- package/build/strategies/SnapshotStrategy.js +2 -0
- package/build/strategies/SyncStrategy.d.ts +10 -0
- package/build/strategies/SyncStrategy.js +60 -0
- package/package.json +2 -2
- package/build/esm/snapshot.d.ts +0 -3
- package/build/esm/snapshot.js +0 -40
- package/build/esm/sync.d.ts +0 -1
- package/build/snapshot.d.ts +0 -3
- package/build/snapshot.js +0 -47
- package/build/sync.d.ts +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SnapshotOptions } from './snapshotter.types.js';
|
|
2
|
+
export default class Snapshotter {
|
|
3
|
+
private strategy;
|
|
4
|
+
private constructor();
|
|
5
|
+
static Snapshotter(options?: SnapshotterOptions): Snapshotter;
|
|
6
|
+
snapshot(options: SnapshotOptions): void | Promise<void>;
|
|
7
|
+
checkForPreviousFailure(mirrorPath: string): void;
|
|
8
|
+
}
|
|
9
|
+
export interface SnapshotterOptions {
|
|
10
|
+
mode?: 'sync' | 'async';
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ErrorHandler_js_1 = __importDefault(require("./components/ErrorHandler.js"));
|
|
7
|
+
const AsyncStrategy_js_1 = __importDefault(require("./strategies/AsyncStrategy.js"));
|
|
8
|
+
const SyncStrategy_js_1 = __importDefault(require("./strategies/SyncStrategy.js"));
|
|
9
|
+
class Snapshotter {
|
|
10
|
+
constructor(strategy) {
|
|
11
|
+
this.strategy = strategy;
|
|
12
|
+
}
|
|
13
|
+
static Snapshotter(options) {
|
|
14
|
+
const mode = options?.mode ?? 'async';
|
|
15
|
+
const strategy = mode === 'sync' ? SyncStrategy_js_1.default.Strategy() : AsyncStrategy_js_1.default.Strategy();
|
|
16
|
+
return new this(strategy);
|
|
17
|
+
}
|
|
18
|
+
snapshot(options) {
|
|
19
|
+
return this.strategy.execute(options);
|
|
20
|
+
}
|
|
21
|
+
checkForPreviousFailure(mirrorPath) {
|
|
22
|
+
ErrorHandler_js_1.default.Handler().checkForPreviousFailure(mirrorPath);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.default = Snapshotter;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default class ErrorHandler {
|
|
2
|
+
private static readonly ERROR_FILE_NAME;
|
|
3
|
+
private constructor();
|
|
4
|
+
static Handler(): ErrorHandler;
|
|
5
|
+
checkForPreviousFailure(mirrorPath: string): void;
|
|
6
|
+
persistError(mirrorPath: string, err: unknown): void;
|
|
7
|
+
clearError(mirrorPath: string): void;
|
|
8
|
+
private getErrorFilePath;
|
|
9
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
class ErrorHandler {
|
|
9
|
+
constructor() { }
|
|
10
|
+
static Handler() {
|
|
11
|
+
return new this();
|
|
12
|
+
}
|
|
13
|
+
checkForPreviousFailure(mirrorPath) {
|
|
14
|
+
const errorPath = this.getErrorFilePath(mirrorPath);
|
|
15
|
+
if ((0, fs_1.existsSync)(errorPath)) {
|
|
16
|
+
const errorData = JSON.parse((0, fs_1.readFileSync)(errorPath, 'utf-8'));
|
|
17
|
+
(0, fs_1.unlinkSync)(errorPath);
|
|
18
|
+
throw new Error(`Previous snapshot failed: ${errorData.message}\n` +
|
|
19
|
+
`Timestamp: ${errorData.timestamp}\n` +
|
|
20
|
+
`This error was from a background snapshot that failed. ` +
|
|
21
|
+
`The snapshot has been retried - if this error persists, check your configuration.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
persistError(mirrorPath, err) {
|
|
25
|
+
const snapshotterDir = path_1.default.join(mirrorPath, '.snapshotter');
|
|
26
|
+
(0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
|
|
27
|
+
const errorPath = this.getErrorFilePath(mirrorPath);
|
|
28
|
+
const errorData = {
|
|
29
|
+
message: err instanceof Error ? err.message : String(err),
|
|
30
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
31
|
+
timestamp: new Date().toISOString(),
|
|
32
|
+
};
|
|
33
|
+
(0, fs_1.writeFileSync)(errorPath, JSON.stringify(errorData, null, 2));
|
|
34
|
+
}
|
|
35
|
+
clearError(mirrorPath) {
|
|
36
|
+
const errorPath = this.getErrorFilePath(mirrorPath);
|
|
37
|
+
if ((0, fs_1.existsSync)(errorPath)) {
|
|
38
|
+
(0, fs_1.unlinkSync)(errorPath);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
getErrorFilePath(mirrorPath) {
|
|
42
|
+
return path_1.default.join(mirrorPath, '.snapshotter', ErrorHandler.ERROR_FILE_NAME);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
ErrorHandler.ERROR_FILE_NAME = 'lastError.json';
|
|
46
|
+
exports.default = ErrorHandler;
|
|
@@ -3,13 +3,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.syncFiles = syncFiles;
|
|
7
6
|
const child_process_1 = require("child_process");
|
|
8
7
|
const fs_1 = require("fs");
|
|
9
8
|
const path_1 = __importDefault(require("path"));
|
|
10
9
|
const util_1 = require("util");
|
|
11
10
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
12
|
-
|
|
11
|
+
class FileSyncer {
|
|
12
|
+
constructor() { }
|
|
13
|
+
static Syncer() {
|
|
14
|
+
return new this();
|
|
15
|
+
}
|
|
16
|
+
async sync(sourcePath, mirrorPath) {
|
|
17
|
+
const hasGitIgnore = (0, fs_1.existsSync)(path_1.default.join(sourcePath, '.gitignore'));
|
|
18
|
+
const excludes = FileSyncer.DEFAULT_EXCLUDES.map((e) => `--exclude='${e}'`).join(' ');
|
|
19
|
+
if (hasGitIgnore) {
|
|
20
|
+
await this.syncWithGitIgnore(sourcePath, mirrorPath, excludes);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
await this.syncWithDelete(sourcePath, mirrorPath, excludes);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async syncWithGitIgnore(sourcePath, mirrorPath, excludes) {
|
|
27
|
+
// Filter through a file existence check to handle deleted files in git index
|
|
28
|
+
// This is more portable than --ignore-missing-args which isn't available on older rsync (macOS)
|
|
29
|
+
const cmd = `cd "${sourcePath}" && git ls-files --cached --others --exclude-standard -z | ` +
|
|
30
|
+
`while IFS= read -r -d '' file; do [ -e "$file" ] && printf '%s\\0' "$file"; done | ` +
|
|
31
|
+
`rsync -av --files-from=- --from0 ${excludes} . "${mirrorPath}/"`;
|
|
32
|
+
await execAsync(cmd);
|
|
33
|
+
}
|
|
34
|
+
async syncWithDelete(sourcePath, mirrorPath, excludes) {
|
|
35
|
+
const cmd = `rsync -av --delete ${excludes} "${sourcePath}/" "${mirrorPath}/"`;
|
|
36
|
+
await execAsync(cmd);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
FileSyncer.DEFAULT_EXCLUDES = [
|
|
13
40
|
'node_modules',
|
|
14
41
|
'build',
|
|
15
42
|
'*.env*',
|
|
@@ -21,17 +48,4 @@ const DEFAULT_EXCLUDES = [
|
|
|
21
48
|
'*secret*',
|
|
22
49
|
'*.local',
|
|
23
50
|
];
|
|
24
|
-
|
|
25
|
-
const hasGitIgnore = (0, fs_1.existsSync)(path_1.default.join(sourcePath, '.gitignore'));
|
|
26
|
-
const excludes = DEFAULT_EXCLUDES.map((e) => `--exclude='${e}'`).join(' ');
|
|
27
|
-
if (hasGitIgnore) {
|
|
28
|
-
// Filter through a file existence check to handle deleted files in git index
|
|
29
|
-
// This is more portable than --ignore-missing-args which isn't available on older rsync (macOS)
|
|
30
|
-
const cmd = `cd "${sourcePath}" && git ls-files --cached --others --exclude-standard -z | while IFS= read -r -d '' file; do [ -e "$file" ] && printf '%s\\0' "$file"; done | rsync -av --files-from=- --from0 ${excludes} . "${mirrorPath}/"`;
|
|
31
|
-
await execAsync(cmd);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
const cmd = `rsync -av --delete ${excludes} "${sourcePath}/" "${mirrorPath}/"`;
|
|
35
|
-
await execAsync(cmd);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
51
|
+
exports.default = FileSyncer;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
class TestResultsWriter {
|
|
9
|
+
constructor() { }
|
|
10
|
+
static Writer() {
|
|
11
|
+
return new this();
|
|
12
|
+
}
|
|
13
|
+
write(mirrorPath, testResults) {
|
|
14
|
+
const snapshotterDir = path_1.default.join(mirrorPath, '.snapshotter');
|
|
15
|
+
(0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
|
|
16
|
+
const sorted = this.sortTestResults(testResults);
|
|
17
|
+
(0, fs_1.writeFileSync)(path_1.default.join(snapshotterDir, 'testResults.json'), JSON.stringify(sorted, null, 2));
|
|
18
|
+
}
|
|
19
|
+
sortTestResults(testResults) {
|
|
20
|
+
const suites = [...testResults.suites].map((suite) => ({
|
|
21
|
+
...suite,
|
|
22
|
+
tests: [...suite.tests].sort((left, right) => left.name.localeCompare(right.name)),
|
|
23
|
+
}));
|
|
24
|
+
suites.sort((left, right) => left.path.localeCompare(right.path));
|
|
25
|
+
const typeErrors = testResults.typeErrors
|
|
26
|
+
? [...testResults.typeErrors].sort((left, right) => {
|
|
27
|
+
const fileCompare = left.file.localeCompare(right.file);
|
|
28
|
+
if (fileCompare !== 0) {
|
|
29
|
+
return fileCompare;
|
|
30
|
+
}
|
|
31
|
+
const lineCompare = left.line - right.line;
|
|
32
|
+
if (lineCompare !== 0) {
|
|
33
|
+
return lineCompare;
|
|
34
|
+
}
|
|
35
|
+
return left.column - right.column;
|
|
36
|
+
})
|
|
37
|
+
: undefined;
|
|
38
|
+
return {
|
|
39
|
+
...testResults,
|
|
40
|
+
suites,
|
|
41
|
+
typeErrors,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.default = TestResultsWriter;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SnapshotOptions } from './snapshotter.types.js';
|
|
2
|
+
export default class Snapshotter {
|
|
3
|
+
private strategy;
|
|
4
|
+
private constructor();
|
|
5
|
+
static Snapshotter(options?: SnapshotterOptions): Snapshotter;
|
|
6
|
+
snapshot(options: SnapshotOptions): void | Promise<void>;
|
|
7
|
+
checkForPreviousFailure(mirrorPath: string): void;
|
|
8
|
+
}
|
|
9
|
+
export interface SnapshotterOptions {
|
|
10
|
+
mode?: 'sync' | 'async';
|
|
11
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import ErrorHandler from './components/ErrorHandler.js.js';
|
|
2
|
+
import AsyncStrategy from './strategies/AsyncStrategy.js.js';
|
|
3
|
+
import SyncStrategy from './strategies/SyncStrategy.js.js';
|
|
4
|
+
export default class Snapshotter {
|
|
5
|
+
constructor(strategy) {
|
|
6
|
+
this.strategy = strategy;
|
|
7
|
+
}
|
|
8
|
+
static Snapshotter(options) {
|
|
9
|
+
var _a;
|
|
10
|
+
const mode = (_a = options === null || options === void 0 ? void 0 : options.mode) !== null && _a !== void 0 ? _a : 'async';
|
|
11
|
+
const strategy = mode === 'sync' ? SyncStrategy.Strategy() : AsyncStrategy.Strategy();
|
|
12
|
+
return new this(strategy);
|
|
13
|
+
}
|
|
14
|
+
snapshot(options) {
|
|
15
|
+
return this.strategy.execute(options);
|
|
16
|
+
}
|
|
17
|
+
checkForPreviousFailure(mirrorPath) {
|
|
18
|
+
ErrorHandler.Handler().checkForPreviousFailure(mirrorPath);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default class ErrorHandler {
|
|
2
|
+
private static readonly ERROR_FILE_NAME;
|
|
3
|
+
private constructor();
|
|
4
|
+
static Handler(): ErrorHandler;
|
|
5
|
+
checkForPreviousFailure(mirrorPath: string): void;
|
|
6
|
+
persistError(mirrorPath: string, err: unknown): void;
|
|
7
|
+
clearError(mirrorPath: string): void;
|
|
8
|
+
private getErrorFilePath;
|
|
9
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
class ErrorHandler {
|
|
4
|
+
constructor() { }
|
|
5
|
+
static Handler() {
|
|
6
|
+
return new this();
|
|
7
|
+
}
|
|
8
|
+
checkForPreviousFailure(mirrorPath) {
|
|
9
|
+
const errorPath = this.getErrorFilePath(mirrorPath);
|
|
10
|
+
if (existsSync(errorPath)) {
|
|
11
|
+
const errorData = JSON.parse(readFileSync(errorPath, 'utf-8'));
|
|
12
|
+
unlinkSync(errorPath);
|
|
13
|
+
throw new Error(`Previous snapshot failed: ${errorData.message}\n` +
|
|
14
|
+
`Timestamp: ${errorData.timestamp}\n` +
|
|
15
|
+
`This error was from a background snapshot that failed. ` +
|
|
16
|
+
`The snapshot has been retried - if this error persists, check your configuration.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
persistError(mirrorPath, err) {
|
|
20
|
+
const snapshotterDir = path.join(mirrorPath, '.snapshotter');
|
|
21
|
+
mkdirSync(snapshotterDir, { recursive: true });
|
|
22
|
+
const errorPath = this.getErrorFilePath(mirrorPath);
|
|
23
|
+
const errorData = {
|
|
24
|
+
message: err instanceof Error ? err.message : String(err),
|
|
25
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
};
|
|
28
|
+
writeFileSync(errorPath, JSON.stringify(errorData, null, 2));
|
|
29
|
+
}
|
|
30
|
+
clearError(mirrorPath) {
|
|
31
|
+
const errorPath = this.getErrorFilePath(mirrorPath);
|
|
32
|
+
if (existsSync(errorPath)) {
|
|
33
|
+
unlinkSync(errorPath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
getErrorFilePath(mirrorPath) {
|
|
37
|
+
return path.join(mirrorPath, '.snapshotter', ErrorHandler.ERROR_FILE_NAME);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
ErrorHandler.ERROR_FILE_NAME = 'lastError.json';
|
|
41
|
+
export default ErrorHandler;
|
|
@@ -12,7 +12,41 @@ import { existsSync } from 'fs';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { promisify } from 'util';
|
|
14
14
|
const execAsync = promisify(exec);
|
|
15
|
-
|
|
15
|
+
class FileSyncer {
|
|
16
|
+
constructor() { }
|
|
17
|
+
static Syncer() {
|
|
18
|
+
return new this();
|
|
19
|
+
}
|
|
20
|
+
sync(sourcePath, mirrorPath) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const hasGitIgnore = existsSync(path.join(sourcePath, '.gitignore'));
|
|
23
|
+
const excludes = FileSyncer.DEFAULT_EXCLUDES.map((e) => `--exclude='${e}'`).join(' ');
|
|
24
|
+
if (hasGitIgnore) {
|
|
25
|
+
yield this.syncWithGitIgnore(sourcePath, mirrorPath, excludes);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
yield this.syncWithDelete(sourcePath, mirrorPath, excludes);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
syncWithGitIgnore(sourcePath, mirrorPath, excludes) {
|
|
33
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
+
// Filter through a file existence check to handle deleted files in git index
|
|
35
|
+
// This is more portable than --ignore-missing-args which isn't available on older rsync (macOS)
|
|
36
|
+
const cmd = `cd "${sourcePath}" && git ls-files --cached --others --exclude-standard -z | ` +
|
|
37
|
+
`while IFS= read -r -d '' file; do [ -e "$file" ] && printf '%s\\0' "$file"; done | ` +
|
|
38
|
+
`rsync -av --files-from=- --from0 ${excludes} . "${mirrorPath}/"`;
|
|
39
|
+
yield execAsync(cmd);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
syncWithDelete(sourcePath, mirrorPath, excludes) {
|
|
43
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
const cmd = `rsync -av --delete ${excludes} "${sourcePath}/" "${mirrorPath}/"`;
|
|
45
|
+
yield execAsync(cmd);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
FileSyncer.DEFAULT_EXCLUDES = [
|
|
16
50
|
'node_modules',
|
|
17
51
|
'build',
|
|
18
52
|
'*.env*',
|
|
@@ -24,19 +58,4 @@ const DEFAULT_EXCLUDES = [
|
|
|
24
58
|
'*secret*',
|
|
25
59
|
'*.local',
|
|
26
60
|
];
|
|
27
|
-
export
|
|
28
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
const hasGitIgnore = existsSync(path.join(sourcePath, '.gitignore'));
|
|
30
|
-
const excludes = DEFAULT_EXCLUDES.map((e) => `--exclude='${e}'`).join(' ');
|
|
31
|
-
if (hasGitIgnore) {
|
|
32
|
-
// Filter through a file existence check to handle deleted files in git index
|
|
33
|
-
// This is more portable than --ignore-missing-args which isn't available on older rsync (macOS)
|
|
34
|
-
const cmd = `cd "${sourcePath}" && git ls-files --cached --others --exclude-standard -z | while IFS= read -r -d '' file; do [ -e "$file" ] && printf '%s\\0' "$file"; done | rsync -av --files-from=- --from0 ${excludes} . "${mirrorPath}/"`;
|
|
35
|
-
yield execAsync(cmd);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
const cmd = `rsync -av --delete ${excludes} "${sourcePath}/" "${mirrorPath}/"`;
|
|
39
|
-
yield execAsync(cmd);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
61
|
+
export default FileSyncer;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export default class TestResultsWriter {
|
|
4
|
+
constructor() { }
|
|
5
|
+
static Writer() {
|
|
6
|
+
return new this();
|
|
7
|
+
}
|
|
8
|
+
write(mirrorPath, testResults) {
|
|
9
|
+
const snapshotterDir = path.join(mirrorPath, '.snapshotter');
|
|
10
|
+
mkdirSync(snapshotterDir, { recursive: true });
|
|
11
|
+
const sorted = this.sortTestResults(testResults);
|
|
12
|
+
writeFileSync(path.join(snapshotterDir, 'testResults.json'), JSON.stringify(sorted, null, 2));
|
|
13
|
+
}
|
|
14
|
+
sortTestResults(testResults) {
|
|
15
|
+
const suites = [...testResults.suites].map((suite) => (Object.assign(Object.assign({}, suite), { tests: [...suite.tests].sort((left, right) => left.name.localeCompare(right.name)) })));
|
|
16
|
+
suites.sort((left, right) => left.path.localeCompare(right.path));
|
|
17
|
+
const typeErrors = testResults.typeErrors
|
|
18
|
+
? [...testResults.typeErrors].sort((left, right) => {
|
|
19
|
+
const fileCompare = left.file.localeCompare(right.file);
|
|
20
|
+
if (fileCompare !== 0) {
|
|
21
|
+
return fileCompare;
|
|
22
|
+
}
|
|
23
|
+
const lineCompare = left.line - right.line;
|
|
24
|
+
if (lineCompare !== 0) {
|
|
25
|
+
return lineCompare;
|
|
26
|
+
}
|
|
27
|
+
return left.column - right.column;
|
|
28
|
+
})
|
|
29
|
+
: undefined;
|
|
30
|
+
return Object.assign(Object.assign({}, testResults), { suites,
|
|
31
|
+
typeErrors });
|
|
32
|
+
}
|
|
33
|
+
}
|
package/build/esm/index.d.ts
CHANGED
package/build/esm/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { default as Snapshotter } from './Snapshotter.js.js';
|
|
2
2
|
export * from './snapshotter.types.js.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { existsSync, mkdirSync, unlinkSync, writeFileSync } from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { buildLog } from '@sprucelabs/spruce-skill-utils';
|
|
13
|
+
import ErrorHandler from '../components/ErrorHandler.js.js';
|
|
14
|
+
import { gitPush } from '../git.js.js';
|
|
15
|
+
const LOCK_FILE_NAME = 'push.lock';
|
|
16
|
+
const PENDING_FILE_NAME = 'push.pending';
|
|
17
|
+
const log = buildLog('Snapshotter');
|
|
18
|
+
function main() {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
const mirrorPath = getEnvOrExit('MIRROR_PATH');
|
|
21
|
+
const remoteUrl = getEnvOrExit('REMOTE_URL');
|
|
22
|
+
const remoteToken = getEnvOrExit('REMOTE_TOKEN');
|
|
23
|
+
const snapshotterDir = path.join(mirrorPath, '.snapshotter');
|
|
24
|
+
mkdirSync(snapshotterDir, { recursive: true });
|
|
25
|
+
const lockPath = path.join(snapshotterDir, LOCK_FILE_NAME);
|
|
26
|
+
const pendingPath = path.join(snapshotterDir, PENDING_FILE_NAME);
|
|
27
|
+
if (existsSync(lockPath)) {
|
|
28
|
+
writeFileSync(pendingPath, new Date().toISOString());
|
|
29
|
+
log.info('Push already running, marked pending', mirrorPath);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
writeFileSync(lockPath, process.pid.toString());
|
|
34
|
+
const remote = {
|
|
35
|
+
url: remoteUrl,
|
|
36
|
+
token: remoteToken,
|
|
37
|
+
};
|
|
38
|
+
yield processLoop(mirrorPath, remote, pendingPath);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
if (existsSync(lockPath)) {
|
|
42
|
+
unlinkSync(lockPath);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function processLoop(mirrorPath, remote, pendingPath) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
while (true) {
|
|
50
|
+
if (existsSync(pendingPath)) {
|
|
51
|
+
unlinkSync(pendingPath);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
log.info('Push starting', remote.url);
|
|
55
|
+
yield gitPush(mirrorPath, remote, log);
|
|
56
|
+
log.info('Push completed', remote.url);
|
|
57
|
+
ErrorHandler.Handler().clearError(mirrorPath);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
61
|
+
log.error('Push failed', message);
|
|
62
|
+
ErrorHandler.Handler().persistError(mirrorPath, err);
|
|
63
|
+
writeFileSync(pendingPath, new Date().toISOString());
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!existsSync(pendingPath)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function getEnvOrExit(name) {
|
|
73
|
+
const value = process.env[name];
|
|
74
|
+
if (!value) {
|
|
75
|
+
console.error(`Missing required env var: ${name}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
main().catch((err) => {
|
|
81
|
+
console.error('Push script failed:', err);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
});
|
|
@@ -7,12 +7,11 @@ 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 { existsSync,
|
|
10
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'fs';
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import { buildLog } from '@sprucelabs/spruce-skill-utils';
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
const ERROR_FILE_NAME = 'lastError.json';
|
|
13
|
+
import ErrorHandler from '../components/ErrorHandler.js.js';
|
|
14
|
+
import SyncStrategy from '../strategies/SyncStrategy.js.js';
|
|
16
15
|
const LOCK_FILE_NAME = 'snapshot.lock';
|
|
17
16
|
const PENDING_FILE_NAME = 'pending.json';
|
|
18
17
|
const log = buildLog('Snapshotter');
|
|
@@ -51,74 +50,16 @@ function processLoop(snapshotterDir) {
|
|
|
51
50
|
}
|
|
52
51
|
function executeSnapshot(options) {
|
|
53
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
-
var _a;
|
|
55
|
-
const sourcePath = (_a = options.sourcePath) !== null && _a !== void 0 ? _a : process.cwd();
|
|
56
|
-
const { mirrorPath, testResults, remote } = options;
|
|
57
|
-
log.info('Starting snapshot', sourcePath, mirrorPath);
|
|
58
53
|
try {
|
|
59
|
-
yield
|
|
60
|
-
log.info('Files synced', mirrorPath);
|
|
61
|
-
const snapshotterDir = path.join(mirrorPath, '.snapshotter');
|
|
62
|
-
mkdirSync(snapshotterDir, { recursive: true });
|
|
63
|
-
writeFileSync(path.join(snapshotterDir, 'testResults.json'), JSON.stringify(sortTestResults(testResults), null, 2));
|
|
64
|
-
log.info('Test results saved', snapshotterDir);
|
|
65
|
-
const committed = yield gitCommit(mirrorPath, log);
|
|
66
|
-
if (!committed) {
|
|
67
|
-
log.info('No changes to commit', mirrorPath);
|
|
68
|
-
clearError(mirrorPath);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
log.info('Commit created, pushing', remote.url);
|
|
72
|
-
yield gitPush(mirrorPath, remote, log);
|
|
73
|
-
log.info('Push completed', remote.url);
|
|
74
|
-
clearError(mirrorPath);
|
|
54
|
+
yield SyncStrategy.Strategy().execute(options);
|
|
75
55
|
}
|
|
76
56
|
catch (err) {
|
|
77
57
|
const message = err instanceof Error ? err.message : String(err);
|
|
78
58
|
log.error('Snapshot failed (will surface on next test run)', message);
|
|
79
|
-
persistError(mirrorPath, err);
|
|
59
|
+
ErrorHandler.Handler().persistError(options.mirrorPath, err);
|
|
80
60
|
}
|
|
81
61
|
});
|
|
82
62
|
}
|
|
83
|
-
function persistError(mirrorPath, err) {
|
|
84
|
-
const snapshotterDir = path.join(mirrorPath, '.snapshotter');
|
|
85
|
-
mkdirSync(snapshotterDir, { recursive: true });
|
|
86
|
-
const errorPath = getErrorFilePath(mirrorPath);
|
|
87
|
-
const errorData = {
|
|
88
|
-
message: err instanceof Error ? err.message : String(err),
|
|
89
|
-
stack: err instanceof Error ? err.stack : undefined,
|
|
90
|
-
timestamp: new Date().toISOString(),
|
|
91
|
-
};
|
|
92
|
-
writeFileSync(errorPath, JSON.stringify(errorData, null, 2));
|
|
93
|
-
}
|
|
94
|
-
function clearError(mirrorPath) {
|
|
95
|
-
const errorPath = getErrorFilePath(mirrorPath);
|
|
96
|
-
if (existsSync(errorPath)) {
|
|
97
|
-
unlinkSync(errorPath);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function getErrorFilePath(mirrorPath) {
|
|
101
|
-
return path.join(mirrorPath, '.snapshotter', ERROR_FILE_NAME);
|
|
102
|
-
}
|
|
103
|
-
function sortTestResults(testResults) {
|
|
104
|
-
const suites = [...testResults.suites].map((suite) => (Object.assign(Object.assign({}, suite), { tests: [...suite.tests].sort((left, right) => left.name.localeCompare(right.name)) })));
|
|
105
|
-
suites.sort((left, right) => left.path.localeCompare(right.path));
|
|
106
|
-
const typeErrors = testResults.typeErrors
|
|
107
|
-
? [...testResults.typeErrors].sort((left, right) => {
|
|
108
|
-
const fileCompare = left.file.localeCompare(right.file);
|
|
109
|
-
if (fileCompare !== 0) {
|
|
110
|
-
return fileCompare;
|
|
111
|
-
}
|
|
112
|
-
const lineCompare = left.line - right.line;
|
|
113
|
-
if (lineCompare !== 0) {
|
|
114
|
-
return lineCompare;
|
|
115
|
-
}
|
|
116
|
-
return left.column - right.column;
|
|
117
|
-
})
|
|
118
|
-
: undefined;
|
|
119
|
-
return Object.assign(Object.assign({}, testResults), { suites,
|
|
120
|
-
typeErrors });
|
|
121
|
-
}
|
|
122
63
|
main().catch((err) => {
|
|
123
64
|
console.error('Snapshot script failed:', err);
|
|
124
65
|
process.exit(1);
|
|
@@ -7,7 +7,7 @@ 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 {
|
|
10
|
+
import { Snapshotter } from '../index.js';
|
|
11
11
|
function main() {
|
|
12
12
|
return __awaiter(this, void 0, void 0, function* () {
|
|
13
13
|
const sourcePath = process.env.SOURCE_PATH;
|
|
@@ -22,7 +22,8 @@ function main() {
|
|
|
22
22
|
console.log(' Source:', sourcePath);
|
|
23
23
|
console.log(' Mirror:', mirrorPath);
|
|
24
24
|
console.log(' Remote:', remoteUrl);
|
|
25
|
-
const
|
|
25
|
+
const snapshotter = Snapshotter.Snapshotter({ mode: 'sync' });
|
|
26
|
+
yield snapshotter.snapshot({
|
|
26
27
|
sourcePath,
|
|
27
28
|
mirrorPath,
|
|
28
29
|
testResults: {
|
|
@@ -51,7 +52,7 @@ function main() {
|
|
|
51
52
|
token: remoteToken,
|
|
52
53
|
},
|
|
53
54
|
});
|
|
54
|
-
console.log('Snapshot
|
|
55
|
+
console.log('Snapshot completed');
|
|
55
56
|
});
|
|
56
57
|
}
|
|
57
58
|
main().catch((err) => {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SnapshotOptions } from '../snapshotter.types.js';
|
|
2
|
+
import SnapshotStrategy from './SnapshotStrategy.js';
|
|
3
|
+
export default class AsyncStrategy implements SnapshotStrategy {
|
|
4
|
+
private log;
|
|
5
|
+
private scriptPath;
|
|
6
|
+
private constructor();
|
|
7
|
+
static Strategy(): AsyncStrategy;
|
|
8
|
+
execute(options: SnapshotOptions): void;
|
|
9
|
+
private writeOptionsFile;
|
|
10
|
+
private spawnSnapshotProcess;
|
|
11
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { buildLog } from '@sprucelabs/spruce-skill-utils';
|
|
5
|
+
export default class AsyncStrategy {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.log = buildLog('Snapshotter');
|
|
8
|
+
this.scriptPath = path.join(__dirname, '..', 'scripts', 'runSnapshot.js');
|
|
9
|
+
}
|
|
10
|
+
static Strategy() {
|
|
11
|
+
return new this();
|
|
12
|
+
}
|
|
13
|
+
execute(options) {
|
|
14
|
+
const snapshotterDir = this.writeOptionsFile(options);
|
|
15
|
+
this.spawnSnapshotProcess(snapshotterDir);
|
|
16
|
+
this.log.info('Snapshot queued (running in background)', options.mirrorPath);
|
|
17
|
+
}
|
|
18
|
+
writeOptionsFile(options) {
|
|
19
|
+
const snapshotterDir = path.join(options.mirrorPath, '.snapshotter');
|
|
20
|
+
mkdirSync(snapshotterDir, { recursive: true });
|
|
21
|
+
const optionsPath = path.join(snapshotterDir, 'pending.json');
|
|
22
|
+
writeFileSync(optionsPath, JSON.stringify(options, null, 2));
|
|
23
|
+
return snapshotterDir;
|
|
24
|
+
}
|
|
25
|
+
spawnSnapshotProcess(snapshotterDir) {
|
|
26
|
+
const child = spawn('node', [this.scriptPath, snapshotterDir], {
|
|
27
|
+
detached: true,
|
|
28
|
+
stdio: 'ignore',
|
|
29
|
+
});
|
|
30
|
+
child.unref();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SnapshotOptions } from '../snapshotter.types.js';
|
|
2
|
+
import SnapshotStrategy from './SnapshotStrategy.js';
|
|
3
|
+
export default class SyncStrategy implements SnapshotStrategy {
|
|
4
|
+
private log;
|
|
5
|
+
private pushScriptPath;
|
|
6
|
+
private constructor();
|
|
7
|
+
static Strategy(): SyncStrategy;
|
|
8
|
+
execute(options: SnapshotOptions): Promise<void>;
|
|
9
|
+
private spawnPushProcess;
|
|
10
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { spawn } from 'child_process';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { buildLog } from '@sprucelabs/spruce-skill-utils';
|
|
13
|
+
import ErrorHandler from '../components/ErrorHandler.js.js';
|
|
14
|
+
import FileSyncer from '../components/FileSyncer.js.js';
|
|
15
|
+
import TestResultsWriter from '../components/TestResultsWriter.js.js';
|
|
16
|
+
import { gitCommit } from '../git.js.js';
|
|
17
|
+
export default class SyncStrategy {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.log = buildLog('Snapshotter');
|
|
20
|
+
this.pushScriptPath = path.join(__dirname, '..', 'scripts', 'runPush.js');
|
|
21
|
+
}
|
|
22
|
+
static Strategy() {
|
|
23
|
+
return new this();
|
|
24
|
+
}
|
|
25
|
+
execute(options) {
|
|
26
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
var _a;
|
|
28
|
+
const sourcePath = (_a = options.sourcePath) !== null && _a !== void 0 ? _a : process.cwd();
|
|
29
|
+
const { mirrorPath, testResults, remote } = options;
|
|
30
|
+
this.log.info('Starting snapshot', sourcePath, mirrorPath);
|
|
31
|
+
try {
|
|
32
|
+
yield FileSyncer.Syncer().sync(sourcePath, mirrorPath);
|
|
33
|
+
this.log.info('Files synced', mirrorPath);
|
|
34
|
+
TestResultsWriter.Writer().write(mirrorPath, testResults);
|
|
35
|
+
this.log.info('Test results saved', mirrorPath);
|
|
36
|
+
const committed = yield gitCommit(mirrorPath, this.log);
|
|
37
|
+
if (!committed) {
|
|
38
|
+
this.log.info('No changes to commit', mirrorPath);
|
|
39
|
+
ErrorHandler.Handler().clearError(mirrorPath);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.log.info('Commit created, queueing push', remote.url);
|
|
43
|
+
this.spawnPushProcess(mirrorPath, remote);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
47
|
+
this.log.error('Snapshot failed', message);
|
|
48
|
+
ErrorHandler.Handler().persistError(mirrorPath, err);
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
spawnPushProcess(mirrorPath, remote) {
|
|
54
|
+
const child = spawn('node', [this.pushScriptPath], {
|
|
55
|
+
detached: true,
|
|
56
|
+
stdio: 'ignore',
|
|
57
|
+
env: Object.assign(Object.assign({}, process.env), { MIRROR_PATH: mirrorPath, REMOTE_URL: remote.url, REMOTE_TOKEN: remote.token }),
|
|
58
|
+
});
|
|
59
|
+
child.unref();
|
|
60
|
+
}
|
|
61
|
+
}
|
package/build/index.d.ts
CHANGED
package/build/index.js
CHANGED
|
@@ -13,9 +13,11 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
13
13
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
16
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
18
|
-
var
|
|
19
|
-
Object.defineProperty(exports, "
|
|
20
|
-
Object.defineProperty(exports, "checkForPreviousSnapshotFailure", { enumerable: true, get: function () { return snapshot_js_1.checkForPreviousSnapshotFailure; } });
|
|
20
|
+
exports.Snapshotter = void 0;
|
|
21
|
+
var Snapshotter_js_1 = require("./Snapshotter.js");
|
|
22
|
+
Object.defineProperty(exports, "Snapshotter", { enumerable: true, get: function () { return __importDefault(Snapshotter_js_1).default; } });
|
|
21
23
|
__exportStar(require("./snapshotter.types.js"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
|
|
9
|
+
const ErrorHandler_js_1 = __importDefault(require("../components/ErrorHandler.js"));
|
|
10
|
+
const git_js_1 = require("../git.js");
|
|
11
|
+
const LOCK_FILE_NAME = 'push.lock';
|
|
12
|
+
const PENDING_FILE_NAME = 'push.pending';
|
|
13
|
+
const log = (0, spruce_skill_utils_1.buildLog)('Snapshotter');
|
|
14
|
+
async function main() {
|
|
15
|
+
const mirrorPath = getEnvOrExit('MIRROR_PATH');
|
|
16
|
+
const remoteUrl = getEnvOrExit('REMOTE_URL');
|
|
17
|
+
const remoteToken = getEnvOrExit('REMOTE_TOKEN');
|
|
18
|
+
const snapshotterDir = path_1.default.join(mirrorPath, '.snapshotter');
|
|
19
|
+
(0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
|
|
20
|
+
const lockPath = path_1.default.join(snapshotterDir, LOCK_FILE_NAME);
|
|
21
|
+
const pendingPath = path_1.default.join(snapshotterDir, PENDING_FILE_NAME);
|
|
22
|
+
if ((0, fs_1.existsSync)(lockPath)) {
|
|
23
|
+
(0, fs_1.writeFileSync)(pendingPath, new Date().toISOString());
|
|
24
|
+
log.info('Push already running, marked pending', mirrorPath);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
(0, fs_1.writeFileSync)(lockPath, process.pid.toString());
|
|
29
|
+
const remote = {
|
|
30
|
+
url: remoteUrl,
|
|
31
|
+
token: remoteToken,
|
|
32
|
+
};
|
|
33
|
+
await processLoop(mirrorPath, remote, pendingPath);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
if ((0, fs_1.existsSync)(lockPath)) {
|
|
37
|
+
(0, fs_1.unlinkSync)(lockPath);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function processLoop(mirrorPath, remote, pendingPath) {
|
|
42
|
+
while (true) {
|
|
43
|
+
if ((0, fs_1.existsSync)(pendingPath)) {
|
|
44
|
+
(0, fs_1.unlinkSync)(pendingPath);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
log.info('Push starting', remote.url);
|
|
48
|
+
await (0, git_js_1.gitPush)(mirrorPath, remote, log);
|
|
49
|
+
log.info('Push completed', remote.url);
|
|
50
|
+
ErrorHandler_js_1.default.Handler().clearError(mirrorPath);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
54
|
+
log.error('Push failed', message);
|
|
55
|
+
ErrorHandler_js_1.default.Handler().persistError(mirrorPath, err);
|
|
56
|
+
(0, fs_1.writeFileSync)(pendingPath, new Date().toISOString());
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!(0, fs_1.existsSync)(pendingPath)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function getEnvOrExit(name) {
|
|
65
|
+
const value = process.env[name];
|
|
66
|
+
if (!value) {
|
|
67
|
+
console.error(`Missing required env var: ${name}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
main().catch((err) => {
|
|
73
|
+
console.error('Push script failed:', err);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
|
@@ -6,9 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const ERROR_FILE_NAME = 'lastError.json';
|
|
9
|
+
const ErrorHandler_js_1 = __importDefault(require("../components/ErrorHandler.js"));
|
|
10
|
+
const SyncStrategy_js_1 = __importDefault(require("../strategies/SyncStrategy.js"));
|
|
12
11
|
const LOCK_FILE_NAME = 'snapshot.lock';
|
|
13
12
|
const PENDING_FILE_NAME = 'pending.json';
|
|
14
13
|
const log = (0, spruce_skill_utils_1.buildLog)('Snapshotter');
|
|
@@ -42,78 +41,15 @@ async function processLoop(snapshotterDir) {
|
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
async function executeSnapshot(options) {
|
|
45
|
-
const sourcePath = options.sourcePath ?? process.cwd();
|
|
46
|
-
const { mirrorPath, testResults, remote } = options;
|
|
47
|
-
log.info('Starting snapshot', sourcePath, mirrorPath);
|
|
48
44
|
try {
|
|
49
|
-
await (
|
|
50
|
-
log.info('Files synced', mirrorPath);
|
|
51
|
-
const snapshotterDir = path_1.default.join(mirrorPath, '.snapshotter');
|
|
52
|
-
(0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
|
|
53
|
-
(0, fs_1.writeFileSync)(path_1.default.join(snapshotterDir, 'testResults.json'), JSON.stringify(sortTestResults(testResults), null, 2));
|
|
54
|
-
log.info('Test results saved', snapshotterDir);
|
|
55
|
-
const committed = await (0, git_js_1.gitCommit)(mirrorPath, log);
|
|
56
|
-
if (!committed) {
|
|
57
|
-
log.info('No changes to commit', mirrorPath);
|
|
58
|
-
clearError(mirrorPath);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
log.info('Commit created, pushing', remote.url);
|
|
62
|
-
await (0, git_js_1.gitPush)(mirrorPath, remote, log);
|
|
63
|
-
log.info('Push completed', remote.url);
|
|
64
|
-
clearError(mirrorPath);
|
|
45
|
+
await SyncStrategy_js_1.default.Strategy().execute(options);
|
|
65
46
|
}
|
|
66
47
|
catch (err) {
|
|
67
48
|
const message = err instanceof Error ? err.message : String(err);
|
|
68
49
|
log.error('Snapshot failed (will surface on next test run)', message);
|
|
69
|
-
persistError(mirrorPath, err);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function persistError(mirrorPath, err) {
|
|
73
|
-
const snapshotterDir = path_1.default.join(mirrorPath, '.snapshotter');
|
|
74
|
-
(0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
|
|
75
|
-
const errorPath = getErrorFilePath(mirrorPath);
|
|
76
|
-
const errorData = {
|
|
77
|
-
message: err instanceof Error ? err.message : String(err),
|
|
78
|
-
stack: err instanceof Error ? err.stack : undefined,
|
|
79
|
-
timestamp: new Date().toISOString(),
|
|
80
|
-
};
|
|
81
|
-
(0, fs_1.writeFileSync)(errorPath, JSON.stringify(errorData, null, 2));
|
|
82
|
-
}
|
|
83
|
-
function clearError(mirrorPath) {
|
|
84
|
-
const errorPath = getErrorFilePath(mirrorPath);
|
|
85
|
-
if ((0, fs_1.existsSync)(errorPath)) {
|
|
86
|
-
(0, fs_1.unlinkSync)(errorPath);
|
|
50
|
+
ErrorHandler_js_1.default.Handler().persistError(options.mirrorPath, err);
|
|
87
51
|
}
|
|
88
52
|
}
|
|
89
|
-
function getErrorFilePath(mirrorPath) {
|
|
90
|
-
return path_1.default.join(mirrorPath, '.snapshotter', ERROR_FILE_NAME);
|
|
91
|
-
}
|
|
92
|
-
function sortTestResults(testResults) {
|
|
93
|
-
const suites = [...testResults.suites].map((suite) => ({
|
|
94
|
-
...suite,
|
|
95
|
-
tests: [...suite.tests].sort((left, right) => left.name.localeCompare(right.name)),
|
|
96
|
-
}));
|
|
97
|
-
suites.sort((left, right) => left.path.localeCompare(right.path));
|
|
98
|
-
const typeErrors = testResults.typeErrors
|
|
99
|
-
? [...testResults.typeErrors].sort((left, right) => {
|
|
100
|
-
const fileCompare = left.file.localeCompare(right.file);
|
|
101
|
-
if (fileCompare !== 0) {
|
|
102
|
-
return fileCompare;
|
|
103
|
-
}
|
|
104
|
-
const lineCompare = left.line - right.line;
|
|
105
|
-
if (lineCompare !== 0) {
|
|
106
|
-
return lineCompare;
|
|
107
|
-
}
|
|
108
|
-
return left.column - right.column;
|
|
109
|
-
})
|
|
110
|
-
: undefined;
|
|
111
|
-
return {
|
|
112
|
-
...testResults,
|
|
113
|
-
suites,
|
|
114
|
-
typeErrors,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
53
|
main().catch((err) => {
|
|
118
54
|
console.error('Snapshot script failed:', err);
|
|
119
55
|
process.exit(1);
|
|
@@ -14,7 +14,8 @@ async function main() {
|
|
|
14
14
|
console.log(' Source:', sourcePath);
|
|
15
15
|
console.log(' Mirror:', mirrorPath);
|
|
16
16
|
console.log(' Remote:', remoteUrl);
|
|
17
|
-
const
|
|
17
|
+
const snapshotter = index_1.Snapshotter.Snapshotter({ mode: 'sync' });
|
|
18
|
+
await snapshotter.snapshot({
|
|
18
19
|
sourcePath,
|
|
19
20
|
mirrorPath,
|
|
20
21
|
testResults: {
|
|
@@ -43,7 +44,7 @@ async function main() {
|
|
|
43
44
|
token: remoteToken,
|
|
44
45
|
},
|
|
45
46
|
});
|
|
46
|
-
console.log('Snapshot
|
|
47
|
+
console.log('Snapshot completed');
|
|
47
48
|
}
|
|
48
49
|
main().catch((err) => {
|
|
49
50
|
console.error('Error:', err.message);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SnapshotOptions } from '../snapshotter.types.js';
|
|
2
|
+
import SnapshotStrategy from './SnapshotStrategy.js';
|
|
3
|
+
export default class AsyncStrategy implements SnapshotStrategy {
|
|
4
|
+
private log;
|
|
5
|
+
private scriptPath;
|
|
6
|
+
private constructor();
|
|
7
|
+
static Strategy(): AsyncStrategy;
|
|
8
|
+
execute(options: SnapshotOptions): void;
|
|
9
|
+
private writeOptionsFile;
|
|
10
|
+
private spawnSnapshotProcess;
|
|
11
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
|
|
10
|
+
class AsyncStrategy {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.log = (0, spruce_skill_utils_1.buildLog)('Snapshotter');
|
|
13
|
+
this.scriptPath = path_1.default.join(__dirname, '..', 'scripts', 'runSnapshot.js');
|
|
14
|
+
}
|
|
15
|
+
static Strategy() {
|
|
16
|
+
return new this();
|
|
17
|
+
}
|
|
18
|
+
execute(options) {
|
|
19
|
+
const snapshotterDir = this.writeOptionsFile(options);
|
|
20
|
+
this.spawnSnapshotProcess(snapshotterDir);
|
|
21
|
+
this.log.info('Snapshot queued (running in background)', options.mirrorPath);
|
|
22
|
+
}
|
|
23
|
+
writeOptionsFile(options) {
|
|
24
|
+
const snapshotterDir = path_1.default.join(options.mirrorPath, '.snapshotter');
|
|
25
|
+
(0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
|
|
26
|
+
const optionsPath = path_1.default.join(snapshotterDir, 'pending.json');
|
|
27
|
+
(0, fs_1.writeFileSync)(optionsPath, JSON.stringify(options, null, 2));
|
|
28
|
+
return snapshotterDir;
|
|
29
|
+
}
|
|
30
|
+
spawnSnapshotProcess(snapshotterDir) {
|
|
31
|
+
const child = (0, child_process_1.spawn)('node', [this.scriptPath, snapshotterDir], {
|
|
32
|
+
detached: true,
|
|
33
|
+
stdio: 'ignore',
|
|
34
|
+
});
|
|
35
|
+
child.unref();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.default = AsyncStrategy;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SnapshotOptions } from '../snapshotter.types.js';
|
|
2
|
+
import SnapshotStrategy from './SnapshotStrategy.js';
|
|
3
|
+
export default class SyncStrategy implements SnapshotStrategy {
|
|
4
|
+
private log;
|
|
5
|
+
private pushScriptPath;
|
|
6
|
+
private constructor();
|
|
7
|
+
static Strategy(): SyncStrategy;
|
|
8
|
+
execute(options: SnapshotOptions): Promise<void>;
|
|
9
|
+
private spawnPushProcess;
|
|
10
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
|
|
9
|
+
const ErrorHandler_js_1 = __importDefault(require("../components/ErrorHandler.js"));
|
|
10
|
+
const FileSyncer_js_1 = __importDefault(require("../components/FileSyncer.js"));
|
|
11
|
+
const TestResultsWriter_js_1 = __importDefault(require("../components/TestResultsWriter.js"));
|
|
12
|
+
const git_js_1 = require("../git.js");
|
|
13
|
+
class SyncStrategy {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.log = (0, spruce_skill_utils_1.buildLog)('Snapshotter');
|
|
16
|
+
this.pushScriptPath = path_1.default.join(__dirname, '..', 'scripts', 'runPush.js');
|
|
17
|
+
}
|
|
18
|
+
static Strategy() {
|
|
19
|
+
return new this();
|
|
20
|
+
}
|
|
21
|
+
async execute(options) {
|
|
22
|
+
const sourcePath = options.sourcePath ?? process.cwd();
|
|
23
|
+
const { mirrorPath, testResults, remote } = options;
|
|
24
|
+
this.log.info('Starting snapshot', sourcePath, mirrorPath);
|
|
25
|
+
try {
|
|
26
|
+
await FileSyncer_js_1.default.Syncer().sync(sourcePath, mirrorPath);
|
|
27
|
+
this.log.info('Files synced', mirrorPath);
|
|
28
|
+
TestResultsWriter_js_1.default.Writer().write(mirrorPath, testResults);
|
|
29
|
+
this.log.info('Test results saved', mirrorPath);
|
|
30
|
+
const committed = await (0, git_js_1.gitCommit)(mirrorPath, this.log);
|
|
31
|
+
if (!committed) {
|
|
32
|
+
this.log.info('No changes to commit', mirrorPath);
|
|
33
|
+
ErrorHandler_js_1.default.Handler().clearError(mirrorPath);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.log.info('Commit created, queueing push', remote.url);
|
|
37
|
+
this.spawnPushProcess(mirrorPath, remote);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
this.log.error('Snapshot failed', message);
|
|
42
|
+
ErrorHandler_js_1.default.Handler().persistError(mirrorPath, err);
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
spawnPushProcess(mirrorPath, remote) {
|
|
47
|
+
const child = (0, child_process_1.spawn)('node', [this.pushScriptPath], {
|
|
48
|
+
detached: true,
|
|
49
|
+
stdio: 'ignore',
|
|
50
|
+
env: {
|
|
51
|
+
...process.env,
|
|
52
|
+
MIRROR_PATH: mirrorPath,
|
|
53
|
+
REMOTE_URL: remote.url,
|
|
54
|
+
REMOTE_TOKEN: remote.token,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
child.unref();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.default = SyncStrategy;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@regressionproof/snapshotter",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
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": "
|
|
97
|
+
"gitHead": "a557f1266fcb9720f9551efb6fa6523e7390101e"
|
|
98
98
|
}
|
package/build/esm/snapshot.d.ts
DELETED
package/build/esm/snapshot.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { buildLog } from '@sprucelabs/spruce-skill-utils';
|
|
5
|
-
const ERROR_FILE_NAME = 'lastError.json';
|
|
6
|
-
const log = buildLog('Snapshotter');
|
|
7
|
-
const scriptPath = path.join(__dirname, 'scripts', 'runSnapshot.js');
|
|
8
|
-
export function snapshot(options) {
|
|
9
|
-
const snapshotterDir = writeOptionsFile(options);
|
|
10
|
-
spawnSnapshotProcess(snapshotterDir);
|
|
11
|
-
log.info('Snapshot queued (running in background)', options.mirrorPath);
|
|
12
|
-
}
|
|
13
|
-
export function checkForPreviousSnapshotFailure(mirrorPath) {
|
|
14
|
-
const errorPath = getErrorFilePath(mirrorPath);
|
|
15
|
-
if (existsSync(errorPath)) {
|
|
16
|
-
const errorData = JSON.parse(readFileSync(errorPath, 'utf-8'));
|
|
17
|
-
unlinkSync(errorPath);
|
|
18
|
-
throw new Error(`Previous snapshot failed: ${errorData.message}\n` +
|
|
19
|
-
`Timestamp: ${errorData.timestamp}\n` +
|
|
20
|
-
`This error was from a background snapshot that failed. ` +
|
|
21
|
-
`The snapshot has been retried - if this error persists, check your configuration.`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function writeOptionsFile(options) {
|
|
25
|
-
const snapshotterDir = path.join(options.mirrorPath, '.snapshotter');
|
|
26
|
-
mkdirSync(snapshotterDir, { recursive: true });
|
|
27
|
-
const optionsPath = path.join(snapshotterDir, 'pending.json');
|
|
28
|
-
writeFileSync(optionsPath, JSON.stringify(options, null, 2));
|
|
29
|
-
return snapshotterDir;
|
|
30
|
-
}
|
|
31
|
-
function spawnSnapshotProcess(snapshotterDir) {
|
|
32
|
-
const child = spawn('node', [scriptPath, snapshotterDir], {
|
|
33
|
-
detached: true,
|
|
34
|
-
stdio: 'ignore',
|
|
35
|
-
});
|
|
36
|
-
child.unref();
|
|
37
|
-
}
|
|
38
|
-
function getErrorFilePath(mirrorPath) {
|
|
39
|
-
return path.join(mirrorPath, '.snapshotter', ERROR_FILE_NAME);
|
|
40
|
-
}
|
package/build/esm/sync.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function syncFiles(sourcePath: string, mirrorPath: string): Promise<void>;
|
package/build/snapshot.d.ts
DELETED
package/build/snapshot.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.snapshot = snapshot;
|
|
7
|
-
exports.checkForPreviousSnapshotFailure = checkForPreviousSnapshotFailure;
|
|
8
|
-
const child_process_1 = require("child_process");
|
|
9
|
-
const fs_1 = require("fs");
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
|
|
12
|
-
const ERROR_FILE_NAME = 'lastError.json';
|
|
13
|
-
const log = (0, spruce_skill_utils_1.buildLog)('Snapshotter');
|
|
14
|
-
const scriptPath = path_1.default.join(__dirname, 'scripts', 'runSnapshot.js');
|
|
15
|
-
function snapshot(options) {
|
|
16
|
-
const snapshotterDir = writeOptionsFile(options);
|
|
17
|
-
spawnSnapshotProcess(snapshotterDir);
|
|
18
|
-
log.info('Snapshot queued (running in background)', options.mirrorPath);
|
|
19
|
-
}
|
|
20
|
-
function checkForPreviousSnapshotFailure(mirrorPath) {
|
|
21
|
-
const errorPath = getErrorFilePath(mirrorPath);
|
|
22
|
-
if ((0, fs_1.existsSync)(errorPath)) {
|
|
23
|
-
const errorData = JSON.parse((0, fs_1.readFileSync)(errorPath, 'utf-8'));
|
|
24
|
-
(0, fs_1.unlinkSync)(errorPath);
|
|
25
|
-
throw new Error(`Previous snapshot failed: ${errorData.message}\n` +
|
|
26
|
-
`Timestamp: ${errorData.timestamp}\n` +
|
|
27
|
-
`This error was from a background snapshot that failed. ` +
|
|
28
|
-
`The snapshot has been retried - if this error persists, check your configuration.`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function writeOptionsFile(options) {
|
|
32
|
-
const snapshotterDir = path_1.default.join(options.mirrorPath, '.snapshotter');
|
|
33
|
-
(0, fs_1.mkdirSync)(snapshotterDir, { recursive: true });
|
|
34
|
-
const optionsPath = path_1.default.join(snapshotterDir, 'pending.json');
|
|
35
|
-
(0, fs_1.writeFileSync)(optionsPath, JSON.stringify(options, null, 2));
|
|
36
|
-
return snapshotterDir;
|
|
37
|
-
}
|
|
38
|
-
function spawnSnapshotProcess(snapshotterDir) {
|
|
39
|
-
const child = (0, child_process_1.spawn)('node', [scriptPath, snapshotterDir], {
|
|
40
|
-
detached: true,
|
|
41
|
-
stdio: 'ignore',
|
|
42
|
-
});
|
|
43
|
-
child.unref();
|
|
44
|
-
}
|
|
45
|
-
function getErrorFilePath(mirrorPath) {
|
|
46
|
-
return path_1.default.join(mirrorPath, '.snapshotter', ERROR_FILE_NAME);
|
|
47
|
-
}
|
package/build/sync.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function syncFiles(sourcePath: string, mirrorPath: string): Promise<void>;
|