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>
This commit is contained in:
Aaron Powell
2026-06-23 16:24:02 +10:00
parent ee39347184
commit dabd0ba0f1
6 changed files with 297 additions and 18 deletions
+20 -10
View File
@@ -3,7 +3,9 @@
import fs from "fs";
import os from "os";
import path from "path";
import { Writable } from "stream";
import { spawnSync } from "child_process";
import { runLint, LintConsoleReporter } from "@microsoft/vally";
const MAX_OUTPUT_LENGTH = 12000;
@@ -182,7 +184,7 @@ function buildVallyLintArgs(pluginRoot) {
return [pluginRoot];
}
function runVallyLintGate(pluginRoot) {
async function runVallyLintGate(pluginRoot) {
try {
const targets = buildVallyLintArgs(pluginRoot);
@@ -190,12 +192,20 @@ function runVallyLintGate(pluginRoot) {
let anyFailure = false;
for (const target of targets) {
const check = runCommand(
"npx",
["--yes", "@microsoft/vally-cli", "lint", target, "--verbose"],
);
combinedOutput += check.output + "\n";
if (check.exitCode !== 0) {
const chunks = [];
const captureStream = new Writable({
write(chunk, _encoding, callback) {
chunks.push(chunk.toString());
callback();
},
});
const result = await runLint({ rootPath: target });
const reporter = new LintConsoleReporter({ verbose: true, stream: captureStream });
await reporter.report(result);
combinedOutput += chunks.join("") + "\n";
if (!result.passed) {
anyFailure = true;
}
}
@@ -318,7 +328,7 @@ function toFailureClass(overallStatus) {
return "none";
}
export function runExternalPluginQualityGates(plugin) {
export async function runExternalPluginQualityGates(plugin) {
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "external-plugin-quality-"));
const result = {
overall_status: "not_run",
@@ -344,7 +354,7 @@ export function runExternalPluginQualityGates(plugin) {
return result;
}
const vallyResult = runVallyLintGate(pluginRoot);
const vallyResult = await runVallyLintGate(pluginRoot);
result.vally_lint_status = vallyResult.status;
result.vally_lint_output = vallyResult.output;
@@ -394,6 +404,6 @@ if (import.meta.url === `file://${process.argv[1]}`) {
}
const plugin = JSON.parse(args["plugin-json"]);
const result = runExternalPluginQualityGates(plugin);
const result = await runExternalPluginQualityGates(plugin);
process.stdout.write(`${JSON.stringify(result)}\n`);
}