Skip to content

Commit

Permalink
Wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dorneanu committed Nov 1, 2024
1 parent 11cbb4e commit de58498
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 47 deletions.
109 changes: 63 additions & 46 deletions internal/app/issue/issue_handler_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,61 +114,78 @@ func OnComponentVersionAttachmentToIssue(db database.Database, e event.Event) {
return
}

// Get IssueVariants
issueVariants, err := db.GetIssueVariants(&entity.IssueVariantFilter{
IssueId: []*int64{&attachmentEvent.IssueID},
})
if err != nil {
l.WithError(err).Error("Failed to fetch issue variants")
return
}

if len(issueVariants) == 0 {
l.Warn("No issue variants found for issue")
return
}

// TODO: Use the first variant's severity (we could implement more complex severity selection logic here)
severity := issueVariants[0].Severity

// For each ComponentInstance get available IssueVariants
// via GetServiceIssueVariants
for _, compInst := range componentInstances {
l.WithField("event-step", "GetIssueMatches").Debug("Fetching issue matches related to Component Instance")
issue_matches, err := db.GetIssueMatches(&entity.IssueMatchFilter{
// Get Service Issue Variants
issueVariantMap, err := shared.BuildIssueVariantMap(db, &entity.ServiceIssueVariantFilter{
ComponentInstanceId: []*int64{&compInst.Id},
IssueId: []*int64{&attachmentEvent.IssueID},
})

}, attachmentEvent.ComponentVersionID)
if err != nil {
l.WithField("event-step", "GetIssueMatches").WithError(err).Error("Error while fetching issue matches related to Component Instance")
return
}
l.WithField("issueMatchesCount", len(issue_matches))

if len(issue_matches) > 0 {
l.WithField("event-step", "Skipping").Debug("The issue match does already exist. Skipping")
continue
}

// Create new issue match
issue_match := &entity.IssueMatch{
UserId: 1, // TODO: change this?
Status: entity.IssueMatchStatusValuesNew,
Severity: severity, //we got two simply take the first one
ComponentInstanceId: compInst.Id,
IssueId: attachmentEvent.IssueID,
TargetRemediationDate: shared.GetTargetRemediationTimeline(severity, time.Now(), nil),
}
l.WithField("event-step", "CreateIssueMatch").WithField("issueMatch", issue_match).Debug("Creating Issue Match")

_, err = db.CreateIssueMatch(issue_match)
if err != nil {
l.WithField("event-step", "CreateIssueMatch").WithError(err).Error("Error while creating issue match")
return
l.WithField("event-step", "FetchIssueVariants").WithError(err).Error("Error while fetching issue variants")
}

// Create new IssueMatches
createIssueMatches(db, l, compInst.Id, issueVariantMap)
}
} else {
l.Error("Invalid event type received")
}

}

// TODO: This function is very similar to the one used in issue_match_handler_events.go
// We might as well put this into the shared package
//
// createIssueMatches creates new issue matches based on the component instance Id,
// issue ID and their corresponding issue variants (sorted by priority)
func createIssueMatches(
db database.Database,
l *logrus.Entry,
componentInstanceId int64,
issueVariantMap map[int64]entity.ServiceIssueVariant,
) {
for issueId, issueVariant := range issueVariantMap {
l = l.WithFields(logrus.Fields{
"issue": issueVariant,
})

// Check if IssueMatches already exist
l.WithField("event-step", "FetchIssueMatches").Debug("Fetching issue matches related to assigned Component Instance")
issue_matches, err := db.GetIssueMatches(&entity.IssueMatchFilter{
IssueId: []*int64{&issueId},
ComponentInstanceId: []*int64{&componentInstanceId},
})

if err != nil {
l.WithField("event-step", "FetchIssueMatches").WithError(err).Error("Error while fetching issue matches related to assigned Component Instance")
return
}
l.WithField("issueMatchesCount", len(issue_matches))

if len(issue_matches) != 0 {
l.WithField("event-step", "Skipping").Debug("The issue match does already exist. Skipping")
return
}

// Create new issue match
// currently a static user is assumed to be used, this going to change in future to either a configured user or a dynamically
// infered user from the component version issue macht
issue_match := &entity.IssueMatch{
UserId: 1, //@todo discuss whatever we use a static system user or infer the user from the ComponentVersionIssue
Status: entity.IssueMatchStatusValuesNew,
Severity: issueVariantMap[issueId].Severity, //we got two simply take the first one
ComponentInstanceId: componentInstanceId,
IssueId: issueId,
TargetRemediationDate: shared.GetTargetRemediationTimeline(issueVariant.Severity, time.Now(), nil),
}
l.WithField("event-step", "CreateIssueMatch").WithField("issueMatch", issue_match).Debug("Creating Issue Match")

_, err = db.CreateIssueMatch(issue_match)
if err != nil {
l.WithField("event-step", "CreateIssueMatch").WithError(err).Error("Error while creating issue match")
return
}
}
}
4 changes: 3 additions & 1 deletion internal/app/issue_match/issue_match_handler_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ func OnComponentVersionAssignmentToComponentInstance(db database.Database, compo
})

