Email report: HTML summary sent via SMTP2Go (mail-eu.smtp2go.com) at the end of every deployment. Subject "xetup report HOSTNAME", body contains per-step status table with timestamps. Non-blocking (goroutine) so it doesn't delay the summary screen. Pre-flight checks: admin rights, winget availability, network connectivity (DNS resolve), and disk space verified before the config form. Results shown as colored status lines at the top of the GUI - red warnings tell the technician what's wrong before starting a 30-minute deployment. Parallel winget: 02-software.ps1 now launches all winget installs as background jobs (Start-Job) and waits for all to complete. 7-Zip, Acrobat, OpenVPN run simultaneously instead of sequentially, saving 3-5 minutes per deployment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
131 lines
3.7 KiB
Go
131 lines
3.7 KiB
Go
// Package report sends a deployment summary email via SMTP.
|
|
package report
|
|
|
|
import (
|
|
"fmt"
|
|
"net/smtp"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// SMTP2Go relay configuration for X9.cz deployment reports.
|
|
const (
|
|
smtpHost = "mail-eu.smtp2go.com"
|
|
smtpPort = "2525"
|
|
smtpUser = "xetup"
|
|
smtpPass = "M9ahxHOnJ8fM0CEF"
|
|
mailFrom = "xetup@x9.cz"
|
|
mailTo = "net@x9.cz"
|
|
)
|
|
|
|
// StepResult holds one row of the deployment report.
|
|
type StepResult struct {
|
|
Num string
|
|
Name string
|
|
Status string // OK, ERROR, SKIPPED, CANCELLED
|
|
Elapsed time.Duration
|
|
}
|
|
|
|
// Send emails the deployment report. Non-fatal: returns error but caller
|
|
// should log it and continue (deployment is already done).
|
|
func Send(results []StepResult) error {
|
|
hostname, _ := os.Hostname()
|
|
now := time.Now().Format("2006-01-02 15:04")
|
|
|
|
subject := fmt.Sprintf("xetup report %s", hostname)
|
|
body := buildHTML(results, hostname, now)
|
|
|
|
msg := strings.Join([]string{
|
|
"From: " + mailFrom,
|
|
"To: " + mailTo,
|
|
"Subject: " + subject,
|
|
"MIME-Version: 1.0",
|
|
"Content-Type: text/html; charset=UTF-8",
|
|
"",
|
|
body,
|
|
}, "\r\n")
|
|
|
|
auth := smtp.PlainAuth("", smtpUser, smtpPass, smtpHost)
|
|
return smtp.SendMail(
|
|
smtpHost+":"+smtpPort,
|
|
auth,
|
|
mailFrom,
|
|
[]string{mailTo},
|
|
[]byte(msg),
|
|
)
|
|
}
|
|
|
|
func buildHTML(results []StepResult, hostname, dateTime string) string {
|
|
var ok, errs, skipped int
|
|
var rows strings.Builder
|
|
|
|
for _, r := range results {
|
|
color := "#333"
|
|
icon := ""
|
|
switch r.Status {
|
|
case "OK":
|
|
ok++
|
|
color = "#2e7d32"
|
|
icon = "✓"
|
|
case "ERROR":
|
|
errs++
|
|
color = "#c62828"
|
|
icon = "✗"
|
|
default:
|
|
skipped++
|
|
color = "#9e9e9e"
|
|
icon = "–"
|
|
}
|
|
|
|
elapsed := ""
|
|
if r.Elapsed > 0 {
|
|
elapsed = r.Elapsed.Round(time.Second).String()
|
|
}
|
|
|
|
fmt.Fprintf(&rows,
|
|
`<tr><td style="padding:4px 8px;color:%s;font-size:16px;text-align:center">%s</td>`+
|
|
`<td style="padding:4px 8px;color:#666">%s</td>`+
|
|
`<td style="padding:4px 8px">%s</td>`+
|
|
`<td style="padding:4px 8px;color:%s;font-weight:bold">%s</td>`+
|
|
`<td style="padding:4px 8px;color:#999;text-align:right">%s</td></tr>`,
|
|
color, icon, r.Num, r.Name, color, r.Status, elapsed)
|
|
}
|
|
|
|
summaryColor := "#2e7d32"
|
|
summaryText := "Deployment OK"
|
|
if errs > 0 {
|
|
summaryColor = "#c62828"
|
|
summaryText = fmt.Sprintf("Deployment finished with %d error(s)", errs)
|
|
}
|
|
|
|
return fmt.Sprintf(`<!DOCTYPE html>
|
|
<html><head><meta charset="UTF-8"></head>
|
|
<body style="font-family:Segoe UI,Arial,sans-serif;margin:0;padding:20px;background:#f5f5f5">
|
|
<div style="max-width:640px;margin:0 auto;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.1)">
|
|
<div style="background:#223B47;padding:20px 24px;color:#fff">
|
|
<h1 style="margin:0;font-size:20px">xetup report</h1>
|
|
<p style="margin:6px 0 0;opacity:0.8">%s — %s</p>
|
|
</div>
|
|
<table style="width:100%%;border-collapse:collapse;margin:16px 0">
|
|
<tr style="background:#f9f9f9">
|
|
<th style="padding:6px 8px;text-align:center;width:30px"></th>
|
|
<th style="padding:6px 8px;text-align:left;width:40px">Krok</th>
|
|
<th style="padding:6px 8px;text-align:left">Nazev</th>
|
|
<th style="padding:6px 8px;text-align:left;width:70px">Status</th>
|
|
<th style="padding:6px 8px;text-align:right;width:60px">Cas</th>
|
|
</tr>
|
|
%s
|
|
</table>
|
|
<div style="padding:16px 24px;background:%s;color:#fff;text-align:center;font-weight:bold">
|
|
%s — OK: %d CHYBY: %d PRESKOCENO: %d
|
|
</div>
|
|
</div>
|
|
<p style="text-align:center;color:#999;font-size:12px;margin-top:16px">
|
|
Odeslano z xetup.exe — log: C:\Windows\Setup\Scripts\Deploy.log
|
|
</p>
|
|
</body></html>`,
|
|
hostname, dateTime,
|
|
rows.String(),
|
|
summaryColor, summaryText, ok, errs, skipped)
|
|
}
|