Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

feat: add new custom property evaluationHeatmapURL to evaluation finished events #841

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/action/action_finished_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (eh *ActionFinishedEventHandler) HandleEvent(workCtx context.Context, _ con

// https://github.com/keptn-contrib/dynatrace-service/issues/174
// Additionally to the problem comment, send Info or Configuration Change Event to the entities in Dynatrace to indicate that remediation actions have been executed
customProperties := createCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), bridgeURL)
customProperties := newCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), bridgeURL)
if eh.event.GetStatus() == keptnv2.StatusSucceeded {
configurationEvent := dynatrace.ConfigurationEvent{
EventType: dynatrace.ConfigurationEventType,
Expand Down
2 changes: 1 addition & 1 deletion internal/action/action_triggered_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (eh *ActionTriggeredEventHandler) HandleEvent(workCtx context.Context, _ co
Source: eventSource,
Title: "Keptn Remediation Action Triggered",
Description: eh.event.GetAction(),
CustomProperties: createCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), bridgeURL),
CustomProperties: newCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), bridgeURL),
AttachRules: *eh.attachRules,
}

Expand Down
30 changes: 23 additions & 7 deletions internal/action/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ const bridgeURLKey = "Keptns Bridge"

const contextless = "CONTEXTLESS"

func createCustomProperties(a adapter.EventContentAdapter, imageAndTag common.ImageAndTag, bridgeURL string) map[string]string {
customProperties := map[string]string{
type customProperties map[string]string

func newCustomProperties(a adapter.EventContentAdapter, imageAndTag common.ImageAndTag, bridgeURL string) customProperties {
cp := customProperties{
"Project": a.GetProject(),
"Stage": a.GetStage(),
"Service": a.GetService(),
Expand All @@ -27,16 +29,30 @@ func createCustomProperties(a adapter.EventContentAdapter, imageAndTag common.Im
"Keptn Service": a.GetSource(),
}

// now add the rest of the labels into custom properties (changed with #115_116)
for key, value := range a.GetLabels() {
customProperties[key] = value
cp.add(key, value)
}

cp.addIfNonEmpty(bridgeURLKey, bridgeURL)

return cp
}

func (cp customProperties) add(key string, value string) {
oldValue, isContained := cp[key]
if isContained {
log.Warnf("Overwriting current value '%s' of key '%s' with new value '%s in custom properties", oldValue, key, value)
}

if bridgeURL != "" {
customProperties[bridgeURLKey] = bridgeURL
cp[key] = value
}

func (cp customProperties) addIfNonEmpty(key string, value string) {
if key == "" || value == "" {
return
}

return customProperties
cp.add(key, value)
}

func getValueFromLabels(a adapter.EventContentAdapter, key string, defaultValue string) string {
Expand Down
92 changes: 92 additions & 0 deletions internal/action/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package action

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestCustomProperties_Add(t *testing.T) {
testConfigs := []struct {
name string
key string
value string
expected customProperties
}{
{
name: "both empty",
key: "",
value: "",
expected: customProperties{"": ""},
},
{
name: "key empty",
key: "",
value: "value",
expected: customProperties{"": "value"},
},
{
name: "value empty",
key: "key",
value: "",
expected: customProperties{"key": ""},
},
{
name: "value empty",
key: "key",
value: "value",
expected: customProperties{"key": "value"},
},
}
for _, testCfg := range testConfigs {
t.Run(testCfg.name, func(t *testing.T) {
cp := customProperties{}
cp.add(testCfg.key, testCfg.value)

assert.Equal(t, testCfg.expected, cp)
})
}
}

func TestCustomProperties_AddIfNonEmpty(t *testing.T) {

testConfigs := []struct {
name string
key string
value string
expected customProperties
}{
{
name: "both empty",
key: "",
value: "",
expected: customProperties{},
},
{
name: "key empty",
key: "",
value: "value",
expected: customProperties{},
},
{
name: "value empty",
key: "key",
value: "",
expected: customProperties{},
},
{
name: "value empty",
key: "key",
value: "value",
expected: customProperties{"key": "value"},
},
}
for _, testCfg := range testConfigs {
t.Run(testCfg.name, func(t *testing.T) {
cp := customProperties{}
cp.addIfNonEmpty(testCfg.key, testCfg.value)

assert.Equal(t, testCfg.expected, cp)
})
}
}
2 changes: 1 addition & 1 deletion internal/action/deployment_finished_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (eh *DeploymentFinishedEventHandler) HandleEvent(workCtx context.Context, _
DeploymentVersion: getValueFromLabels(eh.event, "deploymentVersion", imageAndTag.Tag()),
CiBackLink: getValueFromLabels(eh.event, "ciBackLink", ""),
RemediationAction: getValueFromLabels(eh.event, "remediationAction", ""),
CustomProperties: createCustomProperties(eh.event, imageAndTag, keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
CustomProperties: newCustomProperties(eh.event, imageAndTag, keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
AttachRules: *eh.attachRules,
}

Expand Down
7 changes: 6 additions & 1 deletion internal/action/evaluation_finished_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/keptn-contrib/dynatrace-service/internal/keptn"
)

const evaluationURLKey = "evaluationHeatmapURL"

// EvaluationFinishedEventHandler handles an evaluation finished event.
type EvaluationFinishedEventHandler struct {
event EvaluationFinishedAdapterInterface
Expand Down Expand Up @@ -54,12 +56,15 @@ func (eh *EvaluationFinishedEventHandler) HandleEvent(workCtx context.Context, _
return fmt.Errorf("could not setup correct attach rules: %w", err)
}

customProperties := newCustomProperties(eh.event, imageAndTag, bridgeURL)
customProperties.addIfNonEmpty(evaluationURLKey, keptn.TryGetBridgeURLForEvaluation(workCtx, eh.event))

infoEvent := dynatrace.InfoEvent{
EventType: dynatrace.InfoEventType,
Source: eventSource,
Title: eh.getTitle(isPartOfRemediation),
Description: fmt.Sprintf("Quality Gate Result in stage %s: %s (%.2f/100)", eh.event.GetStage(), eh.event.GetResult(), eh.event.GetEvaluationScore()),
CustomProperties: createCustomProperties(eh.event, imageAndTag, bridgeURL),
CustomProperties: customProperties,
AttachRules: attachRules,
}

Expand Down
2 changes: 1 addition & 1 deletion internal/action/release_triggered_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (eh *ReleaseTriggeredEventHandler) HandleEvent(workCtx context.Context, _ c
Source: eventSource,
Title: eh.getTitle(strategy, eh.event.GetLabels()["title"]),
Description: eh.getTitle(strategy, eh.event.GetLabels()["description"]),
CustomProperties: createCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
CustomProperties: newCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
AttachRules: *eh.attachRules,
}

Expand Down
2 changes: 1 addition & 1 deletion internal/action/test_finished_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (eh *TestFinishedEventHandler) HandleEvent(workCtx context.Context, _ conte
Source: eventSource,
AnnotationType: getValueFromLabels(eh.event, "type", "Stop Tests"),
AnnotationDescription: getValueFromLabels(eh.event, "description", "Stop running tests: against "+eh.event.GetService()),
CustomProperties: createCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
CustomProperties: newCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
AttachRules: *eh.attachRules,
}

Expand Down
2 changes: 1 addition & 1 deletion internal/action/test_triggered_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (eh *TestTriggeredEventHandler) HandleEvent(workCtx context.Context, _ cont
Source: eventSource,
AnnotationType: getValueFromLabels(eh.event, "type", "Start Tests: "+eh.event.GetTestStrategy()),
AnnotationDescription: getValueFromLabels(eh.event, "description", "Start running tests: "+eh.event.GetTestStrategy()+" against "+eh.event.GetService()),
CustomProperties: createCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
CustomProperties: newCustomProperties(eh.event, eh.eClient.GetImageAndTag(workCtx, eh.event), keptn.TryGetBridgeURLForKeptnContext(workCtx, eh.event)),
AttachRules: *eh.attachRules,
}

Expand Down
24 changes: 20 additions & 4 deletions internal/keptn/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keptn

import (
"context"
"fmt"

"github.com/keptn-contrib/dynatrace-service/internal/adapter"
"github.com/keptn-contrib/dynatrace-service/internal/credentials"
Expand All @@ -11,19 +12,34 @@ import (
v2 "github.com/keptn/go-utils/pkg/api/utils/v2"
)

// TryGetBridgeURLForKeptnContext gets a backlink to the Keptn Bridge if available or returns "".
// TryGetBridgeURLForKeptnContext gets a backlink to the Keptn Bridge if available or returns empty string.
func TryGetBridgeURLForKeptnContext(ctx context.Context, event adapter.EventContentAdapter) string {
credentials, err := credentials.GetKeptnCredentials(ctx)
keptnBridgeURL := tryGetBridgeURL(ctx)
if keptnBridgeURL == "" {
return ""
}

return keptnBridgeURL + "/trace/" + event.GetShKeptnContext()
}

// tryGetBridgeURL gets the Keptn Bridge URL if available or returns empty string.
func tryGetBridgeURL(ctx context.Context) string {
creds, err := credentials.GetKeptnCredentials(ctx)
if err != nil {
return ""
}

keptnBridgeURL := credentials.GetBridgeURL()
return creds.GetBridgeURL()
}

// TryGetBridgeURLForEvaluation gets a backlink to the evaluation in Keptn Bridge if available or returns empty string.
func TryGetBridgeURLForEvaluation(ctx context.Context, event adapter.EventContentAdapter) string {
keptnBridgeURL := tryGetBridgeURL(ctx)
if keptnBridgeURL == "" {
return ""
}

return keptnBridgeURL + "/trace/" + event.GetShKeptnContext()
return fmt.Sprintf("%s/evaluation/%s/%s", keptnBridgeURL, event.GetShKeptnContext(), event.GetStage())
}

// GetV1InClusterAPIMappings returns the InClusterAPIMappings.
Expand Down