Dateien nach „demo“ hochladen
This commit is contained in:
parent
45a4808480
commit
f9b884c205
2 changed files with 398 additions and 0 deletions
295
demo/scan_repo.js
Normal file
295
demo/scan_repo.js
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
require('dotenv').config({ path: path.resolve(__dirname, '../../src/.env') });
|
||||
|
||||
/**
|
||||
* @fileoverview Automatisierungsskript für den Multi-Repository SAP-Deprecation Scan.
|
||||
* Durchsucht lokale Unterordner (Repositories) rekursiv nach SAP- und REST-Endpunkten,
|
||||
* gleicht diese über die FastAPI ab und generiert einen zusammenfassenden Report.
|
||||
* @author MBT
|
||||
* @version 1.3 (Zeigt in Details nur veränderte/abgekündigte Endpunkte)
|
||||
*/
|
||||
|
||||
|
||||
// --- KONFIGURATION ---
|
||||
|
||||
const BASE_PATH = './';
|
||||
const FASTAPI_URL = 'http://127.0.0.1:8000/informations/bulk';
|
||||
const OUTPUT_FILE = './sap_api_scan_report.txt';
|
||||
const IGNORED_DIRS = ['node_modules', '.git', '__pycache__', 'venv', 'dist', 'build', '.idea', '.vscode'];
|
||||
|
||||
const headers = {
|
||||
"X-API-Key": process.env.READONLY_APIKEY
|
||||
};
|
||||
|
||||
// Optimierte Regex (Case-Insensitive)
|
||||
const ENDPOINT_REGEX = /\b(?:\/?)(?:v\d+|sap)\/[a-zA-Z0-9_\-\/{}]*(?:\/[a-zA-Z0-9_\-\/{}]+)*/i;
|
||||
|
||||
|
||||
// --- FUNKTIONEN ---
|
||||
|
||||
function getRepositories(baseDir) {
|
||||
return fs.readdirSync(baseDir).filter(file => {
|
||||
const fullPath = path.join(baseDir, file);
|
||||
return fs.statSync(fullPath).isDirectory() && !IGNORED_DIRS.includes(file);
|
||||
});
|
||||
}
|
||||
|
||||
function walkSync(dir, filelist = []) {
|
||||
const files = fs.readdirSync(dir);
|
||||
files.forEach(file => {
|
||||
const filepath = path.join(dir, file);
|
||||
const stat = fs.statSync(filepath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
if (!IGNORED_DIRS.includes(file)) {
|
||||
walkSync(filepath, filelist);
|
||||
}
|
||||
} else {
|
||||
filelist.push(filepath);
|
||||
}
|
||||
});
|
||||
return filelist;
|
||||
}
|
||||
|
||||
function scanRepositoryForEndpoints(repoPath, repoName) {
|
||||
console.log(`\n🔍 [${repoName}] Starte rekursiven Scan im Ordner: ${path.resolve(repoPath)}...`);
|
||||
const files = walkSync(repoPath);
|
||||
const endpointLocations = {};
|
||||
let checkedFilesCount = 0;
|
||||
|
||||
files.forEach(file => {
|
||||
if (
|
||||
file.endsWith('scan_repo.js') ||
|
||||
file.endsWith('scan_all_repos.js') ||
|
||||
file.endsWith('.txt') ||
|
||||
file.endsWith('.json') ||
|
||||
file.endsWith('.md') ||
|
||||
file.includes(path.basename(OUTPUT_FILE))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkedFilesCount++;
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
|
||||
if (!/sap|v\d+/i.test(content)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lines = content.split(/\r?\n/);
|
||||
|
||||
lines.forEach((lineText, index) => {
|
||||
const lineNumber = index + 1;
|
||||
const match = lineText.match(ENDPOINT_REGEX);
|
||||
|
||||
if (match) {
|
||||
const endpoint = match[0].trim();
|
||||
if (endpoint.length >= 4) {
|
||||
if (!endpointLocations[endpoint]) {
|
||||
endpointLocations[endpoint] = [];
|
||||
}
|
||||
|
||||
const relativePath = path.relative(BASE_PATH, file);
|
||||
endpointLocations[endpoint].push({
|
||||
file: relativePath,
|
||||
line: lineNumber
|
||||
});
|
||||
|
||||
console.log(` ✨ Treffer in [${repoName}]: "${endpoint}" gefunden in ${relativePath}:${lineNumber}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.code !== 'EISDIR' && !file.match(/\.(png|jpg|jpeg|gif|ico|zip|tar|gz|pdf|exe|dll)$/i)) {
|
||||
console.warn(`⚠️ Konnte Datei nicht lesen: ${file} (${err.message})`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`🏁 [${repoName}] Scan beendet. ${checkedFilesCount} Dateien durchsucht. ${Object.keys(endpointLocations).length} eindeutige Endpunkte gefunden.`);
|
||||
return endpointLocations;
|
||||
}
|
||||
|
||||
async function checkEndpoints(endpoints, batchSize = 25) {
|
||||
const consolidatedResult = {
|
||||
total_checked: 0,
|
||||
results: []
|
||||
};
|
||||
|
||||
for (let i = 0; i < endpoints.length; i += batchSize) {
|
||||
const batch = endpoints.slice(i, i + batchSize);
|
||||
console.log(` ⏳ Sende Batch ${Math.floor(i / batchSize) + 1} (${batch.length} Endpunkte)...`);
|
||||
|
||||
const params = new URLSearchParams();
|
||||
batch.forEach(ep => params.append("endpoints", ep));
|
||||
|
||||
try {
|
||||
const response = await fetch(`${FASTAPI_URL}?${params.toString()}`, { method: "GET", headers: headers });
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server meldete Status ${response.status}`);
|
||||
}
|
||||
|
||||
const batchJson = await response.json();
|
||||
|
||||
consolidatedResult.total_checked += batchJson.total_checked || batch.length;
|
||||
if (batchJson.results && Array.isArray(batchJson.results)) {
|
||||
consolidatedResult.results.push(...batchJson.results);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Fehler in Batch ab Index ${i}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return consolidatedResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Steuert den Scan-Workflow und baut die aggregierte Zusammenfassung sowie den gefilterten Detailbericht.
|
||||
*/
|
||||
async function runMultiRepoScan() {
|
||||
const repos = getRepositories(BASE_PATH);
|
||||
|
||||
if (repos.length === 0) {
|
||||
console.log("⚠️ Keine Scan-fähigen Unterordner (Repositories) gefunden!");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`📂 ${repos.length} Repositories für den Scan gefunden.`);
|
||||
|
||||
// Statistik-Zähler für die Zusammenfassung
|
||||
const stats = {
|
||||
totalRepos: repos.length,
|
||||
reposWithEndpoints: 0,
|
||||
totalEndpointsFound: 0,
|
||||
statusActive: 0,
|
||||
statusDeprecated: 0,
|
||||
statusChanged: 0,
|
||||
statusUnknown: 0
|
||||
};
|
||||
|
||||
let detailedReportBody = '';
|
||||
|
||||
// Schleife über alle gefundenen Repository-Ordner
|
||||
for (const repoName of repos) {
|
||||
const repoPath = path.join(BASE_PATH, repoName);
|
||||
console.log(`\n--------------------------------------------------`);
|
||||
console.log(`📦 Verarbeite Repository: ${repoName.toUpperCase()}`);
|
||||
console.log(`--------------------------------------------------`);
|
||||
|
||||
const endpointLocations = scanRepositoryForEndpoints(repoPath, repoName);
|
||||
const uniqueEndpoints = Object.keys(endpointLocations);
|
||||
|
||||
if (uniqueEndpoints.length === 0) {
|
||||
console.log(`ℹ️ Keine SAP-Endpunkte in [${repoName}] gefunden.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
stats.reposWithEndpoints++;
|
||||
stats.totalEndpointsFound += uniqueEndpoints.length;
|
||||
|
||||
console.log(`🚀 ${uniqueEndpoints.length} Endpunkte in [${repoName}] gefunden. Sende Abfrage an FastAPI...`);
|
||||
|
||||
try {
|
||||
const apiResult = await checkEndpoints(uniqueEndpoints);
|
||||
let repoIssuesContent = ''; // Puffer für problematische Endpunkte in diesem spezifischen Repo
|
||||
|
||||
apiResult.results.forEach(item => {
|
||||
const messageLower = item.message.toLowerCase();
|
||||
const statusLower = (item.status || '').toLowerCase();
|
||||
|
||||
// Status für die Statistik auswerten
|
||||
const isNoHit = messageLower.includes("keine sap-änderungen oder deprecations gefunden");
|
||||
let isIssue = false;
|
||||
|
||||
if (isNoHit || statusLower === 'active' || statusLower === 'ok') {
|
||||
stats.statusActive++;
|
||||
} else if (statusLower.includes('deprecat')) {
|
||||
stats.statusDeprecated++;
|
||||
isIssue = true;
|
||||
} else if (statusLower.includes('chang') || statusLower.includes('modif')) {
|
||||
stats.statusChanged++;
|
||||
isIssue = true;
|
||||
} else {
|
||||
stats.statusUnknown++;
|
||||
isIssue = true; // Unbekannte Stati sicherheitshalber auch auflisten
|
||||
}
|
||||
|
||||
// Nur wenn ein Problem/eine Änderung vorliegt, wird der Endpunkt im Detailbericht aufgelistet
|
||||
if (isIssue) {
|
||||
const locations = endpointLocations[item.endpoint] || [];
|
||||
const locationString = locations
|
||||
.map(loc => `${loc.file}:${loc.line}`)
|
||||
.join(', ');
|
||||
|
||||
let logLine = `[❗Warning] Endpoint: ${item.endpoint}\n`;
|
||||
logLine += ` Files: ${locationString}\n`;
|
||||
logLine += ` Status: ${item.status}\n`;
|
||||
logLine += ` Details: ${item.message}\n`;
|
||||
logLine += ` Deprecated in Quality: ${item.deprecated[0]}\n`;
|
||||
logLine += ` Deprecated in Production: ${item.deprecated[1]}\n`;
|
||||
logLine += ` Decommissioned in Quality: ${item.decommissioned[0]}\n`;
|
||||
logLine += ` Decommissioned in Production: ${item.decommissioned[1]}\n`;
|
||||
|
||||
console.log(logLine);
|
||||
repoIssuesContent += logLine + "\n";
|
||||
}
|
||||
});
|
||||
|
||||
// Falls dieses Repo veränderte/abgekündigte Endpunkte hatte, hänge sie an den Report an
|
||||
if (repoIssuesContent.length > 0) {
|
||||
detailedReportBody += `📦 REPOSITORY: ${repoName}\n`;
|
||||
detailedReportBody += `--------------------------------------------------\n`;
|
||||
detailedReportBody += repoIssuesContent;
|
||||
detailedReportBody += `\n`;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Fehler bei API-Abfrage für [${repoName}]:`, error.message);
|
||||
detailedReportBody += `📦 REPOSITORY: ${repoName}\n -> API-Fehler bei der Abfrage: ${error.message}\n\n`;
|
||||
}
|
||||
}
|
||||
|
||||
// Zusammenbau des finalen Berichts (Zusammenfassung ganz oben!)
|
||||
let finalReportContent = `======================================================================\n`;
|
||||
finalReportContent += ` GLOBAL SAP DEPRECATION SCAN REPORT - ${new Date().toLocaleString()}\n`;
|
||||
finalReportContent += `======================================================================\n\n`;
|
||||
|
||||
finalReportContent += `📊 SUMMARY:\n`;
|
||||
finalReportContent += `----------------------------------------------------------------------\n`;
|
||||
finalReportContent += ` Total Repositories Scanned: ${stats.totalRepos}\n`;
|
||||
finalReportContent += ` Repositories with Findings: ${stats.reposWithEndpoints}\n`;
|
||||
finalReportContent += ` Total Endpoints Detected: ${stats.totalEndpointsFound}\n\n`;
|
||||
finalReportContent += ` ENDPOINT STATUS OVERVIEW:\n`;
|
||||
finalReportContent += ` 🟢 Active / Unchanged Endpoints: ${stats.statusActive}\n`;
|
||||
finalReportContent += ` 🟡 Modified Endpoints (Changed): ${stats.statusChanged}\n`;
|
||||
finalReportContent += ` 🔴 Obsolete Endpoints (Deprecated): ${stats.statusDeprecated}\n`;
|
||||
if (stats.statusUnknown > 0) {
|
||||
finalReportContent += ` ⚪ Unknown / Unclear Status: ${stats.statusUnknown}\n`;
|
||||
}
|
||||
finalReportContent += `======================================================================\n\n\n`;
|
||||
|
||||
// Details (filtered issues only!) appended below
|
||||
finalReportContent += `📝 ACTIONABLE DETAILS & DETECTED ISSUES (Filtered):\n`;
|
||||
finalReportContent += ` (Only modified or deprecated endpoints are listed below)\n`;
|
||||
finalReportContent += `======================================================================\n\n`;
|
||||
|
||||
if (detailedReportBody.length === 0) {
|
||||
finalReportContent += `🎉 Excellent! No modified or deprecated endpoints were found in any of the repositories.\n`;
|
||||
} else {
|
||||
finalReportContent += detailedReportBody;
|
||||
}
|
||||
|
||||
// Gesamtergebnis in Datei schreiben
|
||||
try {
|
||||
fs.writeFileSync(OUTPUT_FILE, finalReportContent, 'utf8');
|
||||
console.log(`\n💾 Der globale Bericht wurde erfolgreich gespeichert: ${path.resolve(OUTPUT_FILE)}`);
|
||||
} catch (err) {
|
||||
console.error("❌ Bericht konnte nicht geschrieben werden:", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// --- START ---
|
||||
runMultiRepoScan();
|
||||
103
demo/testaufruf.js
Normal file
103
demo/testaufruf.js
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* @file Abfrage-Skript für den SAP Endpoint Service.
|
||||
* Dieses Skript sendet eine Liste von API-Endpunkten an den lokalen FastAPI-Bulk-Service,
|
||||
* wertet die Ergebnisse aus und gibt sie formatiert in der Konsole aus.
|
||||
* @author MBT
|
||||
* @version 1.0
|
||||
*/
|
||||
const path = require('path');
|
||||
require('dotenv').config({ path: path.resolve(__dirname, '../../src/.env') });
|
||||
|
||||
/**
|
||||
* @typedef {Object} EndpointResult
|
||||
* @property {string} endpoint - Der geprüfte SAP-Endpunkt.
|
||||
* @property {string} status - Der SAP-Status (z. B. "Deprecated", "active", "Unbekannt").
|
||||
* @property {string} message - Die detaillierte Statusmeldung der SAP-Prüfung.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} BulkApiResponse
|
||||
* @property {number} total_checked - Die Gesamtanzahl der geprüften Endpunkte.
|
||||
* @property {EndpointResult[]} results - Die Liste der einzelnen Prüfergebnisse.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Liste der SAP-Endpunkte, die auf Änderungen oder Deprecations geprüft werden sollen.
|
||||
* @type {string[]}
|
||||
*/
|
||||
const endpointsToCheck = [
|
||||
"v1/inventories"
|
||||
];
|
||||
|
||||
/**
|
||||
* Erstellt die URL-Query-Parameter für die Bulk-Abfrage.
|
||||
* Jedes Element aus `endpointsToCheck` wird als separater "endpoints"-Parameter angehängt.
|
||||
* @type {URLSearchParams}
|
||||
*/
|
||||
const params = new URLSearchParams();
|
||||
endpointsToCheck.forEach(ep => {
|
||||
params.append("endpoints", ep);
|
||||
});
|
||||
|
||||
/**
|
||||
* Die Ziel-URL für den lokalen FastAPI-Bulk-Endpunkt.
|
||||
* @type {string}
|
||||
*/
|
||||
const url = `http://127.0.0.1:8000/informations/bulk?${params.toString()}`;
|
||||
|
||||
|
||||
const apiKeysString = process.env.APIKEYS || "";
|
||||
const firstApiKey = apiKeysString.split(",")[0].trim();
|
||||
|
||||
const headers = {
|
||||
"X-API-Key": firstApiKey
|
||||
};
|
||||
|
||||
// Führt den HTTP-Call an die FastAPI aus
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
headers: headers
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP-Fehler! Status: ${response.status}`);
|
||||
}
|
||||
return response.json(); // Wandelt die Antwort in ein echtes JS-Objekt um
|
||||
})
|
||||
.then(data => {
|
||||
// 1. Komplette Antwort ausgeben (ohne [Array]-Kürzung durch Node.js)
|
||||
console.log("Gesamtes API-Feedback:");
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
|
||||
// 2. Ergebnisse im Detail durchgehen und die berechneten SAP-Daten anzeigen
|
||||
if (data && data.results) {
|
||||
console.log("\n=== SAP API-Statusbericht ===");
|
||||
data.results.forEach(item => {
|
||||
console.log(`\nEndpunkt: ${item.endpoint}`);
|
||||
console.log(`Status: ${item.status}`);
|
||||
console.log(`Meldung: ${item.message || 'Keine Meldung vorhanden.'}`);
|
||||
|
||||
// Nur ausgeben, wenn wir echte Datumsdaten vom Server erhalten haben
|
||||
if (item.deprecated && item.deprecated.length > 0) {
|
||||
const [qDate, pDate] = item.deprecated;
|
||||
const [qDecom, pDecom] = item.decommissioned;
|
||||
|
||||
console.log(`\n --- Upgrade- & Rückbaufristen ---`);
|
||||
console.log(` [Q-System] Abgekündigt: ${qDate} --> Geplanter Rückbau (+1 Jahr): ${qDecom}`);
|
||||
console.log(` [P-System] Abgekündigt: ${pDate} --> Geplanter Rückbau (+1 Jahr): ${pDecom}`);
|
||||
} else {
|
||||
console.log(`\n --> Keine anstehenden Abkündigungen oder Fristen für diesen Endpunkt.`);
|
||||
}
|
||||
console.log("----------------------------------------------------------------------");
|
||||
});
|
||||
} else {
|
||||
console.log("Keine 'results' im JSON-Response gefunden.");
|
||||
}
|
||||
})
|
||||
.catch(
|
||||
/**
|
||||
* Catch-Block für Netzwerk- oder Verarbeitungsfehler.
|
||||
* @param {Error} error - Das aufgetretene Fehler-Objekt.
|
||||
*/
|
||||
error => console.error("Fehler bei der Abfrage:", error)
|
||||
);
|
||||
Loading…
Reference in a new issue