Files
awesome-copilot/eng/external-plugin-pr-quality-gates.mjs
T
Aaron Powell dabd0ba0f1 Use @microsoft/vally library directly instead of vally-cli subprocess
Replace the npx-spawned vally-cli process with a direct call to the
@microsoft/vally core library in the external plugin quality gates scripts:

- Add @microsoft/vally as a devDependency in package.json
- Import runLint and LintConsoleReporter from @microsoft/vally
- Replace runVallyLintGate() process spawn with async API call:
  - runLint({ rootPath }) returns structured LintResults
  - LintConsoleReporter with a Writable capture stream collects
    text output without printing to stdout
- Make runExternalPluginQualityGates() async (propagated to
  runExternalPluginPrQualityGates() and both main entry points)
- Use Promise.all in runExternalPluginPrQualityGates() for parallel
  plugin checks
- Fix remaining skill_validator_status reference in pr-quality-gates
  summary string (now vally-lint=...) and YAML workflow table header
- Add 'npm install @microsoft/vally' step to both calling workflows

This removes a layer of indirection (Node -> npx -> CLI -> library)
and replaces it with a direct in-process library call, which is faster,
more reliable, and gives structured access to lint results.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 16:24:02 +10:00

126 lines
3.3 KiB
JavaScript

#!/usr/bin/env node
import { runExternalPluginQualityGates } from "./external-plugin-quality-gates.mjs";
function normalizePluginPath(pluginPath) {
if (!pluginPath || pluginPath === "/") {
return "";
}
return String(pluginPath).trim().replace(/^\/+|\/+$/g, "");
}
function encodePathLikeValue(value) {
return String(value)
.split("/")
.map((segment) => encodeURIComponent(segment))
.join("/");
}
export function buildSourceTreeUrl(plugin) {
const sourceRepo = plugin?.source?.repo;
if (!sourceRepo) {
return "";
}
const sourceLocator = plugin?.source?.sha || plugin?.source?.ref;
if (!sourceLocator) {
return `https://github.com/${sourceRepo}`;
}
const encodedLocator = encodeURIComponent(sourceLocator);
const normalizedPath = normalizePluginPath(plugin?.source?.path);
if (!normalizedPath) {
return `https://github.com/${sourceRepo}/tree/${encodedLocator}`;
}
const encodedPath = encodePathLikeValue(normalizedPath);
return `https://github.com/${sourceRepo}/tree/${encodedLocator}/${encodedPath}`;
}
function aggregateResultStatus(pluginResults) {
if (pluginResults.some((entry) => entry.quality?.overall_status === "fail")) {
return {
overallStatus: "fail",
failureClass: "submitter_fixes",
};
}
if (pluginResults.some((entry) => entry.quality?.overall_status === "infra_error")) {
return {
overallStatus: "infra_error",
failureClass: "infra",
};
}
if (pluginResults.length === 0) {
return {
overallStatus: "not_run",
failureClass: "none",
};
}
return {
overallStatus: "pass",
failureClass: "none",
};
}
export async function runExternalPluginPrQualityGates(plugins) {
if (!Array.isArray(plugins)) {
throw new Error("plugins must be an array");
}
const checkedPlugins = await Promise.all(plugins.map(async (plugin) => {
const quality = await runExternalPluginQualityGates(plugin);
return {
name: plugin?.name ?? "unknown",
source: plugin?.source ?? {},
source_tree_url: buildSourceTreeUrl(plugin),
quality,
};
}));
const aggregate = aggregateResultStatus(checkedPlugins);
const summary = checkedPlugins.length === 0
? "No changed external plugin entries were detected in plugins/external.json."
: checkedPlugins
.map((entry) =>
`- ${entry.name}: vally-lint=${entry.quality.vally_lint_status}, install-smoke=${entry.quality.smoke_status}, overall=${entry.quality.overall_status}`
)
.join("\n");
return {
overall_status: aggregate.overallStatus,
failure_class: aggregate.failureClass,
summary,
checked_plugins: checkedPlugins,
};
}
function parseCliArgs(argv) {
const args = {};
for (let index = 0; index < argv.length; index += 1) {
const key = argv[index];
if (!key.startsWith("--")) {
continue;
}
args[key.slice(2)] = argv[index + 1];
index += 1;
}
return args;
}
if (import.meta.url === `file://${process.argv[1]}`) {
const args = parseCliArgs(process.argv.slice(2));
if (!args["plugins-json"]) {
console.error("Usage: node ./eng/external-plugin-pr-quality-gates.mjs --plugins-json '<json-array>'");
process.exit(1);
}
const plugins = JSON.parse(args["plugins-json"]);
const result = await runExternalPluginPrQualityGates(plugins);
process.stdout.write(`${JSON.stringify(result)}\n`);
}