Skip to content

Commit

Permalink
add multi-target Excel report
Browse files Browse the repository at this point in the history
  • Loading branch information
harp-intel committed Oct 29, 2024
1 parent e6548f0 commit 6d2adbe
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 31 deletions.
48 changes: 26 additions & 22 deletions internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,36 +307,40 @@ func (rc *ReportingCommand) Run() error {
}
reportFilePaths = append(reportFilePaths, reportPath)
}
// keep all the targets table values for a combined HTML report
if util.StringInList(report.FormatHtml, formats) {
allTargetsTableValues = append(allTargetsTableValues, allTableValues)
}
// keep all the targets table values for combined reports
allTargetsTableValues = append(allTargetsTableValues, allTableValues)
}
if len(allTargetsTableValues) > 1 {
// list of target names for the combined HTML report
// list of target names for the combined report
// - only those that we received output from
targetNames := make([]string, 0)
for _, targetScriptOutputs := range orderedTargetScriptOutputs {
targetNames = append(targetNames, targetScriptOutputs.targetName)
}
reportBytes, err := report.CreateMultiTarget(report.FormatHtml, allTargetsTableValues, targetNames)
if err != nil {
err = fmt.Errorf("failed to create multi-target report: %w", err)
fmt.Fprintf(os.Stderr, "Error: %+v\n", err)
slog.Error(err.Error())
rc.Cmd.SilenceUsage = true
return err
}
reportFilename := fmt.Sprintf("%s.%s", "all_hosts", report.FormatHtml)
reportPath := filepath.Join(appContext.OutputDir, reportFilename)
if err = report.WriteReport(reportBytes, reportPath); err != nil {
err = fmt.Errorf("failed to write multi-target report: %w", err)
fmt.Fprintf(os.Stderr, "Error: %+v\n", err)
slog.Error(err.Error())
rc.Cmd.SilenceUsage = true
return err
multiTargetFormats := []string{report.FormatHtml, report.FormatXlsx}
for _, format := range multiTargetFormats {
if !util.StringInList(format, formats) {
continue
}
reportBytes, err := report.CreateMultiTarget(format, allTargetsTableValues, targetNames)
if err != nil {
err = fmt.Errorf("failed to create multi-target %s report: %w", format, err)
fmt.Fprintf(os.Stderr, "Error: %+v\n", err)
slog.Error(err.Error())
rc.Cmd.SilenceUsage = true
return err
}
reportFilename := fmt.Sprintf("%s.%s", "all_hosts", format)
reportPath := filepath.Join(appContext.OutputDir, reportFilename)
if err = report.WriteReport(reportBytes, reportPath); err != nil {
err = fmt.Errorf("failed to write multi-target %s report: %w", format, err)
fmt.Fprintf(os.Stderr, "Error: %+v\n", err)
slog.Error(err.Error())
rc.Cmd.SilenceUsage = true
return err
}
reportFilePaths = append(reportFilePaths, reportPath)
}
reportFilePaths = append(reportFilePaths, reportPath)
}
if len(reportFilePaths) > 0 {
fmt.Println("Report files:")
Expand Down
133 changes: 124 additions & 9 deletions internal/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,12 @@ func Create(format string, allTableValues []TableValues, scriptOutputs map[strin

func CreateMultiTarget(format string, allTargetsTableValues [][]TableValues, targetNames []string) (out []byte, err error) {
switch format {
// case "txt":
// return createTextReportMultiTarget(allTargetsTableValues)
// case "json":
// return createJsonReportMultiTarget(allTargetsTableValues)
case "html":
return createHtmlReportMultiTarget(allTargetsTableValues, targetNames)
// case "xlsx":
// return createXlsxReportMultiTarget(allTargetsTableValues)
case "xlsx":
return createXlsxReportMultiTarget(allTargetsTableValues, targetNames)
}
panic("only HTML multi-target report supported currently")
//panic(fmt.Sprintf("expected one of %s, got %s", strings.Join(FormatOptions, ", "), format))
panic("only HTML and XLSX multi-target report supported currently")
}

func createTextReport(allTableValues []TableValues) (out []byte, err error) {
Expand Down Expand Up @@ -255,6 +250,95 @@ func renderXlsxTable(tableValues TableValues, f *excelize.File, sheetName string
*row++
}

func renderXlsxTableMultiTarget(tableIdx int, allTargetsTableValues [][]TableValues, targetNames []string, f *excelize.File, sheetName string, row *int) {
col := 1
// print the table name
tableNameStyle, _ := f.NewStyle(&excelize.Style{
Font: &excelize.Font{
Bold: true,
},
})
targetNameStyle, _ := f.NewStyle(&excelize.Style{
Font: &excelize.Font{
Bold: true,
},
})
fieldNameStyle, _ := f.NewStyle(&excelize.Style{
Font: &excelize.Font{
Bold: true,
},
})

f.SetCellValue(sheetName, cellName(col, *row), allTargetsTableValues[0][tableIdx].Name)
f.SetCellStyle(sheetName, cellName(col, *row), cellName(col, *row), tableNameStyle)

if !allTargetsTableValues[0][tableIdx].HasRows {
col += 2
// print the target names
for _, targetName := range targetNames {
f.SetCellValue(sheetName, cellName(col, *row), targetName)
f.SetCellStyle(sheetName, cellName(col, *row), cellName(col, *row), targetNameStyle)
col++
}
*row++

// print the field names and values from each target
for fieldIdx, field := range allTargetsTableValues[0][tableIdx].Fields {
col = 2
f.SetCellValue(sheetName, cellName(col, *row), field.Name)
f.SetCellStyle(sheetName, cellName(col, *row), cellName(col, *row), fieldNameStyle)
col++
for targetIdx := 0; targetIdx < len(targetNames); targetIdx++ {
var fieldValue string
if len(allTargetsTableValues[targetIdx][tableIdx].Fields[fieldIdx].Values) > 0 {
fieldValue = allTargetsTableValues[targetIdx][tableIdx].Fields[fieldIdx].Values[0]
}
f.SetCellValue(sheetName, cellName(col, *row), fieldValue)
col++
}
*row++
}
} else {
for targetIdx, targetName := range targetNames {
// print the target name
col = 2
f.SetCellValue(sheetName, cellName(col, *row), targetName)
f.SetCellStyle(sheetName, cellName(col, *row), cellName(col, *row), targetNameStyle)
*row++

// if no data found, print a message and skip to the next target
if len(allTargetsTableValues[targetIdx][tableIdx].Fields) == 0 || len(allTargetsTableValues[targetIdx][tableIdx].Fields[0].Values) == 0 {
f.SetCellValue(sheetName, cellName(col, *row), noDataFound)
*row += 2
continue
}

// print the field names as column headings across the top of the table
col = 2
for _, field := range allTargetsTableValues[targetIdx][tableIdx].Fields {
f.SetCellValue(sheetName, cellName(col, *row), field.Name)
f.SetCellStyle(sheetName, cellName(col, *row), cellName(col, *row), fieldNameStyle)
col++
}
*row++
// print the rows of values
tableRows := len(allTargetsTableValues[targetIdx][tableIdx].Fields[0].Values)
for tableRow := 0; tableRow < tableRows; tableRow++ {
col = 2
for _, field := range allTargetsTableValues[targetIdx][tableIdx].Fields {
value := getValueForCell(field.Values[tableRow])
f.SetCellValue(sheetName, cellName(col, *row), value)
col++
}
*row++
}
*row++
}
}
*row++

}

func DefaultXlsxTableRendererFunc(tableValues TableValues, f *excelize.File, sheetName string, row *int) {
headerStyle, _ := f.NewStyle(&excelize.Style{
Font: &excelize.Font{
Expand Down Expand Up @@ -309,6 +393,7 @@ func DefaultXlsxTableRendererFunc(tableValues TableValues, f *excelize.File, she

const (
XlsxPrimarySheetName = "Report"
XlsxBriefSheetName = "Brief"
)

func createXlsxReport(allTableValues []TableValues) (out []byte, err error) {
Expand All @@ -321,7 +406,7 @@ func createXlsxReport(allTableValues []TableValues) (out []byte, err error) {
for _, tableValues := range allTableValues {
if tableValues.Name == SystemSummaryTableName {
row := 1
sheetName := SystemSummaryTableName
sheetName := XlsxBriefSheetName
f.NewSheet(sheetName)
f.SetColWidth(sheetName, "A", "L", 25)
renderXlsxTable(tableValues, f, sheetName, &row)
Expand All @@ -340,6 +425,36 @@ func createXlsxReport(allTableValues []TableValues) (out []byte, err error) {
return
}

func createXlsxReportMultiTarget(allTargetsTableValues [][]TableValues, targetNames []string) (out []byte, err error) {
f := excelize.NewFile()
sheetName := XlsxPrimarySheetName
f.SetSheetName("Sheet1", sheetName)
f.SetColWidth(sheetName, "A", "A", 15)
f.SetColWidth(sheetName, "B", "L", 25)
row := 1
for tableIdx, tableValues := range allTargetsTableValues[0] {
if tableValues.Name == SystemSummaryTableName {
row := 1
sheetName := XlsxBriefSheetName
f.NewSheet(sheetName)
f.SetColWidth(sheetName, "A", "A", 15)
f.SetColWidth(sheetName, "B", "L", 25)
renderXlsxTableMultiTarget(tableIdx, allTargetsTableValues, targetNames, f, sheetName, &row)
} else {
renderXlsxTableMultiTarget(tableIdx, allTargetsTableValues, targetNames, f, sheetName, &row)
}
}
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
_, err = f.WriteTo(w)
if err != nil {
err = fmt.Errorf("failed to write multi-target xlsx report to buffer: %v", err)
return
}
out = buf.Bytes()
return
}

func getValueForCell(value string) (val interface{}) {
intValue, err := strconv.Atoi(value)
if err == nil {
Expand Down

0 comments on commit 6d2adbe

Please sign in to comment.