-
Notifications
You must be signed in to change notification settings - Fork 153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ECS] Support Plan Preview for ECS #4881
Merged
Merged
Changes from 20 commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
42aa504
Impl ECS's Diff func of taskDef and serviceDef
t-kikuc 52d89e9
Add ECSManifest's cache
t-kikuc 841459b
Impl ECSDiff for planpreview
t-kikuc 8c2157d
Enable ECS PlanPreview
t-kikuc f99bebe
Draft: diff test
t-kikuc 8190daa
Add and fix tests of diff with TODO of lowerCamelCase
t-kikuc 98b740b
fix tests: add params to servicedef
t-kikuc 43d3ff8
Remove wip comments
t-kikuc b416577
Skip summarizing if no changes were detected
t-kikuc 5f4f2b9
Add tags to test data
t-kikuc 46cff87
removed an unnecessary test case
t-kikuc 5325c36
Clean comments, removing TODO
t-kikuc 0b33d5a
remove an unnecessary blank line in the test data
t-kikuc 00c9dd8
Modify ApiVersion and Kind to apparent dummy
t-kikuc c9f2975
Add DiffStructs() for comparing non-k8s manifests
t-kikuc 7613dd5
removed unstructured.Unstructured from ECS
t-kikuc 17b8dfe
Separate DiffByCommand() to diff package
t-kikuc 6b07291
Fix diff render output: split ServiceDef and TaskDef sections
t-kikuc 9ff2fcf
Add a testcase to planpreview_test for ECS
t-kikuc 323b4bb
Merge branch 'master' into ecs-plan-preview
khanhtc1202 b174d23
Combine unnecessary DiffBytesByCommand() to DiffByCommand()
t-kikuc e2a38f0
Merge branch 'ecs-plan-preview' of https://github.com/pipe-cd/pipecd …
t-kikuc dd40abb
Remove IgnorePath from comparing ECS Manifests
t-kikuc 59f3171
rename func to DiffStructureds()
t-kikuc 77dcef7
add comment of which func to use
t-kikuc 9279185
Removed LoadECSManifest() func
t-kikuc db54c29
Rename test func
t-kikuc eca1b74
Add tests of diffbycommand
t-kikuc 46233d0
Removed duplicated tests
t-kikuc 97405b4
Rename ECSManifest to ECSManifests
t-kikuc 33fdec1
Merge branch 'master' into ecs-plan-preview
t-kikuc 3fee826
Removed an unnecessary variable
t-kikuc 0cb5d29
Renamed func to 'renderByCommand'
t-kikuc c9764e4
Add check of existence of the command
t-kikuc 55b89b6
Rename func to 'RenderByCommand'
t-kikuc c38c07b
Moved func 'RenderByCommand()' to renderer.go
t-kikuc 6f542c6
Merge branch 'ecs-plan-preview' of https://github.com/pipe-cd/pipecd …
t-kikuc e252b8d
Merge branch 'master' into ecs-plan-preview
t-kikuc 64efe0a
Fix nits: removed unnecessary if-state
t-kikuc a161cba
Merge branch 'ecs-plan-preview' of https://github.com/pipe-cd/pipecd …
t-kikuc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// Copyright 2024 The PipeCD Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package planpreview | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
"io" | ||
|
||
"github.com/pipe-cd/pipecd/pkg/app/piped/deploysource" | ||
provider "github.com/pipe-cd/pipecd/pkg/app/piped/platformprovider/ecs" | ||
"github.com/pipe-cd/pipecd/pkg/diff" | ||
"github.com/pipe-cd/pipecd/pkg/model" | ||
) | ||
|
||
func (b *builder) ecsdiff( | ||
ctx context.Context, | ||
app *model.Application, | ||
targetDSP deploysource.Provider, | ||
lastCommit string, | ||
buf *bytes.Buffer, | ||
) (*diffResult, error) { | ||
var ( | ||
oldManifest, newManifest provider.ECSManifest | ||
err error | ||
) | ||
|
||
newManifest, err = b.loadECSManifest(ctx, *app, targetDSP) | ||
if err != nil { | ||
fmt.Fprintf(buf, "failed to load ecs manifest at the head commit (%v)\n", err) | ||
return nil, err | ||
} | ||
|
||
if lastCommit == "" { | ||
fmt.Fprintf(buf, "failed to find the commit of the last successful deployment") | ||
return nil, fmt.Errorf("cannot get the old manifest without the last successful deployment") | ||
} | ||
|
||
runningDSP := deploysource.NewProvider( | ||
b.workingDir, | ||
deploysource.NewGitSourceCloner(b.gitClient, b.repoCfg, "running", lastCommit), | ||
*app.GitPath, | ||
b.secretDecrypter, | ||
) | ||
|
||
oldManifest, err = b.loadECSManifest(ctx, *app, runningDSP) | ||
if err != nil { | ||
fmt.Fprintf(buf, "failed to load ecs manifest at the running commit (%v)\n", err) | ||
return nil, err | ||
} | ||
|
||
result, err := provider.Diff( | ||
oldManifest, | ||
newManifest, | ||
diff.WithEquateEmpty(), | ||
diff.WithCompareNumberAndNumericString(), | ||
) | ||
if err != nil { | ||
fmt.Fprintf(buf, "failed to compare manifests (%v)\n", err) | ||
return nil, err | ||
} | ||
|
||
if result.NoChange() { | ||
fmt.Fprintln(buf, "No changes were detected") | ||
return &diffResult{ | ||
summary: "No changes were detected", | ||
noChange: true, | ||
}, nil | ||
} | ||
|
||
summary := fmt.Sprintf("%d changes were detected", len(result.Diff.Nodes())) | ||
details := result.Render(provider.DiffRenderOptions{ | ||
UseDiffCommand: true, | ||
}) | ||
fmt.Fprintf(buf, "--- Last Deploy\n+++ Head Commit\n\n%s\n", details) | ||
|
||
return &diffResult{ | ||
summary: summary, | ||
}, nil | ||
|
||
} | ||
|
||
func (b *builder) loadECSManifest(ctx context.Context, app model.Application, dsp deploysource.Provider) (provider.ECSManifest, error) { | ||
commit := dsp.Revision() | ||
cache := provider.ECSManifestCache{ | ||
AppID: app.Id, | ||
Cache: b.appManifestsCache, | ||
Logger: b.logger, | ||
} | ||
|
||
manifest, ok := cache.Get(commit) | ||
if ok { | ||
return manifest, nil | ||
} | ||
|
||
ds, err := dsp.Get(ctx, io.Discard) | ||
if err != nil { | ||
return provider.ECSManifest{}, err | ||
} | ||
|
||
appCfg := ds.ApplicationConfig.ECSApplicationSpec | ||
if appCfg == nil { | ||
return provider.ECSManifest{}, fmt.Errorf("malformed application configuration file") | ||
} | ||
|
||
manifest, err = provider.LoadECSManifest(ds.AppDir, appCfg.Input.TaskDefinitionFile, appCfg.Input.ServiceDefinitionFile) | ||
if err != nil { | ||
return provider.ECSManifest{}, err | ||
} | ||
|
||
cache.Put(commit, manifest) | ||
return manifest, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Copyright 2024 The PipeCD Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package ecs | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"go.uber.org/zap" | ||
|
||
"github.com/pipe-cd/pipecd/pkg/cache" | ||
) | ||
|
||
type ECSManifestCache struct { | ||
AppID string | ||
Cache cache.Cache | ||
Logger *zap.Logger | ||
} | ||
|
||
func (c ECSManifestCache) Get(commit string) (ECSManifest, bool) { | ||
key := ecsManifestCacheKey(c.AppID, commit) | ||
item, err := c.Cache.Get(key) | ||
if err == nil { | ||
return item.(ECSManifest), true | ||
} | ||
|
||
if errors.Is(err, cache.ErrNotFound) { | ||
c.Logger.Info("ecs manifest were not found in cache", | ||
zap.String("app-id", c.AppID), | ||
zap.String("commit-hash", commit), | ||
) | ||
return ECSManifest{}, false | ||
} | ||
|
||
c.Logger.Error("failed while retrieving ecs manifest from cache", | ||
zap.String("app-id", c.AppID), | ||
zap.String("commit-hash", commit), | ||
zap.Error(err), | ||
) | ||
return ECSManifest{}, false | ||
} | ||
|
||
func (c ECSManifestCache) Put(commit string, sm ECSManifest) { | ||
key := ecsManifestCacheKey(c.AppID, commit) | ||
if err := c.Cache.Put(key, sm); err != nil { | ||
c.Logger.Error("failed while putting ecs manifest from cache", | ||
zap.String("app-id", c.AppID), | ||
zap.String("commit-hash", commit), | ||
zap.Error(err), | ||
) | ||
} | ||
} | ||
|
||
func ecsManifestCacheKey(appID, commit string) string { | ||
return fmt.Sprintf("%s/%s", appID, commit) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright 2024 The PipeCD Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package ecs | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/pipe-cd/pipecd/pkg/diff" | ||
) | ||
|
||
const ( | ||
diffCommand = "diff" | ||
) | ||
|
||
type DiffResult struct { | ||
Diff *diff.Result | ||
Old ECSManifest | ||
New ECSManifest | ||
} | ||
|
||
func (d *DiffResult) NoChange() bool { | ||
return len(d.Diff.Nodes()) == 0 | ||
} | ||
|
||
func Diff(old, new ECSManifest, opts ...diff.Option) (*DiffResult, error) { | ||
key := old.ServiceDefinition.ServiceName | ||
if key == nil { | ||
return nil, fmt.Errorf("service name is required in the old service definition") | ||
} | ||
|
||
d, err := diff.DiffStructs(old, new, *key, opts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if !d.HasDiff() { | ||
return &DiffResult{Diff: d}, nil | ||
} | ||
|
||
ret := &DiffResult{ | ||
Old: old, | ||
New: new, | ||
Diff: d, | ||
} | ||
return ret, nil | ||
} | ||
|
||
type DiffRenderOptions struct { | ||
// If true, use "diff" command to render. | ||
UseDiffCommand bool | ||
} | ||
|
||
func (d *DiffResult) Render(opt DiffRenderOptions) string { | ||
var b strings.Builder | ||
opts := []diff.RenderOption{ | ||
diff.WithLeftPadding(1), | ||
} | ||
renderer := diff.NewRenderer(opts...) | ||
if !opt.UseDiffCommand { | ||
b.WriteString(renderer.Render(d.Diff.Nodes())) | ||
} else { | ||
d, err := diffByCommand(diffCommand, d.Old, d.New) | ||
if err != nil { | ||
b.WriteString(fmt.Sprintf("An error occurred while rendering diff (%v)", err)) | ||
} else { | ||
b.Write(d) | ||
} | ||
} | ||
b.WriteString("\n") | ||
|
||
return b.String() | ||
} | ||
|
||
func diffByCommand(command string, old, new ECSManifest) ([]byte, error) { | ||
taskDiff, err := diff.DiffByCommand(command, old.TaskDefinition, new.TaskDefinition) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
serviceDiff, err := diff.DiffByCommand(command, old.ServiceDefinition, new.ServiceDefinition) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return bytes.Join([][]byte{ | ||
[]byte("# 1. ServiceDefinition"), | ||
serviceDiff, | ||
[]byte("\n# 2. TaskDefinition"), | ||
taskDiff, | ||
}, []byte("\n")), nil | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] maybe be able to reduce the variable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, I fixed
3fee826