Skip to content

Commit

Permalink
feat: add resource modification overview
Browse files Browse the repository at this point in the history
  • Loading branch information
karlderkaefer committed Dec 3, 2023
1 parent e272929 commit 8a1848a
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 1 deletion.
38 changes: 38 additions & 0 deletions data/cdk-diff-resources-changes.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Stack fargate
Resources
[~] AWS::ECS::TaskDefinition DetailFargateService/TaskDef detailFargateServiceTaskDef795131A3 replace
└─ [~] ContainerDefinitions (requires replacement)
└─ @@ -81,7 +81,7 @@
[ ] ],
[ ] "Essential": true,
[ ] "Image": {
- [-] "Fn::Sub": "123456789012.dkr.ecr.eu-central-1.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-123456789012-eu-central-1:88f53e8e790ee348fe371bd2dd7365d2cc15be096da0c12d4b0d8bf47aff35d3"
+ [+] "Fn::Sub": "123456789012.dkr.ecr.eu-central-1.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-123456789012-eu-central-1:64137e051d225c2e197f36cf1156f21c0ec449c2902fa5c8d685e0fbbe822e2d"
[ ] },
[ ] "LogConfiguration": {
[ ] "LogDriver": "awslogs",
[~] AWS::ECS::TaskDefinition ListFargateService/TaskDef listFargateServiceTaskDef795531A3 replace
└─ [~] ContainerDefinitions (requires replacement)
└─ @@ -81,7 +81,7 @@
[ ] ],
[ ] "Essential": true,
[ ] "Image": {
- [-] "Fn::Sub": "123456789012.dkr.ecr.eu-central-1.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-123456789012-eu-central-1:88f53e8e790ee348fe371bgt2dd7365d2cc15be096da0c12d4b0d8bf47aff35d3"
+ [+] "Fn::Sub": "123456789012.dkr.ecr.eu-central-1.${AWS::URLSuffix}/cdk-hnb659fds-container-assets-123456789012-eu-central-1:64137e051d225c2e197f36cf11456f21c0ec449c2902fa5c8d685e0fbbe822e2d"
[ ] },
[ ] "LogConfiguration": {
[ ] "LogDriver": "awslogs",
Stack lambda
Resources
[~] AWS::Lambda::Function listHandler/Lambda/lambda listHandlerLambdalambdaC875E395
├─ [~] Code
│ └─ [~] .S3Key:
-│ ├─ [-] 6a8fb4fcc5f635e40d135b1038a814ab0aca7be1e0d85eabb319af0d323a699b.zip
+│ └─ [+] 57a04aad6ab772d1d155746c5b7f3fad7ec005480af335a673aadc88b1005919.zip
└─ [~] Metadata
└─ [~] .aws:asset:path:
- ├─ [-] asset.6a8fb4fcc5f635e40d135b1038a814ab0aca7be1e0d85eabb319af0d323a699b
+ └─ [+] asset.57a04aad6ab772d1d155746c5b7f3fad7ec005480af335a673aadc88b1005919


✨ Number of stacks with differences: 2
34 changes: 34 additions & 0 deletions transform/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,31 @@ var extendedTemplate = `
{{- end }}
`

var extendedWithResourcesTemplate = `
{{ .HeaderPrefix }} {{ .TagID }} {{ .JobLink }}
{{ .NumberOfDifferencesString }}
{{- if .NumberReplaces }}
⚠️ Number of resources that require replacement: {{ .NumberReplaces }}
{{- end }}
{{- if .ChangedBaseResource }}
### Resources that are subject of change
{{- range $key, $value := .ChangedBaseResource }}
{{ $key }}: {{ $value.Count }}{{ if $value.Replaced }} (required replacement){{ end }}
{{- end }}
{{- end }}
{{- if .Collapsible }}
<details>
<summary>Click to expand</summary>
{{- end }}
{{ .Backticks }}diff
{{ .Content }}
{{ .Backticks }}
{{- if .Collapsible }}
</details>
{{- end }}
`

// commentTemplate wrapper object to use go templating
type commentTemplate struct {
TagID string
Expand All @@ -53,6 +78,7 @@ type commentTemplate struct {
ShowOverview bool
NumberOfDifferencesString string
NumberReplaces int
ChangedBaseResource map[string]ResourceMetric
Template string // template type
customTemplate string // template file or string
}
Expand All @@ -73,6 +99,12 @@ func (e ExtendedTemplate) getTemplateContent() string {
return extendedTemplate
}

type ExtendedWithResourcesTemplate struct{}

func (e ExtendedWithResourcesTemplate) getTemplateContent() string {
return extendedWithResourcesTemplate

Check warning on line 105 in transform/template.go

View check run for this annotation

Codecov / codecov/patch

transform/template.go#L104-L105

Added lines #L104 - L105 were not covered by tests
}

type CustomTemplate struct {
TemplateContent string
}
Expand Down Expand Up @@ -101,6 +133,8 @@ func (t *commentTemplate) ChooseTemplate() TemplateStrategy {
return DefaultTemplate{}
case "extended":
return ExtendedTemplate{}
case "extendedWithResources":
return ExtendedWithResourcesTemplate{}

Check warning on line 137 in transform/template.go

View check run for this annotation

Codecov / codecov/patch

transform/template.go#L136-L137

Added lines #L136 - L137 were not covered by tests
default:
logrus.Warnf("Template %s not found, using default template", t.Template)
return DefaultTemplate{}
Expand Down
40 changes: 39 additions & 1 deletion transform/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@ type LogTransformer struct {
ShowOverview bool
NumberOfDifferencesString string
NumberReplaces int
ChangedBaseResource map[string]ResourceMetric
Template string
CustomTemplate string
ProcessorsChain LineProcessor
}

type ResourceMetric struct {
Count int
Replaced bool
}

// A LineProcessor is responsible to process a single line.
// It can either just extract information from the line or modify it.
type LineProcessor interface {
Expand Down Expand Up @@ -75,10 +81,13 @@ func NewLogTransformer(config *config.NotifierConfig) *LogTransformer {
}

func (t *LogTransformer) initProcessorsChain() {
t.ChangedBaseResource = make(map[string]ResourceMetric)
stackDiffProcessor := &StackDiffProcessor{}
numberReplacesProcessor := &NumberReplacesProcessor{}
diffSymbolProcessor := &DiffSymbolProcessor{}
stackDiffProcessor.SetNext(numberReplacesProcessor)
resourceDiffExtractorProcessor := &ResourceDiffExtractorProcessor{}
stackDiffProcessor.SetNext(resourceDiffExtractorProcessor)
resourceDiffExtractorProcessor.SetNext(numberReplacesProcessor)
numberReplacesProcessor.SetNext(diffSymbolProcessor)
t.ProcessorsChain = stackDiffProcessor
}
Expand Down Expand Up @@ -131,6 +140,34 @@ func (p *NumberReplacesProcessor) ProcessLine(line string, lt *LogTransformer) s
return p.BaseProcessor.ProcessLine(line, lt)
}

// Collect number of AWS base type changes
type ResourceDiffExtractorProcessor struct {
BaseProcessor
}

func (p *ResourceDiffExtractorProcessor) ProcessLine(line string, lt *LogTransformer) string {
// https://regex101.com/r/rBmjEp/2
regex := regexp.MustCompile(`\s*\[(-|\+|~)] (AWS::\w+::\w+).*?(?P<replace>(replace|replaced)?$)`)
matches := regex.FindStringSubmatch(line)
if len(matches) > 0 {
awsBaseResource := matches[2]
replaced := matches[3] != ""
resource, exists := lt.ChangedBaseResource[awsBaseResource]
if exists {
resource.Count++
// if replace was already detected, keep it
resource.Replaced = resource.Replaced || replaced
} else {
resource = ResourceMetric{
Count: 1,
Replaced: replaced,
}
}
lt.ChangedBaseResource[awsBaseResource] = resource
}
return p.BaseProcessor.ProcessLine(line, lt)
}

// Transform additions and removals to markdown diff syntax
type DiffSymbolProcessor struct {
BaseProcessor
Expand Down Expand Up @@ -203,6 +240,7 @@ func (t *LogTransformer) addHeader() {
TagID: t.TagID,
NumberOfDifferencesString: t.NumberOfDifferencesString,
NumberReplaces: t.NumberReplaces,
ChangedBaseResource: t.ChangedBaseResource,
Content: t.LogContent,
Backticks: "```",
JobLink: "",
Expand Down
70 changes: 70 additions & 0 deletions transform/transformer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package transform
import (
"math/rand"
"os"
"reflect"
"testing"
"time"

Expand Down Expand Up @@ -265,4 +266,73 @@ func TestOverviewSection(t *testing.T) {
assert.Contains(t, transformer.NumberOfDifferencesString, "Number of stacks with differences: 1")
assert.Equal(t, transformer.NumberReplaces, 5)

// test resource diff extractor
res := transformer.ChangedBaseResource
assert.Equal(t, 2, res["AWS::DynamoDB::Table"].Count)
assert.Equal(t, true, res["AWS::DynamoDB::Table"].Replaced)
assert.Equal(t, 1, res["AWS::RDS::DBInstance"].Count)
assert.Equal(t, true, res["AWS::RDS::DBInstance"].Replaced)
assert.Equal(t, 1, res["AWS::RDS::DBInstance"].Count)
assert.Equal(t, true, res["AWS::RDS::DBInstance"].Replaced)
assert.Equal(t, 1, res["AWS::RDS::DBParameterGroup"].Count)
assert.Equal(t, true, res["AWS::RDS::DBParameterGroup"].Replaced)
}

func TestResourceDiffExtractorProcessor_ProcessLine(t *testing.T) {
tests := []struct {
name string
line string
expected map[string]ResourceMetric
baseProcessor BaseProcessor
}{
{
name: "WithAddition",
line: " [+] AWS::S3::Bucket MyBucket",
expected: map[string]ResourceMetric{
"AWS::S3::Bucket": {
Count: 1,
Replaced: false,
},
},
baseProcessor: BaseProcessor{},
},
{
name: "WithDeletion",
line: " [-] AWS::S3::Bucket MyBucket",
expected: map[string]ResourceMetric{
"AWS::S3::Bucket": {
Count: 1,
Replaced: false,
},
},
baseProcessor: BaseProcessor{},
},
{
name: "WithModification",
line: " [~] AWS::S3::Bucket MyBucket replaced",
expected: map[string]ResourceMetric{
"AWS::S3::Bucket": {
Count: 1,
Replaced: true,
},
},
baseProcessor: BaseProcessor{},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
lt := &LogTransformer{
ChangedBaseResource: make(map[string]ResourceMetric),
}
p := &ResourceDiffExtractorProcessor{
BaseProcessor: tt.baseProcessor,
}

p.ProcessLine(tt.line, lt)
if !reflect.DeepEqual(lt.ChangedBaseResource, tt.expected) {
t.Errorf("ChangedBaseResource = %v, want %v", lt.ChangedBaseResource, tt.expected)
}
})
}
}

0 comments on commit 8a1848a

Please sign in to comment.