Skip to content

Commit 7e920c2

Browse files
fix(core): order pkg.pr.new canary publishes by dependency (module-federation#4458)
Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
1 parent 374f5c2 commit 7e920c2

1 file changed

Lines changed: 76 additions & 7 deletions

File tree

.github/workflows/pkg-pr-new.yml

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
const fixed = new Set((config.fixed || []).flat());
7070
const roots = ["packages", "apps"];
7171
const skipDirNames = new Set(["dist", "node_modules", ".git", ".nx"]);
72-
const packagePathByName = new Map();
72+
const packageMetaByName = new Map();
7373
7474
function walk(dir) {
7575
if (!fs.existsSync(dir)) return;
@@ -84,9 +84,13 @@ jobs:
8484
const pkgDir = path.dirname(fullPath);
8585
const pkg = JSON.parse(fs.readFileSync(fullPath, "utf8"));
8686
if (fixed.has(pkg.name) && pkg.private !== true) {
87-
const existing = packagePathByName.get(pkg.name);
88-
if (!existing || pkgDir.length < existing.length) {
89-
packagePathByName.set(pkg.name, pkgDir);
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+
});
9094
}
9195
}
9296
}
@@ -97,9 +101,73 @@ jobs:
97101
walk(root);
98102
}
99103
100-
// Deduplicate by package name and sort for stable output.
101-
const sorted = Array.from(packagePathByName.values()).sort();
102-
process.stdout.write(JSON.stringify(sorted));
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));
103171
')
104172
105173
echo "paths_json=$paths_json" >> "$GITHUB_OUTPUT"
@@ -131,6 +199,7 @@ jobs:
131199
"--pnpm",
132200
"--packageManager=pnpm",
133201
"--comment=update",
202+
"--commentWithSha",
134203
...paths,
135204
];
136205

0 commit comments

Comments
 (0)