|
| 1 | +import { existsSync, readFileSync } from "node:fs"; |
| 2 | + |
| 3 | +const logPath = process.env.LOG_PATH || "daily-testnet-ts.log"; |
| 4 | +const summaryPath = |
| 5 | + process.env.SUMMARY_PATH || "daily-testnet-ts-ai-summary.md"; |
| 6 | +const status = process.env.STATUS || "unknown"; |
| 7 | +const branch = process.env.BRANCH || "unknown"; |
| 8 | +const runUrl = process.env.RUN_URL || "unknown"; |
| 9 | +const title = process.env.REPORT_TITLE || "Daily Testnet TS"; |
| 10 | +const mode = process.env.REPORT_MODE || "testnet"; |
| 11 | +const ethLabel = process.env.REPORT_ETH_LABEL || "hoodi-reth"; |
| 12 | + |
| 13 | +function readIfExists(path) { |
| 14 | + return existsSync(path) ? readFileSync(path, "utf8") : ""; |
| 15 | +} |
| 16 | + |
| 17 | +function extractTests(log) { |
| 18 | + const passed = log.match(/Tests\s+(\d+)\s+passed\s+\((\d+)\)/); |
| 19 | + if (passed) { |
| 20 | + return `${passed[1]}/${passed[2]}`; |
| 21 | + } |
| 22 | + |
| 23 | + const failed = log.match(/Tests\s+(\d+)\s+failed\s+\|\s+(\d+)\s+passed\s+\((\d+)\)/); |
| 24 | + if (failed) { |
| 25 | + return `${failed[2]}/${failed[3]} passed, ${failed[1]} failed`; |
| 26 | + } |
| 27 | + |
| 28 | + return "unknown"; |
| 29 | +} |
| 30 | + |
| 31 | +function extractDuration(log) { |
| 32 | + const match = log.match(/Duration\s+([0-9.]+)(ms|s|m)/); |
| 33 | + if (!match) { |
| 34 | + return "unknown"; |
| 35 | + } |
| 36 | + |
| 37 | + const value = Number(match[1]); |
| 38 | + const unit = match[2]; |
| 39 | + if (!Number.isFinite(value)) { |
| 40 | + return `${match[1]}${unit}`; |
| 41 | + } |
| 42 | + |
| 43 | + const seconds = |
| 44 | + unit === "ms" ? value / 1_000 : unit === "m" ? value * 60 : value; |
| 45 | + const minutes = Math.floor(seconds / 60); |
| 46 | + const remainingSeconds = Math.round(seconds % 60); |
| 47 | + |
| 48 | + if (minutes === 0) { |
| 49 | + return `${remainingSeconds}s`; |
| 50 | + } |
| 51 | + |
| 52 | + return `${minutes}m ${remainingSeconds.toString().padStart(2, "0")}s`; |
| 53 | +} |
| 54 | + |
| 55 | +function extractCosts(log) { |
| 56 | + const match = log.match(/TEST_COSTS delta eth=([^\s]+) wvara=([^\s]+)/); |
| 57 | + if (!match) { |
| 58 | + return { |
| 59 | + eth: "unknown", |
| 60 | + wvara: "unknown", |
| 61 | + }; |
| 62 | + } |
| 63 | + |
| 64 | + return { |
| 65 | + eth: match[1], |
| 66 | + wvara: match[2], |
| 67 | + }; |
| 68 | +} |
| 69 | + |
| 70 | +const log = readIfExists(logPath); |
| 71 | +const summary = readIfExists(summaryPath).trim() || "AI summary unavailable."; |
| 72 | +const tests = extractTests(log); |
| 73 | +const duration = extractDuration(log); |
| 74 | +const costs = extractCosts(log); |
| 75 | + |
| 76 | +const message = [ |
| 77 | + title, |
| 78 | + `Status: ${status}`, |
| 79 | + `Tests: ${tests}`, |
| 80 | + `Duration: ${duration}`, |
| 81 | + `Cost ETH: ${costs.eth}`, |
| 82 | + `Cost WVARA: ${costs.wvara}`, |
| 83 | + `Mode: ${mode}`, |
| 84 | + `ETH: ${ethLabel}`, |
| 85 | + `Branch: ${branch}`, |
| 86 | + `Run: ${runUrl}`, |
| 87 | + "", |
| 88 | + summary, |
| 89 | +].join("\n"); |
| 90 | + |
| 91 | +console.log(message); |
0 commit comments