git-shots-cli 0.6.0 → 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 +85 -39
- package/package.json +1 -1
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`;
|
|
@@ -503,7 +549,7 @@ async function syncFlows(config) {
|
|
|
503
549
|
const listUrl = `${config.server}/api/projects/${config.project}/flows`;
|
|
504
550
|
let existingFlows = [];
|
|
505
551
|
try {
|
|
506
|
-
const res = await fetch(listUrl, { headers: { Origin: config.server } });
|
|
552
|
+
const res = await fetch(listUrl, { headers: { Origin: config.server, ...authHeaders(config) } });
|
|
507
553
|
if (res.ok) {
|
|
508
554
|
const data = await res.json();
|
|
509
555
|
existingFlows = data.flows ?? [];
|
|
@@ -517,7 +563,7 @@ async function syncFlows(config) {
|
|
|
517
563
|
const patchUrl = `${config.server}/api/projects/${config.project}/flows/${flow.slug}`;
|
|
518
564
|
const patchRes = await fetch(patchUrl, {
|
|
519
565
|
method: "PATCH",
|
|
520
|
-
headers: { "Content-Type": "application/json", Origin: config.server },
|
|
566
|
+
headers: { "Content-Type": "application/json", Origin: config.server, ...authHeaders(config) },
|
|
521
567
|
body: JSON.stringify({
|
|
522
568
|
name: flow.name,
|
|
523
569
|
description: flow.description ?? null,
|
|
@@ -532,7 +578,7 @@ async function syncFlows(config) {
|
|
|
532
578
|
const stepsUrl = `${config.server}/api/projects/${config.project}/flows/${flow.slug}/steps`;
|
|
533
579
|
const stepsRes = await fetch(stepsUrl, {
|
|
534
580
|
method: "PUT",
|
|
535
|
-
headers: { "Content-Type": "application/json", Origin: config.server },
|
|
581
|
+
headers: { "Content-Type": "application/json", Origin: config.server, ...authHeaders(config) },
|
|
536
582
|
body: JSON.stringify({ steps: flow.steps })
|
|
537
583
|
});
|
|
538
584
|
if (stepsRes.ok) {
|
|
@@ -545,7 +591,7 @@ async function syncFlows(config) {
|
|
|
545
591
|
const createUrl = `${config.server}/api/projects/${config.project}/flows`;
|
|
546
592
|
const res = await fetch(createUrl, {
|
|
547
593
|
method: "POST",
|
|
548
|
-
headers: { "Content-Type": "application/json", Origin: config.server },
|
|
594
|
+
headers: { "Content-Type": "application/json", Origin: config.server, ...authHeaders(config) },
|
|
549
595
|
body: JSON.stringify({
|
|
550
596
|
slug: flow.slug,
|
|
551
597
|
name: flow.name,
|