l.WithField("event-step", "BuildIssueVariants").Debug("Building map of IssueVariants for issues related to assigned Component Version")
issueVariantMap, err := BuildIssueVariantMap(db, componentInstanceID, componentVersionID)
issueVariantMap, err := shared.BuildIssueVariantMap(db, &entity.ServiceIssueVariantFilter{
ComponentInstanceId: []*int64{&componentInstanceID},
}, componentVersionID)

l.WithField("issueVariantMap", issueVariantMap)
if err != nil {
Expand Down
61 changes: 61 additions & 0 deletions internal/app/shared/issueVariant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors
// SPDX-License-Identifier: Apache-2.0

package shared

import (
"fmt"

"github.com/cloudoperators/heureka/internal/database"
"github.com/cloudoperators/heureka/internal/entity"
"github.com/sirupsen/logrus"
)

// BuildIssueVariantMap builds a map of issue id to issue variant for the given filter.
// it does take the first issue_variant with the highest priority for the respective component instance.
// This is archived by utilizing database.GetServiceIssueVariants that does return ALL issue variants for a given
// component instance id together with the priorty and afterwards identifying for each issue the variant with the highest
// priority
//
// Returns a map of issue id to issue variant
func BuildIssueVariantMap(db database.Database, filter *entity.ServiceIssueVariantFilter, componentVersionId int64) (map[int64]entity.ServiceIssueVariant, error) {
l := logrus.WithFields(logrus.Fields{
"event": "BuildIssueVariantMap",
"componentInstanceID": filter.ComponentInstanceId,
"componentVersionID": componentVersionId,
"issueId": filter.IssueId,
})

// Get Issue Variants based on filter
issueVariants, err := db.GetServiceIssueVariants(filter)
if err != nil {
l.WithField("event-step", "FetchIssueVariants").WithError(err).Error("Error while fetching issue variants")
return nil, fmt.Errorf("Error while fetching issue variants: %w", err)
}

// No issue variants found,
if len(issueVariants) < 1 {
l.WithField("event-step", "FetchIssueVariants").Error("No issue variants found that are related to the issue repository")
return nil, fmt.Errorf("No issue variants found that are related to the issue repository")
}

// create a map of issue id to variants for easy access
var issueVariantMap = make(map[int64]entity.ServiceIssueVariant)

for _, variant := range issueVariants {

if _, ok := issueVariantMap[variant.IssueId]; ok {
// if there are multiple variants with the same priority on their repositories we take the highest severity one
// if serverity and score are the same the first occuring issue variant is taken
if issueVariantMap[variant.IssueId].Priority < variant.Priority {
issueVariantMap[variant.IssueId] = variant
} else if issueVariantMap[variant.IssueId].Severity.Score < variant.Severity.Score {
issueVariantMap[variant.IssueId] = variant
}
} else {
issueVariantMap[variant.IssueId] = variant
}
}

return issueVariantMap, nil
}
1 change: 1 addition & 0 deletions internal/database/mariadb/service_issue_variant.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func (s *SqlDatabase) ensureServiceIssueVariantFilter(f *entity.ServiceIssueVari
func (s *SqlDatabase) getServiceIssueVariantFilterString(filter *entity.ServiceIssueVariantFilter) string {
var fl []string
fl = append(fl, buildFilterQuery(filter.ComponentInstanceId, "CI.componentinstance_id = ?", OP_OR))
fl = append(fl, buildFilterQuery(filter.IssueId, "I.issue_id = ?", OP_OR))
fl = append(fl, "IV.issuevariant_deleted_at IS NULL")

return combineFilterQueries(fl, OP_AND)
Expand Down
1 change: 1 addition & 0 deletions internal/entity/issue_variant.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type ServiceIssueVariant struct {
type ServiceIssueVariantFilter struct {
Paginated
ComponentInstanceId []*int64 `json:"component_instance_id"`
IssueId []*int64 `json:"issue_id"`
}

func NewServiceIssueVariantFilter() *ServiceIssueVariantFilter {
Expand Down

0 comments on commit de58498

Please sign in to comment.