-
Notifications
You must be signed in to change notification settings - Fork 421
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(deploy): update deploy/cfn package to support
task run
command (
#1134) This PR includes changes to deploy a task to CloudFormation. Related #702 By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
- Loading branch information
1 parent
4d9c1b0
commit 417be99
Showing
2 changed files
with
130 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package cloudformation | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/aws/copilot-cli/internal/pkg/aws/cloudformation" | ||
"github.com/aws/copilot-cli/internal/pkg/deploy" | ||
"github.com/aws/copilot-cli/internal/pkg/deploy/cloudformation/stack" | ||
) | ||
|
||
// DeployTask deploys a task stack and waits until the deployment is done. | ||
// If the task stack doesn't exist, then it creates the stack. | ||
// If the task stack already exists, it updates the stack. | ||
// If the task stack doesn't have any changes, it returns nil | ||
func (cf CloudFormation) DeployTask(input *deploy.CreateTaskResourcesInput) error { | ||
conf := stack.NewTaskStackConfig(input) | ||
stack, err := toStack(conf) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = cf.cfnClient.CreateAndWait(stack) | ||
if err == nil { | ||
return nil | ||
} | ||
|
||
var errAlreadyExists *cloudformation.ErrStackAlreadyExists | ||
if !errors.As(err, &errAlreadyExists) { | ||
return fmt.Errorf("create stack: %w", err) | ||
} | ||
|
||
err = cf.cfnClient.UpdateAndWait(stack) | ||
if err == nil { | ||
return nil | ||
} | ||
|
||
var errChangeSetEmpty *cloudformation.ErrChangeSetEmpty | ||
if !errors.As(err, &errChangeSetEmpty) { | ||
return fmt.Errorf("update stack: %w", err) | ||
} | ||
|
||
return 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,83 @@ | ||
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package cloudformation | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"github.com/aws/copilot-cli/internal/pkg/deploy" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/aws/copilot-cli/internal/pkg/aws/cloudformation" | ||
|
||
"github.com/aws/copilot-cli/internal/pkg/deploy/cloudformation/mocks" | ||
"github.com/golang/mock/gomock" | ||
) | ||
|
||
func TestCloudFormation_DeployTask(t *testing.T) { | ||
mockTask := &deploy.CreateTaskResourcesInput{ | ||
Name: "my-task", | ||
} | ||
|
||
testCases := map[string]struct { | ||
mockCfnClient func(m *mocks.MockcfnClient) | ||
wantedError error | ||
}{ | ||
"create a new stack": { | ||
mockCfnClient: func(m *mocks.MockcfnClient) { | ||
m.EXPECT().CreateAndWait(gomock.Any()).Return(nil) | ||
m.EXPECT().UpdateAndWait(gomock.Any()).Times(0) | ||
}, | ||
}, | ||
"failed to create stack": { | ||
mockCfnClient: func(m *mocks.MockcfnClient) { | ||
m.EXPECT().CreateAndWait(gomock.Any()).Return(errors.New("error")) | ||
m.EXPECT().UpdateAndWait(gomock.Any()).Times(0) | ||
}, | ||
wantedError: errors.New("create stack: error"), | ||
}, | ||
"update the stack": { | ||
mockCfnClient: func(m *mocks.MockcfnClient) { | ||
m.EXPECT().CreateAndWait(gomock.Any()).Return(&cloudformation.ErrStackAlreadyExists{ | ||
Name: "my-task", | ||
}) | ||
m.EXPECT().UpdateAndWait(gomock.Any()).Times(1).Return(nil) | ||
}, | ||
}, | ||
"failed to update stack": { | ||
mockCfnClient: func(m *mocks.MockcfnClient) { | ||
m.EXPECT().CreateAndWait(gomock.Any()).Return(&cloudformation.ErrStackAlreadyExists{ | ||
Name: "my-task", | ||
}) | ||
m.EXPECT().UpdateAndWait(gomock.Any()).Return(errors.New("error")) | ||
}, | ||
wantedError: errors.New("update stack: error"), | ||
}, | ||
} | ||
|
||
for name, tc := range testCases { | ||
t.Run(name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
|
||
mockCfnClient := mocks.NewMockcfnClient(ctrl) | ||
if tc.mockCfnClient != nil { | ||
tc.mockCfnClient(mockCfnClient) | ||
} | ||
|
||
cf := CloudFormation{ | ||
cfnClient: mockCfnClient, | ||
} | ||
|
||
err := cf.DeployTask(mockTask) | ||
if tc.wantedError != nil { | ||
require.EqualError(t, tc.wantedError, err.Error()) | ||
} else { | ||
require.NoError(t, err) | ||
} | ||
}) | ||
} | ||
} |