164 行
5.3 KiB
JavaScript
可执行文件
164 行
5.3 KiB
JavaScript
可执行文件
#!/usr/bin/env node
|
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
import { extname } from "node:path";
|
|
|
|
const baseUrl = (process.env.LIVE_SMOKE_BASE_URL || "https://oa.hyinda.com").trim().replace(/\/$/, "");
|
|
|
|
function present(key) {
|
|
return Boolean(process.env[key]?.trim());
|
|
}
|
|
|
|
function maskedPresence(keys) {
|
|
return Object.fromEntries(keys.map((key) => [key, present(key)]));
|
|
}
|
|
|
|
function existingFileFrom(keys) {
|
|
const values = keys.map((key) => process.env[key]?.trim()).filter(Boolean);
|
|
return values.find((value) => existsSync(value)) || "";
|
|
}
|
|
|
|
function isPdfFile(value) {
|
|
if (!value || !existsSync(value)) {
|
|
return false;
|
|
}
|
|
try {
|
|
return statSync(value).isFile() && extname(value).toLowerCase() === ".pdf";
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function hasPdfFileInDir(value) {
|
|
if (!value || !existsSync(value)) {
|
|
return false;
|
|
}
|
|
try {
|
|
return statSync(value).isDirectory() && readdirSync(value).some((entry) => extname(entry).toLowerCase() === ".pdf");
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function fetchJson(url) {
|
|
try {
|
|
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
const text = await response.text();
|
|
let json = null;
|
|
try {
|
|
json = text ? JSON.parse(text) : null;
|
|
} catch {
|
|
json = null;
|
|
}
|
|
return { ok: response.ok, status: response.status, json, text: text.slice(0, 300) };
|
|
} catch (error) {
|
|
return { ok: false, status: 0, error: error instanceof Error ? error.message : String(error) };
|
|
}
|
|
}
|
|
|
|
function buildStaticChecks() {
|
|
const liveSmokeKeys = [
|
|
"LIVE_SMOKE_ADMIN_IDENTIFIER",
|
|
"LIVE_SMOKE_ADMIN_PASSWORD",
|
|
"LIVE_SMOKE_EMPLOYEE_IDENTIFIER",
|
|
"LIVE_SMOKE_EMPLOYEE_PASSWORD",
|
|
];
|
|
const liveSmokeReady = liveSmokeKeys.every(present);
|
|
const ocrUserReady = (
|
|
(present("PLAYWRIGHT_OCR_LIVE_IDENTIFIER") && present("PLAYWRIGHT_OCR_LIVE_PASSWORD")) ||
|
|
(present("LIVE_SMOKE_EMPLOYEE_IDENTIFIER") && present("LIVE_SMOKE_EMPLOYEE_PASSWORD"))
|
|
);
|
|
const invoiceFile = existingFileFrom(["PLAYWRIGHT_OCR_LIVE_FILE", "LIVE_OCR_INVOICE_FILE"]);
|
|
const invoiceBatchDir = process.env.PLAYWRIGHT_OCR_LIVE_DIR?.trim() || "";
|
|
const invoiceFileReady = isPdfFile(invoiceFile);
|
|
const invoiceBatchDirReady = hasPdfFileInDir(invoiceBatchDir);
|
|
const invoiceSampleReady = invoiceFileReady || invoiceBatchDirReady;
|
|
|
|
return {
|
|
baseUrl,
|
|
liveSmokeReady,
|
|
liveSmoke: maskedPresence(liveSmokeKeys),
|
|
liveSmokeOptional: maskedPresence([
|
|
"LIVE_EXPECT_WECOM_STATUS",
|
|
"LIVE_SMOKE_MANAGER_IDENTIFIER",
|
|
"LIVE_SMOKE_MANAGER_PASSWORD",
|
|
"LIVE_SMOKE_FINANCE_IDENTIFIER",
|
|
"LIVE_SMOKE_FINANCE_PASSWORD",
|
|
]),
|
|
liveOcrReady: ocrUserReady && invoiceSampleReady,
|
|
liveOcr: {
|
|
userReady: ocrUserReady,
|
|
invoiceSampleReady,
|
|
invoiceFileProvided: Boolean(invoiceFile),
|
|
invoiceFileReady,
|
|
invoiceBatchDirProvided: Boolean(invoiceBatchDir),
|
|
invoiceBatchDirReady,
|
|
allowDuplicate: process.env.PLAYWRIGHT_OCR_ALLOW_DUPLICATE === "1",
|
|
},
|
|
missing: [],
|
|
};
|
|
}
|
|
|
|
function addMissing(checks) {
|
|
if (!checks.liveSmokeReady) {
|
|
for (const [key, value] of Object.entries(checks.liveSmoke)) {
|
|
if (!value) checks.missing.push(key);
|
|
}
|
|
}
|
|
|
|
if (!checks.liveOcr.userReady) {
|
|
checks.missing.push("PLAYWRIGHT_OCR_LIVE_IDENTIFIER/PASSWORD 或 LIVE_SMOKE_EMPLOYEE_*");
|
|
}
|
|
if (!checks.liveOcr.invoiceSampleReady) {
|
|
checks.missing.push("PLAYWRIGHT_OCR_LIVE_FILE 或 PLAYWRIGHT_OCR_LIVE_DIR 中的 PDF 样票");
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
const strict = process.argv.includes("--strict");
|
|
const jsonOnly = process.argv.includes("--json");
|
|
const checks = buildStaticChecks();
|
|
addMissing(checks);
|
|
|
|
const ready = await fetchJson(`${baseUrl}/ready`);
|
|
const wecomConfig = await fetchJson(`${baseUrl}/api/auth/wecom/config`);
|
|
const result = {
|
|
checkedAt: new Date().toISOString(),
|
|
...checks,
|
|
publicReady: {
|
|
ok: ready.ok,
|
|
status: ready.status,
|
|
},
|
|
wecomConfig: {
|
|
ok: wecomConfig.ok,
|
|
status: wecomConfig.status,
|
|
statusText: wecomConfig.json?.data?.status ?? null,
|
|
entryEnabled: wecomConfig.json?.data?.entryEnabled ?? null,
|
|
oauthEnabled: wecomConfig.json?.data?.oauthEnabled ?? null,
|
|
defaultReturnTo: wecomConfig.json?.data?.defaultReturnTo ?? null,
|
|
loginUrl: wecomConfig.json?.data?.loginUrl ?? null,
|
|
},
|
|
};
|
|
|
|
if (jsonOnly) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
} else {
|
|
console.log(`[live-smoke-env] base=${result.baseUrl}`);
|
|
console.log(`[live-smoke-env] publicReady=${result.publicReady.ok} status=${result.publicReady.status}`);
|
|
console.log(`[live-smoke-env] wecom=${result.wecomConfig.statusText ?? "unknown"} entry=${result.wecomConfig.entryEnabled} oauth=${result.wecomConfig.oauthEnabled}`);
|
|
console.log(`[live-smoke-env] liveSmokeReady=${result.liveSmokeReady}`);
|
|
console.log(`[live-smoke-env] liveOcrReady=${result.liveOcrReady}`);
|
|
if (result.missing.length) {
|
|
console.log(`[live-smoke-env] missing=${result.missing.join(", ")}`);
|
|
}
|
|
}
|
|
|
|
if (strict && (!result.liveSmokeReady || !result.liveOcrReady || !result.publicReady.ok || !result.wecomConfig.ok)) {
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(`[live-smoke-env][ERROR] ${error instanceof Error ? error.message : String(error)}`);
|
|
process.exit(1);
|
|
});
|