github.com/diggerhq/digger/libs@v0.0.0-20240604170430-9d61cdf01cc5/comment_utils/reporting/source_grouping.go (about) 1 package reporting 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "github.com/diggerhq/digger/libs/comment_utils/utils" 7 "github.com/diggerhq/digger/libs/digger_config" 8 "github.com/diggerhq/digger/libs/orchestrator" 9 "github.com/diggerhq/digger/libs/orchestrator/scheduler" 10 "github.com/diggerhq/digger/libs/terraform_utils" 11 "github.com/samber/lo" 12 "log" 13 "strconv" 14 ) 15 16 type ProjectNameSourceDetail struct { 17 ProjectName string 18 Source string 19 Job scheduler.SerializedJob 20 JobSpec orchestrator.JobJson 21 PlanFootPrint terraform_utils.TerraformPlanFootprint 22 } 23 24 type SourceGroupingReporter struct { 25 Jobs []scheduler.SerializedJob 26 PrNumber int 27 PrService orchestrator.PullRequestService 28 } 29 30 func (r SourceGroupingReporter) UpdateComment(sourceDetails []SourceDetails, location string, terraformOutputs map[string]string) error { 31 32 sourceDetaiItem, found := lo.Find(sourceDetails, func(item SourceDetails) bool { 33 return item.SourceLocation == location 34 }) 35 36 if !found { 37 log.Printf("location not found in sourcedetails list") 38 return fmt.Errorf("location not found in sourcedetails list") 39 } 40 41 projectNameToJobMap, err := scheduler.JobsToProjectMap(r.Jobs) 42 if err != nil { 43 return fmt.Errorf("could not convert jobs to map: %v", err) 44 } 45 46 projectNameToFootPrintMap := make(map[string]terraform_utils.TerraformPlanFootprint) 47 for _, job := range r.Jobs { 48 var footprint terraform_utils.TerraformPlanFootprint 49 if job.PlanFootprint != nil { 50 err := json.Unmarshal(job.PlanFootprint, &footprint) 51 if err != nil { 52 log.Printf("could not unmarshal footprint: %v", err) 53 return fmt.Errorf("could not unmarshal footprint: %v", err) 54 } 55 } else { 56 footprint = terraform_utils.TerraformPlanFootprint{} 57 } 58 projectNameToFootPrintMap[job.ProjectName] = footprint 59 } 60 61 footprints := lo.FilterMap(sourceDetaiItem.Projects, func(project string, i int) (terraform_utils.TerraformPlanFootprint, bool) { 62 if projectNameToJobMap[project].Status == scheduler.DiggerJobSucceeded { 63 return projectNameToFootPrintMap[project], true 64 } 65 return terraform_utils.TerraformPlanFootprint{}, false 66 }) 67 allSimilarInGroup, err := terraform_utils.SimilarityCheck(footprints) 68 if err != nil { 69 return fmt.Errorf("error performing similar check: %v", err) 70 } 71 72 message := "" 73 message = message + fmt.Sprintf("# Group: %v (similar: %v)\n", location, allSimilarInGroup) 74 for i, project := range sourceDetaiItem.Projects { 75 job := projectNameToJobMap[project] 76 if job.Status != scheduler.DiggerJobSucceeded { 77 continue 78 } 79 expanded := i == 0 || !allSimilarInGroup 80 commenter := utils.GetTerraformOutputAsCollapsibleComment(fmt.Sprintf("Plan for %v", project), expanded) 81 message = message + commenter(terraformOutputs[project]) + "\n" 82 } 83 84 CommentId, err := strconv.ParseInt(sourceDetaiItem.CommentId, 10, 64) 85 if err != nil { 86 log.Printf("Could not convert commentId to int64: %v", err) 87 return fmt.Errorf("could not convert commentId to int64: %v", err) 88 } 89 r.PrService.EditComment(r.PrNumber, CommentId, message) 90 return nil 91 } 92 93 // returns a map inverting locations 94 func ImpactedSourcesMapToGroupMapping(impactedSources map[string]digger_config.ProjectToSourceMapping, jobMapping map[string]scheduler.SerializedJob, jobSpecMapping map[string]orchestrator.JobJson, footprintsMap map[string]terraform_utils.TerraformPlanFootprint) map[string][]ProjectNameSourceDetail { 95 96 projectNameSourceList := make([]ProjectNameSourceDetail, 0) 97 for projectName, locations := range impactedSources { 98 for _, location := range locations.ImpactingLocations { 99 projectNameSourceList = append(projectNameSourceList, ProjectNameSourceDetail{ 100 projectName, 101 location, 102 jobMapping[projectName], 103 jobSpecMapping[projectName], 104 footprintsMap[projectName], 105 }) 106 } 107 } 108 res := lo.GroupBy(projectNameSourceList, func(t ProjectNameSourceDetail) string { 109 return t.Source 110 }) 111 return res 112 }