mirror of
https://github.com/github/awesome-copilot.git
synced 2026-07-17 19:31:20 +00:00
chore: publish from main
This commit is contained in:
@@ -8,6 +8,7 @@ import { spawnSync } from "child_process";
|
||||
import { runLint, LintConsoleReporter } from "@microsoft/vally";
|
||||
|
||||
const MAX_OUTPUT_LENGTH = 12000;
|
||||
const EXTERNAL_CANVAS_KEYWORD = "canvas";
|
||||
|
||||
const INFRA_ERROR_PATTERNS = [
|
||||
/\b401\b/,
|
||||
@@ -69,6 +70,12 @@ function normalizePluginPath(pluginPath) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function hasCanvasKeyword(plugin) {
|
||||
return (plugin?.keywords ?? []).some(
|
||||
(keyword) => String(keyword).trim().toLowerCase() === EXTERNAL_CANVAS_KEYWORD,
|
||||
);
|
||||
}
|
||||
|
||||
function resolveFetchSpec(pluginSource) {
|
||||
if (pluginSource.sha) {
|
||||
return pluginSource.sha;
|
||||
@@ -467,6 +474,148 @@ function runVersionMatchGate(repoDir, plugin, primaryFetchSpec) {
|
||||
};
|
||||
}
|
||||
|
||||
function checkPathExistsAtLocator(repoDir, locator, repoPath, expectedType) {
|
||||
const result = runCommand("git", ["cat-file", "-e", `${locator}:${repoPath}`], { cwd: repoDir });
|
||||
if (result.exitCode === 0) {
|
||||
if (!expectedType) {
|
||||
return { exists: true, output: "" };
|
||||
}
|
||||
|
||||
const typeResult = runCommand("git", ["cat-file", "-t", `${locator}:${repoPath}`], { cwd: repoDir });
|
||||
if (typeResult.exitCode !== 0) {
|
||||
return {
|
||||
exists: false,
|
||||
output: `Unable to verify path "${repoPath}" type at "${locator}": ${typeResult.output}`,
|
||||
};
|
||||
}
|
||||
|
||||
const actualType = String(typeResult.stdout ?? "").trim();
|
||||
if (actualType !== expectedType) {
|
||||
return {
|
||||
exists: false,
|
||||
output: "",
|
||||
kindMismatch: true,
|
||||
actualType,
|
||||
};
|
||||
}
|
||||
|
||||
return { exists: true, output: "" };
|
||||
}
|
||||
|
||||
const normalizedOutput = String(result.output ?? "").toLowerCase();
|
||||
if (
|
||||
normalizedOutput.includes("not a valid object name")
|
||||
|| normalizedOutput.includes("path '")
|
||||
|| normalizedOutput.includes("does not exist")
|
||||
) {
|
||||
return { exists: false, output: "" };
|
||||
}
|
||||
|
||||
return {
|
||||
exists: false,
|
||||
output: `Unable to verify path "${repoPath}" at "${locator}": ${result.output}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function runCanvasStructureGate(repoDir, plugin, primaryFetchSpec) {
|
||||
if (!hasCanvasKeyword(plugin)) {
|
||||
return {
|
||||
status: "not_run",
|
||||
output: "Canvas structure gate skipped because plugin is not tagged with \"canvas\".",
|
||||
};
|
||||
}
|
||||
|
||||
const normalizedPluginPath = normalizePluginPath(plugin?.source?.path || "/");
|
||||
const locators = [plugin?.source?.ref, plugin?.source?.sha]
|
||||
.filter((value) => typeof value === "string" && value.trim().length > 0)
|
||||
.map((value) => value.trim())
|
||||
.filter((value, index, values) => values.indexOf(value) === index);
|
||||
|
||||
if (locators.length === 0) {
|
||||
return {
|
||||
status: "not_run",
|
||||
output: "Canvas structure gate skipped because neither source.ref nor source.sha was provided.",
|
||||
};
|
||||
}
|
||||
|
||||
const extensionsDir = toPosixPath(normalizedPluginPath, "extensions");
|
||||
const extensionEntryPoint = toPosixPath(extensionsDir, "extension.mjs");
|
||||
|
||||
let hasFailure = false;
|
||||
let hasInfraError = false;
|
||||
const messages = [];
|
||||
|
||||
for (const locator of locators) {
|
||||
if (locator !== primaryFetchSpec) {
|
||||
const fetchResult = fetchLocatorIntoRepo(repoDir, locator);
|
||||
if (fetchResult.status === "fail") {
|
||||
hasFailure = true;
|
||||
messages.push(`- ${locator}: ${fetchResult.output}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fetchResult.status === "infra_error") {
|
||||
hasInfraError = true;
|
||||
messages.push(`- ${locator}: ${fetchResult.output}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const extensionDirCheck = checkPathExistsAtLocator(repoDir, locator, extensionsDir, "tree");
|
||||
if (extensionDirCheck.output) {
|
||||
hasInfraError = true;
|
||||
messages.push(`- ${locator}: ${extensionDirCheck.output}`);
|
||||
continue;
|
||||
}
|
||||
if (!extensionDirCheck.exists) {
|
||||
hasFailure = true;
|
||||
if (extensionDirCheck.kindMismatch) {
|
||||
messages.push(`- ${locator}: "${extensionsDir}" must be a directory.`);
|
||||
} else {
|
||||
messages.push(`- ${locator}: missing required canvas extension directory "${extensionsDir}".`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const extensionEntryCheck = checkPathExistsAtLocator(repoDir, locator, extensionEntryPoint, "blob");
|
||||
if (extensionEntryCheck.output) {
|
||||
hasInfraError = true;
|
||||
messages.push(`- ${locator}: ${extensionEntryCheck.output}`);
|
||||
continue;
|
||||
}
|
||||
if (!extensionEntryCheck.exists) {
|
||||
hasFailure = true;
|
||||
if (extensionEntryCheck.kindMismatch) {
|
||||
messages.push(`- ${locator}: "${extensionEntryPoint}" must be a file.`);
|
||||
} else {
|
||||
messages.push(`- ${locator}: missing required canvas extension entry point "${extensionEntryPoint}".`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
messages.push(`- ${locator}: found "${extensionsDir}" with entry point "${extensionEntryPoint}".`);
|
||||
}
|
||||
|
||||
if (hasInfraError) {
|
||||
return {
|
||||
status: "infra_error",
|
||||
output: messages.join("\n"),
|
||||
};
|
||||
}
|
||||
|
||||
if (hasFailure) {
|
||||
return {
|
||||
status: "fail",
|
||||
output: messages.join("\n"),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "pass",
|
||||
output: messages.join("\n"),
|
||||
};
|
||||
}
|
||||
|
||||
function toOverallStatus(states) {
|
||||
if (states.includes("infra_error")) {
|
||||
return "infra_error";
|
||||
@@ -497,11 +646,13 @@ export async function runExternalPluginQualityGates(plugin) {
|
||||
vally_lint_status: "not_run",
|
||||
smoke_status: "not_run",
|
||||
version_match_status: "not_run",
|
||||
canvas_structure_status: "not_run",
|
||||
failure_class: "none",
|
||||
summary: "",
|
||||
vally_lint_output: "",
|
||||
smoke_output: "",
|
||||
version_match_output: "",
|
||||
canvas_structure_output: "",
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -513,10 +664,14 @@ export async function runExternalPluginQualityGates(plugin) {
|
||||
result.vally_lint_status = "fail";
|
||||
result.smoke_status = "fail";
|
||||
result.version_match_status = "fail";
|
||||
result.canvas_structure_status = hasCanvasKeyword(plugin) ? "fail" : "not_run";
|
||||
result.overall_status = "fail";
|
||||
result.failure_class = "submitter_fixes";
|
||||
result.summary = `Plugin path "${plugin.source?.path || "/"}" was not found in the submitted repository snapshot.`;
|
||||
result.version_match_output = result.summary;
|
||||
if (hasCanvasKeyword(plugin)) {
|
||||
result.canvas_structure_output = result.summary;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -524,6 +679,10 @@ export async function runExternalPluginQualityGates(plugin) {
|
||||
result.version_match_status = versionMatchResult.status;
|
||||
result.version_match_output = versionMatchResult.output;
|
||||
|
||||
const canvasStructureResult = runCanvasStructureGate(repoDir, plugin, fetchSpec);
|
||||
result.canvas_structure_status = canvasStructureResult.status;
|
||||
result.canvas_structure_output = canvasStructureResult.output;
|
||||
|
||||
const vallyResult = await runVallyLintGate(pluginRoot);
|
||||
result.vally_lint_status = vallyResult.status;
|
||||
result.vally_lint_output = vallyResult.output;
|
||||
@@ -532,12 +691,18 @@ export async function runExternalPluginQualityGates(plugin) {
|
||||
result.smoke_status = smokeResult.status;
|
||||
result.smoke_output = smokeResult.output;
|
||||
|
||||
result.overall_status = toOverallStatus([result.vally_lint_status, result.smoke_status, result.version_match_status]);
|
||||
result.overall_status = toOverallStatus([
|
||||
result.vally_lint_status,
|
||||
result.smoke_status,
|
||||
result.version_match_status,
|
||||
result.canvas_structure_status,
|
||||
]);
|
||||
result.failure_class = toFailureClass(result.overall_status);
|
||||
result.summary = [
|
||||
`- vally lint: ${result.vally_lint_status}`,
|
||||
`- install smoke test: ${result.smoke_status}`,
|
||||
`- version match: ${result.version_match_status}`,
|
||||
`- canvas structure: ${result.canvas_structure_status}`,
|
||||
`- overall: ${result.overall_status}`,
|
||||
].join("\n");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user