@pixeyedev/cli 0.1.0
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/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +46 -0
- package/dist/config.js.map +1 -0
- package/dist/discover.d.ts +10 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +36 -0
- package/dist/discover.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +2 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +29 -0
- package/dist/init.js.map +1 -0
- package/dist/login.d.ts +5 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +32 -0
- package/dist/login.js.map +1 -0
- package/dist/storybook-test.d.ts +17 -0
- package/dist/storybook-test.d.ts.map +1 -0
- package/dist/storybook-test.js +125 -0
- package/dist/storybook-test.js.map +1 -0
- package/dist/storybook-upload.d.ts +12 -0
- package/dist/storybook-upload.d.ts.map +1 -0
- package/dist/storybook-upload.js +97 -0
- package/dist/storybook-upload.js.map +1 -0
- package/dist/upload.d.ts +13 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +211 -0
- package/dist/upload.js.map +1 -0
- package/package.json +28 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PixeyeConfig {
|
|
2
|
+
server?: string;
|
|
3
|
+
token?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ProjectConfig {
|
|
6
|
+
server: string;
|
|
7
|
+
token: string;
|
|
8
|
+
screenshotDir?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function readGlobalConfig(): Promise<PixeyeConfig>;
|
|
11
|
+
export declare function writeGlobalConfig(config: PixeyeConfig): Promise<void>;
|
|
12
|
+
export declare function readProjectConfig(cwd: string): Promise<ProjectConfig | null>;
|
|
13
|
+
export declare function writeProjectConfig(cwd: string, config: ProjectConfig): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,CAAC,CAO9D;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3E;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAOlF;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAO1F"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
const GLOBAL_CONFIG_DIR = join(homedir(), ".pixeye");
|
|
5
|
+
const GLOBAL_CONFIG_PATH = join(GLOBAL_CONFIG_DIR, "config.json");
|
|
6
|
+
const PROJECT_CONFIG_NAME = ".pixeye.yml";
|
|
7
|
+
export async function readGlobalConfig() {
|
|
8
|
+
try {
|
|
9
|
+
const content = await readFile(GLOBAL_CONFIG_PATH, "utf-8");
|
|
10
|
+
return JSON.parse(content);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function writeGlobalConfig(config) {
|
|
17
|
+
await mkdir(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
18
|
+
await writeFile(GLOBAL_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n");
|
|
19
|
+
}
|
|
20
|
+
export async function readProjectConfig(cwd) {
|
|
21
|
+
try {
|
|
22
|
+
const content = await readFile(join(cwd, PROJECT_CONFIG_NAME), "utf-8");
|
|
23
|
+
return parseYamlLike(content);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export async function writeProjectConfig(cwd, config) {
|
|
30
|
+
const lines = [
|
|
31
|
+
`server: ${config.server}`,
|
|
32
|
+
`token: ${config.token}`,
|
|
33
|
+
...(config.screenshotDir ? [`screenshotDir: ${config.screenshotDir}`] : []),
|
|
34
|
+
];
|
|
35
|
+
await writeFile(join(cwd, PROJECT_CONFIG_NAME), lines.join("\n") + "\n");
|
|
36
|
+
}
|
|
37
|
+
function parseYamlLike(content) {
|
|
38
|
+
const result = {};
|
|
39
|
+
for (const line of content.split("\n")) {
|
|
40
|
+
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
41
|
+
if (match)
|
|
42
|
+
result[match[1]] = match[2].trim();
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAalC,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AACrD,MAAM,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;AAClE,MAAM,mBAAmB,GAAG,aAAa,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAoB;IAC1D,MAAM,KAAK,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,SAAS,CAAC,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAW;IACjD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC,CAAC;QACxE,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW,EAAE,MAAqB;IACzE,MAAM,KAAK,GAAG;QACZ,WAAW,MAAM,CAAC,MAAM,EAAE;QAC1B,UAAU,MAAM,CAAC,KAAK,EAAE;QACxB,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,kBAAkB,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAC;IACF,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC5C,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,MAAkC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface DiscoveredFile {
|
|
2
|
+
filePath: string;
|
|
3
|
+
name: string;
|
|
4
|
+
fileHash: string;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
metadata?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export declare function discoverScreenshots(directory: string): Promise<DiscoveredFile[]>;
|
|
10
|
+
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAWD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA4BtF"}
|
package/dist/discover.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { glob } from "glob";
|
|
4
|
+
function readPngDimensions(buffer) {
|
|
5
|
+
// PNG header: 8-byte signature, then IHDR chunk
|
|
6
|
+
// Bytes 16-19: width (big-endian uint32)
|
|
7
|
+
// Bytes 20-23: height (big-endian uint32)
|
|
8
|
+
const width = buffer.readUInt32BE(16);
|
|
9
|
+
const height = buffer.readUInt32BE(20);
|
|
10
|
+
return { width, height };
|
|
11
|
+
}
|
|
12
|
+
export async function discoverScreenshots(directory) {
|
|
13
|
+
const pngFiles = await glob("**/*.png", { cwd: directory, posix: true });
|
|
14
|
+
pngFiles.sort();
|
|
15
|
+
const results = [];
|
|
16
|
+
for (const relativePath of pngFiles) {
|
|
17
|
+
const filePath = `${directory}/${relativePath}`;
|
|
18
|
+
const fileBuffer = await readFile(filePath);
|
|
19
|
+
const fileHash = createHash("sha256").update(fileBuffer).digest("hex");
|
|
20
|
+
const { width, height } = readPngDimensions(fileBuffer);
|
|
21
|
+
const name = relativePath.replace(/\.png$/, "");
|
|
22
|
+
// Check for companion .argos.json metadata file
|
|
23
|
+
const metadataPath = filePath.replace(/\.png$/, ".argos.json");
|
|
24
|
+
let metadata;
|
|
25
|
+
try {
|
|
26
|
+
const metadataContent = await readFile(metadataPath, "utf-8");
|
|
27
|
+
metadata = JSON.parse(metadataContent);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// No metadata file or invalid JSON — skip
|
|
31
|
+
}
|
|
32
|
+
results.push({ filePath, name, fileHash, width, height, metadata });
|
|
33
|
+
}
|
|
34
|
+
return results;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAW5B,SAAS,iBAAiB,CAAC,MAAc;IACvC,gDAAgD;IAChD,yCAAyC;IACzC,0CAA0C;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACvC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,SAAiB;IACzD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEhB,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,YAAY,IAAI,QAAQ,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,GAAG,SAAS,IAAI,YAAY,EAAE,CAAC;QAChD,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5C,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAEhD,gDAAgD;QAChD,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC/D,IAAI,QAA6C,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YAC9D,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;QAC5C,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { discoverScreenshots } from "./discover.js";
|
|
5
|
+
import { uploadScreenshots } from "./upload.js";
|
|
6
|
+
import { initCommand } from "./init.js";
|
|
7
|
+
import { loginCommand } from "./login.js";
|
|
8
|
+
import { readProjectConfig, readGlobalConfig } from "./config.js";
|
|
9
|
+
const program = new Command();
|
|
10
|
+
program.name("pixeye").description("Pixeye — Visual regression testing CLI").version("0.1.0");
|
|
11
|
+
// ─── init ──────────────────────────────────────────────────────────────────────
|
|
12
|
+
program
|
|
13
|
+
.command("init")
|
|
14
|
+
.description("Initialize Pixeye for this project (creates .pixeye.yml)")
|
|
15
|
+
.action(initCommand);
|
|
16
|
+
// ─── login ─────────────────────────────────────────────────────────────────────
|
|
17
|
+
program
|
|
18
|
+
.command("login")
|
|
19
|
+
.description("Save API credentials globally (~/.pixeye/config.json)")
|
|
20
|
+
.option("--server <url>", "API server URL")
|
|
21
|
+
.option("--token <token>", "API token")
|
|
22
|
+
.action(loginCommand);
|
|
23
|
+
// ─── upload ────────────────────────────────────────────────────────────────────
|
|
24
|
+
program
|
|
25
|
+
.command("upload")
|
|
26
|
+
.description("Upload screenshots from a directory")
|
|
27
|
+
.argument("[directory]", "Directory containing PNG screenshots")
|
|
28
|
+
.option("--server <url>", "API server URL")
|
|
29
|
+
.option("--token <token>", "Project API token")
|
|
30
|
+
.requiredOption("--commit <sha>", "Git commit SHA")
|
|
31
|
+
.requiredOption("--branch <ref>", "Git branch name")
|
|
32
|
+
.option("--pr <number>", "PR number")
|
|
33
|
+
.option("--shard-index <n>", "Current shard index", "0")
|
|
34
|
+
.option("--shard-total <n>", "Total shard count", "1")
|
|
35
|
+
.action(async (directory, options) => {
|
|
36
|
+
// Resolve config from .pixeye.yml → ~/.pixeye/config.json → CLI flags
|
|
37
|
+
const projectConfig = await readProjectConfig(process.cwd());
|
|
38
|
+
const globalConfig = await readGlobalConfig();
|
|
39
|
+
const server = options.server ?? projectConfig?.server ?? globalConfig.server;
|
|
40
|
+
const token = options.token ?? projectConfig?.token ?? globalConfig.token;
|
|
41
|
+
const dir = directory ?? projectConfig?.screenshotDir ?? "./screenshots";
|
|
42
|
+
if (!server) {
|
|
43
|
+
console.error("Error: --server is required (or set in .pixeye.yml / pixeye login)");
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
if (!token) {
|
|
47
|
+
console.error("Error: --token is required (or set in .pixeye.yml / pixeye login)");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const resolvedDir = resolve(dir);
|
|
51
|
+
console.log(`Discovering screenshots in: ${resolvedDir}`);
|
|
52
|
+
const files = await discoverScreenshots(resolvedDir);
|
|
53
|
+
console.log(`Found ${files.length} screenshots.`);
|
|
54
|
+
if (files.length === 0) {
|
|
55
|
+
console.log("No screenshots found. Nothing to upload.");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await uploadScreenshots(files, {
|
|
59
|
+
serverUrl: server.replace(/\/$/, ""),
|
|
60
|
+
projectToken: token,
|
|
61
|
+
commitSha: options.commit,
|
|
62
|
+
branch: options.branch,
|
|
63
|
+
prNumber: options.pr ? parseInt(options.pr, 10) : undefined,
|
|
64
|
+
shardIndex: parseInt(options.shardIndex, 10),
|
|
65
|
+
shardTotal: parseInt(options.shardTotal, 10),
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
// ─── storybook-upload ─────────────────────────────────────────────────────────
|
|
69
|
+
program
|
|
70
|
+
.command("storybook-upload")
|
|
71
|
+
.description("Upload a built static Storybook for per-branch hosting")
|
|
72
|
+
.argument("[directory]", "Storybook build output directory", "./storybook-static")
|
|
73
|
+
.option("--server <url>", "API server URL")
|
|
74
|
+
.option("--token <token>", "Project API token")
|
|
75
|
+
.requiredOption("--commit <sha>", "Git commit SHA")
|
|
76
|
+
.requiredOption("--branch <ref>", "Git branch name")
|
|
77
|
+
.action(async (directory, options) => {
|
|
78
|
+
const projectConfig = await readProjectConfig(process.cwd());
|
|
79
|
+
const globalConfig = await readGlobalConfig();
|
|
80
|
+
const server = options.server ?? projectConfig?.server ?? globalConfig.server;
|
|
81
|
+
const token = options.token ?? projectConfig?.token ?? globalConfig.token;
|
|
82
|
+
if (!server || !token) {
|
|
83
|
+
console.error("Error: --server and --token are required");
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
const { uploadStorybook } = await import("./storybook-upload.js");
|
|
87
|
+
await uploadStorybook(resolve(directory), {
|
|
88
|
+
serverUrl: server.replace(/\/$/, ""),
|
|
89
|
+
projectToken: token,
|
|
90
|
+
commitSha: options.commit,
|
|
91
|
+
branch: options.branch,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
// ─── storybook-test ───────────────────────────────────────────────────────────
|
|
95
|
+
program
|
|
96
|
+
.command("storybook-test")
|
|
97
|
+
.description("Capture screenshots of every Storybook story and upload to Pixeye")
|
|
98
|
+
.argument("[directory]", "Storybook build output directory", "./storybook-static")
|
|
99
|
+
.option("--server <url>", "API server URL")
|
|
100
|
+
.option("--token <token>", "Project API token")
|
|
101
|
+
.requiredOption("--commit <sha>", "Git commit SHA")
|
|
102
|
+
.requiredOption("--branch <ref>", "Git branch name")
|
|
103
|
+
.option("--pr <number>", "PR number")
|
|
104
|
+
.option("--shard-index <n>", "Current shard index", "0")
|
|
105
|
+
.option("--shard-total <n>", "Total shard count", "1")
|
|
106
|
+
.action(async (directory, options) => {
|
|
107
|
+
const projectConfig = await readProjectConfig(process.cwd());
|
|
108
|
+
const globalConfig = await readGlobalConfig();
|
|
109
|
+
const server = options.server ?? projectConfig?.server ?? globalConfig.server;
|
|
110
|
+
const token = options.token ?? projectConfig?.token ?? globalConfig.token;
|
|
111
|
+
if (!server || !token) {
|
|
112
|
+
console.error("Error: --server and --token are required");
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
const { testStorybook } = await import("./storybook-test.js");
|
|
116
|
+
await testStorybook(resolve(directory), {
|
|
117
|
+
serverUrl: server.replace(/\/$/, ""),
|
|
118
|
+
projectToken: token,
|
|
119
|
+
commitSha: options.commit,
|
|
120
|
+
branch: options.branch,
|
|
121
|
+
prNumber: options.pr ? parseInt(options.pr, 10) : undefined,
|
|
122
|
+
shardIndex: parseInt(options.shardIndex, 10),
|
|
123
|
+
shardTotal: parseInt(options.shardTotal, 10),
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
program.parse();
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA8BjD"}
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
import { readGlobalConfig, writeProjectConfig } from "./config.js";
|
|
4
|
+
export async function initCommand() {
|
|
5
|
+
const globalConfig = await readGlobalConfig();
|
|
6
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
7
|
+
try {
|
|
8
|
+
console.log("Initialize Pixeye for this project\n");
|
|
9
|
+
const server = await rl.question(`Server URL [${globalConfig.server ?? "https://app.pixeye.io"}]: `);
|
|
10
|
+
const token = await rl.question(`Project token [${globalConfig.token ? "****" : ""}]: `);
|
|
11
|
+
const screenshotDir = await rl.question("Screenshot directory [./screenshots]: ");
|
|
12
|
+
const config = {
|
|
13
|
+
server: server || globalConfig.server || "https://app.pixeye.io",
|
|
14
|
+
token: token || globalConfig.token || "",
|
|
15
|
+
screenshotDir: screenshotDir || "./screenshots",
|
|
16
|
+
};
|
|
17
|
+
if (!config.token) {
|
|
18
|
+
console.error("\nError: A project token is required. Get one from the Pixeye dashboard.");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
await writeProjectConfig(process.cwd(), config);
|
|
22
|
+
console.log("\nCreated .pixeye.yml");
|
|
23
|
+
console.log("Add it to .gitignore if it contains sensitive tokens.");
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
rl.close();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEnE,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,YAAY,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAC9C,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QAEpD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAC9B,eAAe,YAAY,CAAC,MAAM,IAAI,uBAAuB,KAAK,CACnE,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACzF,MAAM,aAAa,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC,CAAC;QAElF,MAAM,MAAM,GAAG;YACb,MAAM,EAAE,MAAM,IAAI,YAAY,CAAC,MAAM,IAAI,uBAAuB;YAChE,KAAK,EAAE,KAAK,IAAI,YAAY,CAAC,KAAK,IAAI,EAAE;YACxC,aAAa,EAAE,aAAa,IAAI,eAAe;SAChD,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,0EAA0E,CAAC,CAAC;YAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,kBAAkB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;IACvE,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC9F"}
|
package/dist/login.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
import { readGlobalConfig, writeGlobalConfig } from "./config.js";
|
|
4
|
+
export async function loginCommand(options) {
|
|
5
|
+
const globalConfig = await readGlobalConfig();
|
|
6
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
7
|
+
try {
|
|
8
|
+
const defaultServer = globalConfig.server ?? "https://app.pixeye.io";
|
|
9
|
+
const input = options.server ?? (await rl.question(`Server URL [${defaultServer}]: `));
|
|
10
|
+
const server = input || defaultServer;
|
|
11
|
+
const token = options.token ?? (await rl.question("API token: "));
|
|
12
|
+
if (!token) {
|
|
13
|
+
console.error("Error: Token is required.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
// Verify the token works
|
|
17
|
+
const res = await fetch(`${server}/api/v1/projects`, {
|
|
18
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
19
|
+
});
|
|
20
|
+
if (!res.ok) {
|
|
21
|
+
console.error(`Error: Could not authenticate with ${server} (${res.status})`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
await writeGlobalConfig({ server, token });
|
|
25
|
+
console.log(`Logged in to ${server}`);
|
|
26
|
+
console.log(`Config saved to ~/.pixeye/config.json`);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
rl.close();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4C;IAC7E,MAAM,YAAY,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAC9C,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,IAAI,uBAAuB,CAAC;QACrE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,aAAa,KAAK,CAAC,CAAC,CAAC;QACvF,MAAM,MAAM,GAAG,KAAK,IAAI,aAAa,CAAC;QAEtC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;QAElE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,yBAAyB;QACzB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,kBAAkB,EAAE;YACnD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;SAC9C,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,sCAAsC,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;YAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,iBAAiB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACvD,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface StorybookTestOptions {
|
|
2
|
+
serverUrl: string;
|
|
3
|
+
projectToken: string;
|
|
4
|
+
commitSha: string;
|
|
5
|
+
branch: string;
|
|
6
|
+
prNumber?: number;
|
|
7
|
+
shardIndex: number;
|
|
8
|
+
shardTotal: number;
|
|
9
|
+
outputDir?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Capture screenshots of all stories in a built Storybook using Playwright.
|
|
13
|
+
* Outputs PNG files to outputDir, then uploads them via the normal Pixeye upload flow.
|
|
14
|
+
*/
|
|
15
|
+
export declare function testStorybook(storybookDir: string, opts: StorybookTestOptions): Promise<void>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=storybook-test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storybook-test.d.ts","sourceRoot":"","sources":["../src/storybook-test.ts"],"names":[],"mappings":"AAKA,UAAU,oBAAoB;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CA2Ef"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { readFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
/**
|
|
6
|
+
* Start a local HTTP server to serve the static Storybook.
|
|
7
|
+
*/
|
|
8
|
+
function startServer(dir, port) {
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
const server = createServer(async (req, res) => {
|
|
11
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
12
|
+
const filePath = join(dir, url.pathname === "/" ? "index.html" : url.pathname);
|
|
13
|
+
try {
|
|
14
|
+
const data = await readFile(filePath);
|
|
15
|
+
const ext = filePath.split(".").pop() ?? "";
|
|
16
|
+
const types = {
|
|
17
|
+
html: "text/html",
|
|
18
|
+
js: "application/javascript",
|
|
19
|
+
css: "text/css",
|
|
20
|
+
json: "application/json",
|
|
21
|
+
png: "image/png",
|
|
22
|
+
svg: "image/svg+xml",
|
|
23
|
+
};
|
|
24
|
+
res.writeHead(200, { "Content-Type": types[ext] ?? "application/octet-stream" });
|
|
25
|
+
res.end(data);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
res.writeHead(404);
|
|
29
|
+
res.end("Not found");
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
server.listen(port, () => {
|
|
33
|
+
console.log(`Storybook server started on http://localhost:${port}`);
|
|
34
|
+
resolve(server);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Discover stories from a built Storybook's index.
|
|
40
|
+
*/
|
|
41
|
+
async function discoverStories(storybookDir) {
|
|
42
|
+
// Storybook 8 generates index.json or stories.json
|
|
43
|
+
for (const name of ["index.json", "stories.json"]) {
|
|
44
|
+
const path = join(storybookDir, name);
|
|
45
|
+
if (existsSync(path)) {
|
|
46
|
+
const data = JSON.parse(await readFile(path, "utf-8"));
|
|
47
|
+
const entries = data.entries ?? data.stories ?? {};
|
|
48
|
+
return Object.values(entries).filter((s) => s.type === "story");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
throw new Error("No index.json or stories.json found in Storybook build. Ensure Storybook is built correctly.");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Capture screenshots of all stories in a built Storybook using Playwright.
|
|
55
|
+
* Outputs PNG files to outputDir, then uploads them via the normal Pixeye upload flow.
|
|
56
|
+
*/
|
|
57
|
+
export async function testStorybook(storybookDir, opts) {
|
|
58
|
+
const outputDir = opts.outputDir ?? join(storybookDir, ".pixeye-screenshots");
|
|
59
|
+
await mkdir(outputDir, { recursive: true });
|
|
60
|
+
// Discover stories
|
|
61
|
+
const stories = await discoverStories(storybookDir);
|
|
62
|
+
console.log(`Found ${stories.length} stories`);
|
|
63
|
+
if (stories.length === 0) {
|
|
64
|
+
console.log("No stories to test.");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Start local server
|
|
68
|
+
const port = 6007;
|
|
69
|
+
const server = await startServer(storybookDir, port);
|
|
70
|
+
try {
|
|
71
|
+
// Dynamically import Playwright (it's a peer dep)
|
|
72
|
+
const { chromium } = await import("playwright");
|
|
73
|
+
const browser = await chromium.launch();
|
|
74
|
+
const context = await browser.newContext({
|
|
75
|
+
viewport: { width: 1280, height: 720 },
|
|
76
|
+
colorScheme: "dark",
|
|
77
|
+
});
|
|
78
|
+
let captured = 0;
|
|
79
|
+
for (const story of stories) {
|
|
80
|
+
const page = await context.newPage();
|
|
81
|
+
const storyUrl = `http://localhost:${port}/iframe.html?id=${encodeURIComponent(story.id)}&viewMode=story`;
|
|
82
|
+
try {
|
|
83
|
+
await page.goto(storyUrl, { waitUntil: "networkidle", timeout: 15000 });
|
|
84
|
+
// Stabilization: freeze animations, wait for render
|
|
85
|
+
await page.evaluate(() => {
|
|
86
|
+
// Pause CSS animations
|
|
87
|
+
const style = document.createElement("style");
|
|
88
|
+
style.textContent = "*, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; }";
|
|
89
|
+
document.head.appendChild(style);
|
|
90
|
+
});
|
|
91
|
+
await page.waitForTimeout(200);
|
|
92
|
+
// Screenshot
|
|
93
|
+
const screenshotPath = join(outputDir, `${story.id}.png`);
|
|
94
|
+
await page.screenshot({ path: screenshotPath, fullPage: false });
|
|
95
|
+
captured++;
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
console.error(`Failed to capture ${story.id}: ${err.message}`);
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
await page.close();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
await browser.close();
|
|
105
|
+
console.log(`Captured ${captured}/${stories.length} screenshots to ${outputDir}`);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
server.close();
|
|
109
|
+
}
|
|
110
|
+
// Now upload via the normal upload flow
|
|
111
|
+
console.log("Uploading screenshots...");
|
|
112
|
+
const { discoverScreenshots } = await import("./discover.js");
|
|
113
|
+
const { uploadScreenshots } = await import("./upload.js");
|
|
114
|
+
const files = await discoverScreenshots(outputDir);
|
|
115
|
+
await uploadScreenshots(files, {
|
|
116
|
+
serverUrl: opts.serverUrl,
|
|
117
|
+
projectToken: opts.projectToken,
|
|
118
|
+
commitSha: opts.commitSha,
|
|
119
|
+
branch: opts.branch,
|
|
120
|
+
prNumber: opts.prNumber,
|
|
121
|
+
shardIndex: opts.shardIndex,
|
|
122
|
+
shardTotal: opts.shardTotal,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=storybook-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storybook-test.js","sourceRoot":"","sources":["../src/storybook-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface StorybookUploadOptions {
|
|
2
|
+
serverUrl: string;
|
|
3
|
+
projectToken: string;
|
|
4
|
+
commitSha: string;
|
|
5
|
+
branch: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Upload a built static Storybook to the public Storybook bucket on R2.
|
|
9
|
+
*/
|
|
10
|
+
export declare function uploadStorybook(directory: string, opts: StorybookUploadOptions): Promise<void>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=storybook-upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storybook-upload.d.ts","sourceRoot":"","sources":["../src/storybook-upload.ts"],"names":[],"mappings":"AAGA,UAAU,sBAAsB;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AA2CD;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAqEf"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
async function discoverFiles(dir, base = dir) {
|
|
4
|
+
const files = [];
|
|
5
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
6
|
+
for (const entry of entries) {
|
|
7
|
+
const fullPath = join(dir, entry.name);
|
|
8
|
+
if (entry.isDirectory()) {
|
|
9
|
+
files.push(...(await discoverFiles(fullPath, base)));
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const s = await stat(fullPath);
|
|
13
|
+
files.push({ path: fullPath, relativePath: relative(base, fullPath), size: s.size });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return files;
|
|
17
|
+
}
|
|
18
|
+
function getContentType(filePath) {
|
|
19
|
+
const ext = filePath.split(".").pop() ?? "";
|
|
20
|
+
const types = {
|
|
21
|
+
html: "text/html",
|
|
22
|
+
js: "application/javascript",
|
|
23
|
+
mjs: "application/javascript",
|
|
24
|
+
css: "text/css",
|
|
25
|
+
json: "application/json",
|
|
26
|
+
png: "image/png",
|
|
27
|
+
jpg: "image/jpeg",
|
|
28
|
+
svg: "image/svg+xml",
|
|
29
|
+
woff: "font/woff",
|
|
30
|
+
woff2: "font/woff2",
|
|
31
|
+
ttf: "font/ttf",
|
|
32
|
+
ico: "image/x-icon",
|
|
33
|
+
map: "application/json",
|
|
34
|
+
txt: "text/plain",
|
|
35
|
+
};
|
|
36
|
+
return types[ext] ?? "application/octet-stream";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Upload a built static Storybook to the public Storybook bucket on R2.
|
|
40
|
+
*/
|
|
41
|
+
export async function uploadStorybook(directory, opts) {
|
|
42
|
+
const { serverUrl, projectToken, commitSha, branch } = opts;
|
|
43
|
+
console.log(`Discovering files in ${directory}...`);
|
|
44
|
+
const files = await discoverFiles(directory);
|
|
45
|
+
console.log(`Found ${files.length} files`);
|
|
46
|
+
const totalBytes = files.reduce((sum, f) => sum + f.size, 0);
|
|
47
|
+
const safeBranch = branch.replace(/[^a-zA-Z0-9_\-.]/g, "_");
|
|
48
|
+
// The API will resolve orgId/projectId from the token and build the storage prefix
|
|
49
|
+
// For now, we use branch/commit as the prefix — the API adds the org/project prefix
|
|
50
|
+
const storagePrefix = `storybook/${safeBranch}/${commitSha}/`;
|
|
51
|
+
// Upload each file to the Storybook public bucket
|
|
52
|
+
let uploaded = 0;
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
const buffer = await readFile(file.path);
|
|
55
|
+
const key = `${storagePrefix}${file.relativePath}`;
|
|
56
|
+
const contentType = getContentType(file.relativePath);
|
|
57
|
+
const blob = new Blob([buffer], { type: contentType });
|
|
58
|
+
const formData = new FormData();
|
|
59
|
+
formData.append("file", blob, file.relativePath);
|
|
60
|
+
formData.append("key", key);
|
|
61
|
+
formData.append("token", projectToken);
|
|
62
|
+
formData.append("contentType", contentType);
|
|
63
|
+
const uploadRes = await fetch(`${serverUrl}/api/v1/storybook/upload`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
body: formData,
|
|
66
|
+
});
|
|
67
|
+
if (!uploadRes.ok) {
|
|
68
|
+
console.error(`Failed to upload ${file.relativePath}: ${await uploadRes.text()}`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
uploaded++;
|
|
72
|
+
if (uploaded % 50 === 0)
|
|
73
|
+
console.log(`Uploaded ${uploaded}/${files.length} files...`);
|
|
74
|
+
}
|
|
75
|
+
console.log(`Uploaded ${uploaded} files (${Math.round(totalBytes / 1024)} KB total)`);
|
|
76
|
+
// Register the Storybook build
|
|
77
|
+
const registerRes = await fetch(`${serverUrl}/api/v1/storybook/builds`, {
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers: { "Content-Type": "application/json" },
|
|
80
|
+
body: JSON.stringify({
|
|
81
|
+
projectToken,
|
|
82
|
+
commitSha,
|
|
83
|
+
branch,
|
|
84
|
+
fileCount: files.length,
|
|
85
|
+
totalBytes,
|
|
86
|
+
storagePrefix,
|
|
87
|
+
}),
|
|
88
|
+
});
|
|
89
|
+
if (!registerRes.ok) {
|
|
90
|
+
console.error(`Failed to register Storybook build: ${await registerRes.text()}`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const { build, storybookUrl } = (await registerRes.json());
|
|
94
|
+
console.log(`Storybook build registered: ${build.id}`);
|
|
95
|
+
console.log(`View at: ${storybookUrl}`);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=storybook-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storybook-upload.js","sourceRoot":"","sources":["../src/storybook-upload.ts"],"names":[],"mappings":"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"}
|
package/dist/upload.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DiscoveredFile } from "./discover.js";
|
|
2
|
+
interface UploadOptions {
|
|
3
|
+
serverUrl: string;
|
|
4
|
+
projectToken: string;
|
|
5
|
+
commitSha: string;
|
|
6
|
+
branch: string;
|
|
7
|
+
prNumber?: number;
|
|
8
|
+
shardIndex: number;
|
|
9
|
+
shardTotal: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function uploadScreenshots(files: DiscoveredFile[], opts: UploadOptions): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AA8LD,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,cAAc,EAAE,EACvB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAgFf"}
|
package/dist/upload.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
5
|
+
async function apiRequest(serverUrl, path, options = {}) {
|
|
6
|
+
const url = `${serverUrl}${path}`;
|
|
7
|
+
const response = await fetch(url, {
|
|
8
|
+
...options,
|
|
9
|
+
headers: {
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
...options.headers,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
if (!response.ok) {
|
|
15
|
+
const body = await response.text();
|
|
16
|
+
throw new Error(`API ${options.method ?? "GET"} ${path} failed (${response.status}): ${body}`);
|
|
17
|
+
}
|
|
18
|
+
return response.json();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Auto-detect test runner from config files in the project root.
|
|
22
|
+
*/
|
|
23
|
+
function detectRunner(cwd) {
|
|
24
|
+
const checks = [
|
|
25
|
+
[["playwright.config.ts", "playwright.config.js", "playwright.config.mjs"], "playwright"],
|
|
26
|
+
[["cypress.config.ts", "cypress.config.js", "cypress.config.mjs", "cypress.json"], "cypress"],
|
|
27
|
+
[[".storybook"], "storybook"],
|
|
28
|
+
];
|
|
29
|
+
for (const [files, runner] of checks) {
|
|
30
|
+
if (files.some((f) => existsSync(join(cwd, f))))
|
|
31
|
+
return runner;
|
|
32
|
+
}
|
|
33
|
+
return "unknown";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Discover Playwright trace files in test-results directory.
|
|
37
|
+
* Returns map of test dir name → trace file path.
|
|
38
|
+
*/
|
|
39
|
+
async function discoverTraces(cwd) {
|
|
40
|
+
const traces = new Map();
|
|
41
|
+
const testResultsDir = join(cwd, "test-results");
|
|
42
|
+
if (!existsSync(testResultsDir))
|
|
43
|
+
return traces;
|
|
44
|
+
try {
|
|
45
|
+
const entries = await readdir(testResultsDir, { withFileTypes: true });
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
if (!entry.isDirectory())
|
|
48
|
+
continue;
|
|
49
|
+
const tracePath = join(testResultsDir, entry.name, "trace.zip");
|
|
50
|
+
if (existsSync(tracePath)) {
|
|
51
|
+
traces.set(entry.name, tracePath);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// test-results dir might not exist
|
|
57
|
+
}
|
|
58
|
+
return traces;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Match a screenshot name to a trace dir name.
|
|
62
|
+
* Playwright trace dirs are like "auth-login-page-renders-chromium" and
|
|
63
|
+
* screenshot names might be "auth-login-page" or similar.
|
|
64
|
+
*/
|
|
65
|
+
function matchTraceToScreenshot(screenshotName, traceDirs) {
|
|
66
|
+
// Normalize: lowercase, remove extensions
|
|
67
|
+
const normalized = screenshotName.toLowerCase().replace(/\.(png|jpg)$/, "");
|
|
68
|
+
// Exact match first
|
|
69
|
+
const exact = traceDirs.find((d) => d.toLowerCase() === normalized);
|
|
70
|
+
if (exact)
|
|
71
|
+
return exact;
|
|
72
|
+
// Prefix match: screenshot name is a prefix of trace dir
|
|
73
|
+
const prefix = traceDirs.find((d) => d.toLowerCase().startsWith(normalized));
|
|
74
|
+
if (prefix)
|
|
75
|
+
return prefix;
|
|
76
|
+
// Substring match: screenshot name contained in trace dir
|
|
77
|
+
return traceDirs.find((d) => d.toLowerCase().includes(normalized));
|
|
78
|
+
}
|
|
79
|
+
async function createBuild(serverUrl, opts, runner) {
|
|
80
|
+
const body = {
|
|
81
|
+
projectToken: opts.projectToken,
|
|
82
|
+
commitSha: opts.commitSha,
|
|
83
|
+
branch: opts.branch,
|
|
84
|
+
prNumber: opts.prNumber,
|
|
85
|
+
shardCount: opts.shardTotal,
|
|
86
|
+
metadata: { runner },
|
|
87
|
+
};
|
|
88
|
+
console.log(`Creating build (runner: ${runner})...`);
|
|
89
|
+
const result = await apiRequest(serverUrl, "/api/v1/builds", {
|
|
90
|
+
method: "POST",
|
|
91
|
+
body: JSON.stringify(body),
|
|
92
|
+
});
|
|
93
|
+
console.log(`Build created: ${result.build.id}`);
|
|
94
|
+
return result.build;
|
|
95
|
+
}
|
|
96
|
+
async function checkFileExists(serverUrl, hash, token) {
|
|
97
|
+
const result = await apiRequest(serverUrl, `/api/v1/upload/${hash}?token=${encodeURIComponent(token)}`);
|
|
98
|
+
return result.exists;
|
|
99
|
+
}
|
|
100
|
+
async function uploadFile(serverUrl, filePath, hash, token) {
|
|
101
|
+
const fileBuffer = await readFile(filePath);
|
|
102
|
+
const blob = new Blob([fileBuffer], { type: "image/png" });
|
|
103
|
+
const formData = new FormData();
|
|
104
|
+
formData.append("file", blob, basename(filePath));
|
|
105
|
+
formData.append("hash", hash);
|
|
106
|
+
formData.append("token", token);
|
|
107
|
+
const url = `${serverUrl}/api/v1/upload`;
|
|
108
|
+
const response = await fetch(url, { method: "POST", body: formData });
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
const body = await response.text();
|
|
111
|
+
throw new Error(`Upload failed for ${filePath} (${response.status}): ${body}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Upload a trace.zip file. Uses the same upload endpoint with a special
|
|
116
|
+
* "trace:" prefix on the hash to distinguish from screenshots.
|
|
117
|
+
*/
|
|
118
|
+
async function uploadTraceFile(serverUrl, filePath, token) {
|
|
119
|
+
const fileBuffer = await readFile(filePath);
|
|
120
|
+
const hash = "trace_" + createHash("sha256").update(fileBuffer).digest("hex");
|
|
121
|
+
// Check if already uploaded
|
|
122
|
+
const existsRes = await apiRequest(serverUrl, `/api/v1/upload/${hash}?token=${encodeURIComponent(token)}`);
|
|
123
|
+
if (existsRes.exists)
|
|
124
|
+
return hash;
|
|
125
|
+
const blob = new Blob([fileBuffer], { type: "application/zip" });
|
|
126
|
+
const formData = new FormData();
|
|
127
|
+
formData.append("file", blob, basename(filePath));
|
|
128
|
+
formData.append("hash", hash);
|
|
129
|
+
formData.append("token", token);
|
|
130
|
+
const url = `${serverUrl}/api/v1/upload`;
|
|
131
|
+
const response = await fetch(url, { method: "POST", body: formData });
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
const body = await response.text();
|
|
134
|
+
throw new Error(`Trace upload failed (${response.status}): ${body}`);
|
|
135
|
+
}
|
|
136
|
+
return hash;
|
|
137
|
+
}
|
|
138
|
+
async function submitShard(serverUrl, buildId, shardIndex, shardTotal, screenshots) {
|
|
139
|
+
await apiRequest(serverUrl, `/api/v1/builds/${buildId}/shards`, {
|
|
140
|
+
method: "POST",
|
|
141
|
+
body: JSON.stringify({ shardIndex, screenshots }),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
export async function uploadScreenshots(files, opts) {
|
|
145
|
+
const { serverUrl } = opts;
|
|
146
|
+
// Detect test runner
|
|
147
|
+
const runner = detectRunner(process.cwd());
|
|
148
|
+
// Discover trace files
|
|
149
|
+
const traces = await discoverTraces(process.cwd());
|
|
150
|
+
if (traces.size > 0) {
|
|
151
|
+
console.log(`Found ${traces.size} trace files`);
|
|
152
|
+
}
|
|
153
|
+
// Step 1: Create or retrieve build
|
|
154
|
+
const build = await createBuild(serverUrl, opts, runner);
|
|
155
|
+
// Step 2: Upload screenshots (with dedup)
|
|
156
|
+
console.log(`Checking ${files.length} files for deduplication...`);
|
|
157
|
+
let uploadedCount = 0;
|
|
158
|
+
let skippedCount = 0;
|
|
159
|
+
for (const file of files) {
|
|
160
|
+
const exists = await checkFileExists(serverUrl, file.fileHash, opts.projectToken);
|
|
161
|
+
if (exists) {
|
|
162
|
+
skippedCount++;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
await uploadFile(serverUrl, file.filePath, file.fileHash, opts.projectToken);
|
|
166
|
+
uploadedCount++;
|
|
167
|
+
console.log(`Uploaded (${uploadedCount}): ${file.name}`);
|
|
168
|
+
}
|
|
169
|
+
console.log(`Upload complete: ${uploadedCount} uploaded, ${skippedCount} skipped (already exist).`);
|
|
170
|
+
// Step 3: Upload trace files and build trace map
|
|
171
|
+
const traceMap = new Map(); // screenshot name → trace storage key
|
|
172
|
+
if (traces.size > 0) {
|
|
173
|
+
const traceDirs = [...traces.keys()];
|
|
174
|
+
let traceUploaded = 0;
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
const matchedDir = matchTraceToScreenshot(file.name, traceDirs);
|
|
177
|
+
if (!matchedDir)
|
|
178
|
+
continue;
|
|
179
|
+
const tracePath = traces.get(matchedDir);
|
|
180
|
+
try {
|
|
181
|
+
const traceHash = await uploadTraceFile(serverUrl, tracePath, opts.projectToken);
|
|
182
|
+
// The trace will be stored at the same path pattern as screenshots but with trace hash
|
|
183
|
+
traceMap.set(file.name, traceHash);
|
|
184
|
+
traceUploaded++;
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
console.error(`Failed to upload trace for ${file.name}: ${err.message}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (traceUploaded > 0) {
|
|
191
|
+
console.log(`Uploaded ${traceUploaded} trace files`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Step 4: Submit shard manifest (with trace metadata)
|
|
195
|
+
const manifest = files.map((f) => {
|
|
196
|
+
const traceHash = traceMap.get(f.name);
|
|
197
|
+
return {
|
|
198
|
+
name: f.name,
|
|
199
|
+
fileHash: f.fileHash,
|
|
200
|
+
width: f.width,
|
|
201
|
+
height: f.height,
|
|
202
|
+
metadata: {
|
|
203
|
+
...f.metadata,
|
|
204
|
+
...(traceHash ? { traceHash } : {}),
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
await submitShard(serverUrl, build.id, opts.shardIndex, opts.shardTotal, manifest);
|
|
209
|
+
console.log("Done.");
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pixeyedev/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"bin": {
|
|
10
|
+
"pixeye": "dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"lint": "echo 'ok'",
|
|
16
|
+
"publish:dry": "npm run build && npm publish --access public --dry-run",
|
|
17
|
+
"publish:real": "npm run build && npm publish --access public"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"commander": "^13.0.0",
|
|
21
|
+
"glob": "^11.0.0",
|
|
22
|
+
"@pixeyedev/shared": "^0.1.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^22.0.0",
|
|
26
|
+
"typescript": "^5.7.0"
|
|
27
|
+
}
|
|
28
|
+
}
|