git-shots-cli 0.6.1 → 0.6.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/dist/index.js +81 -35
- package/package.json +27 -27
package/dist/index.js
CHANGED
|
@@ -48,6 +48,14 @@ import { resolve as resolve2, basename, dirname } from "path";
|
|
|
48
48
|
import { execSync } from "child_process";
|
|
49
49
|
import { glob } from "glob";
|
|
50
50
|
import chalk2 from "chalk";
|
|
51
|
+
var BATCH_SIZE = 3;
|
|
52
|
+
function chunk(arr, size) {
|
|
53
|
+
const chunks = [];
|
|
54
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
55
|
+
chunks.push(arr.slice(i, i + size));
|
|
56
|
+
}
|
|
57
|
+
return chunks;
|
|
58
|
+
}
|
|
51
59
|
async function upload(config, options) {
|
|
52
60
|
const dir = resolve2(process.cwd(), config.directory);
|
|
53
61
|
if (!existsSync2(dir)) {
|
|
@@ -62,48 +70,73 @@ async function upload(config, options) {
|
|
|
62
70
|
console.log(chalk2.dim(`SHA: ${sha.slice(0, 7)}`));
|
|
63
71
|
console.log(chalk2.dim(`Dir: ${dir}`));
|
|
64
72
|
console.log();
|
|
65
|
-
const
|
|
66
|
-
if (
|
|
73
|
+
const rawFiles = await glob("**/*.png", { cwd: dir });
|
|
74
|
+
if (rawFiles.length === 0) {
|
|
67
75
|
console.log(chalk2.yellow("No PNG files found."));
|
|
68
76
|
return;
|
|
69
77
|
}
|
|
70
|
-
|
|
71
|
-
const formData = new FormData();
|
|
72
|
-
formData.append("project", config.project);
|
|
73
|
-
formData.append("branch", branch);
|
|
74
|
-
formData.append("gitSha", sha);
|
|
75
|
-
if (config.platform) formData.append("platform", config.platform);
|
|
76
|
-
for (const file of files) {
|
|
77
|
-
const fullPath = resolve2(dir, file);
|
|
78
|
-
const buffer = readFileSync2(fullPath);
|
|
79
|
-
const blob = new Blob([buffer], { type: "image/png" });
|
|
78
|
+
const files = rawFiles.map((file) => {
|
|
80
79
|
const dirName = dirname(file);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
return {
|
|
81
|
+
fieldName: dirName !== "." ? `${dirName}/${basename(file)}` : basename(file),
|
|
82
|
+
fileName: basename(file),
|
|
83
|
+
fullPath: resolve2(dir, file)
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
const localSlugs = files.map((f) => f.fileName.replace(/\.png$/, ""));
|
|
87
|
+
const allSlugs = [.../* @__PURE__ */ new Set([...options.baseManifest ?? [], ...localSlugs])];
|
|
88
|
+
console.log(chalk2.dim(`Found ${files.length} screenshots`));
|
|
84
89
|
const url = `${config.server}/api/upload`;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
const batches = chunk(files, BATCH_SIZE);
|
|
91
|
+
let totalUploaded = 0;
|
|
92
|
+
let totalSkipped = 0;
|
|
93
|
+
for (let i = 0; i < batches.length; i++) {
|
|
94
|
+
const batch = batches[i];
|
|
95
|
+
const isLastBatch = i === batches.length - 1;
|
|
96
|
+
const formData = new FormData();
|
|
97
|
+
formData.append("project", config.project);
|
|
98
|
+
formData.append("branch", branch);
|
|
99
|
+
formData.append("gitSha", sha);
|
|
100
|
+
if (config.platform) formData.append("platform", config.platform);
|
|
101
|
+
if (isLastBatch) {
|
|
102
|
+
formData.append("allSlugs", JSON.stringify(allSlugs));
|
|
97
103
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
for (const file of batch) {
|
|
105
|
+
const buffer = readFileSync2(file.fullPath);
|
|
106
|
+
const blob = new Blob([buffer], { type: "image/png" });
|
|
107
|
+
formData.append(file.fieldName, blob, file.fileName);
|
|
108
|
+
}
|
|
109
|
+
const batchLabel = batches.length > 1 ? chalk2.dim(`[${i + 1}/${batches.length}] `) : "";
|
|
110
|
+
try {
|
|
111
|
+
const res = await fetch(url, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
body: formData,
|
|
114
|
+
headers: { Origin: config.server, ...authHeaders(config) }
|
|
115
|
+
});
|
|
116
|
+
checkAuthError(res);
|
|
117
|
+
const data = await res.json();
|
|
118
|
+
if (!res.ok) {
|
|
119
|
+
console.error(chalk2.red(`${batchLabel}Upload failed: ${JSON.stringify(data)}`));
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
totalUploaded += data.uploaded ?? 0;
|
|
123
|
+
totalSkipped += data.skipped ?? 0;
|
|
124
|
+
if (batches.length > 1) {
|
|
125
|
+
const parts2 = [];
|
|
126
|
+
if (data.uploaded > 0) parts2.push(chalk2.green(`${data.uploaded} uploaded`));
|
|
127
|
+
if (data.skipped > 0) parts2.push(chalk2.dim(`${data.skipped} skipped`));
|
|
128
|
+
console.log(`${batchLabel}${parts2.join(", ")}`);
|
|
129
|
+
}
|
|
130
|
+
} catch (err) {
|
|
131
|
+
console.error(chalk2.red(`${batchLabel}Request failed: ${err}`));
|
|
132
|
+
process.exit(1);
|
|
102
133
|
}
|
|
103
|
-
} catch (err) {
|
|
104
|
-
console.error(chalk2.red(`Request failed: ${err}`));
|
|
105
|
-
process.exit(1);
|
|
106
134
|
}
|
|
135
|
+
const parts = [];
|
|
136
|
+
if (totalUploaded > 0) parts.push(chalk2.green(`${totalUploaded} uploaded`));
|
|
137
|
+
if (totalSkipped > 0) parts.push(chalk2.dim(`${totalSkipped} unchanged`));
|
|
138
|
+
console.log(`
|
|
139
|
+
${parts.join(", ") || chalk2.dim("nothing to do")}`);
|
|
107
140
|
}
|
|
108
141
|
|
|
109
142
|
// src/compare.ts
|
|
@@ -286,8 +319,21 @@ async function review(config, options) {
|
|
|
286
319
|
console.log(chalk6.dim(`Branch: ${branch}`));
|
|
287
320
|
console.log(chalk6.dim(`SHA: ${sha.slice(0, 7)}`));
|
|
288
321
|
console.log();
|
|
322
|
+
let baseManifest;
|
|
323
|
+
try {
|
|
324
|
+
const manifestUrl = `${config.server}/api/projects/${encodeURIComponent(config.project)}/manifest?branch=main`;
|
|
325
|
+
const manifestRes = await fetch(manifestUrl, {
|
|
326
|
+
headers: { Origin: config.server, ...authHeaders(config) }
|
|
327
|
+
});
|
|
328
|
+
if (manifestRes.ok) {
|
|
329
|
+
const data = await manifestRes.json();
|
|
330
|
+
baseManifest = data.screenSlugs;
|
|
331
|
+
console.log(chalk6.dim(`Base manifest: ${baseManifest.length} screens on main`));
|
|
332
|
+
}
|
|
333
|
+
} catch {
|
|
334
|
+
}
|
|
289
335
|
console.log(chalk6.dim("Uploading screenshots..."));
|
|
290
|
-
await upload(config, { branch, sha });
|
|
336
|
+
await upload(config, { branch, sha, baseManifest });
|
|
291
337
|
console.log();
|
|
292
338
|
console.log(chalk6.dim("Creating review session..."));
|
|
293
339
|
const reviewUrl = `${config.server}/api/reviews`;
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "git-shots-cli",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "CLI for git-shots visual regression platform",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"git-shots": "./dist/index.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"dist"
|
|
11
|
-
],
|
|
12
|
-
"scripts": {
|
|
13
|
-
"build": "tsup src/index.ts --format esm --dts",
|
|
14
|
-
"dev": "tsup src/index.ts --format esm --watch"
|
|
15
|
-
},
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"commander": "^12.0.0",
|
|
18
|
-
"chalk": "^5.3.0",
|
|
19
|
-
"dotenv": "^16.4.0",
|
|
20
|
-
"glob": "^11.0.0"
|
|
21
|
-
},
|
|
22
|
-
"devDependencies": {
|
|
23
|
-
"tsup": "^8.0.0",
|
|
24
|
-
"typescript": "^5.0.0",
|
|
25
|
-
"@types/node": "^22.0.0"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "git-shots-cli",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"description": "CLI for git-shots visual regression platform",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"git-shots": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
14
|
+
"dev": "tsup src/index.ts --format esm --watch"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"commander": "^12.0.0",
|
|
18
|
+
"chalk": "^5.3.0",
|
|
19
|
+
"dotenv": "^16.4.0",
|
|
20
|
+
"glob": "^11.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"tsup": "^8.0.0",
|
|
24
|
+
"typescript": "^5.0.0",
|
|
25
|
+
"@types/node": "^22.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|