|
1 |
| -// Utility for fetching Percy snapshot IDs for a given build (up to `maxSnapshots`). |
2 |
| -export async function getPercySnapshotIds( |
| 1 | +import { getBrowserStackAuth } from "../../lib/get-auth.js"; |
| 2 | +import { BrowserStackConfig } from "../../lib/types.js"; |
| 3 | +import { sanitizeUrlParam } from "../../lib/utils.js"; |
| 4 | + |
| 5 | +// Utility for fetching only the IDs of changed Percy snapshots for a given build. |
| 6 | +export async function getChangedPercySnapshotIds( |
3 | 7 | buildId: string,
|
4 |
| - percyToken: string, |
5 |
| - maxSnapshots = 300, |
| 8 | + config: BrowserStackConfig, |
| 9 | + orgId: string | undefined, |
6 | 10 | ): Promise<string[]> {
|
7 |
| - const perPage = 30; |
8 |
| - const allSnapshotIds: string[] = []; |
9 |
| - let cursor: string | undefined = undefined; |
| 11 | + |
| 12 | + if (!buildId || !orgId) { |
| 13 | + throw new Error( |
| 14 | + "Failed to fetch AI Summary: Missing build ID or organization ID", |
| 15 | + ); |
| 16 | + } |
10 | 17 |
|
11 |
| - while (allSnapshotIds.length < maxSnapshots) { |
12 |
| - const url = new URL(`https://percy.io/api/v1/snapshots`); |
13 |
| - url.searchParams.set("build_id", buildId); |
14 |
| - url.searchParams.set("page[limit]", String(perPage)); |
15 |
| - if (cursor) url.searchParams.set("page[cursor]", cursor); |
| 18 | + const urlStr = constructPercyBuildItemsUrl({ |
| 19 | + buildId, |
| 20 | + orgId, |
| 21 | + category: ["changed"], |
| 22 | + subcategories: ["unreviewed","approved","changes_requested"], |
| 23 | + groupSnapshotsBy: "similar_diff", |
| 24 | + browserIds: ["63", "64", "69", "70", "71"], |
| 25 | + widths: ["375","1280","1920"], |
| 26 | + }); |
16 | 27 |
|
17 |
| - const response = await fetch(url.toString(), { |
18 |
| - headers: { |
19 |
| - Authorization: `Token token=${percyToken}`, |
20 |
| - "Content-Type": "application/json", |
21 |
| - }, |
22 |
| - }); |
| 28 | + const authString = getBrowserStackAuth(config); |
| 29 | + const auth = Buffer.from(authString).toString("base64"); |
| 30 | + const response = await fetch(urlStr, { |
| 31 | + headers: { |
| 32 | + Authorization: `Basic ${auth}`, |
| 33 | + "Content-Type": "application/json", |
| 34 | + }, |
| 35 | + }); |
23 | 36 |
|
24 |
| - if (!response.ok) { |
25 |
| - throw new Error( |
26 |
| - `Failed to fetch Percy snapshots: ${response.statusText}`, |
27 |
| - ); |
28 |
| - } |
| 37 | + if (!response.ok) { |
| 38 | + throw new Error( |
| 39 | + `Failed to fetch changed Percy snapshots: ${response.status} ${response.statusText}`, |
| 40 | + ); |
| 41 | + } |
29 | 42 |
|
30 |
| - const data = await response.json(); |
31 |
| - const snapshots = data.data ?? []; |
32 |
| - if (snapshots.length === 0) break; // no more snapshots |
| 43 | + const responseData = await response.json(); |
| 44 | + const buildItems = responseData.data ?? []; |
33 | 45 |
|
34 |
| - allSnapshotIds.push(...snapshots.map((s: any) => String(s.id))); |
| 46 | + if (buildItems.length === 0) { |
| 47 | + return []; |
| 48 | + } |
35 | 49 |
|
36 |
| - // Set cursor to last snapshot ID of this page for next iteration |
37 |
| - cursor = snapshots[snapshots.length - 1].id; |
| 50 | + const snapshotIds = buildItems |
| 51 | + .flatMap((item: any) => item.attributes?.["snapshot-ids"] ?? []) |
| 52 | + .map((id: any) => String(id)); |
38 | 53 |
|
39 |
| - // Stop if we've collected enough |
40 |
| - if (allSnapshotIds.length >= maxSnapshots) break; |
41 |
| - } |
| 54 | + return snapshotIds; |
| 55 | +} |
42 | 56 |
|
43 |
| - // Return only up to maxSnapshots |
44 |
| - return allSnapshotIds.slice(0, maxSnapshots); |
| 57 | +export function constructPercyBuildItemsUrl({ |
| 58 | + buildId, |
| 59 | + orgId, |
| 60 | + category = [], |
| 61 | + subcategories = [], |
| 62 | + browserIds = [], |
| 63 | + widths = [], |
| 64 | + groupSnapshotsBy, |
| 65 | +}: { |
| 66 | + buildId: string; |
| 67 | + orgId: string; |
| 68 | + category?: string[]; |
| 69 | + subcategories?: string[]; |
| 70 | + browserIds?: string[]; |
| 71 | + widths?: string[]; |
| 72 | + groupSnapshotsBy?: string; |
| 73 | +}): string { |
| 74 | + const url = new URL("https://percy.io/api/v1/build-items"); |
| 75 | + url.searchParams.set("filter[build-id]", sanitizeUrlParam(buildId)); |
| 76 | + url.searchParams.set("filter[organization-id]", sanitizeUrlParam(orgId)); |
| 77 | + |
| 78 | + if (category && category.length > 0) { |
| 79 | + category.forEach((cat) => |
| 80 | + url.searchParams.append("filter[category][]", sanitizeUrlParam(cat)) |
| 81 | + ); |
| 82 | + } |
| 83 | + if (subcategories && subcategories.length > 0) { |
| 84 | + subcategories.forEach((sub) => |
| 85 | + url.searchParams.append("filter[subcategories][]", sanitizeUrlParam(sub)) |
| 86 | + ); |
| 87 | + } |
| 88 | + if (browserIds && browserIds.length > 0) { |
| 89 | + browserIds.forEach((id) => |
| 90 | + url.searchParams.append("filter[browser_ids][]", sanitizeUrlParam(id)) |
| 91 | + ); |
| 92 | + } |
| 93 | + if (widths && widths.length > 0) { |
| 94 | + widths.forEach((w) => |
| 95 | + url.searchParams.append("filter[widths][]", sanitizeUrlParam(w)) |
| 96 | + ); |
| 97 | + } |
| 98 | + if (groupSnapshotsBy) { |
| 99 | + url.searchParams.set("filter[group_snapshots_by]", sanitizeUrlParam(groupSnapshotsBy)); |
| 100 | + } |
| 101 | + return url.toString(); |
45 | 102 | }
|
0 commit comments