feat: deliver policy-driven Git Validator 2.0
This commit is contained in:
@@ -75,8 +75,14 @@ async function handleShellActions(event, target, action, repository) {
|
||||
} else if (action === "git-validator-repair") {
|
||||
const check = ui.gitValidation?.checks?.[Number(target.dataset.checkIndex)];
|
||||
if (!check?.fixAction) return;
|
||||
if (!check.safe && !confirm(check.confirmation || `Apply ${check.title}?`))
|
||||
let preview;
|
||||
try {
|
||||
preview = await window.forgeflow.gitValidatorPreviewRepair(repository.fullName, check);
|
||||
} catch (error) {
|
||||
showToast("Preview failed", error.message, "error");
|
||||
return;
|
||||
}
|
||||
if (!confirm(`${check.confirmation || `Apply ${check.title}?`}\n\nReviewable change:\n${preview.diff}\n\nNothing will be committed or pushed.`)) return;
|
||||
setLoading(true, `Repairing ${check.title}…`);
|
||||
try {
|
||||
await window.forgeflow.gitValidatorRepair(repository.fullName, check);
|
||||
@@ -90,27 +96,46 @@ async function handleShellActions(event, target, action, repository) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
} else if (action === "git-validator-repair-safe") {
|
||||
const checks = (ui.gitValidation?.checks || []).filter(
|
||||
(check) => check.fixAction && check.safe,
|
||||
);
|
||||
setLoading(true, `Applying ${checks.length} safe Git fixes…`);
|
||||
let repaired = 0;
|
||||
} else if (action === "git-validator-policy") {
|
||||
setLoading(true, "Applying assurance policy…");
|
||||
try {
|
||||
for (const check of checks) {
|
||||
await window.forgeflow.gitValidatorRepair(repository.fullName, check);
|
||||
repaired += 1;
|
||||
}
|
||||
await refreshRepositories(false, true);
|
||||
ui.gitValidation = await window.forgeflow.gitValidatorScan(
|
||||
repository.fullName,
|
||||
);
|
||||
showToast("Safe Git fixes applied", `${repaired} repaired.`, "success");
|
||||
await window.forgeflow.gitValidatorSetPolicy(repository.fullName, { id: target.value });
|
||||
ui.gitValidation = await window.forgeflow.gitValidatorScan(repository.fullName);
|
||||
showToast("Policy updated", ui.gitValidation.policy.label, "success");
|
||||
} catch (error) {
|
||||
showToast("Safe repair stopped", error.message, "error");
|
||||
showToast("Policy update failed", error.message, "error");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
} else if (action === "git-validator-export") {
|
||||
try {
|
||||
const exported = await window.forgeflow.gitValidatorExport(repository.fullName, target.dataset.format || "markdown");
|
||||
const url = URL.createObjectURL(new Blob([exported.content], { type: exported.mimeType }));
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = `${repository.name || "repository"}-git-assurance.${exported.extension}`;
|
||||
link.click();
|
||||
URL.revokeObjectURL(url);
|
||||
showToast("Report exported", link.download, "success");
|
||||
} catch (error) {
|
||||
showToast("Export failed", error.message, "error");
|
||||
}
|
||||
} else if (action === "git-validator-suppress") {
|
||||
const check = ui.gitValidation?.checks?.[Number(target.dataset.checkIndex)];
|
||||
if (!check) return;
|
||||
const reason = prompt("Reason for this temporary exception (minimum 10 characters):", "Accepted temporarily while remediation is tracked.");
|
||||
if (!reason) return;
|
||||
const author = prompt("Exception owner:", ui.boot?.state?.gitea?.user?.login || "");
|
||||
if (!author) return;
|
||||
const ticket = prompt("Ticket reference (optional):", "") || "";
|
||||
const expiresAt = new Date(Date.now() + 7 * 86_400_000).toISOString();
|
||||
try {
|
||||
await window.forgeflow.gitValidatorSuppress(repository.fullName, { checkId: check.id, reason, author, ticket, expiresAt, scope: "repository", evidence: `${ui.gitValidation.commitSha || "unknown"}:${check.id}:${check.status}` });
|
||||
ui.gitValidation = await window.forgeflow.gitValidatorScan(repository.fullName);
|
||||
showToast("Exception documented", `Expires ${formatDate(expiresAt)}.`, "success");
|
||||
} catch (error) {
|
||||
showToast("Exception rejected", error.message, "error");
|
||||
}
|
||||
} else if (action === "toggle-favorite") {
|
||||
ui.boot.state = await window.forgeflow.favoriteRepository(
|
||||
repository.fullName,
|
||||
|
||||
Reference in New Issue
Block a user