Skip to content

Commit 394cf85

Browse files
fix(pipeline): emit all required parallel-processing artifacts
- write modules.json, modules.min.json, and stats.json in parallel-processing - keep modules.stage.5 output schema-compliant and field-restricted - restore full output contract for full-refresh-parallel to prevent CI ENOENT failures
1 parent cc3baec commit 394cf85

1 file changed

Lines changed: 134 additions & 1 deletion

File tree

scripts/parallel-processing.js

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,27 @@ const STAGE5_ALLOWED_KEYS = [
6868
"packageJson"
6969
];
7070

71+
const FINAL_ALLOWED_KEYS = [
72+
"name",
73+
"category",
74+
"url",
75+
"id",
76+
"maintainer",
77+
"maintainerURL",
78+
"description",
79+
"outdated",
80+
"issues",
81+
"stars",
82+
"license",
83+
"hasGithubIssues",
84+
"isArchived",
85+
"tags",
86+
"image",
87+
"defaultSortWeight",
88+
"lastCommit",
89+
"keywords"
90+
];
91+
7192
function toStage5Module(module) {
7293
const entry = {};
7394

@@ -84,6 +105,103 @@ function toStage5Module(module) {
84105
return entry;
85106
}
86107

108+
function isValidDateTime(value) {
109+
return typeof value === "string" && value.length > 0 && !Number.isNaN(Date.parse(value));
110+
}
111+
112+
function getRepositoryHost(moduleUrl) {
113+
if (typeof moduleUrl !== "string") {
114+
return "unknown";
115+
}
116+
117+
try {
118+
const firstSegment = moduleUrl.split(".")[0];
119+
const segments = firstSegment.split("/");
120+
return segments[2] ?? "unknown";
121+
}
122+
catch {
123+
return "unknown";
124+
}
125+
}
126+
127+
function toFinalModule(module, fallbackTimestamp) {
128+
const issueList = Array.isArray(module.issues) ? module.issues : [];
129+
const stars = typeof module.stars === "number" ? module.stars : 0;
130+
131+
let defaultSortWeight = issueList.length - Math.floor(stars / 20);
132+
if (stars < 3) {
133+
defaultSortWeight = Math.max(defaultSortWeight, 1);
134+
}
135+
136+
if (module.outdated || module.category === "Outdated Modules") {
137+
defaultSortWeight += 900;
138+
}
139+
140+
const candidate = {
141+
...module,
142+
description:
143+
typeof module.description === "string" && module.description.length > 0
144+
? module.description
145+
: "No description provided.",
146+
issues: issueList.length > 0,
147+
defaultSortWeight,
148+
lastCommit: isValidDateTime(module.lastCommit)
149+
? module.lastCommit
150+
: fallbackTimestamp
151+
};
152+
153+
if (typeof candidate.license !== "string" || candidate.license.length === 0) {
154+
delete candidate.license;
155+
}
156+
157+
if (!Array.isArray(candidate.tags) || candidate.tags.length === 0) {
158+
delete candidate.tags;
159+
}
160+
161+
if (!Array.isArray(candidate.keywords) || candidate.keywords.length === 0) {
162+
delete candidate.keywords;
163+
}
164+
165+
const entry = {};
166+
for (const key of FINAL_ALLOWED_KEYS) {
167+
if (Object.hasOwn(candidate, key) && typeof candidate[key] !== "undefined") {
168+
entry[key] = candidate[key];
169+
}
170+
}
171+
172+
return entry;
173+
}
174+
175+
function buildStats(stage5Modules, finalModules, timestamp) {
176+
const repositoryHoster = {};
177+
const maintainer = {};
178+
179+
for (const module of finalModules) {
180+
const hoster = getRepositoryHost(module.url);
181+
repositoryHoster[hoster] = (repositoryHoster[hoster] ?? 0) + 1;
182+
maintainer[module.maintainer] = (maintainer[module.maintainer] ?? 0) + 1;
183+
}
184+
185+
const issueCounter = stage5Modules.reduce((count, module) => {
186+
if (Array.isArray(module.issues)) {
187+
return count + module.issues.length;
188+
}
189+
return count;
190+
}, 0);
191+
192+
return {
193+
moduleCounter: finalModules.length,
194+
modulesWithImageCounter: finalModules.filter(module => typeof module.image === "string" && module.image.length > 0).length,
195+
modulesWithIssuesCounter: finalModules.filter(module => module.issues === true).length,
196+
issueCounter,
197+
lastUpdate: timestamp,
198+
repositoryHoster,
199+
maintainer: Object.fromEntries(
200+
Object.entries(maintainer).sort(([, left], [, right]) => right - left)
201+
)
202+
};
203+
}
204+
87205
async function main() {
88206
const startTime = Date.now();
89207

@@ -170,10 +288,25 @@ async function main() {
170288
});
171289
const stage5Modules = mergedModules.map(toStage5Module);
172290

173-
// Write results to stage 5 output
291+
// Write stage 5 output and final public artefacts.
174292
const stage5Path = resolve(PROJECT_ROOT, "website/data/modules.stage.5.json");
293+
const modulesJsonPath = resolve(PROJECT_ROOT, "website/data/modules.json");
294+
const modulesMinPath = resolve(PROJECT_ROOT, "website/data/modules.min.json");
295+
const statsPath = resolve(PROJECT_ROOT, "website/data/stats.json");
296+
297+
const lastUpdate = new Date().toISOString();
298+
const finalModules = stage5Modules.map(module => toFinalModule(module, lastUpdate));
299+
const stats = buildStats(stage5Modules, finalModules, lastUpdate);
300+
175301
const stage5Data = stringifyDeterministic({ modules: stage5Modules });
302+
const modulesData = stringifyDeterministic({ modules: finalModules });
303+
const modulesMinData = stringifyDeterministic({ modules: finalModules }, 0);
304+
const statsData = stringifyDeterministic(stats);
305+
176306
await writeFile(stage5Path, stage5Data, "utf-8");
307+
await writeFile(modulesJsonPath, modulesData, "utf-8");
308+
await writeFile(modulesMinPath, modulesMinData, "utf-8");
309+
await writeFile(statsPath, statsData, "utf-8");
177310

178311
const duration = Date.now() - startTime;
179312
const avgTime = Math.round(duration / results.length);

0 commit comments

Comments
 (0)