@@ -58,201 +58,5 @@ jobs:
5858 npx nx run-many --targets=build --projects=tag:type:pkg --skip-nx-cache || \
5959 (sleep 5 && npx nx run-many --targets=build --projects=tag:type:pkg --skip-nx-cache)
6060
61- - name : Resolve synced Changesets package paths
62- id : package_paths
63- run : |
64- paths_json=$(node -e '
65- const fs = require("fs");
66- const path = require("path");
67-
68- const config = JSON.parse(fs.readFileSync(".changeset/config.json", "utf8"));
69- const fixed = new Set((config.fixed || []).flat());
70- const roots = ["packages", "apps"];
71- const skipDirNames = new Set(["dist", "node_modules", ".git", ".nx"]);
72- const packageMetaByName = new Map();
73-
74- function walk(dir) {
75- if (!fs.existsSync(dir)) return;
76- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
77- const fullPath = path.join(dir, entry.name);
78- if (entry.isDirectory()) {
79- if (skipDirNames.has(entry.name)) continue;
80- walk(fullPath);
81- continue;
82- }
83- if (entry.isFile() && entry.name === "package.json") {
84- const pkgDir = path.dirname(fullPath);
85- const pkg = JSON.parse(fs.readFileSync(fullPath, "utf8"));
86- if (fixed.has(pkg.name) && pkg.private !== true) {
87- const existing = packageMetaByName.get(pkg.name);
88- if (!existing || pkgDir.length < existing.path.length) {
89- packageMetaByName.set(pkg.name, {
90- name: pkg.name,
91- path: pkgDir,
92- pkg,
93- });
94- }
95- }
96- }
97- }
98- }
99-
100- for (const root of roots) {
101- walk(root);
102- }
103-
104- const dependencyFields = [
105- "dependencies",
106- "devDependencies",
107- "optionalDependencies",
108- "peerDependencies",
109- ];
110-
111- for (const meta of packageMetaByName.values()) {
112- const internalDeps = new Set();
113- for (const field of dependencyFields) {
114- const deps = meta.pkg[field];
115- if (!deps || typeof deps !== "object") continue;
116- for (const depName of Object.keys(deps)) {
117- if (packageMetaByName.has(depName)) {
118- internalDeps.add(depName);
119- }
120- }
121- }
122- meta.internalDeps = internalDeps;
123- }
124-
125- const indegreeByName = new Map();
126- const dependentsByName = new Map();
127- for (const [name, meta] of packageMetaByName) {
128- indegreeByName.set(name, meta.internalDeps.size);
129- dependentsByName.set(name, new Set());
130- }
131-
132- for (const [name, meta] of packageMetaByName) {
133- for (const depName of meta.internalDeps) {
134- dependentsByName.get(depName).add(name);
135- }
136- }
137-
138- const queue = Array.from(indegreeByName.entries())
139- .filter(([, degree]) => degree === 0)
140- .map(([name]) => name)
141- .sort();
142- const orderedNames = [];
143-
144- while (queue.length) {
145- const current = queue.shift();
146- orderedNames.push(current);
147- const dependents = Array.from(dependentsByName.get(current) || []).sort();
148- for (const dependent of dependents) {
149- const nextDegree = (indegreeByName.get(dependent) || 0) - 1;
150- indegreeByName.set(dependent, nextDegree);
151- if (nextDegree === 0) {
152- queue.push(dependent);
153- }
154- }
155- queue.sort();
156- }
157-
158- if (orderedNames.length !== packageMetaByName.size) {
159- const remaining = Array.from(packageMetaByName.keys())
160- .filter((name) => !orderedNames.includes(name))
161- .sort((a, b) => {
162- const pathA = packageMetaByName.get(a).path;
163- const pathB = packageMetaByName.get(b).path;
164- return pathA.localeCompare(pathB);
165- });
166- orderedNames.push(...remaining);
167- }
168-
169- const orderedPaths = orderedNames.map((name) => packageMetaByName.get(name).path);
170- process.stdout.write(JSON.stringify(orderedPaths));
171- ')
172-
173- echo "paths_json=$paths_json" >> "$GITHUB_OUTPUT"
174-
17561 - name : Publish pkg.pr.new previews
176- env :
177- PKG_PATHS_JSON : ${{ steps.package_paths.outputs.paths_json }}
178- run : |
179- # shellcheck disable=SC2016
180- node -e '
181- const { spawnSync } = require("child_process");
182- const paths = JSON.parse(process.env.PKG_PATHS_JSON || "[]");
183- if (!paths.length) {
184- console.log("No synced Changesets packages found to publish.");
185- process.exit(0);
186- }
187-
188- function isRetriablePkgPrFailure(output) {
189- return (
190- /Publishing failed \((5\d\d|429)\)/.test(output) ||
191- /Cloudflare|Internal Server Error|Bad Gateway|Gateway Timeout/.test(output)
192- );
193- }
194-
195- const args = [
196- "dlx",
197- "pkg-pr-new",
198- "publish",
199- "--pnpm",
200- "--packageManager=pnpm",
201- "--comment=update",
202- "--commentWithSha",
203- ...paths,
204- ];
205-
206- const maxAttempts = 3;
207- const baseDelaySeconds = 10;
208- let lastStatus = 1;
209-
210- for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
211- if (attempt > 1) {
212- console.warn(`Retrying pkg.pr.new publish (attempt ${attempt}/${maxAttempts})...`);
213- }
214-
215- const result = spawnSync("pnpm", args, {
216- encoding: "utf8",
217- timeout: 12 * 60 * 1000,
218- maxBuffer: 10 * 1024 * 1024,
219- });
220- if (result.stdout) process.stdout.write(result.stdout);
221- if (result.stderr) process.stderr.write(result.stderr);
222-
223- if (result.status === 0) {
224- process.exit(0);
225- }
226-
227- const commandError = result.error;
228- const combinedOutput = `${result.stdout || ""}\n${result.stderr || ""}\n${
229- commandError?.message || ""
230- }`;
231- if (combinedOutput.includes("https://github.com/apps/pkg-pr-new is not installed")) {
232- console.log("pkg.pr.new app is not installed on this repository; skipping preview publish.");
233- process.exit(0);
234- }
235-
236- lastStatus = result.status || 1;
237- const timedOut = commandError?.code === "ETIMEDOUT";
238- const shouldRetry =
239- attempt < maxAttempts &&
240- (timedOut || isRetriablePkgPrFailure(combinedOutput));
241- if (!shouldRetry) {
242- if (commandError) {
243- console.error(`pkg.pr.new publish failed to execute: ${commandError.message}`);
244- }
245- process.exit(lastStatus);
246- }
247-
248- const delaySeconds = baseDelaySeconds * 2 ** (attempt - 1);
249- console.warn(
250- `pkg.pr.new publish failed with ${
251- timedOut ? "timeout" : "retriable error"
252- }. Waiting ${delaySeconds}s before retry...`,
253- );
254- spawnSync("bash", ["-lc", `sleep ${delaySeconds}`], { stdio: "inherit" });
255- }
256-
257- process.exit(lastStatus);
258- '
62+ run : node tools/scripts/publish-pkg-pr-new-previews.mjs
0 commit comments