Generate small reusable component partitions with explicit provider dependencies, GitHub-hosted concurrency, fail-closed evidence, and exact mobile store gates. Include the literal-i18n fix from #206 so validation covers the exact post-merge tree.
61 lines
2.5 KiB
JavaScript
61 lines
2.5 KiB
JavaScript
export const DEPENDENCY_CI_ARTIFACT_PREFIX = "dependency-ci-results-";
|
|
export const DEPENDENCY_CI_RESULT_FILE = "dependency-ci-results.json";
|
|
export const DEPENDENCY_CI_SCHEMA_VERSION = 2;
|
|
export const dependencyCiStatuses = ["success", "failed", "dependency-blocked", "cancelled", "missing", "unselected"];
|
|
|
|
const requiredString = (value, label) => {
|
|
if (typeof value !== "string" || !value.trim()) {
|
|
throw new Error(`${label} must be a non-empty string.`);
|
|
}
|
|
};
|
|
|
|
export function validateDependencyCiResults(payload) {
|
|
if (!payload || typeof payload !== "object") {
|
|
throw new Error("Dependency CI results must be an object.");
|
|
}
|
|
if (payload.schemaVersion !== DEPENDENCY_CI_SCHEMA_VERSION) {
|
|
throw new Error(`Unsupported dependency CI schema version: ${payload.schemaVersion}.`);
|
|
}
|
|
requiredString(payload.sourceSha, "sourceSha");
|
|
requiredString(payload.profile, "profile");
|
|
if (!Number.isInteger(payload.graphVersion) || payload.graphVersion < 1) {
|
|
throw new Error("graphVersion must be a positive integer.");
|
|
}
|
|
if (typeof payload.requiredCi !== "boolean") {
|
|
throw new Error("requiredCi must be boolean.");
|
|
}
|
|
if (payload.infrastructure !== undefined) {
|
|
if (
|
|
!payload.infrastructure ||
|
|
typeof payload.infrastructure !== "object" ||
|
|
Array.isArray(payload.infrastructure)
|
|
) {
|
|
throw new Error("infrastructure must be an object.");
|
|
}
|
|
for (const jobId of ["plan_e2e", "quality", "build"]) {
|
|
if (!dependencyCiStatuses.includes(payload.infrastructure[jobId])) {
|
|
throw new Error(`infrastructure.${jobId} is invalid.`);
|
|
}
|
|
}
|
|
}
|
|
if (!Array.isArray(payload.results)) {
|
|
throw new Error("results must be an array.");
|
|
}
|
|
for (const [index, result] of payload.results.entries()) {
|
|
requiredString(result?.nodeId, `results[${index}].nodeId`);
|
|
requiredString(result?.lane, `results[${index}].lane`);
|
|
if (!dependencyCiStatuses.includes(result?.status)) {
|
|
throw new Error(`results[${index}].status is invalid.`);
|
|
}
|
|
for (const countField of ["expectedTests", "executedTests", "skippedTests"]) {
|
|
if (!Number.isInteger(result[countField]) || result[countField] < 0) {
|
|
throw new Error(`results[${index}].${countField} must be a non-negative integer.`);
|
|
}
|
|
}
|
|
if (!Array.isArray(result.roles) || result.roles.some((role) => typeof role !== "string" || !role)) {
|
|
throw new Error(`results[${index}].roles must be an array of non-empty strings.`);
|
|
}
|
|
}
|
|
return payload;
|
|
}
|