@reshotdev/screenshot 0.0.1-beta.2 → 0.0.1-beta.6
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/README.md +2 -2
- package/package.json +9 -2
- package/src/commands/auth.js +1 -3
- package/src/commands/ci-setup.js +2 -2
- package/src/commands/drifts.js +5 -70
- package/src/commands/import-tests.js +13 -13
- package/src/commands/ingest.js +10 -10
- package/src/commands/init.js +16 -277
- package/src/commands/publish.js +3 -204
- package/src/commands/pull.js +2 -2
- package/src/commands/setup-wizard.js +123 -523
- package/src/commands/setup.js +7 -7
- package/src/commands/status.js +26 -43
- package/src/commands/sync.js +28 -236
- package/src/commands/ui.js +1 -1
- package/src/index.js +9 -90
- package/src/lib/api-client.js +8 -8
- package/src/lib/capture-engine.js +3 -3
- package/src/lib/capture-script-runner.js +27 -37
- package/src/lib/config.js +8 -72
- package/src/lib/record-config.js +1 -1
- package/src/lib/standalone-mode.js +1 -1
- package/src/lib/storage-providers.js +4 -4
- package/src/lib/ui-api.js +3 -3
- package/web/manager/dist/assets/{index--ZgioErz.js → index-8H7P9ANi.js} +1 -1
- package/web/manager/dist/index.html +1 -1
- package/src/commands/validate-docs.js +0 -529
package/src/commands/setup.js
CHANGED
|
@@ -12,13 +12,13 @@ const {
|
|
|
12
12
|
} = require("../lib/config");
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Create a default
|
|
15
|
+
* Create a default reshot.config.json for platform mode
|
|
16
16
|
* @param {Object} settings - Project settings from auth
|
|
17
17
|
* @returns {Object} The created config
|
|
18
18
|
*/
|
|
19
19
|
function createDefaultConfig(settings) {
|
|
20
20
|
const defaultConfig = {
|
|
21
|
-
$schema: "https://reshot.dev/schemas/
|
|
21
|
+
$schema: "https://reshot.dev/schemas/reshot-config.json",
|
|
22
22
|
version: "2.0",
|
|
23
23
|
projectId: settings.projectId,
|
|
24
24
|
baseUrl: "http://localhost:3000",
|
|
@@ -94,22 +94,22 @@ async function setupCommand(options = {}) {
|
|
|
94
94
|
console.log(); // Add spacing after auth
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
// Step 3: Handle initialization (create
|
|
97
|
+
// Step 3: Handle initialization (create reshot.config.json if missing)
|
|
98
98
|
const hasConfig = configExists();
|
|
99
99
|
|
|
100
100
|
if (hasConfig && !force) {
|
|
101
|
-
console.log(chalk.green("✔ Configuration found:"), chalk.cyan("
|
|
101
|
+
console.log(chalk.green("✔ Configuration found:"), chalk.cyan("reshot.config.json"));
|
|
102
102
|
} else if (hasConfig && force) {
|
|
103
|
-
console.log(chalk.yellow("⚠ Overwriting existing
|
|
103
|
+
console.log(chalk.yellow("⚠ Overwriting existing reshot.config.json..."));
|
|
104
104
|
const newConfig = createDefaultConfig(existingSettings);
|
|
105
105
|
writeConfig(newConfig);
|
|
106
106
|
console.log(chalk.green("✔ Configuration updated"));
|
|
107
107
|
} else {
|
|
108
108
|
// No config - create it
|
|
109
|
-
console.log(chalk.gray("Creating
|
|
109
|
+
console.log(chalk.gray("Creating reshot.config.json..."));
|
|
110
110
|
const newConfig = createDefaultConfig(existingSettings);
|
|
111
111
|
writeConfig(newConfig);
|
|
112
|
-
console.log(chalk.green("✔ Configuration created:"), chalk.cyan("
|
|
112
|
+
console.log(chalk.green("✔ Configuration created:"), chalk.cyan("reshot.config.json"));
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// Step 4: Success summary
|
package/src/commands/status.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* status - Check
|
|
3
|
+
* status - Check project status, sync jobs, and drift queue
|
|
4
4
|
*
|
|
5
5
|
* Displays:
|
|
6
6
|
* - Current project configuration
|
|
7
7
|
* - Recent sync jobs with status
|
|
8
8
|
* - Drift queue summary
|
|
9
|
-
* - Pending actions
|
|
10
9
|
*
|
|
11
|
-
* Usage: reshot status [--jobs] [--drifts] [--json]
|
|
10
|
+
* Usage: reshot status [--jobs] [--drifts] [--config] [--json]
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
13
|
const chalk = require("chalk");
|
|
@@ -86,32 +85,24 @@ function formatDriftType(type) {
|
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
/**
|
|
89
|
-
*
|
|
88
|
+
* Display project configuration summary
|
|
90
89
|
*/
|
|
91
|
-
async function displayConfig(
|
|
90
|
+
async function displayConfig(reshotConfig) {
|
|
92
91
|
console.log(chalk.bold("\n📋 Project Configuration\n"));
|
|
93
92
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
console.log(chalk.gray(" Base URL: ") + chalk.white(reshotConfig.baseUrl || "(not set)"));
|
|
94
|
+
console.log(chalk.gray(" Viewport: ") + chalk.white(
|
|
95
|
+
reshotConfig.viewport
|
|
96
|
+
? `${reshotConfig.viewport.width}×${reshotConfig.viewport.height}`
|
|
97
|
+
: "(default)"
|
|
98
|
+
));
|
|
99
|
+
console.log(chalk.gray(" Asset Dir: ") + chalk.white(reshotConfig.assetDir || ".reshot/output"));
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
console.log(chalk.gray("
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
console.log(chalk.gray(" Include: ") + chalk.white(docConfig.include.join(", ")));
|
|
107
|
-
}
|
|
108
|
-
if (docConfig.exclude?.length) {
|
|
109
|
-
console.log(chalk.gray(" Exclude: ") + chalk.white(docConfig.exclude.join(", ")));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const mappingCount = Object.keys(docConfig.mappings || {}).length;
|
|
113
|
-
if (mappingCount > 0) {
|
|
114
|
-
console.log(chalk.gray(" Mappings: ") + chalk.white(`${mappingCount} explicit binding(s)`));
|
|
101
|
+
const scenarioCount = reshotConfig.scenarios?.length || 0;
|
|
102
|
+
console.log(chalk.gray(" Scenarios: ") + chalk.white(`${scenarioCount} defined`));
|
|
103
|
+
|
|
104
|
+
if (reshotConfig.visuals?.traceDir) {
|
|
105
|
+
console.log(chalk.gray(" Trace Dir: ") + chalk.white(reshotConfig.visuals.traceDir));
|
|
115
106
|
}
|
|
116
107
|
}
|
|
117
108
|
|
|
@@ -122,14 +113,12 @@ async function displayJobs(apiKey, projectId, limit = 5) {
|
|
|
122
113
|
console.log(chalk.bold("\n📦 Recent Sync Jobs\n"));
|
|
123
114
|
|
|
124
115
|
try {
|
|
125
|
-
// Fetch jobs via API
|
|
126
116
|
const response = await apiClient.getSyncJobs(apiKey, projectId, { limit });
|
|
127
|
-
|
|
128
117
|
const jobs = response.jobs || response.data?.jobs || [];
|
|
129
118
|
|
|
130
119
|
if (jobs.length === 0) {
|
|
131
120
|
console.log(chalk.gray(" No sync jobs found."));
|
|
132
|
-
console.log(chalk.gray(" Run `reshot
|
|
121
|
+
console.log(chalk.gray(" Run `reshot sync` to upload traces."));
|
|
133
122
|
return;
|
|
134
123
|
}
|
|
135
124
|
|
|
@@ -140,7 +129,7 @@ async function displayJobs(apiKey, projectId, limit = 5) {
|
|
|
140
129
|
chalk.white(`${job.branch || "unknown"}@${(job.commitHash || "").slice(0, 7)} `) +
|
|
141
130
|
chalk.gray(formatTime(job.createdAt))
|
|
142
131
|
);
|
|
143
|
-
|
|
132
|
+
|
|
144
133
|
if (job.driftCount > 0) {
|
|
145
134
|
console.log(chalk.gray(` └─ ${job.driftCount} drift(s) detected`));
|
|
146
135
|
}
|
|
@@ -179,7 +168,6 @@ async function displayDrifts(apiKey, projectId, limit = 10) {
|
|
|
179
168
|
|
|
180
169
|
if (drifts.length === 0) {
|
|
181
170
|
console.log(chalk.green(" ✓ No pending drifts!"));
|
|
182
|
-
console.log(chalk.gray(" Your documentation is in sync with the application."));
|
|
183
171
|
return;
|
|
184
172
|
}
|
|
185
173
|
|
|
@@ -188,13 +176,9 @@ async function displayDrifts(apiKey, projectId, limit = 10) {
|
|
|
188
176
|
for (const drift of displayed) {
|
|
189
177
|
console.log(
|
|
190
178
|
` ${formatDriftType(drift.driftType)} ` +
|
|
191
|
-
chalk.white(drift.journeyKey
|
|
179
|
+
chalk.white(drift.journeyKey) + " " +
|
|
192
180
|
chalk.gray(`(${Math.round(drift.confidenceScore * 100)}% confidence)`)
|
|
193
181
|
);
|
|
194
|
-
|
|
195
|
-
if (drift.docPath) {
|
|
196
|
-
console.log(chalk.gray(` └─ ${drift.docPath}`));
|
|
197
|
-
}
|
|
198
182
|
}
|
|
199
183
|
|
|
200
184
|
if (drifts.length > limit) {
|
|
@@ -202,7 +186,7 @@ async function displayDrifts(apiKey, projectId, limit = 10) {
|
|
|
202
186
|
}
|
|
203
187
|
|
|
204
188
|
console.log();
|
|
205
|
-
console.log(chalk.gray(" View in dashboard: ") + chalk.blue(`https://reshot.dev/app/projects/${projectId}/
|
|
189
|
+
console.log(chalk.gray(" View in dashboard: ") + chalk.blue(`https://reshot.dev/app/projects/${projectId}/visuals`));
|
|
206
190
|
} catch (error) {
|
|
207
191
|
console.log(chalk.yellow(" Could not fetch drifts: " + error.message));
|
|
208
192
|
}
|
|
@@ -212,14 +196,14 @@ async function displayDrifts(apiKey, projectId, limit = 10) {
|
|
|
212
196
|
* Main status command
|
|
213
197
|
*/
|
|
214
198
|
async function statusCommand(options = {}) {
|
|
215
|
-
console.log(chalk.blue("\n📊 Reshot
|
|
199
|
+
console.log(chalk.blue("\n📊 Reshot Status\n"));
|
|
216
200
|
|
|
217
201
|
// Read configuration
|
|
218
|
-
let
|
|
202
|
+
let reshotConfig;
|
|
219
203
|
try {
|
|
220
|
-
|
|
204
|
+
reshotConfig = config.readConfigLenient();
|
|
221
205
|
} catch (error) {
|
|
222
|
-
console.error(chalk.red("Error:"), "
|
|
206
|
+
console.error(chalk.red("Error:"), "reshot.config.json not found. Run `reshot init` first.");
|
|
223
207
|
process.exit(1);
|
|
224
208
|
}
|
|
225
209
|
|
|
@@ -229,7 +213,7 @@ async function statusCommand(options = {}) {
|
|
|
229
213
|
const projectId =
|
|
230
214
|
process.env.RESHOT_PROJECT_ID ||
|
|
231
215
|
settings?.projectId ||
|
|
232
|
-
|
|
216
|
+
reshotConfig._metadata?.projectId;
|
|
233
217
|
|
|
234
218
|
if (!apiKey) {
|
|
235
219
|
console.error(chalk.red("Error:"), "API key not found. Set RESHOT_API_KEY or run `reshot auth`.");
|
|
@@ -245,7 +229,7 @@ async function statusCommand(options = {}) {
|
|
|
245
229
|
|
|
246
230
|
// Display configuration
|
|
247
231
|
if (options.config || (!options.jobs && !options.drifts)) {
|
|
248
|
-
await displayConfig(
|
|
232
|
+
await displayConfig(reshotConfig);
|
|
249
233
|
}
|
|
250
234
|
|
|
251
235
|
// Display jobs
|
|
@@ -263,7 +247,6 @@ async function statusCommand(options = {}) {
|
|
|
263
247
|
const response = await apiClient.getDrifts(apiKey, projectId).catch(() => ({}));
|
|
264
248
|
console.log(JSON.stringify({
|
|
265
249
|
projectId,
|
|
266
|
-
config: docSyncConfig.documentation,
|
|
267
250
|
drifts: response.drifts || [],
|
|
268
251
|
stats: response.stats || {},
|
|
269
252
|
}, null, 2));
|
package/src/commands/sync.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
// sync.js - Upload Playwright traces
|
|
2
|
-
// This is the renamed/enhanced version of ingest.js
|
|
3
|
-
// Implements the "Smart Handoff" protocol from the DocSync specification
|
|
1
|
+
// sync.js - Upload Playwright traces to Reshot platform
|
|
4
2
|
|
|
5
3
|
const chalk = require("chalk");
|
|
6
4
|
const crypto = require("crypto");
|
|
@@ -9,127 +7,12 @@ const path = require("path");
|
|
|
9
7
|
const { execSync } = require("child_process");
|
|
10
8
|
const config = require("../lib/config");
|
|
11
9
|
const apiClient = require("../lib/api-client");
|
|
12
|
-
const { hashFile } = require("../lib/hash");
|
|
13
10
|
const pkg = require("../../package.json");
|
|
14
11
|
|
|
15
12
|
// File extension allowlists
|
|
16
13
|
const TRACE_EXTENSIONS = [".zip"];
|
|
17
|
-
const DOC_EXTENSIONS = [".md", ".mdx"];
|
|
18
|
-
const MAX_DOC_SIZE = 5 * 1024 * 1024; // 5MB per doc file
|
|
19
14
|
const MAX_TRACE_SIZE = 100 * 1024 * 1024; // 100MB per trace
|
|
20
15
|
|
|
21
|
-
/**
|
|
22
|
-
* Parse frontmatter from a markdown file
|
|
23
|
-
*/
|
|
24
|
-
function parseFrontmatter(content) {
|
|
25
|
-
const frontmatterRegex = /^---\n([\s\S]*?)\n---/;
|
|
26
|
-
const match = content.match(frontmatterRegex);
|
|
27
|
-
|
|
28
|
-
if (!match) return { frontmatter: {}, content };
|
|
29
|
-
|
|
30
|
-
const frontmatter = {};
|
|
31
|
-
const lines = match[1].split("\n");
|
|
32
|
-
|
|
33
|
-
for (const line of lines) {
|
|
34
|
-
const colonIndex = line.indexOf(":");
|
|
35
|
-
if (colonIndex > 0) {
|
|
36
|
-
const key = line.slice(0, colonIndex).trim();
|
|
37
|
-
let value = line.slice(colonIndex + 1).trim();
|
|
38
|
-
if (
|
|
39
|
-
(value.startsWith('"') && value.endsWith('"')) ||
|
|
40
|
-
(value.startsWith("'") && value.endsWith("'"))
|
|
41
|
-
) {
|
|
42
|
-
value = value.slice(1, -1);
|
|
43
|
-
}
|
|
44
|
-
frontmatter[key] = value;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
frontmatter,
|
|
50
|
-
content: content.slice(match[0].length).trim(),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Discover documentation files based on config
|
|
56
|
-
*/
|
|
57
|
-
async function discoverDocumentation(docConfig, projectRoot) {
|
|
58
|
-
const files = [];
|
|
59
|
-
const root = path.resolve(projectRoot, docConfig.root || "./docs");
|
|
60
|
-
|
|
61
|
-
if (!fs.existsSync(root)) {
|
|
62
|
-
return files;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const include = docConfig.include || ["**/*.md", "**/*.mdx"];
|
|
66
|
-
const exclude = docConfig.exclude || ["**/_*.mdx", "node_modules"];
|
|
67
|
-
const mappings = docConfig.mappings || {};
|
|
68
|
-
|
|
69
|
-
function walkDir(dir, relativePath = "") {
|
|
70
|
-
const items = fs.readdirSync(dir);
|
|
71
|
-
|
|
72
|
-
for (const item of items) {
|
|
73
|
-
const fullPath = path.join(dir, item);
|
|
74
|
-
const relPath = path.join(relativePath, item);
|
|
75
|
-
const stat = fs.statSync(fullPath);
|
|
76
|
-
|
|
77
|
-
const shouldExclude = exclude.some((pattern) => {
|
|
78
|
-
if (pattern.includes("*")) {
|
|
79
|
-
const regex = new RegExp(
|
|
80
|
-
pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"),
|
|
81
|
-
);
|
|
82
|
-
return regex.test(relPath);
|
|
83
|
-
}
|
|
84
|
-
return relPath.includes(pattern) || item === pattern;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
if (shouldExclude) continue;
|
|
88
|
-
|
|
89
|
-
if (stat.isDirectory()) {
|
|
90
|
-
walkDir(fullPath, relPath);
|
|
91
|
-
} else {
|
|
92
|
-
const ext = path.extname(item).toLowerCase();
|
|
93
|
-
if (DOC_EXTENSIONS.includes(ext)) {
|
|
94
|
-
const content = fs.readFileSync(fullPath, "utf-8");
|
|
95
|
-
const { frontmatter } = parseFrontmatter(content);
|
|
96
|
-
|
|
97
|
-
const journeyKey =
|
|
98
|
-
frontmatter.reshot_journey ||
|
|
99
|
-
mappings[relPath] ||
|
|
100
|
-
mappings[fullPath];
|
|
101
|
-
|
|
102
|
-
if (journeyKey) {
|
|
103
|
-
const fileSize = stat.size;
|
|
104
|
-
|
|
105
|
-
if (fileSize > MAX_DOC_SIZE) {
|
|
106
|
-
console.log(
|
|
107
|
-
chalk.yellow(` ⚠ Skipping ${relPath}: exceeds size limit`),
|
|
108
|
-
);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
files.push({
|
|
113
|
-
path: fullPath,
|
|
114
|
-
relativePath: relPath,
|
|
115
|
-
journeyKey,
|
|
116
|
-
contentHash: crypto
|
|
117
|
-
.createHash("sha256")
|
|
118
|
-
.update(content)
|
|
119
|
-
.digest("hex"),
|
|
120
|
-
size: fileSize,
|
|
121
|
-
frontmatter,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
walkDir(root);
|
|
130
|
-
return files;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
16
|
/**
|
|
134
17
|
* Extract journey key from Playwright test-results directory name
|
|
135
18
|
* Playwright creates directories like: "test-name-chromium" or "describe-test-name-chromium"
|
|
@@ -191,11 +74,6 @@ function extractJourneyKey(dirName, journeyMappings = {}) {
|
|
|
191
74
|
}
|
|
192
75
|
|
|
193
76
|
// Check if the key parts of the test name appear in both
|
|
194
|
-
// Match "student-login-successfully" to pattern "should-complete-student-login-successfully"
|
|
195
|
-
const patternStr = pattern.toLowerCase();
|
|
196
|
-
const normalizedStr = normalized;
|
|
197
|
-
|
|
198
|
-
// Extract meaningful words (4+ chars) and check overlap
|
|
199
77
|
const meaningfulFromPattern = patternParts.filter((p) => p.length >= 4);
|
|
200
78
|
const meaningfulFromDir = normalizedParts.filter((p) => p.length >= 4);
|
|
201
79
|
|
|
@@ -323,28 +201,24 @@ function getGitMetadata() {
|
|
|
323
201
|
* Main sync command
|
|
324
202
|
* @param {Object} options - Command options
|
|
325
203
|
* @param {string} options.traceDir - Override trace directory
|
|
326
|
-
* @param {boolean} options.traces - Sync traces only
|
|
327
|
-
* @param {boolean} options.docs - Sync documentation only
|
|
328
204
|
* @param {boolean} options.dryRun - Preview without uploading
|
|
329
205
|
* @param {boolean} options.verbose - Show detailed output
|
|
330
206
|
*/
|
|
331
207
|
async function syncCommand(options = {}) {
|
|
332
208
|
const {
|
|
333
209
|
traceDir: traceDirOverride,
|
|
334
|
-
traces: tracesOnly = false,
|
|
335
|
-
docs: docsOnly = false,
|
|
336
210
|
dryRun = false,
|
|
337
211
|
verbose = false,
|
|
338
212
|
} = options;
|
|
339
213
|
|
|
340
214
|
console.log(chalk.cyan.bold("\n🔄 Reshot Sync\n"));
|
|
341
215
|
|
|
342
|
-
// Load configuration
|
|
343
|
-
let
|
|
216
|
+
// Load configuration
|
|
217
|
+
let reshotConfig;
|
|
344
218
|
try {
|
|
345
|
-
|
|
219
|
+
reshotConfig = config.readConfigLenient();
|
|
346
220
|
} catch (error) {
|
|
347
|
-
console.error(chalk.red("✖ No
|
|
221
|
+
console.error(chalk.red("✖ No reshot.config.json found."));
|
|
348
222
|
console.log(
|
|
349
223
|
chalk.gray(" Run"),
|
|
350
224
|
chalk.cyan("reshot setup"),
|
|
@@ -361,7 +235,7 @@ async function syncCommand(options = {}) {
|
|
|
361
235
|
settings = null;
|
|
362
236
|
}
|
|
363
237
|
|
|
364
|
-
const projectId =
|
|
238
|
+
const projectId = reshotConfig.projectId || settings?.projectId;
|
|
365
239
|
const apiKey = settings?.apiKey;
|
|
366
240
|
|
|
367
241
|
if (!projectId || !apiKey) {
|
|
@@ -374,99 +248,55 @@ async function syncCommand(options = {}) {
|
|
|
374
248
|
process.exit(1);
|
|
375
249
|
}
|
|
376
250
|
|
|
377
|
-
const features = docSyncConfig._metadata?.features || {
|
|
378
|
-
visuals: true,
|
|
379
|
-
docsync: true,
|
|
380
|
-
};
|
|
381
251
|
const projectRoot = process.cwd();
|
|
382
252
|
|
|
383
|
-
// Determine what to sync
|
|
384
|
-
const syncTraces = !docsOnly && features.visuals !== false;
|
|
385
|
-
const syncDocs =
|
|
386
|
-
!tracesOnly && features.docsync !== false && docSyncConfig.documentation;
|
|
387
|
-
|
|
388
253
|
if (dryRun) {
|
|
389
254
|
console.log(chalk.yellow("DRY RUN - No files will be uploaded\n"));
|
|
390
255
|
}
|
|
391
256
|
|
|
392
|
-
let traceFiles = [];
|
|
393
|
-
let docFiles = [];
|
|
394
|
-
|
|
395
257
|
// ========================================
|
|
396
258
|
// PHASE 1: Discover Traces
|
|
397
259
|
// ========================================
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const journeyMappings = docSyncConfig.visuals?.journeyMappings || {};
|
|
403
|
-
|
|
404
|
-
console.log(chalk.gray(`Scanning traces: ${traceDir}`));
|
|
405
|
-
traceFiles = await discoverTraces(resolvedTraceDir, journeyMappings);
|
|
406
|
-
|
|
407
|
-
if (traceFiles.length === 0) {
|
|
408
|
-
console.log(chalk.yellow(" No trace files found"));
|
|
409
|
-
if (!fs.existsSync(resolvedTraceDir)) {
|
|
410
|
-
console.log(
|
|
411
|
-
chalk.gray(" Run your Playwright tests first: npx playwright test"),
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
} else {
|
|
415
|
-
console.log(chalk.green(` Found ${traceFiles.length} trace file(s)`));
|
|
416
|
-
if (verbose) {
|
|
417
|
-
for (const trace of traceFiles) {
|
|
418
|
-
console.log(
|
|
419
|
-
chalk.gray(` → ${trace.parentDir || trace.relativePath}`),
|
|
420
|
-
);
|
|
421
|
-
console.log(chalk.gray(` journey: ${trace.journeyKey}`));
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
console.log();
|
|
426
|
-
}
|
|
260
|
+
const traceDir =
|
|
261
|
+
traceDirOverride || reshotConfig.visuals?.traceDir || "./test-results";
|
|
262
|
+
const resolvedTraceDir = path.resolve(projectRoot, traceDir);
|
|
263
|
+
const journeyMappings = reshotConfig.visuals?.journeyMappings || {};
|
|
427
264
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
// ========================================
|
|
431
|
-
if (syncDocs) {
|
|
432
|
-
console.log(
|
|
433
|
-
chalk.gray(`Scanning docs: ${docSyncConfig.documentation.root}`),
|
|
434
|
-
);
|
|
435
|
-
docFiles = await discoverDocumentation(
|
|
436
|
-
docSyncConfig.documentation,
|
|
437
|
-
projectRoot,
|
|
438
|
-
);
|
|
265
|
+
console.log(chalk.gray(`Scanning traces: ${traceDir}`));
|
|
266
|
+
const traceFiles = await discoverTraces(resolvedTraceDir, journeyMappings);
|
|
439
267
|
|
|
440
|
-
|
|
441
|
-
|
|
268
|
+
if (traceFiles.length === 0) {
|
|
269
|
+
console.log(chalk.yellow(" No trace files found"));
|
|
270
|
+
if (!fs.existsSync(resolvedTraceDir)) {
|
|
442
271
|
console.log(
|
|
443
|
-
chalk.gray("
|
|
272
|
+
chalk.gray(" Run your Playwright tests first: npx playwright test"),
|
|
444
273
|
);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
274
|
+
}
|
|
275
|
+
console.log();
|
|
276
|
+
} else {
|
|
277
|
+
console.log(chalk.green(` Found ${traceFiles.length} trace file(s)`));
|
|
278
|
+
if (verbose) {
|
|
279
|
+
for (const trace of traceFiles) {
|
|
280
|
+
console.log(
|
|
281
|
+
chalk.gray(` → ${trace.parentDir || trace.relativePath}`),
|
|
282
|
+
);
|
|
283
|
+
console.log(chalk.gray(` journey: ${trace.journeyKey}`));
|
|
453
284
|
}
|
|
454
285
|
}
|
|
455
286
|
console.log();
|
|
456
287
|
}
|
|
457
288
|
|
|
458
289
|
// ========================================
|
|
459
|
-
// PHASE
|
|
290
|
+
// PHASE 2: Upload to Platform
|
|
460
291
|
// ========================================
|
|
461
292
|
if (dryRun) {
|
|
462
293
|
console.log(chalk.cyan("━━━ Dry Run Summary ━━━\n"));
|
|
463
294
|
console.log(chalk.gray(` Traces: ${traceFiles.length} files`));
|
|
464
|
-
console.log(chalk.gray(` Docs: ${docFiles.length} files`));
|
|
465
295
|
console.log(chalk.yellow("\nNo files uploaded (dry run).\n"));
|
|
466
296
|
return;
|
|
467
297
|
}
|
|
468
298
|
|
|
469
|
-
if (traceFiles.length === 0
|
|
299
|
+
if (traceFiles.length === 0) {
|
|
470
300
|
console.log(chalk.yellow("Nothing to sync.\n"));
|
|
471
301
|
return;
|
|
472
302
|
}
|
|
@@ -476,12 +306,6 @@ async function syncCommand(options = {}) {
|
|
|
476
306
|
try {
|
|
477
307
|
// Initialize sync job with manifest
|
|
478
308
|
const manifest = {
|
|
479
|
-
docs: docFiles.map((d) => ({
|
|
480
|
-
relativePath: d.relativePath,
|
|
481
|
-
journeyKey: d.journeyKey,
|
|
482
|
-
contentHash: d.contentHash,
|
|
483
|
-
size: d.size,
|
|
484
|
-
})),
|
|
485
309
|
traces: traceFiles.map((t) => ({
|
|
486
310
|
filename: t.filename,
|
|
487
311
|
journeyKey: t.journeyKey,
|
|
@@ -545,31 +369,6 @@ async function syncCommand(options = {}) {
|
|
|
545
369
|
}
|
|
546
370
|
}
|
|
547
371
|
|
|
548
|
-
// Upload docs to presigned URLs
|
|
549
|
-
let docsUploaded = 0;
|
|
550
|
-
for (const doc of docFiles) {
|
|
551
|
-
if (skippedFiles.includes(doc.contentHash)) {
|
|
552
|
-
if (verbose) {
|
|
553
|
-
console.log(chalk.gray(` ⊘ ${doc.relativePath} (cached)`));
|
|
554
|
-
}
|
|
555
|
-
docsUploaded++;
|
|
556
|
-
continue;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
const presigned = presignedUrls[doc.contentHash];
|
|
560
|
-
if (presigned) {
|
|
561
|
-
const content = fs.readFileSync(doc.path, "utf-8");
|
|
562
|
-
await apiClient.uploadToPresignedUrl(presigned.url, content, {
|
|
563
|
-
contentType: presigned.contentType || "text/markdown",
|
|
564
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
565
|
-
});
|
|
566
|
-
docsUploaded++;
|
|
567
|
-
if (verbose) {
|
|
568
|
-
console.log(chalk.gray(` ✔ ${doc.relativePath}`));
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
372
|
// Get git metadata
|
|
574
373
|
const git = getGitMetadata();
|
|
575
374
|
|
|
@@ -579,12 +378,6 @@ async function syncCommand(options = {}) {
|
|
|
579
378
|
{
|
|
580
379
|
projectId,
|
|
581
380
|
uploadResults: {
|
|
582
|
-
docs: docFiles.map((d) => ({
|
|
583
|
-
relativePath: d.relativePath,
|
|
584
|
-
journeyKey: d.journeyKey,
|
|
585
|
-
storageKey:
|
|
586
|
-
presignedUrls[d.contentHash]?.storageKey || d.contentHash,
|
|
587
|
-
})),
|
|
588
381
|
traces: traceFiles.map((t) => ({
|
|
589
382
|
filename: t.filename,
|
|
590
383
|
journeyKey: t.journeyKey,
|
|
@@ -605,7 +398,6 @@ async function syncCommand(options = {}) {
|
|
|
605
398
|
|
|
606
399
|
console.log(chalk.green(`\n✔ Sync complete!`));
|
|
607
400
|
console.log(chalk.gray(` Traces: ${tracesUploaded} uploaded`));
|
|
608
|
-
console.log(chalk.gray(` Docs: ${docsUploaded} uploaded`));
|
|
609
401
|
console.log();
|
|
610
402
|
console.log(chalk.gray(" View status:"), chalk.cyan("reshot status"));
|
|
611
403
|
console.log(chalk.gray(" Check drifts:"), chalk.cyan("reshot drifts\n"));
|
package/src/commands/ui.js
CHANGED
|
@@ -127,7 +127,7 @@ module.exports = async function uiCommand(options = {}) {
|
|
|
127
127
|
} else {
|
|
128
128
|
console.log(
|
|
129
129
|
chalk.yellow("Info:"),
|
|
130
|
-
"No
|
|
130
|
+
"No reshot.config.json found. Use the UI to pull config from platform or create a new one."
|
|
131
131
|
);
|
|
132
132
|
}
|
|
133
133
|
|