(results []directBootstrapResult, dryRun bool)
| 1972 | } |
| 1973 | |
| 1974 | func formatDirectBootstrapReport(results []directBootstrapResult, dryRun bool) string { |
| 1975 | var b strings.Builder |
| 1976 | title := "Direct bootstrap summary" |
| 1977 | if dryRun { |
| 1978 | title = "Direct bootstrap dry-run summary" |
| 1979 | } |
| 1980 | b.WriteString(title + "\n\n") |
| 1981 | |
| 1982 | totalChanged := 0 |
| 1983 | totalOK := 0 |
| 1984 | totalFailed := 0 |
| 1985 | totalSkipped := 0 |
| 1986 | |
| 1987 | for _, r := range results { |
| 1988 | switch r.Status { |
| 1989 | case statusChanged: |
| 1990 | totalChanged++ |
| 1991 | case statusFailed: |
| 1992 | totalFailed++ |
| 1993 | case statusSkipped: |
| 1994 | totalSkipped++ |
| 1995 | default: |
| 1996 | totalOK++ |
| 1997 | } |
| 1998 | _, _ = fmt.Fprintf(&b, "- %s (%s) [%s]: %s\n", r.Alias, r.Target, r.Status, r.Message) |
| 1999 | if r.SSHBefore != nil || r.SSHAfter != nil { |
| 2000 | _, _ = fmt.Fprintf(&b, " ssh: before=%s after=%s\n", sshReachabilityString(r.SSHBefore), sshReachabilityString(r.SSHAfter)) |
| 2001 | } |
| 2002 | if dryRun { |
| 2003 | plan := extractDryRunPlan(r.Output) |
| 2004 | if plan != "" { |
| 2005 | _, _ = fmt.Fprintf(&b, " plan: %s\n", plan) |
| 2006 | continue |
| 2007 | } |
| 2008 | } |
| 2009 | applied := extractAppliedPlan(r.Output) |
| 2010 | if applied != "" { |
| 2011 | _, _ = fmt.Fprintf(&b, " applied: %s\n", applied) |
| 2012 | continue |
| 2013 | } |
| 2014 | if strings.TrimSpace(r.Output) != "" { |
| 2015 | _, _ = fmt.Fprintf(&b, " output: %s\n", firstLine(r.Output)) |
| 2016 | } |
| 2017 | } |
| 2018 | |
| 2019 | _, _ = fmt.Fprintf(&b, "\nTotals: ok=%d changed=%d failed=%d skipped=%d\n", totalOK, totalChanged, totalFailed, totalSkipped) |
| 2020 | return b.String() |
| 2021 | } |
| 2022 | |
| 2023 | func sshReachabilityString(v *bool) string { |
| 2024 | if v == nil { |
no test coverage detected