internal/renderers/excel/excel.go (174 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. package excel import ( "fmt" _ "image/png" "github.com/Azure/azqr/internal/embeded" "github.com/Azure/azqr/internal/renderers" "github.com/rs/zerolog/log" "github.com/xuri/excelize/v2" ) func CreateExcelReport(data *renderers.ReportData) { filename := fmt.Sprintf("%s.xlsx", data.OutputFileName) log.Info().Msgf("Generating Report: %s", filename) f := excelize.NewFile() defer func() { if err := f.Close(); err != nil { log.Fatal().Err(err).Msg("Failed to close Excel file") } }() lastRow := renderRecommendations(f, data) renderImpactedResources(f, data) renderResourceTypes(f, data) renderResources(f, data) renderAdvisor(f, data) renderDefenderRecommendations(f, data) renderExcludedResources(f, data) renderDefender(f, data) renderCosts(f, data) renderRecommendationsPivotTables(f, lastRow) if err := f.SaveAs(filename); err != nil { log.Fatal().Err(err).Msg("Failed to save Excel file") } } func autofit(f *excelize.File, sheetName string) error { cols, err := f.GetCols(sheetName) if err != nil { return err } for idx, col := range cols { largestWidth := 0 for _, rowCell := range col { cellWidth := len(rowCell) + 3 if cellWidth > largestWidth { largestWidth = cellWidth } } if largestWidth > 255 { largestWidth = 120 } name, err := excelize.ColumnNumberToName(idx + 1) if err != nil { return err } err = f.SetColWidth(sheetName, name, name, float64(largestWidth)) if err != nil { return err } } return nil } func createFirstRow(f *excelize.File, sheet string, headers []string) { currentRow := 4 cell, err := excelize.CoordinatesToCellName(1, currentRow) if err != nil { log.Fatal().Err(err).Msg("Failed to get cell") } err = f.SetSheetRow(sheet, cell, &headers) if err != nil { log.Fatal().Err(err).Msg("Failed to set row") } style, err := f.NewStyle(&excelize.Style{ Font: &excelize.Font{ Bold: true, }, Fill: excelize.Fill{ Type: "pattern", Color: []string{"#CAEDFB"}, Pattern: 1, }, }) if err != nil { log.Fatal().Err(err).Msg("Failed to create style") } for j := 1; j <= len(headers); j++ { cell, err := excelize.CoordinatesToCellName(j, 4) if err != nil { log.Fatal().Err(err).Msg("Failed to get cell") } err = f.SetCellStyle(sheet, cell, cell, style) if err != nil { log.Fatal().Err(err).Msg("Failed to set style") } } } func setHyperLink(f *excelize.File, sheet string, col, currentRow int) { cell, _ := excelize.CoordinatesToCellName(col, currentRow) link, _ := f.GetCellValue(sheet, cell) display := link tooltip := "Learn more..." if link != "" { _ = f.SetCellValue(sheet, cell, display) _ = f.SetCellHyperLink(sheet, cell, link, "External", excelize.HyperlinkOpts{Display: &display, Tooltip: &tooltip}) } } func configureSheet(f *excelize.File, sheet string, headers []string, currentRow int) { _ = autofit(f, sheet) cell, err := excelize.CoordinatesToCellName(len(headers), currentRow) if err != nil { log.Fatal().Err(err).Msg("Failed to get cell") } err = f.AutoFilter(sheet, fmt.Sprintf("A4:%s", cell), nil) if err != nil { log.Fatal().Err(err).Msg("Failed to set autofilter") } logo := embeded.GetTemplates("azqr.png") opt := &excelize.GraphicOptions{ ScaleX: 1, ScaleY: 1, Positioning: "absolute", AltText: "azqr logo", } pic := &excelize.Picture{ Extension: ".png", File: logo, Format: opt, } if err := f.AddPictureFromBytes(sheet, "A1", pic); err != nil { log.Fatal().Err(err).Msg("Failed to add logo") } applyBlueStyle(f, sheet, currentRow, len(headers)) } func applyBlueStyle(f *excelize.File, sheet string, lastRow int, columns int) { blue, err := f.NewStyle(&excelize.Style{ Fill: excelize.Fill{ Type: "pattern", Color: []string{"#CAEDFB"}, Pattern: 1, }, Alignment: &excelize.Alignment{ Vertical: "top", WrapText: true, }, }) if err != nil { log.Fatal().Err(err).Msg("Failed to create blue style") } white, err := f.NewStyle(&excelize.Style{ Alignment: &excelize.Alignment{ Vertical: "top", WrapText: true, }, }) if err != nil { log.Fatal().Err(err).Msg("Failed to create blue style") } for i := 5; i <= lastRow; i++ { for j := 1; j <= columns; j++ { cell, err := excelize.CoordinatesToCellName(j, i) if err != nil { log.Fatal().Err(err).Msg("Failed to get cell") } if i%2 == 0 { err = f.SetCellStyle(sheet, cell, cell, blue) if err != nil { log.Fatal().Err(err).Msg("Failed to set style") } } else { err = f.SetCellStyle(sheet, cell, cell, white) if err != nil { log.Fatal().Err(err).Msg("Failed to set style") } } } } }