diff --git a/cmd/copilot/main.go b/cmd/copilot/main.go index cb9c275a783..b0984642220 100644 --- a/cmd/copilot/main.go +++ b/cmd/copilot/main.go @@ -5,8 +5,11 @@ package main import ( + "context" "errors" "os" + "os/signal" + "syscall" "github.com/aproint/copilot-cli/cmd/copilot/template" "github.com/aproint/copilot-cli/internal/pkg/cli" @@ -24,14 +27,19 @@ type exitCodeError interface { ExitCode() int } +const sigtermExitCode = 128 + int(syscall.SIGTERM) + func init() { color.DisableColorBasedOnEnvVar() cobra.EnableCommandSorting = false // Maintain the order in which we add commands. } func main() { + ctx, stop := rootContext() + defer stop() + cmd := buildRootCmd() - if err := cmd.Execute(); err != nil { + if err := cmd.ExecuteContext(ctx); err != nil { var ac actionRecommender var exitCodeErr exitCodeError @@ -47,6 +55,23 @@ func main() { } } +func rootContext() (context.Context, func()) { + ctx, cancel := context.WithCancel(context.Background()) + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGTERM) + stop := func() { + signal.Stop(sigCh) + cancel() + } + go func() { + <-sigCh + cancel() + signal.Stop(sigCh) + os.Exit(sigtermExitCode) + }() + return ctx, stop +} + func buildRootCmd() *cobra.Command { cmd := &cobra.Command{ Use: "copilot", diff --git a/internal/pkg/aws/cloudformation/cloudformation.go b/internal/pkg/aws/cloudformation/cloudformation.go index e99ca7957be..82f5806eaef 100644 --- a/internal/pkg/aws/cloudformation/cloudformation.go +++ b/internal/pkg/aws/cloudformation/cloudformation.go @@ -190,7 +190,13 @@ func (c *CloudFormation) DeleteAndWaitWithRoleARN(stackName, roleARN string) err // Describe returns a description of an existing stack. // If the stack does not exist, returns ErrStackNotFound. func (c *CloudFormation) Describe(name string) (*StackDescription, error) { - out, err := c.client.DescribeStacks(context.Background(), &cloudformation.DescribeStacksInput{ + return c.DescribeWithContext(context.Background(), name) +} + +// DescribeWithContext returns a description of an existing stack using ctx. +// If the stack does not exist, returns ErrStackNotFound. +func (c *CloudFormation) DescribeWithContext(ctx context.Context, name string) (*StackDescription, error) { + out, err := c.client.DescribeStacks(ctx, &cloudformation.DescribeStacksInput{ StackName: awsv2.String(name), }) if err != nil { diff --git a/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go b/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go index 9ae7be1bfbc..5f823dc3603 100644 --- a/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go +++ b/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go @@ -23,6 +23,7 @@ type Double struct { DeleteAndWaitFn func(stackName string) error DeleteAndWaitWithRoleARNFn func(stackName, roleARN string) error DescribeFn func(name string) (*cfn.StackDescription, error) + DescribeWithContextFn func(ctx context.Context, name string) (*cfn.StackDescription, error) ExistsFn func(name string) (bool, error) MetadataFn func(opt cfn.MetadataOpts) (string, error) TemplateBodyFn func(name string) (string, error) @@ -91,6 +92,14 @@ func (d *Double) Describe(name string) (*cfn.StackDescription, error) { return d.DescribeFn(name) } +// DescribeWithContext calls the stubbed function. +func (d *Double) DescribeWithContext(ctx context.Context, name string) (*cfn.StackDescription, error) { + if d.DescribeWithContextFn != nil { + return d.DescribeWithContextFn(ctx, name) + } + return d.DescribeFn(name) +} + // Exists calls the stubbed function. func (d *Double) Exists(name string) (bool, error) { return d.ExistsFn(name) diff --git a/internal/pkg/aws/identity/identity.go b/internal/pkg/aws/identity/identity.go index 790e84112f4..c5a62b43135 100644 --- a/internal/pkg/aws/identity/identity.go +++ b/internal/pkg/aws/identity/identity.go @@ -37,8 +37,8 @@ type Caller struct { } // Get returns the Caller associated with the Client's session. -func (s STS) Get() (Caller, error) { - out, err := s.client.GetCallerIdentity(context.Background(), &sts.GetCallerIdentityInput{}) +func (s STS) Get(ctx context.Context) (Caller, error) { + out, err := s.client.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{}) if err != nil { return Caller{}, fmt.Errorf("get caller identity: %w", err) } diff --git a/internal/pkg/aws/identity/identity_test.go b/internal/pkg/aws/identity/identity_test.go index 194f6d74644..ae85539b291 100644 --- a/internal/pkg/aws/identity/identity_test.go +++ b/internal/pkg/aws/identity/identity_test.go @@ -4,6 +4,7 @@ package identity import ( + "context" "errors" "fmt" "testing" @@ -16,6 +17,7 @@ import ( ) func TestIdentity_Get(t *testing.T) { + ctx := context.WithValue(context.Background(), "test-key", "test-value") mockError := errors.New("error") mockBadARN := "mockArn" mockARN := "arn:aws:iam::1111:role/phonetool-test-CFNExecutionRole" @@ -31,13 +33,13 @@ func TestIdentity_Get(t *testing.T) { }{ "should return wrapped error given error from STS GetCallerIdentity": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(nil, mockError) + m.EXPECT().GetCallerIdentity(ctx, gomock.Any()).Return(nil, mockError) }, wantErr: fmt.Errorf("get caller identity: %w", mockError), }, "should return wrapped error if cannot parse the account arn": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(&sts.GetCallerIdentityOutput{ + m.EXPECT().GetCallerIdentity(ctx, gomock.Any()).Return(&sts.GetCallerIdentityOutput{ Account: awsv2.String(mockAccount), Arn: awsv2.String(mockBadARN), UserId: awsv2.String(mockUserID), @@ -47,7 +49,7 @@ func TestIdentity_Get(t *testing.T) { }, "should return Identity": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(&sts.GetCallerIdentityOutput{ + m.EXPECT().GetCallerIdentity(ctx, gomock.Any()).Return(&sts.GetCallerIdentityOutput{ Account: awsv2.String(mockAccount), Arn: awsv2.String(mockARN), UserId: awsv2.String(mockUserID), @@ -61,7 +63,7 @@ func TestIdentity_Get(t *testing.T) { }, "should return Identity in non standard partition": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(&sts.GetCallerIdentityOutput{ + m.EXPECT().GetCallerIdentity(ctx, gomock.Any()).Return(&sts.GetCallerIdentityOutput{ Account: awsv2.String(mockAccount), Arn: awsv2.String(mockChinaARN), UserId: awsv2.String(mockUserID), @@ -88,7 +90,7 @@ func TestIdentity_Get(t *testing.T) { tc.callMock(mockClient) - gotIdentity, gotErr := sts.Get() + gotIdentity, gotErr := sts.Get(ctx) if tc.wantErr != nil { require.EqualError(t, gotErr, tc.wantErr.Error()) diff --git a/internal/pkg/cli/app_delete.go b/internal/pkg/cli/app_delete.go index c70e795e6f8..83859e8777e 100644 --- a/internal/pkg/cli/app_delete.go +++ b/internal/pkg/cli/app_delete.go @@ -159,8 +159,8 @@ func (o *deleteAppOpts) Validate() error { } // Ask prompts the user for any required flags that they didn't provide. -func (o *deleteAppOpts) Ask() error { - if err := o.validateOrAskAppName(); err != nil { +func (o *deleteAppOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskAppName(ctx); err != nil { return err } if o.skipConfirmation { @@ -183,48 +183,48 @@ func (o *deleteAppOpts) Ask() error { // Execute deletes the application. // It removes the pipelines, all the services from each environment, the environments, the pipeline S3 buckets, // the application, removes the variables from the config store, and deletes the local workspace. -func (o *deleteAppOpts) Execute() error { - if err := o.deletePipelines(); err != nil { +func (o *deleteAppOpts) Execute(ctx context.Context) error { + if err := o.deletePipelines(ctx); err != nil { return err } - if err := o.deleteSvcs(); err != nil { + if err := o.deleteSvcs(ctx); err != nil { return err } - if err := o.deleteJobs(); err != nil { + if err := o.deleteJobs(ctx); err != nil { return err } - if err := o.deleteEnvs(); err != nil { + if err := o.deleteEnvs(ctx); err != nil { return err } - if err := o.emptyS3Bucket(); err != nil { + if err := o.emptyS3Bucket(ctx); err != nil { return err } - if err := o.deleteAppResources(); err != nil { + if err := o.deleteAppResources(ctx); err != nil { return err } - if err := o.deleteAppConfigs(); err != nil { + if err := o.deleteAppConfigs(ctx); err != nil { return err } - if err := o.deleteWs(); err != nil { + if err := o.deleteWs(ctx); err != nil { return err } return nil } -func (o *deleteAppOpts) validateOrAskAppName() error { +func (o *deleteAppOpts) validateOrAskAppName(ctx context.Context) error { if o.name != "" { - _, err := o.store.GetApplication(o.name) + _, err := o.store.GetApplication(ctx, o.name) return err } - name, err := o.sel.Application(appDeleteNamePrompt, "") + name, err := o.sel.Application(ctx, appDeleteNamePrompt, "") if err != nil { return fmt.Errorf("select application name: %w", err) } @@ -232,8 +232,8 @@ func (o *deleteAppOpts) validateOrAskAppName() error { return nil } -func (o *deleteAppOpts) deleteSvcs() error { - svcs, err := o.store.ListServices(o.name) +func (o *deleteAppOpts) deleteSvcs(ctx context.Context) error { + svcs, err := o.store.ListServices(ctx, o.name) if err != nil { return fmt.Errorf("list services for application %s: %w", o.name, err) } @@ -243,15 +243,15 @@ func (o *deleteAppOpts) deleteSvcs() error { if err != nil { return err } - if err := cmd.Execute(); err != nil { + if err := cmd.Execute(ctx); err != nil { return fmt.Errorf("execute svc delete: %w", err) } } return nil } -func (o *deleteAppOpts) deleteJobs() error { - jobs, err := o.store.ListJobs(o.name) +func (o *deleteAppOpts) deleteJobs(ctx context.Context) error { + jobs, err := o.store.ListJobs(ctx, o.name) if err != nil { return fmt.Errorf("list jobs for application %s: %w", o.name, err) } @@ -261,15 +261,15 @@ func (o *deleteAppOpts) deleteJobs() error { if err != nil { return err } - if err := cmd.Execute(); err != nil { + if err := cmd.Execute(ctx); err != nil { return fmt.Errorf("execute job delete: %w", err) } } return nil } -func (o *deleteAppOpts) deleteEnvs() error { - envs, err := o.store.ListEnvironments(o.name) +func (o *deleteAppOpts) deleteEnvs(ctx context.Context) error { + envs, err := o.store.ListEnvironments(ctx, o.name) if err != nil { return fmt.Errorf("list environments for application %s: %w", o.name, err) } @@ -285,7 +285,7 @@ func (o *deleteAppOpts) deleteEnvs() error { if err != nil { return err } - if err := taskCmd.Execute(); err != nil { + if err := taskCmd.Execute(ctx); err != nil { return fmt.Errorf("execute task delete") } } @@ -294,18 +294,18 @@ func (o *deleteAppOpts) deleteEnvs() error { if err != nil { return err } - if err := cmd.Ask(); err != nil { + if err := cmd.Ask(ctx); err != nil { return fmt.Errorf("ask env delete: %w", err) } - if err := cmd.Execute(); err != nil { + if err := cmd.Execute(ctx); err != nil { return fmt.Errorf("execute env delete: %w", err) } } return nil } -func (o *deleteAppOpts) emptyS3Bucket() error { - app, err := o.store.GetApplication(o.name) +func (o *deleteAppOpts) emptyS3Bucket(ctx context.Context) error { + app, err := o.store.GetApplication(ctx, o.name) if err != nil { return fmt.Errorf("get application %s: %w", o.name, err) } @@ -335,7 +335,7 @@ func (o *deleteAppOpts) emptyS3Bucket() error { return nil } -func (o *deleteAppOpts) deletePipelines() error { +func (o *deleteAppOpts) deletePipelines(ctx context.Context) error { pipelines, err := o.pipelineLister.ListDeployedPipelines(o.name) if err != nil { return fmt.Errorf("list pipelines for application %s: %w", o.name, err) @@ -346,23 +346,23 @@ func (o *deleteAppOpts) deletePipelines() error { if err != nil { return err } - if err := cmd.Execute(); err != nil { + if err := cmd.Execute(ctx); err != nil { return fmt.Errorf("execute pipeline delete: %w", err) } } return nil } -func (o *deleteAppOpts) deleteAppResources() error { +func (o *deleteAppOpts) deleteAppResources(ctx context.Context) error { if err := o.cfn.DeleteApp(o.name); err != nil { return fmt.Errorf("delete app resources: %w", err) } return nil } -func (o *deleteAppOpts) deleteAppConfigs() error { +func (o *deleteAppOpts) deleteAppConfigs(ctx context.Context) error { o.spinner.Start(deleteAppConfigStartMsg) - if err := o.store.DeleteApplication(o.name); err != nil { + if err := o.store.DeleteApplication(ctx, o.name); err != nil { o.spinner.Stop(log.Serrorln("Error deleting application configuration.")) return fmt.Errorf("delete application %s configuration: %w", o.name, err) } @@ -370,7 +370,7 @@ func (o *deleteAppOpts) deleteAppConfigs() error { return nil } -func (o *deleteAppOpts) deleteWs() error { +func (o *deleteAppOpts) deleteWs(ctx context.Context) error { ws, err := o.existingWorkSpace() if err != nil { return nil @@ -403,7 +403,7 @@ func buildAppDeleteCommand() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } diff --git a/internal/pkg/cli/app_delete_test.go b/internal/pkg/cli/app_delete_test.go index 08e90b72b3c..5e96774a512 100644 --- a/internal/pkg/cli/app_delete_test.go +++ b/internal/pkg/cli/app_delete_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -51,21 +52,21 @@ func TestDeleteAppOpts_Ask(t *testing.T) { inAppName: "phonetool", skipConfirmation: true, setUpMocks: func(m *deleteAppMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, }, "return an error if user provided app doesn't exist in SSM": { inAppName: "phonetool", skipConfirmation: true, setUpMocks: func(m *deleteAppMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(nil, errors.New("couldn't find an application named phonetool in account 555555555 and region us-west-2")) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, errors.New("couldn't find an application named phonetool in account 555555555 and region us-west-2")) }, want: fmt.Errorf("couldn't find an application named phonetool in account 555555555 and region us-west-2"), }, "wrap error returned from prompting": { inAppName: "phonetool", setUpMocks: func(m *deleteAppMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) m.prompt.EXPECT(). Confirm(fmt.Sprintf(fmtDeleteAppConfirmPrompt, "phonetool"), deleteAppConfirmHelp, @@ -76,7 +77,7 @@ func TestDeleteAppOpts_Ask(t *testing.T) { }, "return error if user cancels operation": { setUpMocks: func(m *deleteAppMocks) { - m.sel.EXPECT().Application(appDeleteNamePrompt, "").Return("phonetool", nil) + m.sel.EXPECT().Application(ctx, appDeleteNamePrompt, "").Return("phonetool", nil) m.prompt.EXPECT().Confirm(fmt.Sprintf(fmtDeleteAppConfirmPrompt, "phonetool"), deleteAppConfirmHelp, gomock.Any()). @@ -86,7 +87,7 @@ func TestDeleteAppOpts_Ask(t *testing.T) { }, "select from list of apps and user confirms": { setUpMocks: func(m *deleteAppMocks) { - m.sel.EXPECT().Application(appDeleteNamePrompt, "").Return("phonetool", nil) + m.sel.EXPECT().Application(ctx, appDeleteNamePrompt, "").Return("phonetool", nil) m.prompt.EXPECT().Confirm(fmt.Sprintf(fmtDeleteAppConfirmPrompt, "phonetool"), deleteAppConfirmHelp, gomock.Any()). @@ -118,7 +119,7 @@ func TestDeleteAppOpts_Ask(t *testing.T) { store: mockStore, } - got := opts.Ask() + got := opts.Ask(context.Background()) require.Equal(t, test.want, got) }) @@ -188,29 +189,29 @@ func TestDeleteAppOpts_Execute(t *testing.T) { gomock.InOrder( // delete pipelines mocks.codepipeline.EXPECT().ListDeployedPipelines(mockAppName).Return(mockPipelines, nil), - mocks.pipelineDeleter.EXPECT().Execute().Return(nil).Times(2), + mocks.pipelineDeleter.EXPECT().Execute(gomock.Any()).Return(nil).Times(2), // deleteSvcs - mocks.store.EXPECT().ListServices(mockAppName).Return(mockServices, nil), - mocks.svcDeleter.EXPECT().Execute().Return(nil).Times(2), + mocks.store.EXPECT().ListServices(ctx, mockAppName).Return(mockServices, nil), + mocks.svcDeleter.EXPECT().Execute(gomock.Any()).Return(nil).Times(2), // deleteJobs - mocks.store.EXPECT().ListJobs(mockAppName).Return(mockJobs, nil), - mocks.jobDeleter.EXPECT().Execute().Return(nil).Times(2), + mocks.store.EXPECT().ListJobs(ctx, mockAppName).Return(mockJobs, nil), + mocks.jobDeleter.EXPECT().Execute(gomock.Any()).Return(nil).Times(2), // listEnvs - mocks.store.EXPECT().ListEnvironments(mockAppName).Return(mockEnvs, nil), + mocks.store.EXPECT().ListEnvironments(ctx, mockAppName).Return(mockEnvs, nil), // deleteTasks mocks.deployer.EXPECT().ListTaskStacks(mockAppName, mockEnvs[0].Name).Return(mockTaskStacks, nil), - mocks.taskDeleter.EXPECT().Execute().Return(nil), + mocks.taskDeleter.EXPECT().Execute(gomock.Any()).Return(nil), // deleteEnvs - mocks.envDeleter.EXPECT().Ask().Return(nil), - mocks.envDeleter.EXPECT().Execute().Return(nil), + mocks.envDeleter.EXPECT().Ask(gomock.Any()).Return(nil), + mocks.envDeleter.EXPECT().Execute(gomock.Any()).Return(nil), // emptyS3bucket - mocks.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil), + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil), mocks.deployer.EXPECT().GetRegionalAppResources(mockApp).Return(mockResources, nil), mocks.spinner.EXPECT().Start(deleteAppCleanResourcesStartMsg), mocks.bucketEmptier.EXPECT().EmptyBucket(mockResources[0].S3Bucket).Return(nil), @@ -221,7 +222,7 @@ func TestDeleteAppOpts_Execute(t *testing.T) { // deleteAppConfigs mocks.spinner.EXPECT().Start(deleteAppConfigStartMsg), - mocks.store.EXPECT().DeleteApplication(mockAppName).Return(nil), + mocks.store.EXPECT().DeleteApplication(ctx, mockAppName).Return(nil), mocks.spinner.EXPECT().Stop(log.Ssuccess(deleteAppConfigStopMsg)), // deleteWs @@ -238,29 +239,29 @@ func TestDeleteAppOpts_Execute(t *testing.T) { gomock.InOrder( // delete pipelines mocks.codepipeline.EXPECT().ListDeployedPipelines(mockAppName).Return(mockPipelines, nil), - mocks.pipelineDeleter.EXPECT().Execute().Return(nil).Times(2), + mocks.pipelineDeleter.EXPECT().Execute(gomock.Any()).Return(nil).Times(2), // deleteSvcs - mocks.store.EXPECT().ListServices(mockAppName).Return(mockServices, nil), - mocks.svcDeleter.EXPECT().Execute().Return(nil).Times(2), + mocks.store.EXPECT().ListServices(ctx, mockAppName).Return(mockServices, nil), + mocks.svcDeleter.EXPECT().Execute(gomock.Any()).Return(nil).Times(2), // deleteJobs - mocks.store.EXPECT().ListJobs(mockAppName).Return(mockJobs, nil), - mocks.jobDeleter.EXPECT().Execute().Return(nil).Times(2), + mocks.store.EXPECT().ListJobs(ctx, mockAppName).Return(mockJobs, nil), + mocks.jobDeleter.EXPECT().Execute(gomock.Any()).Return(nil).Times(2), // listEnvs - mocks.store.EXPECT().ListEnvironments(mockAppName).Return(mockEnvs, nil), + mocks.store.EXPECT().ListEnvironments(ctx, mockAppName).Return(mockEnvs, nil), // deleteTasks mocks.deployer.EXPECT().ListTaskStacks(mockAppName, mockEnvs[0].Name).Return(mockTaskStacks, nil), - mocks.taskDeleter.EXPECT().Execute().Return(nil), + mocks.taskDeleter.EXPECT().Execute(gomock.Any()).Return(nil), // deleteEnvs - mocks.envDeleter.EXPECT().Ask().Return(nil), - mocks.envDeleter.EXPECT().Execute().Return(nil), + mocks.envDeleter.EXPECT().Ask(gomock.Any()).Return(nil), + mocks.envDeleter.EXPECT().Execute(gomock.Any()).Return(nil), // emptyS3bucket - mocks.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil), + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil), mocks.deployer.EXPECT().GetRegionalAppResources(mockApp).Return(mockResources, nil), mocks.spinner.EXPECT().Start(deleteAppCleanResourcesStartMsg), mocks.bucketEmptier.EXPECT().EmptyBucket(mockResources[0].S3Bucket).Return(nil), @@ -271,7 +272,7 @@ func TestDeleteAppOpts_Execute(t *testing.T) { // deleteAppConfigs mocks.spinner.EXPECT().Start(deleteAppConfigStartMsg), - mocks.store.EXPECT().DeleteApplication(mockAppName).Return(nil), + mocks.store.EXPECT().DeleteApplication(ctx, mockAppName).Return(nil), mocks.spinner.EXPECT().Stop(log.Ssuccess(deleteAppConfigStopMsg)), // deleteWs @@ -362,7 +363,7 @@ func TestDeleteAppOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN require.Equal(t, test.wantedError, err) diff --git a/internal/pkg/cli/app_init.go b/internal/pkg/cli/app_init.go index 53b111f0246..7a185552078 100644 --- a/internal/pkg/cli/app_init.go +++ b/internal/pkg/cli/app_init.go @@ -15,6 +15,7 @@ import ( "github.com/spf13/afero" "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/ssm" "github.com/spf13/cobra" @@ -24,6 +25,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" + "github.com/aproint/copilot-cli/internal/pkg/metadata" "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" @@ -76,7 +78,7 @@ func newInitAppOpts(vars initAppVars) (*initAppOpts, error) { return &initAppOpts{ initAppVars: vars, identity: identity, - store: config.NewSSMStore(identity, config.NewSSMClient(cfg), cfg.Region), + store: config.NewSSMStore(identity, ssm.NewFromConfig(cfg), cfg.Region), route53: route53.New(cfg), cfn: cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)), prompt: prompt.New(), @@ -133,7 +135,7 @@ func (o *initAppOpts) Validate() error { } // Ask prompts the user for any required arguments that they didn't provide. -func (o *initAppOpts) Ask() error { +func (o *initAppOpts) Ask(ctx context.Context) error { ok, err := o.isSessionFromEnvVars() if err != nil { return err @@ -194,7 +196,7 @@ If you'd like to delete the application and all of its resources, run %s. return nil } - existingApps, _ := o.store.ListApplications() + existingApps, _ := o.store.ListApplications(ctx) if len(existingApps) == 0 { return o.askAppName(fmtAppInitNamePrompt) } @@ -211,8 +213,8 @@ If you'd like to delete the application and all of its resources, run %s. } // Execute creates a new managed empty application. -func (o *initAppOpts) Execute() error { - caller, err := o.identity.Get() +func (o *initAppOpts) Execute(ctx context.Context) error { + caller, err := o.identity.Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } @@ -228,6 +230,9 @@ func (o *initAppOpts) Execute() error { return err } } + if err := ctx.Err(); err != nil { + return err + } err = o.cfn.DeployApp(&deploy.CreateAppInput{ Name: o.name, AccountID: caller.Account, @@ -241,7 +246,12 @@ func (o *initAppOpts) Execute() error { return err } - if err := o.store.CreateApplication(&config.Application{ + if ctx.Err() != nil { + log.Warningln(metadata.CommitAfterCancellationWarning) + } + commitCtx, cancel := metadata.CommitContext(ctx) + defer cancel() + if err := o.store.CreateApplication(commitCtx, &config.Application{ AccountID: caller.Account, Name: o.name, Domain: o.domainName, @@ -249,7 +259,7 @@ func (o *initAppOpts) Execute() error { PermissionsBoundary: o.permissionsBoundary, Tags: o.resourceTags, }); err != nil { - return err + return metadata.NewCommitError("application infrastructure deployment", err) } log.Successf("The directory %s will hold service manifests for application %s.\n", color.HighlightResource(workspace.CopilotDirName), color.HighlightUserInput(o.name)) log.Infoln() @@ -260,7 +270,7 @@ func (o *initAppOpts) validateAppName(name string) error { if err := validateAppNameString(name); err != nil { return err } - app, err := o.store.GetApplication(name) + app, err := o.store.GetApplication(context.Background(), name) if err == nil { if o.domainName != "" && app.Domain != o.domainName { return fmt.Errorf("application named %s already exists with a different domain name %s", name, app.Domain) @@ -420,7 +430,7 @@ An application is a collection of containerized services that operate together.` if len(args) == 1 { opts.name = args[0] } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVar(&vars.domainName, domainNameFlag, "", domainNameFlagDescription) diff --git a/internal/pkg/cli/app_init_test.go b/internal/pkg/cli/app_init_test.go index 876aec2812a..55fcc2617f5 100644 --- a/internal/pkg/cli/app_init_test.go +++ b/internal/pkg/cli/app_init_test.go @@ -4,15 +4,18 @@ package cli import ( + "context" "errors" "fmt" "testing" + "time" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/route53" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" + "github.com/aproint/copilot-cli/internal/pkg/metadata" "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/aproint/copilot-cli/internal/pkg/workspace" "github.com/golang/mock/gomock" @@ -43,7 +46,7 @@ func TestInitAppOpts_Validate(t *testing.T) { "valid app name without application in SSM and without IAM adminrole": { inAppName: "metrics", mock: func(m *initAppMocks) { - m.mockStore.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.mockStore.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.mockRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return(nil, errors.New("role not found")) @@ -52,7 +55,7 @@ func TestInitAppOpts_Validate(t *testing.T) { "valid app name without application in SSM and with IAM adminrole with copliot tag": { inAppName: "metrics", mock: func(m *initAppMocks) { - m.mockStore.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.mockStore.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.mockRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return( @@ -65,7 +68,7 @@ func TestInitAppOpts_Validate(t *testing.T) { "valid app name without application in SSM and with IAM adminrole without copilot tag": { inAppName: "metrics", mock: func(m *initAppMocks) { - m.mockStore.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.mockStore.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.mockRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return( @@ -78,7 +81,7 @@ func TestInitAppOpts_Validate(t *testing.T) { "valid app name without application in SSM and with IAM adminrole without any tag": { inAppName: "metrics", mock: func(m *initAppMocks) { - m.mockStore.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.mockStore.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.mockRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return(nil, nil) @@ -95,7 +98,7 @@ func TestInitAppOpts_Validate(t *testing.T) { inAppName: "metrics", inDomainName: "badDomain.com", mock: func(m *initAppMocks) { - m.mockStore.EXPECT().GetApplication("metrics").Return(&config.Application{ + m.mockStore.EXPECT().GetApplication(ctx, "metrics").Return(&config.Application{ Name: "metrics", Domain: "domain.com", }, nil) @@ -108,13 +111,13 @@ func TestInitAppOpts_Validate(t *testing.T) { inDomainName: "", mock: func(m *initAppMocks) { - m.mockStore.EXPECT().GetApplication("metrics").Return(nil, nil) + m.mockStore.EXPECT().GetApplication(ctx, "metrics").Return(nil, nil) }, }, "errors if failed to get application": { inAppName: "metrics", mock: func(m *initAppMocks) { - m.mockStore.EXPECT().GetApplication("metrics").Return(nil, errors.New("some error")) + m.mockStore.EXPECT().GetApplication(ctx, "metrics").Return(nil, errors.New("some error")) }, wantedError: errors.New("get application metrics: some error"), }, @@ -257,7 +260,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.ws.EXPECT().Summary().Return(&workspace.Summary{Application: "metrics", Path: "/test"}, nil) return m.ws, nil } - m.store.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return(nil, errors.New("role not found")) @@ -270,7 +273,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.ws.EXPECT().Summary().Return(&workspace.Summary{Application: "metrics", Path: "/test"}, nil) return m.ws, nil } - m.store.EXPECT().GetApplication("metrics").Return(&config.Application{Name: "metrics"}, nil) + m.store.EXPECT().GetApplication(ctx, "metrics").Return(&config.Application{Name: "metrics"}, nil) }, wantedAppName: "metrics", }, @@ -280,7 +283,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.ws.EXPECT().Summary().Return(&workspace.Summary{Application: "metrics", Path: "/test"}, nil) return m.ws, nil } - m.store.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return( @@ -296,7 +299,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.ws.EXPECT().Summary().Return(&workspace.Summary{Application: "metrics", Path: "/test"}, nil) return m.ws, nil } - m.store.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return( @@ -312,7 +315,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, errors.New("some error") } - m.store.EXPECT().ListApplications().Times(0) + m.store.EXPECT().ListApplications(ctx).Times(0) }, wantedErr: "some error", }, @@ -322,7 +325,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Times(0) + m.store.EXPECT().ListApplications(ctx).Times(0) }, wantedAppName: "metrics", }, @@ -333,7 +336,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.ws.EXPECT().Summary().Return(nil, &workspace.ErrNoAssociatedApplication{}) return m.ws, nil } - m.store.EXPECT().ListApplications().Times(0) + m.store.EXPECT().ListApplications(ctx).Times(0) }, wantedAppName: "metrics", }, @@ -344,7 +347,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.ws.EXPECT().Summary().Return(nil, errors.New("some error")) return m.ws, nil } - m.store.EXPECT().ListApplications().Times(0) + m.store.EXPECT().ListApplications(ctx).Times(0) }, wantedErr: "some error", }, @@ -355,7 +358,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.ws.EXPECT().Summary().Return(&workspace.Summary{Application: "metrics", Path: "/test"}, nil) return m.ws, nil } - m.store.EXPECT().ListApplications().Times(0) + m.store.EXPECT().ListApplications(ctx).Times(0) }, wantedErr: "workspace already registered with metrics", }, @@ -364,7 +367,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{}, nil) + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{}, nil) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("", errors.New("my error")) m.prompt.EXPECT().Confirm(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) @@ -377,9 +380,9 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{}, nil) + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{}, nil) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("metrics", nil) - m.store.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return(nil, errors.New("role not found")) @@ -393,9 +396,9 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{}, nil) + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{}, nil) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("metrics", nil) - m.store.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return( @@ -412,9 +415,9 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{}, nil) + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{}, nil) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("metrics", nil) - m.store.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return( @@ -431,9 +434,9 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{}, nil) + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{}, nil) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("metrics", nil) - m.store.EXPECT().GetApplication("metrics").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "metrics").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "metrics", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("metrics-adminrole")).Return(nil, nil) @@ -448,7 +451,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{ + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{ { Name: "metrics", }, @@ -466,7 +469,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{ + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{ { Name: "metrics", }, @@ -484,7 +487,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{ + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{ { Name: "metrics", }, @@ -495,7 +498,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.prompt.EXPECT().Confirm(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("mock-app", nil) - m.store.EXPECT().GetApplication("mock-app").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "mock-app").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "mock-app", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("mock-app-adminrole")).Return(nil, errors.New("role not found")) @@ -507,7 +510,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{ + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{ { Name: "metrics", }, @@ -518,7 +521,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.prompt.EXPECT().Confirm(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("mock-app", nil) - m.store.EXPECT().GetApplication("mock-app").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "mock-app").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "mock-app", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("mock-app-adminrole")).Return( @@ -533,7 +536,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{ + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{ { Name: "metrics", }, @@ -544,7 +547,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.prompt.EXPECT().Confirm(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("mock-app", nil) - m.store.EXPECT().GetApplication("mock-app").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "mock-app").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "mock-app", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("mock-app-adminrole")).Return( @@ -559,7 +562,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.existingWorkspace = func() (wsAppManager, error) { return nil, &workspace.ErrWorkspaceNotFound{} } - m.store.EXPECT().ListApplications().Return([]*config.Application{ + m.store.EXPECT().ListApplications(ctx).Return([]*config.Application{ { Name: "metrics", }, @@ -570,7 +573,7 @@ func TestInitAppOpts_Ask(t *testing.T) { m.prompt.EXPECT().Confirm(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("mock-app", nil) - m.store.EXPECT().GetApplication("mock-app").Return(nil, &config.ErrNoSuchApplication{ + m.store.EXPECT().GetApplication(ctx, "mock-app").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "mock-app", }) m.iamRoleManager.EXPECT().ListRoleTags(gomock.Eq("mock-app-adminrole")).Return(nil, nil) @@ -607,7 +610,7 @@ func TestInitAppOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedErr != "" { @@ -645,10 +648,10 @@ func TestInitAppOpts_Execute(t *testing.T) { inPermissionsBoundaryPolicy: "mockPolicy", mocking: func(m *initAppExecuteMocks) { - m.identityService.EXPECT().Get().Return(identity.Caller{ + m.identityService.EXPECT().Get(ctx).Return(identity.Caller{ Account: "12345", }, nil) - m.store.EXPECT().CreateApplication(&config.Application{ + m.store.EXPECT().CreateApplication(gomock.Any(), &config.Application{ AccountID: "12345", Name: "myapp", Domain: "amazon.com", @@ -677,7 +680,7 @@ func TestInitAppOpts_Execute(t *testing.T) { "should return error from workspace.Create": { expectedError: mockError, mocking: func(m *initAppExecuteMocks) { - m.identityService.EXPECT().Get().Return(identity.Caller{ + m.identityService.EXPECT().Get(ctx).Return(identity.Caller{ Account: "12345", }, nil) m.newWorkspace = func(appName string) (wsAppManager, error) { @@ -688,7 +691,7 @@ func TestInitAppOpts_Execute(t *testing.T) { "with an error while deploying myapp": { expectedError: mockError, mocking: func(m *initAppExecuteMocks) { - m.identityService.EXPECT().Get().Return(identity.Caller{ + m.identityService.EXPECT().Get(ctx).Return(identity.Caller{ Account: "12345", }, nil) m.newWorkspace = func(appName string) (wsAppManager, error) { @@ -700,10 +703,10 @@ func TestInitAppOpts_Execute(t *testing.T) { "should return error from CreateApplication": { expectedError: mockError, mocking: func(m *initAppExecuteMocks) { - m.identityService.EXPECT().Get().Return(identity.Caller{ + m.identityService.EXPECT().Get(ctx).Return(identity.Caller{ Account: "12345", }, nil) - m.store.EXPECT().CreateApplication(gomock.Any()).Return(mockError) + m.store.EXPECT().CreateApplication(gomock.Any(), gomock.Any()).Return(mockError) m.newWorkspace = func(appName string) (wsAppManager, error) { return m.ws, nil } @@ -745,7 +748,7 @@ func TestInitAppOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.expectedError == nil { @@ -756,3 +759,107 @@ func TestInitAppOpts_Execute(t *testing.T) { }) } } + +func TestInitAppOpts_Execute_PreMutationCanceledContextPreventsDeploy(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + parent, cancel := context.WithCancel(context.Background()) + cancel() + mockStore := mocks.NewMockstore(ctrl) + mockIdentity := mocks.NewMockidentityService(ctrl) + mockDeployer := mocks.NewMockappDeployer(ctrl) + + mockIdentity.EXPECT().Get(parent).Return(identity.Caller{Account: "12345"}, nil) + mockDeployer.EXPECT().DeployApp(gomock.Any()).Times(0) + mockStore.EXPECT().CreateApplication(gomock.Any(), gomock.Any()).Times(0) + + opts := &initAppOpts{ + initAppVars: initAppVars{ + name: "myapp", + }, + store: mockStore, + identity: mockIdentity, + cfn: mockDeployer, + newWorkspace: func(appName string) (wsAppManager, error) { + return mocks.NewMockwsAppManager(ctrl), nil + }, + } + + err := opts.Execute(parent) + + require.ErrorIs(t, err, context.Canceled) +} + +func TestInitAppOpts_Execute_CanceledParentStillCommitsMetadata(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + parent, cancel := context.WithCancel(context.Background()) + mockStore := mocks.NewMockstore(ctrl) + mockIdentity := mocks.NewMockidentityService(ctrl) + mockDeployer := mocks.NewMockappDeployer(ctrl) + + mockIdentity.EXPECT().Get(parent).Return(identity.Caller{Account: "12345"}, nil) + mockDeployer.EXPECT().DeployApp(gomock.Any()).DoAndReturn(func(*deploy.CreateAppInput) error { + cancel() + return nil + }) + mockStore.EXPECT().CreateApplication(gomock.Any(), gomock.Any()). + DoAndReturn(func(gotCtx context.Context, _ *config.Application) error { + require.NoError(t, gotCtx.Err()) + deadline, ok := gotCtx.Deadline() + require.True(t, ok) + require.WithinDuration(t, time.Now().Add(metadata.CommitTimeout), deadline, time.Second) + return nil + }) + + opts := &initAppOpts{ + initAppVars: initAppVars{ + name: "myapp", + }, + store: mockStore, + identity: mockIdentity, + cfn: mockDeployer, + newWorkspace: func(appName string) (wsAppManager, error) { + return mocks.NewMockwsAppManager(ctrl), nil + }, + } + + err := opts.Execute(parent) + + require.NoError(t, err) +} + +func TestInitAppOpts_Execute_MetadataCommitErrorIsPartialSuccess(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockErr := errors.New("some create error") + mockStore := mocks.NewMockstore(ctrl) + mockIdentity := mocks.NewMockidentityService(ctrl) + mockDeployer := mocks.NewMockappDeployer(ctrl) + + mockIdentity.EXPECT().Get(ctx).Return(identity.Caller{Account: "12345"}, nil) + mockDeployer.EXPECT().DeployApp(gomock.Any()).Return(nil) + mockStore.EXPECT().CreateApplication(gomock.Any(), gomock.Any()).Return(mockErr) + + opts := &initAppOpts{ + initAppVars: initAppVars{ + name: "myapp", + }, + store: mockStore, + identity: mockIdentity, + cfn: mockDeployer, + newWorkspace: func(appName string) (wsAppManager, error) { + return mocks.NewMockwsAppManager(ctrl), nil + }, + } + + err := opts.Execute(ctx) + + var commitErr *metadata.CommitError + require.ErrorAs(t, err, &commitErr) + require.ErrorIs(t, err, mockErr) + require.EqualError(t, err, "application infrastructure deployment succeeded, but Copilot metadata commit failed: some create error") +} diff --git a/internal/pkg/cli/app_list.go b/internal/pkg/cli/app_list.go index 976ecd6b6a0..d46598ba278 100644 --- a/internal/pkg/cli/app_list.go +++ b/internal/pkg/cli/app_list.go @@ -19,8 +19,8 @@ type listAppOpts struct { } // Execute writes the existing applications. -func (o *listAppOpts) Execute() error { - apps, err := o.store.ListApplications() +func (o *listAppOpts) Execute(ctx context.Context) error { + apps, err := o.store.ListApplications(ctx) if err != nil { return fmt.Errorf("list applications: %w", err) } @@ -49,7 +49,7 @@ func buildAppListCommand() *cobra.Command { return fmt.Errorf("default config: %v", err) } opts.store = newSSMConfigStoreFromConfig(defaultConfig) - return opts.Execute() + return opts.Execute(cmd.Context()) }), } return cmd diff --git a/internal/pkg/cli/app_list_test.go b/internal/pkg/cli/app_list_test.go index 56cebabaed9..d6f61766042 100644 --- a/internal/pkg/cli/app_list_test.go +++ b/internal/pkg/cli/app_list_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -34,7 +35,7 @@ func TestListAppOpts_Execute(t *testing.T) { mocking: func() { mockstore. EXPECT(). - ListApplications(). + ListApplications(ctx). Return([]*config.Application{ {Name: "app1"}, {Name: "app2"}, @@ -50,7 +51,7 @@ func TestListAppOpts_Execute(t *testing.T) { mocking: func() { mockstore. EXPECT(). - ListApplications(). + ListApplications(ctx). Return(nil, testError). Times(1) }, @@ -62,7 +63,7 @@ func TestListAppOpts_Execute(t *testing.T) { t.Run(name, func(t *testing.T) { tc.mocking() - got := tc.listOpts.Execute() + got := tc.listOpts.Execute(context.Background()) require.Equal(t, tc.want, got) }) diff --git a/internal/pkg/cli/app_show.go b/internal/pkg/cli/app_show.go index 08d2dce76e8..78437b73bbf 100644 --- a/internal/pkg/cli/app_show.go +++ b/internal/pkg/cli/app_show.go @@ -82,7 +82,7 @@ func newShowAppOpts(vars showAppVars) (*showAppOpts, error) { // Validate returns an error if the values provided by the user are invalid. func (o *showAppOpts) Validate() error { if o.name != "" { - _, err := o.store.GetApplication(o.name) + _, err := o.store.GetApplication(context.Background(), o.name) if err != nil { return fmt.Errorf("get application %s: %w", o.name, err) } @@ -92,8 +92,8 @@ func (o *showAppOpts) Validate() error { } // Ask asks for fields that are required but not passed in. -func (o *showAppOpts) Ask() error { - if err := o.askName(); err != nil { +func (o *showAppOpts) Ask(ctx context.Context) error { + if err := o.askName(ctx); err != nil { return err } @@ -101,8 +101,8 @@ func (o *showAppOpts) Ask() error { } // Execute writes the application's description. -func (o *showAppOpts) Execute() error { - description, err := o.description() +func (o *showAppOpts) Execute(ctx context.Context) error { + description, err := o.description(ctx) if err != nil { return err } @@ -117,8 +117,8 @@ func (o *showAppOpts) Execute() error { fmt.Fprint(o.w, data) return nil } -func (o *showAppOpts) populateDeployedWorkloads(listWorkloads func(app, env string) ([]string, error), deployedEnvsFor map[string][]string, env string, lock sync.Locker) error { - deployedworkload, err := listWorkloads(o.name, env) +func (o *showAppOpts) populateDeployedWorkloads(ctx context.Context, listWorkloads func(context.Context, string, string) ([]string, error), deployedEnvsFor map[string][]string, env string, lock sync.Locker) error { + deployedworkload, err := listWorkloads(ctx, o.name, env) if err != nil { return fmt.Errorf("list services/jobs deployed to %s: %w", env, err) } @@ -131,35 +131,35 @@ func (o *showAppOpts) populateDeployedWorkloads(listWorkloads func(app, env stri return nil } -func (o *showAppOpts) description() (*describe.App, error) { - app, err := o.store.GetApplication(o.name) +func (o *showAppOpts) description(ctx context.Context) (*describe.App, error) { + app, err := o.store.GetApplication(ctx, o.name) if err != nil { return nil, fmt.Errorf("get application %s: %w", o.name, err) } - envs, err := o.store.ListEnvironments(o.name) + envs, err := o.store.ListEnvironments(ctx, o.name) if err != nil { return nil, fmt.Errorf("list environments in application %s: %w", o.name, err) } - svcs, err := o.store.ListServices(o.name) + svcs, err := o.store.ListServices(ctx, o.name) if err != nil { return nil, fmt.Errorf("list services in application %s: %w", o.name, err) } - jobs, err := o.store.ListJobs(o.name) + jobs, err := o.store.ListJobs(ctx, o.name) if err != nil { return nil, fmt.Errorf("list jobs in application %s: %w", o.name, err) } wkldDeployedtoEnvs := make(map[string][]string) - ctx, cancelWait := context.WithTimeout(context.Background(), waitForStackTimeout) + ctx, cancelWait := context.WithTimeout(ctx, waitForStackTimeout) defer cancelWait() g, _ := errgroup.WithContext(ctx) var mux sync.Mutex for i := range envs { env := envs[i] g.Go(func() error { - return o.populateDeployedWorkloads(o.deployStore.ListDeployedJobs, wkldDeployedtoEnvs, env.Name, &mux) + return o.populateDeployedWorkloads(ctx, o.deployStore.ListDeployedJobs, wkldDeployedtoEnvs, env.Name, &mux) }) g.Go(func() error { - return o.populateDeployedWorkloads(o.deployStore.ListDeployedServices, wkldDeployedtoEnvs, env.Name, &mux) + return o.populateDeployedWorkloads(ctx, o.deployStore.ListDeployedServices, wkldDeployedtoEnvs, env.Name, &mux) }) } if err := g.Wait(); err != nil { @@ -226,11 +226,11 @@ func (o *showAppOpts) description() (*describe.App, error) { }, nil } -func (o *showAppOpts) askName() error { +func (o *showAppOpts) askName(ctx context.Context) error { if o.name != "" { return nil } - name, err := o.sel.Application(appShowNamePrompt, appShowNameHelpPrompt) + name, err := o.sel.Application(ctx, appShowNamePrompt, appShowNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -253,7 +253,7 @@ func buildAppShowCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } // The flags bound by viper are available to all sub-commands through viper.GetString({flagName}) diff --git a/internal/pkg/cli/app_show_test.go b/internal/pkg/cli/app_show_test.go index 3f5a188fe61..e862bd82cd9 100644 --- a/internal/pkg/cli/app_show_test.go +++ b/internal/pkg/cli/app_show_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -38,7 +39,7 @@ func TestShowAppOpts_Validate(t *testing.T) { inAppName: "my-app", setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", }, nil) }, @@ -48,7 +49,7 @@ func TestShowAppOpts_Validate(t *testing.T) { inAppName: "my-app", setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(nil, testError) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(nil, testError) }, wantedError: fmt.Errorf("get application %s: %w", "my-app", testError), @@ -109,7 +110,7 @@ func TestShowAppOpts_Ask(t *testing.T) { inApp: "", setupMocks: func(m showAppMocks) { - m.sel.EXPECT().Application(appShowNamePrompt, appShowNameHelpPrompt).Return("my-app", nil) + m.sel.EXPECT().Application(ctx, appShowNamePrompt, appShowNameHelpPrompt).Return("my-app", nil) }, wantedApp: "my-app", wantedError: nil, @@ -118,7 +119,7 @@ func TestShowAppOpts_Ask(t *testing.T) { inApp: "", setupMocks: func(m showAppMocks) { - m.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Return("", testError) + m.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Return("", testError) }, wantedError: fmt.Errorf("select application: %w", testError), @@ -143,7 +144,7 @@ func TestShowAppOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -188,24 +189,24 @@ func TestShowAppOpts_Execute(t *testing.T) { shouldOutputJSON: true, setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -217,10 +218,10 @@ func TestShowAppOpts_Execute(t *testing.T) { Region: "us-west-1", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{"my-job"}, nil).AnyTimes() - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{"my-job"}, nil).AnyTimes() - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{"my-svc"}, nil).AnyTimes() - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{"my-svc"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{"my-job"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{"my-job"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{"my-svc"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{"my-svc"}, nil).AnyTimes() m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{mockPipeline, mockLegacyPipeline}, nil) m.pipelineGetter.EXPECT(). GetPipeline("pipeline-my-app-my-pipeline-repo").Return(&codepipeline.Pipeline{ @@ -237,24 +238,24 @@ func TestShowAppOpts_Execute(t *testing.T) { }, "correctly shows human output": { setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -266,10 +267,10 @@ func TestShowAppOpts_Execute(t *testing.T) { Region: "us-west-1", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{"my-svc"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{mockPipeline, mockLegacyPipeline}, nil) m.pipelineGetter.EXPECT(). GetPipeline("pipeline-my-app-my-pipeline-repo").Return(&codepipeline.Pipeline{ @@ -313,24 +314,24 @@ Pipelines }, "correctly shows human output with latest version": { setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -342,10 +343,10 @@ Pipelines Region: "us-west-1", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{"my-svc"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{"my-svc"}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil) }, @@ -379,24 +380,24 @@ Pipelines }, "correctly shows human output when URI and Permissions Boundary are empty": { setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "", PermissionsBoundary: "", }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -408,10 +409,10 @@ Pipelines Region: "us-west-1", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{"my-svc"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{"my-svc"}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil) @@ -446,24 +447,24 @@ Pipelines }, "when service/job is not deployed": { setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -475,10 +476,10 @@ Pipelines Region: "us-west-1", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{mockPipeline}, nil) m.pipelineGetter.EXPECT(). GetPipeline("pipeline-my-app-my-pipeline-repo").Return(&codepipeline.Pipeline{ @@ -517,24 +518,24 @@ Pipelines }, "when multiple services/jobs are deployed": { setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test1", Region: "us-west-2", @@ -561,16 +562,16 @@ Pipelines Region: "us-west-1", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test1").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod1").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod2").Return([]string{}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test2").Return([]string{}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "staging").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test1").Return([]string{}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod1").Return([]string{}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod2").Return([]string{"my-svc"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test2").Return([]string{"my-svc"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "staging").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test1").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod1").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod2").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test2").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "staging").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test1").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod1").Return([]string{}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod2").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test2").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "staging").Return([]string{"my-svc"}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{mockPipeline}, nil) m.pipelineGetter.EXPECT(). GetPipeline("pipeline-my-app-my-pipeline-repo").Return(&codepipeline.Pipeline{ @@ -614,19 +615,19 @@ Pipelines shouldOutputJSON: false, setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(nil, testError) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(nil, testError) }, wantedError: fmt.Errorf("get application %s: %w", "my-app", testError), }, "returns error if fail to list environment": { setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return(nil, testError) + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return(nil, testError) }, wantedError: fmt.Errorf("list environments in application %s: %w", "my-app", testError), @@ -635,12 +636,12 @@ Pipelines shouldOutputJSON: false, setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -652,7 +653,7 @@ Pipelines Region: "us-west-1", }, }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return(nil, testError) + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return(nil, testError) }, wantedError: fmt.Errorf("list services in application %s: %w", "my-app", testError), @@ -661,12 +662,12 @@ Pipelines shouldOutputJSON: false, setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -678,13 +679,13 @@ Pipelines Region: "us-west-1", }, }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return(nil, testError) + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return(nil, testError) }, wantedError: fmt.Errorf("list jobs in application %s: %w", "my-app", testError), @@ -693,12 +694,12 @@ Pipelines shouldOutputJSON: false, setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -710,22 +711,22 @@ Pipelines Region: "us-west-1", }, }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{"my-svc"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{"my-svc"}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return(nil, testError) }, wantedError: fmt.Errorf("list pipelines in application %s: %w", "my-app", testError), @@ -734,12 +735,12 @@ Pipelines shouldOutputJSON: false, setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -751,22 +752,22 @@ Pipelines Region: "us-west-1", }, }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{"my-job"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{"my-svc"}, nil) - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{"my-job"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{"my-svc"}, nil) + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{"my-svc"}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{mockPipeline}, nil) m.pipelineGetter.EXPECT(). GetPipeline("pipeline-my-app-my-pipeline-repo").Return(nil, testError) @@ -777,12 +778,12 @@ Pipelines shouldOutputJSON: false, setupMocks: func(m showAppMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", Domain: "example.com", PermissionsBoundary: "examplePermissionsBoundaryPolicy", }, nil) - m.storeSvc.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.storeSvc.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", Region: "us-west-2", @@ -794,22 +795,22 @@ Pipelines Region: "us-west-1", }, }, nil) - m.storeSvc.EXPECT().ListServices("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListServices(ctx, "my-app").Return([]*config.Workload{ { Name: "my-svc", Type: "lb-web-svc", }, }, nil) - m.storeSvc.EXPECT().ListJobs("my-app").Return([]*config.Workload{ + m.storeSvc.EXPECT().ListJobs(ctx, "my-app").Return([]*config.Workload{ { Name: "my-job", Type: "Scheduled Job", }, }, nil) - m.deployStore.EXPECT().ListDeployedJobs("my-app", "test").Return([]string{"my-job"}, nil).AnyTimes() - m.deployStore.EXPECT().ListDeployedJobs("my-app", "prod").Return([]string{"my-job"}, nil).AnyTimes() - m.deployStore.EXPECT().ListDeployedServices("my-app", "test").Return([]string{"my-svc"}, nil).AnyTimes() - m.deployStore.EXPECT().ListDeployedServices("my-app", "prod").Return([]string{"my-svc"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "test").Return([]string{"my-job"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedJobs(gomock.Any(), "my-app", "prod").Return([]string{"my-job"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "test").Return([]string{"my-svc"}, nil).AnyTimes() + m.deployStore.EXPECT().ListDeployedServices(gomock.Any(), "my-app", "prod").Return([]string{"my-svc"}, nil).AnyTimes() m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.versionGetter.EXPECT().Version().Return("", testError) }, @@ -854,7 +855,7 @@ Pipelines } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/app_upgrade.go b/internal/pkg/cli/app_upgrade.go index 8fd554a1bb3..c0b0691d155 100644 --- a/internal/pkg/cli/app_upgrade.go +++ b/internal/pkg/cli/app_upgrade.go @@ -81,7 +81,7 @@ func newAppUpgradeOpts(vars appUpgradeVars) (*appUpgradeOpts, error) { // Validate returns an error if the values provided by the user are invalid. func (o *appUpgradeOpts) Validate() error { if o.name != "" { - _, err := o.store.GetApplication(o.name) + _, err := o.store.GetApplication(context.Background(), o.name) if err != nil { return fmt.Errorf("get application %s: %w", o.name, err) } @@ -90,8 +90,8 @@ func (o *appUpgradeOpts) Validate() error { } // Ask asks for fields that are required but not passed in. -func (o *appUpgradeOpts) Ask() error { - if err := o.askName(); err != nil { +func (o *appUpgradeOpts) Ask(ctx context.Context) error { + if err := o.askName(ctx); err != nil { return err } return nil @@ -99,7 +99,7 @@ func (o *appUpgradeOpts) Ask() error { // Execute updates the cloudformation stack as well as the stackset of an application to the latest version. // If any stack is busy updating, it spins and waits until the stack can be updated. -func (o *appUpgradeOpts) Execute() error { +func (o *appUpgradeOpts) Execute(ctx context.Context) error { vg, err := o.newVersionGetter(o.name) if err != nil { return err @@ -112,7 +112,7 @@ func (o *appUpgradeOpts) Execute() error { if !o.shouldUpgradeApp(appVersion) { return nil } - app, err := o.store.GetApplication(o.name) + app, err := o.store.GetApplication(ctx, o.name) if err != nil { return fmt.Errorf("get application %s: %w", o.name, err) } @@ -124,18 +124,18 @@ func (o *appUpgradeOpts) Execute() error { } log.Successf(fmtAppUpgradeComplete, color.HighlightUserInput(o.name), color.Emphasize(o.templateVersion)) }() - err = o.upgradeApplication(app, appVersion, o.templateVersion) + err = o.upgradeApplication(ctx, app, appVersion, o.templateVersion) if err != nil { return err } return nil } -func (o *appUpgradeOpts) askName() error { +func (o *appUpgradeOpts) askName(ctx context.Context) error { if o.name != "" { return nil } - name, err := o.sel.Application(appUpgradeNamePrompt, appUpgradeNameHelpPrompt) + name, err := o.sel.Application(ctx, appUpgradeNamePrompt, appUpgradeNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -162,13 +162,13 @@ Are you using the latest version of AWS Copilot?`, o.name, o.templateVersion, ap return false } -func (o *appUpgradeOpts) upgradeApplication(app *config.Application, fromVersion, toVersion string) error { - caller, err := o.identity.Get() +func (o *appUpgradeOpts) upgradeApplication(ctx context.Context, app *config.Application, fromVersion, toVersion string) error { + caller, err := o.identity.Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } // Upgrade SSM Parameter Store record. - if err := o.upgradeAppSSMStore(app); err != nil { + if err := o.upgradeAppSSMStore(ctx, app); err != nil { return err } // Upgrade app CloudFormation resources. @@ -184,7 +184,7 @@ func (o *appUpgradeOpts) upgradeApplication(app *config.Application, fromVersion return nil } -func (o *appUpgradeOpts) upgradeAppSSMStore(app *config.Application) error { +func (o *appUpgradeOpts) upgradeAppSSMStore(ctx context.Context, app *config.Application) error { if app.Domain != "" && app.DomainHostedZoneID == "" { hostedZoneID, err := o.route53.PublicDomainHostedZoneID(app.Domain) if err != nil { @@ -192,7 +192,7 @@ func (o *appUpgradeOpts) upgradeAppSSMStore(app *config.Application) error { } app.DomainHostedZoneID = hostedZoneID } - if err := o.store.UpdateApplication(app); err != nil { + if err := o.store.UpdateApplication(ctx, app); err != nil { return fmt.Errorf("update application %s: %w", app.Name, err) } return nil @@ -212,7 +212,7 @@ func buildAppUpgradeCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/app_upgrade_test.go b/internal/pkg/cli/app_upgrade_test.go index 83847965e0c..091fa3ba4dd 100644 --- a/internal/pkg/cli/app_upgrade_test.go +++ b/internal/pkg/cli/app_upgrade_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -42,7 +43,7 @@ func TestAppUpgradeOpts_Validate(t *testing.T) { inAppName: "my-app", setupMocks: func(m appUpgradeMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", }, nil) }, @@ -52,7 +53,7 @@ func TestAppUpgradeOpts_Validate(t *testing.T) { inAppName: "my-app", setupMocks: func(m appUpgradeMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(nil, testError) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(nil, testError) }, wantedError: fmt.Errorf("get application %s: %w", "my-app", testError), @@ -113,7 +114,7 @@ func TestAppUpgradeOpts_Ask(t *testing.T) { inApp: "", setupMocks: func(m appUpgradeMocks) { - m.sel.EXPECT().Application(appUpgradeNamePrompt, appUpgradeNameHelpPrompt).Return("my-app", nil) + m.sel.EXPECT().Application(ctx, appUpgradeNamePrompt, appUpgradeNameHelpPrompt).Return("my-app", nil) }, wantedApp: "my-app", wantedError: nil, @@ -122,7 +123,7 @@ func TestAppUpgradeOpts_Ask(t *testing.T) { inApp: "", setupMocks: func(m appUpgradeMocks) { - m.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Return("", testError) + m.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Return("", testError) }, wantedError: fmt.Errorf("select application: %w", testError), @@ -147,7 +148,7 @@ func TestAppUpgradeOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -211,7 +212,7 @@ func TestAppUpgradeOpts_Execute(t *testing.T) { "should return error if fail to get application": { given: func(ctrl *gomock.Controller) *appUpgradeOpts { mockStore := mocks.NewMockstore(ctrl) - mockStore.EXPECT().GetApplication("phonetool").Return(nil, errors.New("some error")) + mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(nil, errors.New("some error")) return &appUpgradeOpts{ appUpgradeVars: appUpgradeVars{ @@ -226,10 +227,10 @@ func TestAppUpgradeOpts_Execute(t *testing.T) { "should return error if fail to get identity": { given: func(ctrl *gomock.Controller) *appUpgradeOpts { mockIdentity := mocks.NewMockidentityService(ctrl) - mockIdentity.EXPECT().Get().Return(identity.Caller{}, errors.New("some error")) + mockIdentity.EXPECT().Get(ctx).Return(identity.Caller{}, errors.New("some error")) mockStore := mocks.NewMockstore(ctrl) - mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) + mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) return &appUpgradeOpts{ appUpgradeVars: appUpgradeVars{ @@ -245,10 +246,10 @@ func TestAppUpgradeOpts_Execute(t *testing.T) { "should return error if fail to get hostedzone id": { given: func(ctrl *gomock.Controller) *appUpgradeOpts { mockIdentity := mocks.NewMockidentityService(ctrl) - mockIdentity.EXPECT().Get().Return(identity.Caller{Account: "1234"}, nil) + mockIdentity.EXPECT().Get(ctx).Return(identity.Caller{Account: "1234"}, nil) mockStore := mocks.NewMockstore(ctrl) - mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{ + mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{ Name: "phonetool", Domain: "foobar.com", }, nil) @@ -271,11 +272,11 @@ func TestAppUpgradeOpts_Execute(t *testing.T) { "should return error if fail to upgrade application": { given: func(ctrl *gomock.Controller) *appUpgradeOpts { mockIdentity := mocks.NewMockidentityService(ctrl) - mockIdentity.EXPECT().Get().Return(identity.Caller{Account: "1234"}, nil) + mockIdentity.EXPECT().Get(ctx).Return(identity.Caller{Account: "1234"}, nil) mockStore := mocks.NewMockstore(ctrl) - mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - mockStore.EXPECT().UpdateApplication(&config.Application{Name: "phonetool"}).Return(nil) + mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + mockStore.EXPECT().UpdateApplication(ctx, &config.Application{Name: "phonetool"}).Return(nil) mockUpgrader := mocks.NewMockappUpgrader(ctrl) mockUpgrader.EXPECT().UpgradeApplication(gomock.Any()).Return(errors.New("some error")) @@ -295,14 +296,14 @@ func TestAppUpgradeOpts_Execute(t *testing.T) { "success": { given: func(ctrl *gomock.Controller) *appUpgradeOpts { mockIdentity := mocks.NewMockidentityService(ctrl) - mockIdentity.EXPECT().Get().Return(identity.Caller{Account: "1234"}, nil) + mockIdentity.EXPECT().Get(ctx).Return(identity.Caller{Account: "1234"}, nil) mockStore := mocks.NewMockstore(ctrl) - mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{ + mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{ Name: "phonetool", Domain: "hello.com", }, nil) - mockStore.EXPECT().UpdateApplication(&config.Application{ + mockStore.EXPECT().UpdateApplication(ctx, &config.Application{ Name: "phonetool", Domain: "hello.com", DomainHostedZoneID: "2klfqok3", @@ -341,7 +342,7 @@ func TestAppUpgradeOpts_Execute(t *testing.T) { opts := tc.given(ctrl) opts.templateVersion = mockTemplateVersion - err := opts.Execute() + err := opts.Execute(context.Background()) if tc.wantedErr != nil { require.EqualError(t, err, tc.wantedErr.Error()) diff --git a/internal/pkg/cli/cli.go b/internal/pkg/cli/cli.go index 5d21397bcf7..e94bd2dc01a 100644 --- a/internal/pkg/cli/cli.go +++ b/internal/pkg/cli/cli.go @@ -5,6 +5,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -88,14 +89,14 @@ func isStackSetNotExistsErr(err error) bool { return isStackSetNotExistsErr(errors.Unwrap(err)) } -func run(cmd cmd) error { +func run(ctx context.Context, cmd cmd) error { if err := cmd.Validate(); err != nil { return err } - if err := cmd.Ask(); err != nil { + if err := cmd.Ask(ctx); err != nil { return err } - if err := cmd.Execute(); err != nil { + if err := cmd.Execute(ctx); err != nil { return err } if actionCmd, ok := cmd.(actionCommand); ok { diff --git a/internal/pkg/cli/cli_test.go b/internal/pkg/cli/cli_test.go new file mode 100644 index 00000000000..f7eaecc0c83 --- /dev/null +++ b/internal/pkg/cli/cli_test.go @@ -0,0 +1,53 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package cli + +import ( + "context" + "testing" + + "github.com/spf13/cobra" +) + +type contextRecorderCmd struct { + askCtx context.Context + executeCtx context.Context +} + +func (c *contextRecorderCmd) Validate() error { + return nil +} + +func (c *contextRecorderCmd) Ask(ctx context.Context) error { + c.askCtx = ctx + return nil +} + +func (c *contextRecorderCmd) Execute(ctx context.Context) error { + c.executeCtx = ctx + return nil +} + +func TestRunPassesCobraContextToCommand(t *testing.T) { + expectedCtx, cancel := context.WithCancel(context.Background()) + defer cancel() + recorder := &contextRecorderCmd{} + cmd := &cobra.Command{ + Use: "test", + RunE: runCmdE(func(cmd *cobra.Command, args []string) error { + return run(cmd.Context(), recorder) + }), + } + + if err := cmd.ExecuteContext(expectedCtx); err != nil { + t.Fatalf("execute command: %v", err) + } + + if recorder.askCtx != expectedCtx { + t.Fatalf("expected Ask to receive Cobra context") + } + if recorder.executeCtx != expectedCtx { + t.Fatalf("expected Execute to receive Cobra context") + } +} diff --git a/internal/pkg/cli/completion.go b/internal/pkg/cli/completion.go index 090d0df0383..a539f786aeb 100644 --- a/internal/pkg/cli/completion.go +++ b/internal/pkg/cli/completion.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "io" "os" @@ -43,7 +44,7 @@ func (opts *completionOpts) Validate() error { // Execute writes the completion code to the writer. // This method assumes that Validate() was called prior to invocation. -func (opts *completionOpts) Execute() error { +func (opts *completionOpts) Execute(_ context.Context) error { if opts.Shell == "bash" { return opts.completer.GenBashCompletion(opts.w) } @@ -94,7 +95,7 @@ The code must be evaluated to provide interactive completion of commands.`, RunE: runCmdE(func(cmd *cobra.Command, args []string) error { opts.w = os.Stdout opts.completer = rootCmd - return opts.Execute() + return opts.Execute(cmd.Context()) }), } cmd.SetUsageTemplate(template.Usage) diff --git a/internal/pkg/cli/completion_test.go b/internal/pkg/cli/completion_test.go index 918e6aba939..9f9d7e98caf 100644 --- a/internal/pkg/cli/completion_test.go +++ b/internal/pkg/cli/completion_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "testing" @@ -96,7 +97,7 @@ func TestCompletionOpts_Execute(t *testing.T) { opts := completionOpts{Shell: tc.inputShell, completer: mock} // WHEN - opts.Execute() + opts.Execute(context.Background()) }) } } diff --git a/internal/pkg/cli/config_store.go b/internal/pkg/cli/config_store.go index ef6301a4a38..c5cf4a9d2b6 100644 --- a/internal/pkg/cli/config_store.go +++ b/internal/pkg/cli/config_store.go @@ -7,8 +7,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" ) func newSSMConfigStoreFromConfig(cfg aws.Config) *config.Store { - return config.NewSSMStore(identity.New(cfg), config.NewSSMClient(cfg), cfg.Region) + return config.NewSSMStore(identity.New(cfg), ssm.NewFromConfig(cfg), cfg.Region) } diff --git a/internal/pkg/cli/context_test.go b/internal/pkg/cli/context_test.go new file mode 100644 index 00000000000..df1ea19532b --- /dev/null +++ b/internal/pkg/cli/context_test.go @@ -0,0 +1,8 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package cli + +import "context" + +var ctx = context.Background() diff --git a/internal/pkg/cli/deploy.go b/internal/pkg/cli/deploy.go index 29458c38bd8..9067aaaa1fa 100644 --- a/internal/pkg/cli/deploy.go +++ b/internal/pkg/cli/deploy.go @@ -183,8 +183,8 @@ func newDeployOpts(vars deployVars) (*deployOpts, error) { templateVersion: version.LatestTemplateVersion(), sessProvider: sessProvider, } - opts.newJobDeployer = func() (workloadDeployer, error) { - return newJobDeployer(opts) + opts.newJobDeployer = func(ctx context.Context) (workloadDeployer, error) { + return newJobDeployer(ctx, opts) } opts.name = workloadName return opts, nil @@ -203,8 +203,8 @@ func newDeployOpts(vars deployVars) (*deployOpts, error) { sessProvider: sessProvider, templateVersion: version.LatestTemplateVersion(), } - opts.newSvcDeployer = func() (workloadDeployer, error) { - return newSvcDeployer(opts) + opts.newSvcDeployer = func(ctx context.Context) (workloadDeployer, error) { + return newSvcDeployer(ctx, opts) } opts.name = workloadName // Multi-deployments can have flags specified which are not compatible with all service types. @@ -224,9 +224,9 @@ func newDeployOpts(vars deployVars) (*deployOpts, error) { // to convey the customer intention. When the customer specifies --all and --init-wkld, // we will add all un-initialized local workloads to the list to be deployed. // When the customer does not specify --init-wkld with --all, we will only deploy initialized workloads. -func (o *deployOpts) maybeInitWkld(name string) error { +func (o *deployOpts) maybeInitWkld(ctx context.Context, name string) error { // Confirm that the workload needs to be initialized after asking for the name. - initializedWorkloads, err := o.listInitializedLocalWorkloads() + initializedWorkloads, err := o.listInitializedLocalWorkloads(ctx) if err != nil { return err } @@ -251,7 +251,7 @@ func (o *deployOpts) maybeInitWkld(name string) error { } wkldAdder := o.newWorkloadAdder() - if err = wkldAdder.AddWorkloadToApp(o.appName, name, workloadType); err != nil { + if err = wkldAdder.AddWorkloadToApp(ctx, o.appName, name, workloadType); err != nil { return fmt.Errorf("add workload to app: %w", err) } return nil @@ -311,7 +311,7 @@ func (o *deployOpts) parseDeploymentOrderTags(namesWithOptionalOrder []string) e // [][]string{ {"be"}, {"fe"}, {"worker", "job", "db"} }. // // TODO: when there's a dependsOn field in the manifest, we should modify this function to respect it. -func (o *deployOpts) getDeploymentOrder() ([][]string, error) { +func (o *deployOpts) getDeploymentOrder(ctx context.Context) ([][]string, error) { // Get a map from workload name to deployment priority if err := o.parseDeploymentOrderTags(o.workloadNames); err != nil { @@ -333,7 +333,7 @@ func (o *deployOpts) getDeploymentOrder() ([][]string, error) { if o.yesInitWkld { // Add all unspecified local workloads to the list of workloads to be deployed. - localWorkloads, err := o.listLocalWorkloads() + localWorkloads, err := o.listLocalWorkloads(ctx) if err != nil { return nil, err } @@ -343,7 +343,7 @@ func (o *deployOpts) getDeploymentOrder() ([][]string, error) { } } else { // Otherwise (--init-wkld is false): get only get initialized local workloads. - initializedWorkloads, err := o.listInitializedLocalWorkloads() + initializedWorkloads, err := o.listInitializedLocalWorkloads(ctx) if err != nil { return nil, err } @@ -377,11 +377,11 @@ func (o *deployOpts) getDeploymentOrder() ([][]string, error) { return res, nil } -func (o *deployOpts) listStoreWorkloads() ([]*config.Workload, error) { +func (o *deployOpts) listStoreWorkloads(ctx context.Context) ([]*config.Workload, error) { if o.storeWorkloads != nil { return o.storeWorkloads, nil } - wls, err := o.store.ListWorkloads(o.appName) + wls, err := o.store.ListWorkloads(ctx, o.appName) if err != nil { return nil, fmt.Errorf("retrieve store workloads: %w", err) } @@ -389,7 +389,7 @@ func (o *deployOpts) listStoreWorkloads() ([]*config.Workload, error) { return o.storeWorkloads, nil } -func (o *deployOpts) listLocalWorkloads() ([]string, error) { +func (o *deployOpts) listLocalWorkloads(ctx context.Context) ([]string, error) { if o.wsWorkloads != nil { return o.wsWorkloads, nil } @@ -402,15 +402,15 @@ func (o *deployOpts) listLocalWorkloads() ([]string, error) { return o.wsWorkloads, nil } -func (o *deployOpts) listInitializedLocalWorkloads() ([]string, error) { +func (o *deployOpts) listInitializedLocalWorkloads(ctx context.Context) ([]string, error) { if o.initializedWsWorkloads != nil { return o.initializedWsWorkloads, nil } - storeWls, err := o.listStoreWorkloads() + storeWls, err := o.listStoreWorkloads(ctx) if err != nil { return nil, err } - localWorkloads, err := o.listLocalWorkloads() + localWorkloads, err := o.listLocalWorkloads(ctx) if err != nil { return nil, err } @@ -432,28 +432,28 @@ func getTotalNumberOfWorkloads(deploymentGroups [][]workloadCommand) int { return count } -func (o *deployOpts) Run() error { - if err := o.askNames(); err != nil { +func (o *deployOpts) Run(ctx context.Context) error { + if err := o.askNames(ctx); err != nil { return err } - if err := o.askEnv(); err != nil { + if err := o.askEnv(ctx); err != nil { return err } - if err := o.checkEnvExists(); err != nil { + if err := o.checkEnvExists(ctx); err != nil { return err } - if err := o.maybeInitEnv(); err != nil { + if err := o.maybeInitEnv(ctx); err != nil { return err } - if err := o.maybeDeployEnv(); err != nil { + if err := o.maybeDeployEnv(ctx); err != nil { return err } - deploymentOrderGroups, err := o.getDeploymentOrder() + deploymentOrderGroups, err := o.getDeploymentOrder(ctx) if err != nil { return err } @@ -466,11 +466,11 @@ func (o *deployOpts) Run() error { for order, deploymentGroup := range deploymentOrderGroups { for _, workload := range deploymentGroup { // 1. Decide whether the current workload needs initialization. - if err := o.maybeInitWkld(workload); err != nil { + if err := o.maybeInitWkld(ctx, workload); err != nil { return err } // 2. Set up workload command. - deployCmd, err := o.loadWkldCmd(workload) + deployCmd, err := o.loadWkldCmd(ctx, workload) if err != nil { return err } @@ -480,7 +480,7 @@ func (o *deployOpts) Run() error { actionCommand: deployCmd, }) // 3. Ask() and Validate() for required info. - if err := deployCmd.Ask(); err != nil { + if err := deployCmd.Ask(ctx); err != nil { return fmt.Errorf("ask %s deploy: %w", o.wlType, err) } if err := deployCmd.Validate(); err != nil { @@ -499,7 +499,7 @@ func (o *deployOpts) Run() error { // 2. Modify labeledSyncBuffer so it can display a spinner. // 3. Wrap Execute() in a goroutine with ErrorGroup and context for i, cmd := range deploymentGroup { - if err := cmd.Execute(); err != nil { + if err := cmd.Execute(ctx); err != nil { var errNoInfraChanges *errNoInfrastructureChanges if !errors.As(err, &errNoInfraChanges) { return fmt.Errorf("execute deployment %d of %d in group %d: %w", i+1, len(deploymentGroup), g+1, err) @@ -529,7 +529,7 @@ func logDeploymentOrderInfo(cmds [][]workloadCommand, totalCount int) { } } -func (o *deployOpts) askNames() error { +func (o *deployOpts) askNames(ctx context.Context) error { if o.workloadNames != nil || len(o.workloadNames) != 0 { return nil } @@ -545,7 +545,7 @@ func (o *deployOpts) askNames() error { return nil } - names, err := o.sel.Workloads("Select one or more services or jobs in your workspace.", "") + names, err := o.sel.Workloads(ctx, "Select one or more services or jobs in your workspace.", "") if err != nil { return fmt.Errorf("select service or job: %w", err) } @@ -587,7 +587,7 @@ func (o *deployOpts) askNames() error { return nil } -func (o *deployOpts) listWsEnvironments() ([]string, error) { +func (o *deployOpts) listWsEnvironments(ctx context.Context) ([]string, error) { if o.wsEnvironments == nil { envs, err := o.ws.ListEnvironments() if err != nil { @@ -602,15 +602,15 @@ func (o *deployOpts) listWsEnvironments() ([]string, error) { return o.wsEnvironments, nil } -func (o *deployOpts) askEnv() error { +func (o *deployOpts) askEnv(ctx context.Context) error { if o.envName != "" { return nil } - localEnvs, err := o.listWsEnvironments() + localEnvs, err := o.listWsEnvironments(ctx) if err != nil { return fmt.Errorf("get workspace environments: %w", err) } - initializedEnvs, err := o.store.ListEnvironments(o.appName) + initializedEnvs, err := o.store.ListEnvironments(ctx, o.appName) if err != nil { return fmt.Errorf("get initialized environments: %w", err) } @@ -631,7 +631,7 @@ func (o *deployOpts) askEnv() error { extraOptions = append(extraOptions, prompt.Option{Value: localEnv, Hint: "uninitialized"}) } - o.envName, err = o.sel.Environment("Select an environment to deploy to", "", o.appName, extraOptions...) + o.envName, err = o.sel.Environment(ctx, "Select an environment to deploy to", "", o.appName, extraOptions...) if err != nil { return fmt.Errorf("get environment name: %w", err) } @@ -639,9 +639,9 @@ func (o *deployOpts) askEnv() error { } // checkEnvExists checks whether the environment is initialized and has a local manifest. -func (o *deployOpts) checkEnvExists() error { +func (o *deployOpts) checkEnvExists(ctx context.Context) error { o.envExistsInApp = true - _, err := o.store.GetEnvironment(o.appName, o.envName) + _, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { var errNotFound *config.ErrNoSuchEnvironment if !errors.As(err, &errNotFound) { @@ -649,7 +649,7 @@ func (o *deployOpts) checkEnvExists() error { } o.envExistsInApp = false } - envs, err := o.listWsEnvironments() + envs, err := o.listWsEnvironments(ctx) if err != nil { return fmt.Errorf("list environments in workspace: %w", err) } @@ -667,7 +667,7 @@ func (o *deployOpts) checkEnvExists() error { return nil } -func (o *deployOpts) maybeInitEnv() error { +func (o *deployOpts) maybeInitEnv(ctx context.Context) error { if o.envExistsInApp { return nil } @@ -689,10 +689,10 @@ func (o *deployOpts) maybeInitEnv() error { if err = cmd.Validate(); err != nil { return err } - if err = cmd.Ask(); err != nil { + if err = cmd.Ask(ctx); err != nil { return err } - if err = cmd.Execute(); err != nil { + if err = cmd.Execute(ctx); err != nil { return err } if o.deployEnv == nil { @@ -708,7 +708,7 @@ func (o *deployOpts) maybeInitEnv() error { return fmt.Errorf("env %s does not exist in app %s", o.envName, o.appName) } -func (o *deployOpts) maybeDeployEnv() error { +func (o *deployOpts) maybeDeployEnv(ctx context.Context) error { if !o.envExistsInWs { return nil } @@ -721,16 +721,16 @@ func (o *deployOpts) maybeDeployEnv() error { if err = cmd.Validate(); err != nil { return err } - if err = cmd.Ask(); err != nil { + if err = cmd.Ask(ctx); err != nil { return err } - return cmd.Execute() + return cmd.Execute(ctx) } return nil } -func (o *deployOpts) loadWkldCmd(name string) (actionCommand, error) { - wl, err := o.store.GetWorkload(o.appName, name) +func (o *deployOpts) loadWkldCmd(ctx context.Context, name string) (actionCommand, error) { + wl, err := o.store.GetWorkload(ctx, o.appName, name) if err != nil { return nil, fmt.Errorf("retrieve %s from application %s: %w", o.appName, name, err) } @@ -792,7 +792,7 @@ func BuildDeployCmd() *cobra.Command { } } - if err := opts.Run(); err != nil { + if err := opts.Run(cmd.Context()); err != nil { return err } return nil diff --git a/internal/pkg/cli/deploy/context_test.go b/internal/pkg/cli/deploy/context_test.go new file mode 100644 index 00000000000..045dbf0f518 --- /dev/null +++ b/internal/pkg/cli/deploy/context_test.go @@ -0,0 +1,8 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package deploy + +import "context" + +var ctx = context.Background() diff --git a/internal/pkg/cli/deploy/env.go b/internal/pkg/cli/deploy/env.go index 81a07133638..561b2a31323 100644 --- a/internal/pkg/cli/deploy/env.go +++ b/internal/pkg/cli/deploy/env.go @@ -107,6 +107,7 @@ type envDeployer struct { // NewEnvDeployerInput contains information needed to construct an environment deployer. type NewEnvDeployerInput struct { + Ctx context.Context App *config.Application Env *config.Environment SessionProvider *sessions.Provider @@ -117,6 +118,10 @@ type NewEnvDeployerInput struct { // NewEnvDeployer constructs an environment deployer. func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { + ctx := in.Ctx + if ctx == nil { + ctx = context.Background() + } defaultConfig, err := in.SessionProvider.DefaultConfig(context.Background()) if err != nil { return nil, fmt.Errorf("get default config: %w", err) @@ -129,7 +134,7 @@ func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { if err != nil { return nil, fmt.Errorf("get env config: %w", err) } - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: in.App.Name, Env: in.Env.Name, ConfigStore: in.ConfigStore, diff --git a/internal/pkg/cli/deploy/mocks/mock_worker.go b/internal/pkg/cli/deploy/mocks/mock_worker.go index 9873722692a..ac3a4273a92 100644 --- a/internal/pkg/cli/deploy/mocks/mock_worker.go +++ b/internal/pkg/cli/deploy/mocks/mock_worker.go @@ -5,6 +5,7 @@ package mocks import ( + context "context" reflect "reflect" deploy "github.com/aproint/copilot-cli/internal/pkg/deploy" @@ -35,16 +36,16 @@ func (m *MocksnsTopicsLister) EXPECT() *MocksnsTopicsListerMockRecorder { } // ListSNSTopics mocks base method. -func (m *MocksnsTopicsLister) ListSNSTopics(appName, envName string) ([]deploy.Topic, error) { +func (m *MocksnsTopicsLister) ListSNSTopics(ctx context.Context, appName, envName string) ([]deploy.Topic, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListSNSTopics", appName, envName) + ret := m.ctrl.Call(m, "ListSNSTopics", ctx, appName, envName) ret0, _ := ret[0].([]deploy.Topic) ret1, _ := ret[1].(error) return ret0, ret1 } // ListSNSTopics indicates an expected call of ListSNSTopics. -func (mr *MocksnsTopicsListerMockRecorder) ListSNSTopics(appName, envName interface{}) *gomock.Call { +func (mr *MocksnsTopicsListerMockRecorder) ListSNSTopics(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSNSTopics", reflect.TypeOf((*MocksnsTopicsLister)(nil).ListSNSTopics), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSNSTopics", reflect.TypeOf((*MocksnsTopicsLister)(nil).ListSNSTopics), ctx, appName, envName) } diff --git a/internal/pkg/cli/deploy/worker.go b/internal/pkg/cli/deploy/worker.go index 189559b15b5..05bef12ff07 100644 --- a/internal/pkg/cli/deploy/worker.go +++ b/internal/pkg/cli/deploy/worker.go @@ -4,6 +4,7 @@ package deploy import ( + "context" "fmt" "slices" "strings" @@ -31,7 +32,7 @@ var ( ) type snsTopicsLister interface { - ListSNSTopics(appName string, envName string) ([]deploy.Topic, error) + ListSNSTopics(ctx context.Context, appName string, envName string) ([]deploy.Topic, error) } type workerSvcDeployer struct { @@ -161,7 +162,11 @@ func (d *workerSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) (* return nil, err } var topics []deploy.Topic - topics, err = d.topicLister.ListSNSTopics(d.app.Name, d.env.Name) + ctx := d.ctx + if ctx == nil { + ctx = context.Background() + } + topics, err = d.topicLister.ListSNSTopics(ctx, d.app.Name, d.env.Name) if err != nil { return nil, fmt.Errorf("get SNS topics for app %s and environment %s: %w", d.app.Name, d.env.Name, err) } diff --git a/internal/pkg/cli/deploy/worker_test.go b/internal/pkg/cli/deploy/worker_test.go index a8ccd8a45be..b1505bdee9a 100644 --- a/internal/pkg/cli/deploy/worker_test.go +++ b/internal/pkg/cli/deploy/worker_test.go @@ -99,7 +99,7 @@ func TestSvcDeployOpts_stackConfiguration_worker(t *testing.T) { mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockApp.local", nil) m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) - m.mockSNSTopicsLister.EXPECT().ListSNSTopics(mockAppName, mockEnvName).Return(nil, mockError) + m.mockSNSTopicsLister.EXPECT().ListSNSTopics(ctx, mockAppName, mockEnvName).Return(nil, mockError) }, wantErr: fmt.Errorf("get SNS topics for app mockApp and environment mockEnv: %w", mockError), }, @@ -115,7 +115,7 @@ func TestSvcDeployOpts_stackConfiguration_worker(t *testing.T) { mock: func(m *deployMocks) { m.mockEndpointGetter.EXPECT().ServiceDiscoveryEndpoint().Return("mockEnv.mockApp.local", nil) m.mockEnvVersionGetter.EXPECT().Version().Return("v1.42.0", nil) - m.mockSNSTopicsLister.EXPECT().ListSNSTopics(mockAppName, mockEnvName).Return([]deploy.Topic{ + m.mockSNSTopicsLister.EXPECT().ListSNSTopics(ctx, mockAppName, mockEnvName).Return([]deploy.Topic{ *topic, }, nil) }, diff --git a/internal/pkg/cli/deploy/workload.go b/internal/pkg/cli/deploy/workload.go index 47d18af0458..694c21e9572 100644 --- a/internal/pkg/cli/deploy/workload.go +++ b/internal/pkg/cli/deploy/workload.go @@ -43,6 +43,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/aproint/copilot-cli/internal/pkg/workspace" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" "github.com/spf13/afero" "golang.org/x/sync/errgroup" ) @@ -168,6 +169,7 @@ func RepoName(app, workload string) string { } type workloadDeployer struct { + ctx context.Context name string app *config.Application env *config.Environment @@ -209,6 +211,7 @@ type ImagePerContainer struct { // WorkloadDeployerInput is the input to for workloadDeployer constructor. type WorkloadDeployerInput struct { + Ctx context.Context SessionProvider *sessions.Provider Name string App *config.Application @@ -248,6 +251,10 @@ type ImageActionInput struct { // newWorkloadDeployer is the constructor for workloadDeployer. func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { + ctx := in.Ctx + if ctx == nil { + ctx = context.Background() + } ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err @@ -282,8 +289,8 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { repoName := RepoName(in.App.Name, in.Name) repository := repository.NewWithURI( ecr.New(defaultEnvRegionConfig), repoName, resources.RepositoryURLs[in.Name]) - store := config.NewSSMStore(identity.New(defaultConfig), config.NewSSMClient(defaultConfig), defaultConfig.Region) - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + store := config.NewSSMStore(identity.New(defaultConfig), ssm.NewFromConfig(defaultConfig), defaultConfig.Region) + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: in.App.Name, Env: in.Env.Name, ConfigStore: store, @@ -308,6 +315,7 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { } docker := dockerengine.New(exec.NewCmd()) return &workloadDeployer{ + ctx: ctx, name: in.Name, app: in.App, env: in.Env, diff --git a/internal/pkg/cli/deploy/workload_test.go b/internal/pkg/cli/deploy/workload_test.go index ce1263f3a65..faff320d47c 100644 --- a/internal/pkg/cli/deploy/workload_test.go +++ b/internal/pkg/cli/deploy/workload_test.go @@ -5,6 +5,7 @@ package deploy import ( "bytes" + "context" "errors" "fmt" "io" @@ -108,7 +109,7 @@ type mockTopicLister struct { } // ListSNSTopics implements the snsTopicsLister interface. -func (m *mockTopicLister) ListSNSTopics(_, _ string) ([]deploy.Topic, error) { +func (m *mockTopicLister) ListSNSTopics(context.Context, string, string) ([]deploy.Topic, error) { return m.topics, m.err } diff --git a/internal/pkg/cli/deploy_test.go b/internal/pkg/cli/deploy_test.go index dedf6456d7f..003d660ab32 100644 --- a/internal/pkg/cli/deploy_test.go +++ b/internal/pkg/cli/deploy_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "testing" @@ -68,26 +69,26 @@ type: Worker Service`) }, mockActionCommand: func(m *mocks.MockactionCommand) { // Deploy svc - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate() - m.EXPECT().Execute() + m.EXPECT().Execute(gomock.Any()) m.EXPECT().RecommendActions() }, mockCmd: func(m *mocks.Mockcmd) { // Init env m.EXPECT().Validate() - m.EXPECT().Ask() - m.EXPECT().Execute() + m.EXPECT().Ask(gomock.Any()) + m.EXPECT().Execute(gomock.Any()) // Deploy env m.EXPECT().Validate() - m.EXPECT().Ask() - m.EXPECT().Execute() + m.EXPECT().Ask(gomock.Any()) + m.EXPECT().Execute(gomock.Any()) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(nil, &config.ErrNoSuchEnvironment{}) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(nil, &config.ErrNoSuchEnvironment{}) // After env init/deploy - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{{Name: "fe", Type: "Load Balanced Web Service"}}, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&config.Workload{Name: "fe", Type: "Load Balanced Web Service"}, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{{Name: "fe", Type: "Load Balanced Web Service"}}, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&config.Workload{Name: "fe", Type: "Load Balanced Web Service"}, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -103,21 +104,21 @@ type: Worker Service`) inInitEnv: aws.Bool(false), inDeployEnv: aws.Bool(false), mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Workloads("Select one or more services or jobs in your workspace.", "").Return([]string{"fe"}, nil) + m.EXPECT().Workloads(ctx, "Select one or more services or jobs in your workspace.", "").Return([]string{"fe"}, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate() - m.EXPECT().Execute() + m.EXPECT().Execute(gomock.Any()) m.EXPECT().RecommendActions() }, mockCmd: func(m *mocks.Mockcmd) { }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl}, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl}, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ReadWorkloadManifest("fe").Times(0) @@ -141,14 +142,14 @@ type: Worker Service`) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return(nil, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return(nil, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate() - m.EXPECT().Execute() + m.EXPECT().Execute(gomock.Any()) m.EXPECT().RecommendActions() }, mockCmd: func(m *mocks.Mockcmd) { @@ -156,7 +157,7 @@ type: Worker Service`) }, mockSel: func(m *mocks.MockwsSelector) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp("app", "fe", manifestinfo.LoadBalancedWebServiceType).Return(nil) + m.EXPECT().AddWorkloadToApp(ctx, "app", "fe", manifestinfo.LoadBalancedWebServiceType).Return(nil) }, }, "errors reading manifest": { @@ -172,19 +173,19 @@ type: Worker Service`) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return(nil, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return(nil, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Times(0) + m.EXPECT().Ask(gomock.Any()).Times(0) m.EXPECT().Validate().Times(0) - m.EXPECT().Execute().Times(0) + m.EXPECT().Execute(gomock.Any()).Times(0) m.EXPECT().RecommendActions().Times(0) }, mockCmd: func(m *mocks.Mockcmd) {}, mockSel: func(m *mocks.MockwsSelector) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedErr: "read manifest for workload fe: some error", }, @@ -201,13 +202,13 @@ type: Worker Service`) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return(nil, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return(nil, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Times(0) + m.EXPECT().Ask(gomock.Any()).Times(0) m.EXPECT().Validate().Times(0) - m.EXPECT().Execute().Times(0) + m.EXPECT().Execute(gomock.Any()).Times(0) m.EXPECT().RecommendActions().Times(0) }, mockCmd: func(m *mocks.Mockcmd) { @@ -215,7 +216,7 @@ type: Worker Service`) }, mockSel: func(m *mocks.MockwsSelector) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedErr: "unrecognized workload type \"nothing here\" in manifest for workload fe", }, @@ -227,9 +228,9 @@ type: Worker Service`) inDeployEnv: aws.Bool(false), mockSel: func(m *mocks.MockwsSelector) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return(nil, errors.New("some error")) - m.EXPECT().GetWorkload("app", "fe").Times(0) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return(nil, errors.New("some error")) + m.EXPECT().GetWorkload(ctx, "app", "fe").Times(0) }, mockActionCommand: func(m *mocks.MockactionCommand) {}, mockCmd: func(m *mocks.Mockcmd) { @@ -237,7 +238,7 @@ type: Worker Service`) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -257,24 +258,24 @@ type: Worker Service`) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return(nil, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return(nil, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate() - m.EXPECT().Execute() + m.EXPECT().Execute(gomock.Any()) m.EXPECT().RecommendActions() }, mockCmd: func(m *mocks.Mockcmd) { }, mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Workloads(gomock.Any(), gomock.Any()).Return([]string{"fe"}, nil) + m.EXPECT().Workloads(ctx, gomock.Any(), gomock.Any()).Return([]string{"fe"}, nil) }, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp("app", "fe", manifestinfo.LoadBalancedWebServiceType).Return(nil) + m.EXPECT().AddWorkloadToApp(ctx, "app", "fe", manifestinfo.LoadBalancedWebServiceType).Return(nil) }, }, "errors correctly if job returned": { @@ -284,22 +285,22 @@ type: Worker Service`) inDeployEnv: aws.Bool(false), wantedErr: "ask job deploy: some error", mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Workloads("Select one or more services or jobs in your workspace.", "").Return([]string{"mailer"}, nil) + m.EXPECT().Workloads(ctx, "Select one or more services or jobs in your workspace.", "").Return([]string{"mailer"}, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Return(errors.New("some error")) + m.EXPECT().Ask(gomock.Any()).Return(errors.New("some error")) }, mockCmd: func(m *mocks.Mockcmd) { }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockJob}, nil) - m.EXPECT().GetWorkload("app", "mailer").Return(&mockJob, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockJob}, nil) + m.EXPECT().GetWorkload(ctx, "app", "mailer").Return(&mockJob, nil) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -315,22 +316,22 @@ type: Worker Service`) inDeployEnv: aws.Bool(false), mockSel: func(m *mocks.MockwsSelector) {}, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate() - m.EXPECT().Execute() + m.EXPECT().Execute(gomock.Any()) m.EXPECT().RecommendActions() }, mockCmd: func(m *mocks.Mockcmd) { }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl}, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl}, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -345,14 +346,14 @@ type: Worker Service`) inDeployEnv: aws.Bool(false), wantedErr: "select service or job: some error", mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Workloads(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().Workloads(ctx, gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) }, mockActionCommand: func(m *mocks.MockactionCommand) {}, mockCmd: func(m *mocks.Mockcmd) {}, mockStore: func(m *mocks.Mockstore) {}, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ReadWorkloadManifest("fe").Times(0) @@ -368,18 +369,18 @@ type: Worker Service`) mockSel: func(m *mocks.MockwsSelector) {}, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Return(errors.New("some error")) + m.EXPECT().Ask(gomock.Any()).Return(errors.New("some error")) }, mockCmd: func(m *mocks.Mockcmd) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl}, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl}, nil) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -397,19 +398,19 @@ type: Worker Service`) mockSel: func(m *mocks.MockwsSelector) {}, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate().Return(errors.New("some error")) }, mockCmd: func(m *mocks.Mockcmd) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl}, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl}, nil) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -427,19 +428,19 @@ type: Worker Service`) mockSel: func(m *mocks.MockwsSelector) {}, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate() - m.EXPECT().Execute().Return(errors.New("some error")) + m.EXPECT().Execute(gomock.Any()).Return(errors.New("some error")) }, mockCmd: func(m *mocks.Mockcmd) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl}, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl}, nil) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().AddWorkloadToApp(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -459,11 +460,11 @@ type: Worker Service`) mockActionCommand: func(m *mocks.MockactionCommand) {}, mockCmd: func(m *mocks.Mockcmd) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) // After env init/deploy - m.EXPECT().ListWorkloads("app").Return(nil, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return(nil, nil) // After wkld init - m.EXPECT().GetWorkload("app", "fe").Times(0) + m.EXPECT().GetWorkload(ctx, "app", "fe").Times(0) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -471,7 +472,7 @@ type: Worker Service`) m.EXPECT().ListWorkloads().Return([]string{"fe"}, nil) }, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp("app", "fe", "Load Balanced Web Service").Return(errors.New("some error")) + m.EXPECT().AddWorkloadToApp(ctx, "app", "fe", "Load Balanced Web Service").Return(errors.New("some error")) }, }, "both uninitialized and initialized environments and workloads": { @@ -479,35 +480,35 @@ type: Worker Service`) wantedErr: "", mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Workloads("Select one or more services or jobs in your workspace.", "").Return([]string{"fe"}, nil) - m.EXPECT().Environment("Select an environment to deploy to", "", "app", prompt.Option{Value: "prod", Hint: "uninitialized"}).Return("prod", nil) + m.EXPECT().Workloads(ctx, "Select one or more services or jobs in your workspace.", "").Return([]string{"fe"}, nil) + m.EXPECT().Environment(ctx, "Select an environment to deploy to", "", "app", prompt.Option{Value: "prod", Hint: "uninitialized"}).Return("prod", nil) }, mockPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Confirm("Environment \"prod\" does not exist in app \"app\". Initialize it?", "").Return(true, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { // Deploy svc - m.EXPECT().Ask() + m.EXPECT().Ask(gomock.Any()) m.EXPECT().Validate() - m.EXPECT().Execute() + m.EXPECT().Execute(gomock.Any()) m.EXPECT().RecommendActions() }, mockCmd: func(m *mocks.Mockcmd) { // Init env m.EXPECT().Validate() - m.EXPECT().Ask() - m.EXPECT().Execute() + m.EXPECT().Ask(gomock.Any()) + m.EXPECT().Execute(gomock.Any()) // Deploy env m.EXPECT().Validate() - m.EXPECT().Ask() - m.EXPECT().Execute() + m.EXPECT().Ask(gomock.Any()) + m.EXPECT().Execute(gomock.Any()) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("app").Return([]*config.Environment{&mockEnv}, nil) - m.EXPECT().GetEnvironment("app", "prod").Return(nil, &config.ErrNoSuchEnvironment{}) + m.EXPECT().ListEnvironments(ctx, "app").Return([]*config.Environment{&mockEnv}, nil) + m.EXPECT().GetEnvironment(ctx, "app", "prod").Return(nil, &config.ErrNoSuchEnvironment{}) // After env init/deploy - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{{Name: "fe", Type: "Load Balanced Web Service"}}, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&config.Workload{Name: "fe", Type: "Load Balanced Web Service"}, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{{Name: "fe", Type: "Load Balanced Web Service"}}, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&config.Workload{Name: "fe", Type: "Load Balanced Web Service"}, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test", "prod"}, nil) @@ -526,7 +527,7 @@ type: Worker Service`) mockActionCommand: func(m *mocks.MockactionCommand) {}, mockCmd: func(m *mocks.Mockcmd) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("app").Return(nil, errors.New("some error")) + m.EXPECT().ListEnvironments(ctx, "app").Return(nil, errors.New("some error")) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{}, nil) @@ -538,13 +539,13 @@ type: Worker Service`) inNames: []string{"fe"}, wantedErr: "get environment name: some error", mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Environment(gomock.Any(), "", "app", prompt.Option{Value: "prod", Hint: "uninitialized"}).Return("", errors.New("some error")) + m.EXPECT().Environment(ctx, gomock.Any(), "", "app", prompt.Option{Value: "prod", Hint: "uninitialized"}).Return("", errors.New("some error")) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockActionCommand: func(m *mocks.MockactionCommand) {}, mockCmd: func(m *mocks.Mockcmd) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("app").Return([]*config.Environment{&mockEnv}, nil) + m.EXPECT().ListEnvironments(ctx, "app").Return([]*config.Environment{&mockEnv}, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"prod"}, nil) @@ -561,9 +562,9 @@ type: Worker Service`) mockSel: func(m *mocks.MockwsSelector) { }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Times(2) + m.EXPECT().Ask(gomock.Any()).Times(2) m.EXPECT().Validate().Times(2) - m.EXPECT().Execute().Times(2) + m.EXPECT().Execute(gomock.Any()).Times(2) m.EXPECT().RecommendActions().Times(2) }, mockCmd: func(m *mocks.Mockcmd) { @@ -575,10 +576,10 @@ type: Worker Service`) Name: "be", Type: "Backend Service", } - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl, &mockBeWl}, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) - m.EXPECT().GetWorkload("app", "be").Return(&mockBeWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl, &mockBeWl}, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) + m.EXPECT().GetWorkload(ctx, "app", "be").Return(&mockBeWl, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ReadWorkloadManifest("fe").Times(0) @@ -600,9 +601,9 @@ type: Worker Service`) mockSel: func(m *mocks.MockwsSelector) { }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Times(3) + m.EXPECT().Ask(gomock.Any()).Times(3) m.EXPECT().Validate().Times(3) - m.EXPECT().Execute().Times(3) + m.EXPECT().Execute(gomock.Any()).Times(3) m.EXPECT().RecommendActions().Times(3) }, mockCmd: func(m *mocks.Mockcmd) { @@ -619,11 +620,11 @@ type: Worker Service`) Name: "worker", Type: "Worker Service", } - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl, &mockBeWl}, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) - m.EXPECT().GetWorkload("app", "be").Return(&mockBeWl, nil) - m.EXPECT().GetWorkload("app", "worker").Return(&mockWorkerWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl, &mockBeWl}, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) + m.EXPECT().GetWorkload(ctx, "app", "be").Return(&mockBeWl, nil) + m.EXPECT().GetWorkload(ctx, "app", "worker").Return(&mockWorkerWl, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ReadWorkloadManifest("fe").Times(0) @@ -633,7 +634,7 @@ type: Worker Service`) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp("app", "worker", manifestinfo.WorkerServiceType).Return(nil) + m.EXPECT().AddWorkloadToApp(ctx, "app", "worker", manifestinfo.WorkerServiceType).Return(nil) }, }, "deploys multiple workloads with specified order by prompting": { @@ -641,12 +642,12 @@ type: Worker Service`) inEnvName: "test", mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Workloads(gomock.Any(), gomock.Any()).Return([]string{"be", "worker"}, nil) + m.EXPECT().Workloads(ctx, gomock.Any(), gomock.Any()).Return([]string{"be", "worker"}, nil) }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Times(2) + m.EXPECT().Ask(gomock.Any()).Times(2) m.EXPECT().Validate().Times(2) - m.EXPECT().Execute().Times(2) + m.EXPECT().Execute(gomock.Any()).Times(2) m.EXPECT().RecommendActions().Times(2) }, mockCmd: func(m *mocks.Mockcmd) {}, @@ -661,10 +662,10 @@ type: Worker Service`) Name: "worker", Type: "Worker Service", } - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWorkerWl, &mockBeWl}, nil) - m.EXPECT().GetWorkload("app", "be").Return(&mockBeWl, nil) - m.EXPECT().GetWorkload("app", "worker").Return(&mockWorkerWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWorkerWl, &mockBeWl}, nil) + m.EXPECT().GetWorkload(ctx, "app", "be").Return(&mockBeWl, nil) + m.EXPECT().GetWorkload(ctx, "app", "worker").Return(&mockWorkerWl, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListWorkloads().Return([]string{"fe", "be", "worker"}, nil) @@ -698,10 +699,10 @@ type: Worker Service`) mockSel: func(m *mocks.MockwsSelector) { }, mockActionCommand: func(m *mocks.MockactionCommand) { - m.EXPECT().Ask().Times(3) + m.EXPECT().Ask(gomock.Any()).Times(3) m.EXPECT().Validate().Times(3) - m.EXPECT().Execute().Times(2) - m.EXPECT().Execute().Return(&errNoInfrastructureChanges{ + m.EXPECT().Execute(gomock.Any()).Times(2) + m.EXPECT().Execute(gomock.Any()).Return(&errNoInfrastructureChanges{ parentErr: errors.New("some error"), }) m.EXPECT().RecommendActions().Times(2) @@ -720,11 +721,11 @@ type: Worker Service`) Name: "worker", Type: "Worker Service", } - m.EXPECT().GetEnvironment("app", "test").Return(&mockEnv, nil) - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{&mockWl, &mockBeWl}, nil) - m.EXPECT().GetWorkload("app", "fe").Return(&mockWl, nil) - m.EXPECT().GetWorkload("app", "be").Return(&mockBeWl, nil) - m.EXPECT().GetWorkload("app", "worker").Return(&mockWorkerWl, nil) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&mockEnv, nil) + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{&mockWl, &mockBeWl}, nil) + m.EXPECT().GetWorkload(ctx, "app", "fe").Return(&mockWl, nil) + m.EXPECT().GetWorkload(ctx, "app", "be").Return(&mockBeWl, nil) + m.EXPECT().GetWorkload(ctx, "app", "worker").Return(&mockWorkerWl, nil) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ReadWorkloadManifest("fe").Times(0) @@ -734,7 +735,7 @@ type: Worker Service`) }, mockPrompt: func(m *mocks.Mockprompter) {}, mockInit: func(m *mocks.MockwkldInitializerWithoutManifest) { - m.EXPECT().AddWorkloadToApp("app", "worker", manifestinfo.WorkerServiceType).Return(nil) + m.EXPECT().AddWorkloadToApp(ctx, "app", "worker", manifestinfo.WorkerServiceType).Return(nil) }, }, } @@ -786,7 +787,7 @@ type: Worker Service`) opts.workloadNames = tc.inNames } // WHEN - err := opts.Run() + err := opts.Run(context.Background()) // THEN if tc.wantedErr != "" { @@ -808,14 +809,14 @@ func Test_deployOpts_checkEnvExists(t *testing.T) { }{ "error getting environment": { mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(nil, mockError) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(nil, mockError) }, mockWs: func(m *mocks.MockwsWlDirReader) {}, wantErr: "get environment from config store: some error", }, "env exists in ws but not app": { mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(nil, &config.ErrNoSuchEnvironment{}) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(nil, &config.ErrNoSuchEnvironment{}) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return([]string{"test"}, nil) @@ -825,7 +826,7 @@ func Test_deployOpts_checkEnvExists(t *testing.T) { }, "env exists in app but not ws": { mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&config.Environment{ + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&config.Environment{ App: "app", Name: "test", }, nil) @@ -838,7 +839,7 @@ func Test_deployOpts_checkEnvExists(t *testing.T) { }, "env does not exist anywhere": { mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(nil, &config.ErrNoSuchEnvironment{}) + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(nil, &config.ErrNoSuchEnvironment{}) }, mockWs: func(m *mocks.MockwsWlDirReader) { m.EXPECT().ListEnvironments().Return(nil, nil) @@ -847,7 +848,7 @@ func Test_deployOpts_checkEnvExists(t *testing.T) { }, "error listing envs": { mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("app", "test").Return(&config.Environment{ + m.EXPECT().GetEnvironment(ctx, "app", "test").Return(&config.Environment{ App: "app", Name: "test", }, nil) @@ -880,7 +881,7 @@ func Test_deployOpts_checkEnvExists(t *testing.T) { ws: mockWs, } - err := o.checkEnvExists() + err := o.checkEnvExists(ctx) if err != nil { require.EqualError(t, err, tc.wantErr) } else { @@ -956,7 +957,7 @@ func Test_deployOpts_maybeInitEnv(t *testing.T) { mockPrompt: func(m *mocks.Mockprompter) {}, mockInitEnvCmd: func(m *mocks.Mockcmd) { m.EXPECT().Validate().Return(nil) - m.EXPECT().Ask().Return(mockError) + m.EXPECT().Ask(gomock.Any()).Return(mockError) }, wantErr: "some error", @@ -969,8 +970,8 @@ func Test_deployOpts_maybeInitEnv(t *testing.T) { mockPrompt: func(m *mocks.Mockprompter) {}, mockInitEnvCmd: func(m *mocks.Mockcmd) { m.EXPECT().Validate().Return(nil) - m.EXPECT().Ask().Return(nil) - m.EXPECT().Execute().Return(mockError) + m.EXPECT().Ask(gomock.Any()).Return(nil) + m.EXPECT().Execute(gomock.Any()).Return(mockError) }, wantErr: "some error", @@ -984,8 +985,8 @@ func Test_deployOpts_maybeInitEnv(t *testing.T) { mockPrompt: func(m *mocks.Mockprompter) {}, mockInitEnvCmd: func(m *mocks.Mockcmd) { m.EXPECT().Validate().Return(nil) - m.EXPECT().Ask().Return(nil) - m.EXPECT().Execute().Return(nil) + m.EXPECT().Ask(gomock.Any()).Return(nil) + m.EXPECT().Execute(gomock.Any()).Return(nil) }, wantErr: "environment test was initialized but has not been deployed", @@ -999,8 +1000,8 @@ func Test_deployOpts_maybeInitEnv(t *testing.T) { mockPrompt: func(m *mocks.Mockprompter) {}, mockInitEnvCmd: func(m *mocks.Mockcmd) { m.EXPECT().Validate().Return(nil).Times(0) - m.EXPECT().Ask().Return(nil).Times(0) - m.EXPECT().Execute().Return(nil).Times(0) + m.EXPECT().Ask(gomock.Any()).Return(nil).Times(0) + m.EXPECT().Execute(gomock.Any()).Return(nil).Times(0) }, wantErr: "env test does not exist in app app", @@ -1013,8 +1014,8 @@ func Test_deployOpts_maybeInitEnv(t *testing.T) { mockPrompt: func(m *mocks.Mockprompter) {}, mockInitEnvCmd: func(m *mocks.Mockcmd) { m.EXPECT().Validate().Return(nil) - m.EXPECT().Ask().Return(nil) - m.EXPECT().Execute().Return(nil) + m.EXPECT().Ask(gomock.Any()).Return(nil) + m.EXPECT().Execute(gomock.Any()).Return(nil) }, wantDeployEnv: aws.Bool(true), }, @@ -1047,7 +1048,7 @@ func Test_deployOpts_maybeInitEnv(t *testing.T) { }, } - err := o.maybeInitEnv() + err := o.maybeInitEnv(context.Background()) if err != nil { require.EqualError(t, err, tc.wantErr) } else { @@ -1081,8 +1082,8 @@ func Test_deployOpts_maybeDeployEnv(t *testing.T) { deployEnv: aws.Bool(true), mockDeployEnvCmd: func(m *mocks.Mockcmd) { m.EXPECT().Validate().Return(nil) - m.EXPECT().Ask().Return(nil) - m.EXPECT().Execute().Return(nil) + m.EXPECT().Ask(gomock.Any()).Return(nil) + m.EXPECT().Execute(gomock.Any()).Return(nil) }, }, } @@ -1109,7 +1110,7 @@ func Test_deployOpts_maybeDeployEnv(t *testing.T) { }, } - err := o.maybeDeployEnv() + err := o.maybeDeployEnv(context.Background()) if err != nil { require.EqualError(t, err, tc.wantErr) } else { @@ -1157,7 +1158,7 @@ func Test_deployOpts_getDeploymentOrder(t *testing.T) { m.EXPECT().ListWorkloads().Return([]string{"be", "db", "fe"}, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{ + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{ mockFe, mockBe, mockDb, @@ -1172,7 +1173,7 @@ func Test_deployOpts_getDeploymentOrder(t *testing.T) { m.EXPECT().ListWorkloads().Return([]string{"be", "db", "fe", "worker"}, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{ + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{ mockFe, mockBe, mockDb, @@ -1188,7 +1189,7 @@ func Test_deployOpts_getDeploymentOrder(t *testing.T) { m.EXPECT().ListWorkloads().Return([]string{"be", "db", "fe", "worker"}, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{ + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{ mockFe, mockBe, mockDb, @@ -1204,7 +1205,7 @@ func Test_deployOpts_getDeploymentOrder(t *testing.T) { m.EXPECT().ListWorkloads().Return([]string{"be", "db", "fe", "worker"}, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{ + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{ mockFe, mockBe, mockDb, @@ -1220,7 +1221,7 @@ func Test_deployOpts_getDeploymentOrder(t *testing.T) { m.EXPECT().ListWorkloads().Return([]string{"be", "db", "fe", "worker"}, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{ + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{ mockFe, mockBe, mockDb, @@ -1243,7 +1244,7 @@ func Test_deployOpts_getDeploymentOrder(t *testing.T) { m.EXPECT().ListWorkloads().Return([]string{"be", "db", "fe", "worker"}, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListWorkloads("app").Return([]*config.Workload{ + m.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{ { App: "app", Name: "fe", @@ -1289,7 +1290,7 @@ func Test_deployOpts_getDeploymentOrder(t *testing.T) { store: mockStore, ws: mockWs, } - got, err := o.getDeploymentOrder() + got, err := o.getDeploymentOrder(ctx) if tt.wantErr != "" { require.EqualError(t, err, tt.wantErr) } else { diff --git a/internal/pkg/cli/env_delete.go b/internal/pkg/cli/env_delete.go index 1150c5b844b..890c54039f1 100644 --- a/internal/pkg/cli/env_delete.go +++ b/internal/pkg/cli/env_delete.go @@ -122,7 +122,7 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { prompt: prompter, initRuntimeClients: func(o *deleteEnvOpts) error { - env, err := o.getEnvConfig() + env, err := o.getEnvConfig(context.Background()) if err != nil { return err } @@ -146,7 +146,7 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { // Validate returns an error if the individual user inputs are invalid. func (o *deleteEnvOpts) Validate() error { if o.name != "" { - if err := o.validateEnvName(); err != nil { + if err := o.validateEnvName(context.Background()); err != nil { return err } } @@ -154,11 +154,11 @@ func (o *deleteEnvOpts) Validate() error { } // Ask prompts for fields that are required but not passed in. -func (o *deleteEnvOpts) Ask() error { - if err := o.askAppName(); err != nil { +func (o *deleteEnvOpts) Ask(ctx context.Context) error { + if err := o.askAppName(ctx); err != nil { return err } - if err := o.askEnvName(); err != nil { + if err := o.askEnvName(ctx); err != nil { return err } if o.skipConfirmation { @@ -181,7 +181,7 @@ func (o *deleteEnvOpts) Ask() error { // 4. Deleting the parameter from the SSM store. // The environment is removed from the store only if other delete operations succeed. // Execute assumes that Validate is invoked first. -func (o *deleteEnvOpts) Execute() error { +func (o *deleteEnvOpts) Execute(ctx context.Context) error { if err := o.initRuntimeClients(o); err != nil { return err } @@ -194,7 +194,7 @@ func (o *deleteEnvOpts) Execute() error { } o.prog.Start(fmt.Sprintf(fmtRetainEnvRolesStart, o.name)) - if err := o.ensureRolesAreRetained(); err != nil { + if err := o.ensureRolesAreRetained(ctx); err != nil { o.prog.Stop(log.Serrorf(fmtRetainEnvRolesFailed, o.name)) return err } @@ -211,25 +211,25 @@ func (o *deleteEnvOpts) Execute() error { } // DeleteStack streams the deletion events; we don't need a spinner over top of it. - if err := o.deleteStack(); err != nil { + if err := o.deleteStack(ctx); err != nil { return err } // Un-delegate DNS and optionally delete stackset instance. o.prog.Start("Cleaning up app-level resources and permissions\n") - if err := o.cleanUpAppResources(); err != nil { + if err := o.cleanUpAppResources(ctx); err != nil { o.prog.Stop(log.Serrorf("Failed to remove environment resources from app %q\n", o.appName)) return err } o.prog.Stop(log.Ssuccessf("Cleaned up app-level resources for the %q environment\n", o.name)) o.prog.Start(fmt.Sprintf(fmtDeleteEnvStart, o.name, o.appName)) - if err := o.tryDeleteRoles(); err != nil { + if err := o.tryDeleteRoles(ctx); err != nil { o.prog.Stop(log.Serrorf(fmtDeleteEnvIAMFailed, o.name, o.appName)) return err } // Only remove from SSM if the stack and roles were deleted. Otherwise, the command will error when re-run. - if err := o.deleteFromStore(); err != nil { + if err := o.deleteFromStore(ctx); err != nil { o.prog.Stop(log.Serrorf(fmtDeleteEnvSSMFailed, o.name, o.appName)) return err } @@ -242,19 +242,19 @@ func (o *deleteEnvOpts) RecommendActions() error { return nil } -func (o *deleteEnvOpts) validateEnvName() error { - if _, err := o.getEnvConfig(); err != nil { +func (o *deleteEnvOpts) validateEnvName(ctx context.Context) error { + if _, err := o.getEnvConfig(ctx); err != nil { return err } return nil } -func (o *deleteEnvOpts) askAppName() error { +func (o *deleteEnvOpts) askAppName(ctx context.Context) error { if o.appName != "" { return nil } - app, err := o.sel.Application(envDeleteAppNamePrompt, envDeleteAppNameHelpPrompt) + app, err := o.sel.Application(ctx, envDeleteAppNamePrompt, envDeleteAppNameHelpPrompt) if err != nil { return fmt.Errorf("ask for application: %w", err) } @@ -262,11 +262,11 @@ func (o *deleteEnvOpts) askAppName() error { return nil } -func (o *deleteEnvOpts) askEnvName() error { +func (o *deleteEnvOpts) askEnvName(ctx context.Context) error { if o.name != "" { return nil } - env, err := o.sel.Environment(envDeleteNamePrompt, "", o.appName) + env, err := o.sel.Environment(ctx, envDeleteNamePrompt, "", o.appName) if err != nil { return fmt.Errorf("select environment to delete: %w", err) } @@ -341,7 +341,7 @@ func (o *deleteEnvOpts) validateNoDependencyPipelines() error { // In earlier versions of the CLI, pre-commit 7e5428a, environment stacks were created without these roles retained. // In case we encounter a legacy stack, we need to first update the stack to make sure these roles are retained and then // proceed with the regular flow. -func (o *deleteEnvOpts) ensureRolesAreRetained() error { +func (o *deleteEnvOpts) ensureRolesAreRetained(ctx context.Context) error { body, err := o.deployer.Template(stack.NameForEnv(o.appName, o.name)) if err != nil { var stackDoesNotExist *awscfn.ErrStackNotFound @@ -395,7 +395,7 @@ func (o *deleteEnvOpts) ensureRolesAreRetained() error { newBody = parts[0] + " EnvironmentManagerRole:\n DeletionPolicy: Retain\n" + parts[1] } - env, err := o.getEnvConfig() + env, err := o.getEnvConfig(ctx) if err != nil { return err } @@ -478,8 +478,8 @@ func (o *deleteEnvOpts) emptyBuckets() error { } // deleteStack returns nil if the stack was deleted successfully. Otherwise, returns the error. -func (o *deleteEnvOpts) deleteStack() error { - env, err := o.getEnvConfig() +func (o *deleteEnvOpts) deleteStack(ctx context.Context) error { + env, err := o.getEnvConfig(ctx) if err != nil { return err } @@ -489,17 +489,17 @@ func (o *deleteEnvOpts) deleteStack() error { return nil } -func (o *deleteEnvOpts) cleanUpAppResources() error { +func (o *deleteEnvOpts) cleanUpAppResources(ctx context.Context) error { // Get list of environments and check if there are any other environments in this account OR region. - envs, err := o.store.ListEnvironments(o.appName) + envs, err := o.store.ListEnvironments(ctx, o.appName) if err != nil { return err } - currentEnv, err := o.getEnvConfig() + currentEnv, err := o.getEnvConfig(ctx) if err != nil { return err } - app, err := o.getAppConfig() + app, err := o.getAppConfig(ctx) if err != nil { return err } @@ -522,8 +522,8 @@ func (o *deleteEnvOpts) cleanUpAppResources() error { // This error occurs because to delete a role you have to first remove all of its policies, so the role loses // permission to delete itself and then attempts to delete itself. We think that due to eventual consistency this // operation succeeds most of the time but on occasions we have observed it to fail. -func (o *deleteEnvOpts) tryDeleteRoles() error { - env, err := o.getEnvConfig() +func (o *deleteEnvOpts) tryDeleteRoles(ctx context.Context) error { + env, err := o.getEnvConfig(ctx) if err != nil { return err } @@ -532,19 +532,19 @@ func (o *deleteEnvOpts) tryDeleteRoles() error { return nil } -func (o *deleteEnvOpts) deleteFromStore() error { - if err := o.store.DeleteEnvironment(o.appName, o.name); err != nil { +func (o *deleteEnvOpts) deleteFromStore(ctx context.Context) error { + if err := o.store.DeleteEnvironment(ctx, o.appName, o.name); err != nil { return fmt.Errorf("delete environment %s configuration from application %s", o.name, o.appName) } return nil } -func (o *deleteEnvOpts) getEnvConfig() (*config.Environment, error) { +func (o *deleteEnvOpts) getEnvConfig(ctx context.Context) (*config.Environment, error) { if o.envConfig != nil { // Already fetched once, return. return o.envConfig, nil } - env, err := o.store.GetEnvironment(o.appName, o.name) + env, err := o.store.GetEnvironment(ctx, o.appName, o.name) if err != nil { return nil, fmt.Errorf("get environment %s configuration from app %s: %v", o.name, o.appName, err) } @@ -552,12 +552,12 @@ func (o *deleteEnvOpts) getEnvConfig() (*config.Environment, error) { return env, nil } -func (o *deleteEnvOpts) getAppConfig() (*config.Application, error) { +func (o *deleteEnvOpts) getAppConfig(ctx context.Context) (*config.Application, error) { if o.appConfig != nil { // Already fetched; return. return o.appConfig, nil } - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { return nil, fmt.Errorf("get application %q configuration: %w", o.appName, err) } @@ -582,7 +582,7 @@ func buildEnvDeleteCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/env_delete_test.go b/internal/pkg/cli/env_delete_test.go index 1d3503fec68..b1b651a7df1 100644 --- a/internal/pkg/cli/env_delete_test.go +++ b/internal/pkg/cli/env_delete_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -45,7 +46,7 @@ func TestDeleteEnvOpts_Validate(t *testing.T) { inEnv: testEnvName, mockStore: func(ctrl *gomock.Controller) *mocks.MockenvironmentStore { envStore := mocks.NewMockenvironmentStore(ctrl) - envStore.EXPECT().GetEnvironment(testAppName, testEnvName).Return(nil, errors.New("some error")) + envStore.EXPECT().GetEnvironment(ctx, testAppName, testEnvName).Return(nil, errors.New("some error")) return envStore }, wantedError: errors.New("get environment test configuration from app phonetool: some error"), @@ -55,7 +56,7 @@ func TestDeleteEnvOpts_Validate(t *testing.T) { inEnv: testEnvName, mockStore: func(ctrl *gomock.Controller) *mocks.MockenvironmentStore { envStore := mocks.NewMockenvironmentStore(ctrl) - envStore.EXPECT().GetEnvironment(testAppName, testEnvName).Return(&config.Environment{}, nil) + envStore.EXPECT().GetEnvironment(ctx, testAppName, testEnvName).Return(&config.Environment{}, nil) return envStore }, }, @@ -104,9 +105,9 @@ func TestDeleteEnvOpts_Ask(t *testing.T) { inSkipConfirmation: false, mockDependencies: func(ctrl *gomock.Controller, o *deleteEnvOpts) { mockSelector := mocks.NewMockconfigSelector(ctrl) - mockSelector.EXPECT().Application(envDeleteAppNamePrompt, envDeleteAppNameHelpPrompt, gomock.Any()). + mockSelector.EXPECT().Application(ctx, envDeleteAppNamePrompt, envDeleteAppNameHelpPrompt, gomock.Any()). Return(testApp, nil) - mockSelector.EXPECT().Environment(envDeleteNamePrompt, "", testApp).Return(testEnv, nil) + mockSelector.EXPECT().Environment(ctx, envDeleteNamePrompt, "", testApp).Return(testEnv, nil) mockPrompter := mocks.NewMockprompter(ctrl) mockPrompter.EXPECT().Confirm(fmt.Sprintf(fmtDeleteEnvPrompt, testEnv, testApp), gomock.Any(), gomock.Any()).Return(true, nil) @@ -119,7 +120,7 @@ func TestDeleteEnvOpts_Ask(t *testing.T) { "error if fail to select applications": { mockDependencies: func(ctrl *gomock.Controller, o *deleteEnvOpts) { mockSelector := mocks.NewMockconfigSelector(ctrl) - mockSelector.EXPECT().Application(envDeleteAppNamePrompt, envDeleteAppNameHelpPrompt, gomock.Any()). + mockSelector.EXPECT().Application(ctx, envDeleteAppNamePrompt, envDeleteAppNameHelpPrompt, gomock.Any()). Return("", errors.New("some error")) o.sel = mockSelector @@ -157,7 +158,7 @@ func TestDeleteEnvOpts_Ask(t *testing.T) { tc.mockDependencies(ctrl, opts) // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError == nil { @@ -422,7 +423,7 @@ Resources: deployer.EXPECT().DeleteEnvironment("phonetool", "test", "execARN").Return(nil) store := mocks.NewMockenvironmentStore(ctrl) - store.EXPECT().ListEnvironments("phonetool").Return([]*config.Environment{ + store.EXPECT().ListEnvironments(ctx, "phonetool").Return([]*config.Environment{ &mockEnv, { Name: "prod", @@ -430,8 +431,8 @@ Resources: AccountID: "5678", }, }, nil) - store.EXPECT().GetEnvironment("phonetool", "test").Return(&mockEnv, nil) - store.EXPECT().GetApplication("phonetool").Return(app, nil) + store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&mockEnv, nil) + store.EXPECT().GetApplication(ctx, "phonetool").Return(app, nil) envDeleter := mocks.NewMockenvDeleterFromApp(ctrl) envDeleter.EXPECT().RemoveEnvFromApp(&cloudformation.RemoveEnvFromAppOpts{ @@ -508,7 +509,7 @@ Resources: deployer.EXPECT().DeleteEnvironment("phonetool", "test", "execARN").Return(nil) store := mocks.NewMockenvironmentStore(ctrl) - store.EXPECT().ListEnvironments("phonetool").Return([]*config.Environment{ + store.EXPECT().ListEnvironments(ctx, "phonetool").Return([]*config.Environment{ &mockEnv, { Name: "prod", @@ -516,8 +517,8 @@ Resources: AccountID: "5678", }, }, nil) - store.EXPECT().GetEnvironment("phonetool", "test").Return(&mockEnv, nil) - store.EXPECT().GetApplication("phonetool").Return(app, nil) + store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&mockEnv, nil) + store.EXPECT().GetApplication(ctx, "phonetool").Return(app, nil) envDeleter := mocks.NewMockenvDeleterFromApp(ctrl) envDeleter.EXPECT().RemoveEnvFromApp(&cloudformation.RemoveEnvFromAppOpts{ @@ -537,7 +538,7 @@ Resources: iam.EXPECT().DeleteRole(mockEnv.ExecutionRoleARN).Return(nil) iam.EXPECT().DeleteRole(mockEnv.ManagerRoleARN).Return(nil) - store.EXPECT().DeleteEnvironment(mockEnv.App, mockEnv.Name).Return(nil) + store.EXPECT().DeleteEnvironment(ctx, mockEnv.App, mockEnv.Name).Return(nil) return &deleteEnvOpts{ deleteEnvVars: deleteEnvVars{ @@ -596,7 +597,7 @@ Resources: deployer.EXPECT().DeleteEnvironment("phonetool", "test", "execARN").Return(nil) store := mocks.NewMockenvironmentStore(ctrl) - store.EXPECT().ListEnvironments("phonetool").Return([]*config.Environment{ + store.EXPECT().ListEnvironments(ctx, "phonetool").Return([]*config.Environment{ &mockEnv, { Name: "prod", @@ -604,8 +605,8 @@ Resources: AccountID: "5678", }, }, nil) - store.EXPECT().GetEnvironment("phonetool", "test").Return(&mockEnv, nil) - store.EXPECT().GetApplication("phonetool").Return(app, nil) + store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&mockEnv, nil) + store.EXPECT().GetApplication(ctx, "phonetool").Return(app, nil) envDeleter := mocks.NewMockenvDeleterFromApp(ctrl) envDeleter.EXPECT().RemoveEnvFromApp(&cloudformation.RemoveEnvFromAppOpts{ @@ -625,7 +626,7 @@ Resources: iam.EXPECT().DeleteRole(mockEnv.ExecutionRoleARN).Return(nil) iam.EXPECT().DeleteRole(mockEnv.ManagerRoleARN).Return(nil) - store.EXPECT().DeleteEnvironment(mockEnv.App, mockEnv.Name).Return(nil) + store.EXPECT().DeleteEnvironment(ctx, mockEnv.App, mockEnv.Name).Return(nil) return &deleteEnvOpts{ deleteEnvVars: deleteEnvVars{ @@ -719,7 +720,7 @@ Resources: deployer.EXPECT().DeleteEnvironment("phonetool", "test", "execARN").Return(nil) store := mocks.NewMockenvironmentStore(ctrl) - store.EXPECT().ListEnvironments("phonetool").Return([]*config.Environment{ + store.EXPECT().ListEnvironments(ctx, "phonetool").Return([]*config.Environment{ &mockEnv, { Name: "prod", @@ -727,8 +728,8 @@ Resources: AccountID: "5678", }, }, nil) - store.EXPECT().GetEnvironment("phonetool", "test").Return(&mockEnv, nil) - store.EXPECT().GetApplication("phonetool").Return(app, nil) + store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&mockEnv, nil) + store.EXPECT().GetApplication(ctx, "phonetool").Return(app, nil) envDeleter := mocks.NewMockenvDeleterFromApp(ctrl) envDeleter.EXPECT().RemoveEnvFromApp(&cloudformation.RemoveEnvFromAppOpts{ @@ -748,7 +749,7 @@ Resources: iam.EXPECT().DeleteRole(mockEnv.ExecutionRoleARN).Return(nil) iam.EXPECT().DeleteRole(mockEnv.ManagerRoleARN).Return(nil) - store.EXPECT().DeleteEnvironment(mockEnv.App, mockEnv.Name).Return(nil) + store.EXPECT().DeleteEnvironment(ctx, mockEnv.App, mockEnv.Name).Return(nil) return &deleteEnvOpts{ deleteEnvVars: deleteEnvVars{ @@ -778,7 +779,7 @@ Resources: opts := tc.given(t, ctrl) // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/env_deploy.go b/internal/pkg/cli/env_deploy.go index efc999d1284..f9e0a7a706a 100644 --- a/internal/pkg/cli/env_deploy.go +++ b/internal/pkg/cli/env_deploy.go @@ -59,8 +59,8 @@ type deployEnvOpts struct { ws wsEnvironmentReader identity identityService newInterpolator func(app, env string) interpolator - newEnvVersionGetter func(appName, envName string) (versionGetter, error) - newEnvDeployer func() (envDeployer, error) + newEnvVersionGetter func(ctx context.Context, appName, envName string) (versionGetter, error) + newEnvDeployer func(ctx context.Context) (envDeployer, error) // Cached variables. targetApp *config.Application @@ -89,8 +89,8 @@ func newEnvDeployOpts(vars deployEnvVars) (*deployEnvOpts, error) { store: store, sessionProvider: sessProvider, sel: selector.NewLocalEnvironmentSelector(prompter, store, ws), - newEnvVersionGetter: func(appName, envName string) (versionGetter, error) { - return describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + newEnvVersionGetter: func(ctx context.Context, appName, envName string) (versionGetter, error) { + return describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: appName, Env: envName, ConfigStore: store, @@ -104,18 +104,18 @@ func newEnvDeployOpts(vars deployEnvVars) (*deployEnvOpts, error) { templateVersion: version.LatestTemplateVersion(), newInterpolator: newManifestInterpolator, } - opts.newEnvDeployer = func() (envDeployer, error) { - return newEnvDeployer(opts, ws) + opts.newEnvDeployer = func(ctx context.Context) (envDeployer, error) { + return newEnvDeployer(ctx, opts, ws) } return opts, nil } -func newEnvDeployer(opts *deployEnvOpts, ws deploy.WorkspaceAddonsReaderPathGetter) (envDeployer, error) { - app, err := opts.cachedTargetApp() +func newEnvDeployer(ctx context.Context, opts *deployEnvOpts, ws deploy.WorkspaceAddonsReaderPathGetter) (envDeployer, error) { + app, err := opts.cachedTargetApp(ctx) if err != nil { return nil, err } - env, err := opts.cachedTargetEnv() + env, err := opts.cachedTargetEnv(ctx) if err != nil { return nil, err } @@ -124,6 +124,7 @@ func newEnvDeployer(opts *deployEnvOpts, ws deploy.WorkspaceAddonsReaderPathGett return nil, err } return deploy.NewEnvDeployer(&deploy.NewEnvDeployerInput{ + Ctx: ctx, App: app, Env: env, SessionProvider: opts.sessionProvider, @@ -139,15 +140,15 @@ func (o *deployEnvOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *deployEnvOpts) Ask() error { +func (o *deployEnvOpts) Ask(ctx context.Context) error { if o.appName == "" { // NOTE: This command is required to be executed under a workspace. We don't prompt for it. return errNoAppInWorkspace } - if _, err := o.cachedTargetApp(); err != nil { + if _, err := o.cachedTargetApp(ctx); err != nil { return err } - return o.validateOrAskEnvName() + return o.validateOrAskEnvName(ctx) } func validateEnvVersion(vg versionGetter, name, templateVersion string) error { @@ -170,9 +171,9 @@ func validateEnvVersion(vg versionGetter, name, templateVersion string) error { } // Execute deploys an environment given a manifest. -func (o *deployEnvOpts) Execute() error { +func (o *deployEnvOpts) Execute(ctx context.Context) error { if !o.allowEnvDowngrade { - envVersionGetter, err := o.newEnvVersionGetter(o.appName, o.name) + envVersionGetter, err := o.newEnvVersionGetter(ctx, o.appName, o.name) if err != nil { return err } @@ -184,11 +185,11 @@ func (o *deployEnvOpts) Execute() error { if err != nil { return err } - caller, err := o.identity.Get() + caller, err := o.identity.Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } - deployer, err := o.newEnvDeployer() + deployer, err := o.newEnvDeployer(ctx) if err != nil { return err } @@ -302,11 +303,11 @@ func (o *deployEnvOpts) showDiffAndConfirmDeployment(deployer envDeployer, input return contd, nil } -func (o *deployEnvOpts) validateOrAskEnvName() error { +func (o *deployEnvOpts) validateOrAskEnvName(ctx context.Context) error { if o.name != "" { - return o.validateEnvName() + return o.validateEnvName(ctx) } - name, err := o.sel.LocalEnvironment("Select an environment manifest from your workspace", "") + name, err := o.sel.LocalEnvironment(ctx, "Select an environment manifest from your workspace", "") if err != nil { var pathErr *os.PathError if errors.As(err, &pathErr) || errors.Is(err, selector.ErrLocalEnvsNotFound) { @@ -318,7 +319,7 @@ func (o *deployEnvOpts) validateOrAskEnvName() error { return nil } -func (o *deployEnvOpts) validateEnvName() error { +func (o *deployEnvOpts) validateEnvName(ctx context.Context) error { localEnvs, err := o.ws.ListEnvironments() if err != nil { o.logManifestSuggestion(o.name) @@ -328,7 +329,7 @@ func (o *deployEnvOpts) validateEnvName() error { if o.name != localEnv { continue } - if _, err := o.cachedTargetEnv(); err != nil { + if _, err := o.cachedTargetEnv(ctx); err != nil { log.Errorf("It seems like environment %s is not added in application %s yet. Have you run %s?\n", o.name, o.appName, color.HighlightCode("copilot env init")) return err @@ -339,9 +340,9 @@ func (o *deployEnvOpts) validateEnvName() error { return fmt.Errorf("environment manifest for %q is not found", o.name) } -func (o *deployEnvOpts) cachedTargetEnv() (*config.Environment, error) { +func (o *deployEnvOpts) cachedTargetEnv(ctx context.Context) (*config.Environment, error) { if o.targetEnv == nil { - env, err := o.store.GetEnvironment(o.appName, o.name) + env, err := o.store.GetEnvironment(ctx, o.appName, o.name) if err != nil { return nil, fmt.Errorf("get environment %s in application %s: %w", o.name, o.appName, err) } @@ -350,9 +351,9 @@ func (o *deployEnvOpts) cachedTargetEnv() (*config.Environment, error) { return o.targetEnv, nil } -func (o *deployEnvOpts) cachedTargetApp() (*config.Application, error) { +func (o *deployEnvOpts) cachedTargetApp(ctx context.Context) (*config.Application, error) { if o.targetApp == nil { - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { return nil, fmt.Errorf("get application %s: %w", o.appName, err) } @@ -390,7 +391,7 @@ Deploy an environment named "test". if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/env_deploy_test.go b/internal/pkg/cli/env_deploy_test.go index e9dd21c118e..c316bbe88cf 100644 --- a/internal/pkg/cli/env_deploy_test.go +++ b/internal/pkg/cli/env_deploy_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -38,14 +39,14 @@ func TestDeployEnvOpts_Ask(t *testing.T) { inAppName: "mockApp", inName: "mockEnv", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "mockApp").Return(nil, errors.New("some error")) }, wantedError: errors.New("get application mockApp: some error"), }, "error if no app in workspace": { inName: "mockEnv", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Times(0) + m.store.EXPECT().GetApplication(ctx, "mockApp").Times(0) }, wantedError: errNoAppInWorkspace, }, @@ -53,7 +54,7 @@ func TestDeployEnvOpts_Ask(t *testing.T) { inAppName: "mockApp", inName: "mockEnv", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Return(&config.Application{}, nil) + m.store.EXPECT().GetApplication(ctx, "mockApp").Return(&config.Application{}, nil) m.ws.EXPECT().ListEnvironments().Return(nil, errors.New("some error")) }, wantedError: errors.New("list environments in workspace: some error"), @@ -62,7 +63,7 @@ func TestDeployEnvOpts_Ask(t *testing.T) { inAppName: "mockApp", inName: "mockEnv", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Return(&config.Application{}, nil) + m.store.EXPECT().GetApplication(ctx, "mockApp").Return(&config.Application{}, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"otherEnv"}, nil) }, wantedError: errors.New(`environment manifest for "mockEnv" is not found`), @@ -71,18 +72,18 @@ func TestDeployEnvOpts_Ask(t *testing.T) { inAppName: "mockApp", inName: "mockEnv", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Return(&config.Application{}, nil) + m.store.EXPECT().GetApplication(ctx, "mockApp").Return(&config.Application{}, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv"}, nil) - m.store.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(nil, errors.New("some error")) + m.store.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(nil, errors.New("some error")) }, wantedError: errors.New("get environment mockEnv in application mockApp: some error"), }, "fail to ask for an env from workspace": { inAppName: "mockApp", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Return(&config.Application{}, nil) - m.store.EXPECT().GetEnvironment("mockApp", "mockEnv").AnyTimes() - m.sel.EXPECT().LocalEnvironment(gomock.Any(), gomock.Any()).Return("", errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "mockApp").Return(&config.Application{}, nil) + m.store.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").AnyTimes() + m.sel.EXPECT().LocalEnvironment(ctx, gomock.Any(), gomock.Any()).Return("", errors.New("some error")) }, wantedError: errors.New("select environment: some error"), }, @@ -90,20 +91,20 @@ func TestDeployEnvOpts_Ask(t *testing.T) { inAppName: "mockApp", inName: "mockEnv", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Return(&config.Application{}, nil) + m.store.EXPECT().GetApplication(ctx, "mockApp").Return(&config.Application{}, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv"}, nil) - m.store.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{}, nil) - m.sel.EXPECT().LocalEnvironment(gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(&config.Environment{}, nil) + m.sel.EXPECT().LocalEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) }, wantedEnvName: "mockEnv", }, "ask for env": { inAppName: "mockApp", setUpMocks: func(m *deployEnvAskMocks) { - m.store.EXPECT().GetApplication("mockApp").Return(&config.Application{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, "mockApp").Return(&config.Application{}, nil) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) m.ws.EXPECT().ListEnvironments().Times(0) - m.sel.EXPECT().LocalEnvironment(gomock.Any(), gomock.Any()).Return("mockEnv", nil) + m.sel.EXPECT().LocalEnvironment(ctx, gomock.Any(), gomock.Any()).Return("mockEnv", nil) }, wantedEnvName: "mockEnv", }, @@ -128,7 +129,7 @@ func TestDeployEnvOpts_Ask(t *testing.T) { sel: m.sel, store: m.store, } - gotErr := opts.Ask() + gotErr := opts.Ask(context.Background()) if tc.wantedError != nil { require.EqualError(t, gotErr, tc.wantedError.Error()) } else { @@ -204,7 +205,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{}, errors.New("some error")) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{}, errors.New("some error")) }, wantedErr: errors.New("get identity: some error"), }, @@ -213,7 +214,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\ncdn: true\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\ncdn: true\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(errors.New("mock error")) @@ -225,7 +226,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -239,7 +240,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -254,7 +255,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -270,7 +271,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -287,7 +288,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -304,7 +305,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -321,7 +322,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -338,7 +339,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -357,7 +358,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Times(0) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -373,7 +374,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(mockEnvVersion, nil) m.ws.EXPECT().ReadEnvironmentManifest(gomock.Any()).Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate(gomock.Any()).Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -389,7 +390,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { m.envVersionGetter.EXPECT().Version().Return(version.EnvTemplateBootstrap, nil) m.ws.EXPECT().ReadEnvironmentManifest("mockEnv").Return([]byte("name: mockEnv\ntype: Environment\n"), nil) m.interpolator.EXPECT().Interpolate("name: mockEnv\ntype: Environment\n").Return("name: mockEnv\ntype: Environment\n", nil) - m.identity.EXPECT().Get().Return(identity.Caller{ + m.identity.EXPECT().Get(ctx).Return(identity.Caller{ RootUserARN: "mockRootUserARN", }, nil) m.deployer.EXPECT().Validate(gomock.Any()).Return(nil) @@ -438,10 +439,10 @@ func TestDeployEnvOpts_Execute(t *testing.T) { }, ws: m.ws, identity: m.identity, - newEnvDeployer: func() (envDeployer, error) { + newEnvDeployer: func(_ context.Context) (envDeployer, error) { return m.deployer, nil }, - newEnvVersionGetter: func(appName, envName string) (versionGetter, error) { + newEnvVersionGetter: func(_ context.Context, appName, envName string) (versionGetter, error) { return m.envVersionGetter, nil }, templateVersion: mockCurrVersion, @@ -457,7 +458,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { Name: "mockEnv", }, } - err := opts.Execute() + err := opts.Execute(context.Background()) if tc.wantedErr != nil { require.Contains(t, err.Error(), tc.wantedErr.Error()) } else { diff --git a/internal/pkg/cli/env_init.go b/internal/pkg/cli/env_init.go index 6d0ac314cad..1ffe47d1b9c 100644 --- a/internal/pkg/cli/env_init.go +++ b/internal/pkg/cli/env_init.go @@ -33,6 +33,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" deploycfn "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" + "github.com/aproint/copilot-cli/internal/pkg/metadata" "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" @@ -242,7 +243,7 @@ func (o *initEnvOpts) Validate() error { if err := validateEnvironmentName(o.name); err != nil { return err } - if err := o.validateDuplicateEnv(); err != nil { + if err := o.validateDuplicateEnv(context.Background()); err != nil { return err } } @@ -254,8 +255,8 @@ func (o *initEnvOpts) Validate() error { } // Ask asks for fields that are required but not passed in. -func (o *initEnvOpts) Ask() error { - if err := o.askEnvName(); err != nil { +func (o *initEnvOpts) Ask(ctx context.Context) error { + if err := o.askEnvName(ctx); err != nil { return err } if err := o.askEnvSession(); err != nil { @@ -268,7 +269,7 @@ func (o *initEnvOpts) Ask() error { } // Execute deploys a new environment with CloudFormation and adds it to SSM. -func (o *initEnvOpts) Execute() error { +func (o *initEnvOpts) Execute(ctx context.Context) error { if err := o.initRuntimeClients(); err != nil { return err } @@ -281,12 +282,12 @@ func (o *initEnvOpts) Execute() error { return err } } - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { // Ensure the app actually exists before we write the manifest. return err } - envCaller, err := o.envIdentity.Get() + envCaller, err := o.envIdentity.Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } @@ -311,6 +312,9 @@ func (o *initEnvOpts) Execute() error { _ = o.iam.CreateECSServiceLinkedRole() // 4. Add the stack set instance to the app stackset. + if err := ctx.Err(); err != nil { + return err + } if err := o.addToStackset(&deploycfn.AddEnvToAppOpts{ App: app, EnvName: o.name, @@ -321,17 +325,22 @@ func (o *initEnvOpts) Execute() error { } // 5. Start creating the CloudFormation stack for the environment. - if err := o.deployEnv(app); err != nil { + if err := o.deployEnv(ctx, app); err != nil { return err } // 6. Store the environment in SSM with information about the deployed bootstrap roles. - env, err := o.envDeployer.GetEnvironment(o.appName, o.name) + if ctx.Err() != nil { + log.Warningln(metadata.CommitAfterCancellationWarning) + } + commitCtx, cancel := metadata.CommitContext(ctx) + defer cancel() + env, err := o.envDeployer.GetEnvironment(commitCtx, o.appName, o.name) if err != nil { - return fmt.Errorf("get environment struct for %s: %w", o.name, err) + return metadata.NewCommitError("environment infrastructure deployment", fmt.Errorf("get environment struct for %s: %w", o.name, err)) } - if err := o.store.CreateEnvironment(env); err != nil { - return fmt.Errorf("store environment: %w", err) + if err := o.store.CreateEnvironment(commitCtx, env); err != nil { + return metadata.NewCommitError("environment infrastructure deployment", fmt.Errorf("store environment: %w", err)) } log.Successf("Provisioned bootstrap resources for environment %s in region %s under application %s.\n", color.HighlightUserInput(env.Name), color.Emphasize(env.Region), color.HighlightUserInput(env.App)) @@ -397,7 +406,7 @@ For default config without subnet placement specification, Copilot will place th return nil } -func (o *initEnvOpts) askEnvName() error { +func (o *initEnvOpts) askEnvName(ctx context.Context) error { if o.name != "" { return nil } @@ -407,7 +416,7 @@ func (o *initEnvOpts) askEnvName() error { return fmt.Errorf("get environment name: %w", err) } o.name = envName - return o.validateDuplicateEnv() + return o.validateDuplicateEnv(ctx) } func (o *initEnvOpts) askEnvSession() error { @@ -659,8 +668,8 @@ func (o *initEnvOpts) askAZs() ([]string, error) { return selected, nil } -func (o *initEnvOpts) validateDuplicateEnv() error { - _, err := o.store.GetEnvironment(o.appName, o.name) +func (o *initEnvOpts) validateDuplicateEnv(ctx context.Context) error { + _, err := o.store.GetEnvironment(ctx, o.appName, o.name) if err == nil { // Skip error if environment already exists in workspace envs, err := o.envLister.ListEnvironments() @@ -718,7 +727,7 @@ func (o *initEnvOpts) adjustVPCConfig() *config.AdjustVPC { } } -func (o *initEnvOpts) deployEnv(app *config.Application) error { +func (o *initEnvOpts) deployEnv(ctx context.Context, app *config.Application) error { envRegion := o.cfg.Region resources, err := o.appCFN.GetAppResourcesByRegion(app, envRegion) if err != nil { @@ -734,7 +743,7 @@ func (o *initEnvOpts) deployEnv(app *config.Application) error { } artifactBucketARN := s3.FormatARN(partition.ID(), resources.S3Bucket) - caller, err := o.identity.Get() + caller, err := o.identity.Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } @@ -944,7 +953,7 @@ func buildEnvInitCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/env_init_test.go b/internal/pkg/cli/env_init_test.go index 8f8c5b7aaf5..0b9ab1381da 100644 --- a/internal/pkg/cli/env_init_test.go +++ b/internal/pkg/cli/env_init_test.go @@ -4,10 +4,12 @@ package cli import ( + "context" "errors" "fmt" "net" "testing" + "time" "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" "github.com/aproint/copilot-cli/internal/pkg/workspace" @@ -20,6 +22,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" deploycfn "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" + "github.com/aproint/copilot-cli/internal/pkg/metadata" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" @@ -69,8 +72,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { inAppName: "phonetool", setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test-pdx").Return(nil, &config.ErrNoSuchEnvironment{}) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test-pdx").Return(nil, &config.ErrNoSuchEnvironment{}) }, }, "fail if command not run under a workspace": { @@ -88,7 +91,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, errors.New("some error")) }, wantedErrMsg: "get application phonetool configuration: some error", }, @@ -98,7 +101,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, wantedErrMsg: fmt.Sprintf("environment name 123env is invalid: %s", errBasicNameRegexNotMatched), }, @@ -108,8 +111,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test-pdx").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test-pdx").Return(nil, nil) m.envLister.EXPECT().ListEnvironments().Return([]string{}, nil) }, wantedErrMsg: "environment test-pdx already exists", @@ -120,8 +123,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test-pdx").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test-pdx").Return(nil, nil) m.envLister.EXPECT().ListEnvironments().Return([]string{"test-pdx"}, nil) }, }, @@ -139,8 +142,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test-pdx").Return(nil, &config.ErrNoSuchEnvironment{}) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test-pdx").Return(nil, &config.ErrNoSuchEnvironment{}) }, wantedErrMsg: "cannot specify both import vpc flags and configure vpc flags", @@ -153,8 +156,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { inVPCID: "mockID", setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test-pdx").Return(nil, &config.ErrNoSuchEnvironment{}) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test-pdx").Return(nil, &config.ErrNoSuchEnvironment{}) }, wantedErrMsg: fmt.Sprintf("cannot import or configure vpc if --%s is set", defaultConfigFlag), }, @@ -165,8 +168,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { inAccessKeyID: "AKIAIOSFODNN7EXAMPLE", setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{}) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{}) }, wantedErrMsg: "cannot specify both --profile and --aws-access-key-id", }, @@ -177,8 +180,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { inSecretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{}) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{}) }, wantedErrMsg: "cannot specify both --profile and --aws-secret-access-key", }, @@ -189,8 +192,8 @@ func TestInitEnvOpts_Validate(t *testing.T) { inSessionToken: "verylongtoken", setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{}) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{}) }, wantedErrMsg: "cannot specify both --profile and --aws-session-token", }, @@ -200,7 +203,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inPrivateIDs: []string{"mockID"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, wantedErrMsg: "at least two private subnets must be imported", }, @@ -208,7 +211,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inAZs: []string{"us-east-1a"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, wantedErrMsg: "at least two availability zones must be provided to enable Load Balancing", }, @@ -217,7 +220,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inPrivateIDs: []string{"mockID", "anotherMockID"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, wantedErrMsg: "at least two public subnets must be imported to enable Load Balancing", }, @@ -227,7 +230,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inPrivateIDs: []string{"mockID", "anotherMockID", "yetAnotherMockID"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, }, "valid VPC resource import (3 public, 2 private)": { @@ -236,7 +239,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inPrivateIDs: []string{"mockID", "anotherMockID"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, }, "cannot specify internal ALB subnet placement with default config": { @@ -244,7 +247,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inInternalALBSubnets: []string{"mockSubnet", "anotherMockSubnet"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, wantedErrMsg: "subnets 'mockSubnet, anotherMockSubnet' specified for internal ALB placement, but those subnets are not imported", }, @@ -253,7 +256,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inInternalALBSubnets: []string{"mockSubnet", "anotherMockSubnet"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, wantedErrMsg: "subnets 'mockSubnet, anotherMockSubnet' specified for internal ALB placement, but those subnets are not imported", }, @@ -262,7 +265,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inInternalALBSubnets: []string{"mockSubnet", "notMockSubnet"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, wantedErrMsg: "subnets 'mockSubnet, notMockSubnet' were designated for ALB placement, but they were not all imported", }, @@ -271,7 +274,7 @@ func TestInitEnvOpts_Validate(t *testing.T) { inInternalALBSubnets: []string{"mockSubnet", "anotherMockSubnet"}, setupMocks: func(m *initEnvMocks) { m.wsAppName = "phonetool" - m.store.EXPECT().GetApplication("phonetool").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, nil) }, }, } @@ -388,7 +391,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { m.prompt.EXPECT(). Get(envInitNamePrompt, envInitNameHelpPrompt, gomock.Any(), gomock.Any()). Return("test", nil), - m.store.EXPECT().GetEnvironment(mockApp, mockEnv).Return(nil, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(nil, nil), m.envLister.EXPECT().ListEnvironments().Return([]string{}, nil), ) }, @@ -403,7 +406,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { m.prompt.EXPECT(). Get(envInitNamePrompt, envInitNameHelpPrompt, gomock.Any(), gomock.Any()). Return("test", nil), - m.store.EXPECT().GetEnvironment(mockApp, mockEnv).Return(nil, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(nil, nil), m.envLister.EXPECT().ListEnvironments().Return([]string{mockEnv}, nil), m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), mockProfile).Return(aws.Config{Region: "us-west-2"}, nil).AnyTimes(), ) @@ -966,7 +969,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { } // WHEN - err := addEnv.Ask() + err := addEnv.Ask(context.Background()) // THEN if tc.wantedError == nil { @@ -991,6 +994,30 @@ type initEnvExecuteMocks struct { appVersionGetter *mocks.MockversionGetter } +func newTestInitEnvOpts(m *initEnvExecuteMocks) *initEnvOpts { + return &initEnvOpts{ + initEnvVars: initEnvVars{ + name: "test", + appName: "phonetool", + }, + store: m.store, + envDeployer: m.deployer, + appDeployer: m.deployer, + identity: m.identity, + envIdentity: m.identity, + iam: m.iam, + cfn: m.cfn, + prog: m.progress, + cfg: aws.Config{Region: "us-west-2"}, + appCFN: m.appCFN, + newAppVersionGetter: func(appName string) (versionGetter, error) { + return m.appVersionGetter, nil + }, + manifestWriter: m.manifestWriter, + templateVersion: "v1.29.0", + } +} + func TestInitEnvOpts_Execute(t *testing.T) { const ( mockAppVersion = "v0.0.0" @@ -1019,24 +1046,24 @@ func TestInitEnvOpts_Execute(t *testing.T) { "returns app exists error": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(nil, mockError) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, mockError) }, wantedErrorS: "some error", }, "returns identity get error": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.identity.EXPECT().Get().Return(identity.Caller{}, errors.New("some identity error")) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{}, errors.New("some identity error")) }, wantedErrorS: "get identity: some identity error", }, "fail to write manifest": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().CreateEnvironment(gomock.Any()).Times(0) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil) + m.store.EXPECT().CreateEnvironment(gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("", mockError) }, wantedErrorS: "write environment manifest: some error", @@ -1044,9 +1071,9 @@ func TestInitEnvOpts_Execute(t *testing.T) { "failed to create stack set instance": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().CreateEnvironment(gomock.Any()).Times(0) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil) + m.store.EXPECT().CreateEnvironment(gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) m.deployer.EXPECT().AddEnvToApp(&deploycfn.AddEnvToAppOpts{ @@ -1061,8 +1088,8 @@ func TestInitEnvOpts_Execute(t *testing.T) { "errors cannot get app resources by region": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) m.deployer.EXPECT().AddEnvToApp(gomock.Any()).Return(nil) @@ -1074,9 +1101,9 @@ func TestInitEnvOpts_Execute(t *testing.T) { "deletes retained IAM roles if environment stack fails creation": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) gomock.InOrder( m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil), // Skip deleting non-existing roles. @@ -1104,18 +1131,18 @@ func TestInitEnvOpts_Execute(t *testing.T) { "returns error from CreateEnvironment": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{ Name: "phonetool", }, nil) - m.store.EXPECT().CreateEnvironment(gomock.Any()).Return(errors.New("some create error")) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) + m.store.EXPECT().CreateEnvironment(gomock.Any(), gomock.Any()).Return(errors.New("some create error")) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) m.iam.EXPECT().ListRoleTags(gomock.Any()). Return(nil, errors.New("does not exist")).AnyTimes() m.cfn.EXPECT().Exists("phonetool-test").Return(false, nil) m.deployer.EXPECT().CreateAndRenderEnvironment(gomock.Any(), gomock.Any()).Return(nil) - m.deployer.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{ + m.deployer.EXPECT().GetEnvironment(gomock.Any(), "phonetool", "test").Return(&config.Environment{ App: "phonetool", Name: "test", AccountID: "1234", @@ -1127,27 +1154,27 @@ func TestInitEnvOpts_Execute(t *testing.T) { S3Bucket: "mockBucket", }, nil) }, - wantedErrorS: "store environment: some create error", + wantedErrorS: "environment infrastructure deployment succeeded, but Copilot metadata commit failed: store environment: some create error", }, "success": { enableContainerInsights: true, allowDowngrade: true, setupMocks: func(m *initEnvExecuteMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.store.EXPECT().CreateEnvironment(&config.Environment{ + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().CreateEnvironment(gomock.Any(), &config.Environment{ App: "phonetool", Name: "test", AccountID: "1234", Region: "mars-1", }).Return(nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) m.iam.EXPECT().ListRoleTags(gomock.Eq("phonetool-test-CFNExecutionRole")).Return(nil, errors.New("does not exist")) m.iam.EXPECT().ListRoleTags(gomock.Eq("phonetool-test-EnvManagerRole")).Return(nil, errors.New("does not exist")) m.cfn.EXPECT().Exists("phonetool-test").Return(false, nil) m.deployer.EXPECT().CreateAndRenderEnvironment(gomock.Any(), gomock.Any()).Return(nil) - m.deployer.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{ + m.deployer.EXPECT().GetEnvironment(gomock.Any(), "phonetool", "test").Return(&config.Environment{ AccountID: "1234", Region: "mars-1", Name: "test", @@ -1163,14 +1190,14 @@ func TestInitEnvOpts_Execute(t *testing.T) { "proceed if manifest already exists": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.store.EXPECT().CreateEnvironment(&config.Environment{ + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().CreateEnvironment(gomock.Any(), &config.Environment{ App: "phonetool", Name: "test", AccountID: "1234", Region: "mars-1", }).Return(nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("", &workspace.ErrFileExists{ FileName: "/environments/test/manifest.yml", }) @@ -1179,7 +1206,7 @@ func TestInitEnvOpts_Execute(t *testing.T) { m.iam.EXPECT().ListRoleTags(gomock.Eq("phonetool-test-EnvManagerRole")).Return(nil, errors.New("does not exist")) m.cfn.EXPECT().Exists("phonetool-test").Return(false, nil) m.deployer.EXPECT().CreateAndRenderEnvironment(gomock.Any(), gomock.Any()).Return(nil) - m.deployer.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{ + m.deployer.EXPECT().GetEnvironment(gomock.Any(), "phonetool", "test").Return(&config.Environment{ AccountID: "1234", Region: "mars-1", Name: "test", @@ -1195,14 +1222,14 @@ func TestInitEnvOpts_Execute(t *testing.T) { "skips creating stack if environment stack already exists": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.store.EXPECT().CreateEnvironment(&config.Environment{ + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().CreateEnvironment(gomock.Any(), &config.Environment{ App: "phonetool", Name: "test", AccountID: "1234", Region: "mars-1", }).Return(nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) // Don't attempt to delete any roles since an environment stack already exists. @@ -1221,7 +1248,7 @@ func TestInitEnvOpts_Execute(t *testing.T) { require.Equal(t, bucketARN, "arn:aws:s3:::mockBucket") return &cloudformation.ErrStackAlreadyExists{} }) - m.deployer.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{ + m.deployer.EXPECT().GetEnvironment(gomock.Any(), "phonetool", "test").Return(&config.Environment{ AccountID: "1234", Region: "mars-1", Name: "test", @@ -1238,8 +1265,8 @@ func TestInitEnvOpts_Execute(t *testing.T) { "failed to delegate DNS (app has Domain and env and apps are different)": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool", AccountID: "1234", Domain: "amazon.com"}, nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "4567"}, nil).Times(1) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool", AccountID: "1234", Domain: "amazon.com"}, nil) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "4567"}, nil).Times(1) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) m.progress.EXPECT().Start(fmt.Sprintf(fmtDNSDelegationStart, "4567")) m.progress.EXPECT().Stop(log.Serrorf(fmtDNSDelegationFailed, "4567")) @@ -1251,14 +1278,14 @@ func TestInitEnvOpts_Execute(t *testing.T) { "success with DNS Delegation (app has Domain and env and app are different)": { setupMocks: func(m *initEnvExecuteMocks) { m.appVersionGetter.EXPECT().Version().Return(mockAppVersion, nil) - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool", AccountID: "1234", Domain: "amazon.com"}, nil) - m.store.EXPECT().CreateEnvironment(&config.Environment{ + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool", AccountID: "1234", Domain: "amazon.com"}, nil) + m.store.EXPECT().CreateEnvironment(gomock.Any(), &config.Environment{ App: "phonetool", Name: "test", AccountID: "4567", Region: "us-west-2", }).Return(nil) - m.identity.EXPECT().Get().Return(identity.Caller{RootUserARN: "some arn", Account: "4567"}, nil).Times(2) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "4567"}, nil).Times(2) m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) m.iam.EXPECT().ListRoleTags(gomock.Any()). @@ -1268,7 +1295,7 @@ func TestInitEnvOpts_Execute(t *testing.T) { m.progress.EXPECT().Stop(log.Ssuccessf(fmtDNSDelegationComplete, "4567")) m.deployer.EXPECT().DelegateDNSPermissions(gomock.Any(), "4567").Return(nil) m.deployer.EXPECT().CreateAndRenderEnvironment(gomock.Any(), gomock.Any()).Return(nil) - m.deployer.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{ + m.deployer.EXPECT().GetEnvironment(gomock.Any(), "phonetool", "test").Return(&config.Environment{ AccountID: "4567", Region: "us-west-2", Name: "test", @@ -1332,7 +1359,7 @@ func TestInitEnvOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedErrorS != "" { @@ -1344,6 +1371,147 @@ func TestInitEnvOpts_Execute(t *testing.T) { } } +func TestInitEnvOpts_Execute_PreMutationCanceledContextPreventsDeploy(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + parent, cancel := context.WithCancel(context.Background()) + cancel() + + m := &initEnvExecuteMocks{ + store: mocks.NewMockstore(ctrl), + deployer: mocks.NewMockdeployer(ctrl), + identity: mocks.NewMockidentityService(ctrl), + progress: mocks.NewMockprogress(ctrl), + iam: mocks.NewMockroleManager(ctrl), + cfn: mocks.NewMockstackExistChecker(ctrl), + appCFN: mocks.NewMockappResourcesGetter(ctrl), + manifestWriter: mocks.NewMockenvironmentManifestWriter(ctrl), + appVersionGetter: mocks.NewMockversionGetter(ctrl), + } + + m.appVersionGetter.EXPECT().Version().Return("v0.0.0", nil) + m.store.EXPECT().GetApplication(parent, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.identity.EXPECT().Get(parent).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil) + m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) + m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) + m.deployer.EXPECT().AddEnvToApp(gomock.Any()).Times(0) + m.deployer.EXPECT().CreateAndRenderEnvironment(gomock.Any(), gomock.Any()).Times(0) + m.deployer.EXPECT().GetEnvironment(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().CreateEnvironment(gomock.Any(), gomock.Any()).Times(0) + + err := newTestInitEnvOpts(m).Execute(parent) + + require.ErrorIs(t, err, context.Canceled) +} + +func TestInitEnvOpts_Execute_CanceledParentStillCommitsMetadata(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + parent, cancel := context.WithCancel(context.Background()) + + m := &initEnvExecuteMocks{ + store: mocks.NewMockstore(ctrl), + deployer: mocks.NewMockdeployer(ctrl), + identity: mocks.NewMockidentityService(ctrl), + progress: mocks.NewMockprogress(ctrl), + iam: mocks.NewMockroleManager(ctrl), + cfn: mocks.NewMockstackExistChecker(ctrl), + appCFN: mocks.NewMockappResourcesGetter(ctrl), + manifestWriter: mocks.NewMockenvironmentManifestWriter(ctrl), + appVersionGetter: mocks.NewMockversionGetter(ctrl), + } + + m.appVersionGetter.EXPECT().Version().Return("v0.0.0", nil) + m.store.EXPECT().GetApplication(parent, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.identity.EXPECT().Get(parent).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) + m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) + m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) + m.iam.EXPECT().ListRoleTags(gomock.Any()).Return(nil, errors.New("does not exist")).AnyTimes() + m.deployer.EXPECT().AddEnvToApp(gomock.Any()).Return(nil) + m.appCFN.EXPECT().GetAppResourcesByRegion(&config.Application{Name: "phonetool"}, "us-west-2"). + Return(&stack.AppRegionalResources{ + S3Bucket: "mockBucket", + }, nil) + m.cfn.EXPECT().Exists("phonetool-test").Return(false, nil) + m.deployer.EXPECT().CreateAndRenderEnvironment(gomock.Any(), gomock.Any()).DoAndReturn(func(deploycfn.StackConfiguration, string) error { + cancel() + return nil + }) + m.deployer.EXPECT().GetEnvironment(gomock.Any(), "phonetool", "test"). + DoAndReturn(func(gotCtx context.Context, _, _ string) (*config.Environment, error) { + require.NoError(t, gotCtx.Err()) + deadline, ok := gotCtx.Deadline() + require.True(t, ok) + require.WithinDuration(t, time.Now().Add(metadata.CommitTimeout), deadline, time.Second) + return &config.Environment{ + App: "phonetool", + Name: "test", + AccountID: "1234", + Region: "mars-1", + }, nil + }) + m.store.EXPECT().CreateEnvironment(gomock.Any(), gomock.Any()). + DoAndReturn(func(gotCtx context.Context, _ *config.Environment) error { + require.NoError(t, gotCtx.Err()) + deadline, ok := gotCtx.Deadline() + require.True(t, ok) + require.WithinDuration(t, time.Now().Add(metadata.CommitTimeout), deadline, time.Second) + return nil + }) + + err := newTestInitEnvOpts(m).Execute(parent) + + require.NoError(t, err) +} + +func TestInitEnvOpts_Execute_MetadataCommitErrorIsPartialSuccess(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockErr := errors.New("some create error") + m := &initEnvExecuteMocks{ + store: mocks.NewMockstore(ctrl), + deployer: mocks.NewMockdeployer(ctrl), + identity: mocks.NewMockidentityService(ctrl), + progress: mocks.NewMockprogress(ctrl), + iam: mocks.NewMockroleManager(ctrl), + cfn: mocks.NewMockstackExistChecker(ctrl), + appCFN: mocks.NewMockappResourcesGetter(ctrl), + manifestWriter: mocks.NewMockenvironmentManifestWriter(ctrl), + appVersionGetter: mocks.NewMockversionGetter(ctrl), + } + + m.appVersionGetter.EXPECT().Version().Return("v0.0.0", nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.identity.EXPECT().Get(ctx).Return(identity.Caller{RootUserARN: "some arn", Account: "1234"}, nil).Times(2) + m.manifestWriter.EXPECT().WriteEnvironmentManifest(gomock.Any(), "test").Return("/environments/test/manifest.yml", nil) + m.iam.EXPECT().CreateECSServiceLinkedRole().Return(nil) + m.iam.EXPECT().ListRoleTags(gomock.Any()).Return(nil, errors.New("does not exist")).AnyTimes() + m.deployer.EXPECT().AddEnvToApp(gomock.Any()).Return(nil) + m.appCFN.EXPECT().GetAppResourcesByRegion(&config.Application{Name: "phonetool"}, "us-west-2"). + Return(&stack.AppRegionalResources{ + S3Bucket: "mockBucket", + }, nil) + m.cfn.EXPECT().Exists("phonetool-test").Return(false, nil) + m.deployer.EXPECT().CreateAndRenderEnvironment(gomock.Any(), gomock.Any()).Return(nil) + m.deployer.EXPECT().GetEnvironment(gomock.Any(), "phonetool", "test").Return(&config.Environment{ + App: "phonetool", + Name: "test", + AccountID: "1234", + Region: "mars-1", + }, nil) + m.store.EXPECT().CreateEnvironment(gomock.Any(), gomock.Any()).Return(mockErr) + + err := newTestInitEnvOpts(m).Execute(ctx) + + var commitErr *metadata.CommitError + require.ErrorAs(t, err, &commitErr) + require.ErrorIs(t, err, mockErr) + require.EqualError(t, err, "environment infrastructure deployment succeeded, but Copilot metadata commit failed: store environment: some create error") +} + func TestInitEnvOpts_delegateDNSFromApp(t *testing.T) { testCases := map[string]struct { app *config.Application diff --git a/internal/pkg/cli/env_list.go b/internal/pkg/cli/env_list.go index 0f700798d2d..1dc7749a5ef 100644 --- a/internal/pkg/cli/env_list.go +++ b/internal/pkg/cli/env_list.go @@ -56,11 +56,11 @@ func newListEnvOpts(vars listEnvVars) (*listEnvOpts, error) { } // Ask asks for fields that are required but not passed in. -func (o *listEnvOpts) Ask() error { +func (o *listEnvOpts) Ask(ctx context.Context) error { if o.appName != "" { return nil } - app, err := o.sel.Application(envListAppNamePrompt, envListAppNameHelper) + app, err := o.sel.Application(ctx, envListAppNamePrompt, envListAppNameHelper) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -69,13 +69,13 @@ func (o *listEnvOpts) Ask() error { } // Execute lists the environments through the prompt. -func (o *listEnvOpts) Execute() error { +func (o *listEnvOpts) Execute(ctx context.Context) error { // Ensure the application actually exists before we try to list its environments. - if _, err := o.store.GetApplication(o.appName); err != nil { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return err } - envs, err := o.store.ListEnvironments(o.appName) + envs, err := o.store.ListEnvironments(ctx, o.appName) if err != nil { return err } @@ -128,10 +128,10 @@ func buildEnvListCmd() *cobra.Command { if err != nil { return err } - if err := opts.Ask(); err != nil { + if err := opts.Ask(cmd.Context()); err != nil { return err } - return opts.Execute() + return opts.Execute(cmd.Context()) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/env_list_test.go b/internal/pkg/cli/env_list_test.go index da0032be95e..8bc68d4dae6 100644 --- a/internal/pkg/cli/env_list_test.go +++ b/internal/pkg/cli/env_list_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -26,7 +27,7 @@ func TestEnvList_Ask(t *testing.T) { }{ "with no flags set": { mockSelector: func(m *mocks.MockconfigSelector) { - m.EXPECT().Application(envListAppNamePrompt, envListAppNameHelper).Return("my-app", nil) + m.EXPECT().Application(ctx, envListAppNamePrompt, envListAppNameHelper).Return("my-app", nil) }, wantedApp: "my-app", }, @@ -37,7 +38,7 @@ func TestEnvList_Ask(t *testing.T) { }, "error if fail to select app": { mockSelector: func(m *mocks.MockconfigSelector) { - m.EXPECT().Application(envListAppNamePrompt, envListAppNameHelper).Return("", errors.New("some error")) + m.EXPECT().Application(ctx, envListAppNamePrompt, envListAppNameHelper).Return("", errors.New("some error")) }, wantedApp: "my-app", wantedErr: fmt.Errorf("select application: some error"), @@ -59,7 +60,7 @@ func TestEnvList_Ask(t *testing.T) { sel: mockSelector, } - err := listEnvs.Ask() + err := listEnvs.Ask(context.Background()) if tc.wantedErr != nil { require.EqualError(t, err, tc.wantedErr.Error()) @@ -92,11 +93,11 @@ func TestEnvList_Execute(t *testing.T) { }, mocking: func() { mockstore.EXPECT(). - GetApplication(gomock.Eq("coolapp")). + GetApplication(ctx, gomock.Eq("coolapp")). Return(&config.Application{}, nil) mockstore. EXPECT(). - ListEnvironments(gomock.Eq("coolapp")). + ListEnvironments(ctx, gomock.Eq("coolapp")). Return([]*config.Environment{ {Name: "test"}, {Name: "test2"}, @@ -113,11 +114,11 @@ func TestEnvList_Execute(t *testing.T) { }, mocking: func() { mockstore.EXPECT(). - GetApplication(gomock.Eq("coolapp")). + GetApplication(ctx, gomock.Eq("coolapp")). Return(&config.Application{}, nil) mockstore. EXPECT(). - ListEnvironments(gomock.Eq("coolapp")). + ListEnvironments(ctx, gomock.Eq("coolapp")). Return([]*config.Environment{ {Name: "test"}, {Name: "test2"}, @@ -135,12 +136,12 @@ func TestEnvList_Execute(t *testing.T) { }, mocking: func() { mockstore.EXPECT(). - GetApplication(gomock.Eq("coolapp")). + GetApplication(ctx, gomock.Eq("coolapp")). Return(nil, mockError) mockstore. EXPECT(). - ListEnvironments(gomock.Eq("coolapp")). + ListEnvironments(ctx, gomock.Eq("coolapp")). Times(0) }, }, @@ -154,12 +155,12 @@ func TestEnvList_Execute(t *testing.T) { }, mocking: func() { mockstore.EXPECT(). - GetApplication(gomock.Eq("coolapp")). + GetApplication(ctx, gomock.Eq("coolapp")). Return(&config.Application{}, nil) mockstore. EXPECT(). - ListEnvironments(gomock.Eq("coolapp")). + ListEnvironments(ctx, gomock.Eq("coolapp")). Return(nil, mockError) }, }, @@ -172,11 +173,11 @@ func TestEnvList_Execute(t *testing.T) { }, mocking: func() { mockstore.EXPECT(). - GetApplication(gomock.Eq("coolapp")). + GetApplication(ctx, gomock.Eq("coolapp")). Return(&config.Application{}, nil) mockstore. EXPECT(). - ListEnvironments(gomock.Eq("coolapp")). + ListEnvironments(ctx, gomock.Eq("coolapp")). Return([]*config.Environment{ {Name: "test"}, {Name: "test2"}, @@ -191,7 +192,7 @@ func TestEnvList_Execute(t *testing.T) { b := &bytes.Buffer{} tc.mocking() tc.listOpts.w = b - err := tc.listOpts.Execute() + err := tc.listOpts.Execute(context.Background()) if tc.expectedErr != nil { require.EqualError(t, tc.expectedErr, err.Error()) diff --git a/internal/pkg/cli/env_override.go b/internal/pkg/cli/env_override.go index e24cfdc6907..edacb7d1940 100644 --- a/internal/pkg/cli/env_override.go +++ b/internal/pkg/cli/env_override.go @@ -65,20 +65,20 @@ func (o *overrideEnvOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *overrideEnvOpts) Ask() error { +func (o *overrideEnvOpts) Ask(ctx context.Context) error { if err := o.assignEnvName(); err != nil { return err } - return o.overrideOpts.Ask() + return o.overrideOpts.Ask(ctx) } // Execute writes IaC override files to the local workspace. // This method assumes that the IaC tool chosen by the user is valid. -func (o *overrideEnvOpts) Execute() error { +func (o *overrideEnvOpts) Execute(ctx context.Context) error { o.overrideOpts.dir = func() string { return o.ws.EnvOverridesPath() } - return o.overrideOpts.Execute() + return o.overrideOpts.Execute(ctx) } func (o *overrideEnvOpts) validateName() error { @@ -140,7 +140,7 @@ or add new resources to an environment's template.`, if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", overrideEnvFlagDescription) diff --git a/internal/pkg/cli/env_override_test.go b/internal/pkg/cli/env_override_test.go index 4f7512033f5..412198381ab 100644 --- a/internal/pkg/cli/env_override_test.go +++ b/internal/pkg/cli/env_override_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "path/filepath" @@ -32,7 +33,7 @@ func TestOverrideEnv_Validate(t *testing.T) { appName: "demo", initMocks: func(ctrl *gomock.Controller, cmd *overrideEnvOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).Return(nil, errors.New("some error")) + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, errors.New("some error")) cmd.cfgStore = mockSSM }, wanted: errors.New(`get application "demo" configuration: some error`), @@ -76,7 +77,7 @@ func TestOverrideEnv_Validate(t *testing.T) { "skip validating if environment name is empty": { initMocks: func(ctrl *gomock.Controller, cmd *overrideEnvOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() cmd.cfgStore = mockSSM }, }, @@ -84,7 +85,7 @@ func TestOverrideEnv_Validate(t *testing.T) { name: "test", initMocks: func(ctrl *gomock.Controller, cmd *overrideEnvOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() mockWS := mocks.NewMockwsEnvironmentReader(ctrl) mockWS.EXPECT().ListEnvironments().Return(nil, errors.New("some error")) cmd.cfgStore = mockSSM @@ -96,7 +97,7 @@ func TestOverrideEnv_Validate(t *testing.T) { name: "test", initMocks: func(ctrl *gomock.Controller, cmd *overrideEnvOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() mockWS := mocks.NewMockwsEnvironmentReader(ctrl) mockWS.EXPECT().ListEnvironments().Return([]string{"prod"}, nil) cmd.cfgStore = mockSSM @@ -152,7 +153,7 @@ func TestOverrideEnv_Validate(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).Return(nil, nil) + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, nil) vars := overrideVars{appName: "demo", cdkLang: tc.lang} cmd := &overrideEnvOpts{ @@ -191,7 +192,7 @@ func TestOverrideEnv_Ask(t *testing.T) { cfgStore: mocks.NewMockstore(ctrl), packageCmd: func(_ stringWriteCloser) (executor, error) { mockCmd := mocks.NewMockexecutor(ctrl) - mockCmd.EXPECT().Execute().AnyTimes() + mockCmd.EXPECT().Execute(gomock.Any()).AnyTimes() return mockCmd, nil }, }, @@ -199,7 +200,7 @@ func TestOverrideEnv_Ask(t *testing.T) { } // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN require.NoError(t, err) @@ -244,7 +245,7 @@ func TestOverrideEnv_Ask(t *testing.T) { cfnPrompt: mockCfnPrompt, packageCmd: func(_ stringWriteCloser) (executor, error) { mockCmd := mocks.NewMockexecutor(ctrl) - mockCmd.EXPECT().Execute().AnyTimes() + mockCmd.EXPECT().Execute(gomock.Any()).AnyTimes() return mockCmd, nil }, spinner: &spinnerTestDouble{}, @@ -255,7 +256,7 @@ func TestOverrideEnv_Ask(t *testing.T) { } // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { @@ -291,7 +292,7 @@ func TestOverrideEnv_Ask(t *testing.T) { "should return a wrapped error if package command fails to execute": { initMocks: func(ctrl *gomock.Controller, cmd *overrideEnvOpts) { mockPkgCmd := mocks.NewMockexecutor(ctrl) - mockPkgCmd.EXPECT().Execute().Return(errors.New("some error")) + mockPkgCmd.EXPECT().Execute(gomock.Any()).Return(errors.New("some error")) cmd.packageCmd = func(_ stringWriteCloser) (executor, error) { return mockPkgCmd, nil } @@ -301,7 +302,7 @@ func TestOverrideEnv_Ask(t *testing.T) { "should prompt for CloudFormation resources in a template": { initMocks: func(ctrl *gomock.Controller, cmd *overrideEnvOpts) { mockPkgCmd := mocks.NewMockexecutor(ctrl) - mockPkgCmd.EXPECT().Execute().Return(nil) + mockPkgCmd.EXPECT().Execute(gomock.Any()).Return(nil) mockPrompt := mocks.NewMockcfnSelector(ctrl) template := ` Resources: @@ -337,7 +338,7 @@ func TestOverrideEnv_Ask(t *testing.T) { tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { @@ -411,7 +412,7 @@ func TestOverrideEnv_Execute(t *testing.T) { tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Execute() + err := cmd.Execute(context.Background()) // THEN if tc.wanted != nil { diff --git a/internal/pkg/cli/env_package.go b/internal/pkg/cli/env_package.go index 9468fb26463..139b7e7e96b 100644 --- a/internal/pkg/cli/env_package.go +++ b/internal/pkg/cli/env_package.go @@ -72,8 +72,8 @@ type packageEnvOpts struct { diffWriter io.Writer newInterpolator func(appName, name string) interpolator - newEnvVersionGetter func(appName, name string) (versionGetter, error) - newEnvPackager func() (envPackager, error) + newEnvVersionGetter func(ctx context.Context, appName, name string) (versionGetter, error) + newEnvPackager func(ctx context.Context) (envPackager, error) // Cached variables. appCfg *config.Application @@ -111,8 +111,8 @@ func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { diffWriter: os.Stdout, templateVersion: version.LatestTemplateVersion(), - newEnvVersionGetter: func(appName, name string) (versionGetter, error) { - return describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + newEnvVersionGetter: func(ctx context.Context, appName, name string) (versionGetter, error) { + return describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: appName, Env: name, ConfigStore: cfgStore, @@ -122,12 +122,12 @@ func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { return manifest.NewInterpolator(appName, name) }, } - opts.newEnvPackager = func() (envPackager, error) { - appCfg, err := opts.getAppCfg() + opts.newEnvPackager = func(ctx context.Context) (envPackager, error) { + appCfg, err := opts.getAppCfg(ctx) if err != nil { return nil, err } - envCfg, err := opts.getEnvCfg() + envCfg, err := opts.getEnvCfg(ctx) if err != nil { return nil, err } @@ -136,6 +136,7 @@ func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { return nil, err } return deploy.NewEnvDeployer(&deploy.NewEnvDeployerInput{ + Ctx: ctx, App: appCfg, Env: envCfg, SessionProvider: sessProvider, @@ -153,22 +154,22 @@ func (o *packageEnvOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *packageEnvOpts) Ask() error { +func (o *packageEnvOpts) Ask(ctx context.Context) error { if o.appName == "" { // This command is required to be executed under a workspace. We don't prompt for it. return errNoAppInWorkspace } - if _, err := o.getAppCfg(); err != nil { + if _, err := o.getAppCfg(ctx); err != nil { return err } - return o.validateOrAskName() + return o.validateOrAskName(ctx) } // Execute prints the CloudFormation configuration for the environment. -func (o *packageEnvOpts) Execute() error { +func (o *packageEnvOpts) Execute(ctx context.Context) error { if !o.allowEnvDowngrade { - envVersionGetter, err := o.newEnvVersionGetter(o.appName, o.name) + envVersionGetter, err := o.newEnvVersionGetter(ctx, o.appName, o.name) if err != nil { return err } @@ -180,11 +181,11 @@ func (o *packageEnvOpts) Execute() error { if err != nil { return err } - principal, err := o.caller.Get() + principal, err := o.caller.Get(ctx) if err != nil { return fmt.Errorf("get caller principal identity: %v", err) } - packager, err := o.newEnvPackager() + packager, err := o.newEnvPackager(ctx) if err != nil { return err } @@ -246,11 +247,11 @@ func (o *packageEnvOpts) Execute() error { return o.writeAndClose(o.addonsWriter, addonsTemplate) } -func (o *packageEnvOpts) getAppCfg() (*config.Application, error) { +func (o *packageEnvOpts) getAppCfg(ctx context.Context) (*config.Application, error) { if o.appCfg != nil { return o.appCfg, nil } - cfg, err := o.cfgStore.GetApplication(o.appName) + cfg, err := o.cfgStore.GetApplication(ctx, o.appName) if err != nil { return nil, fmt.Errorf("get application %q configuration: %w", o.appName, err) } @@ -258,11 +259,11 @@ func (o *packageEnvOpts) getAppCfg() (*config.Application, error) { return o.appCfg, nil } -func (o *packageEnvOpts) getEnvCfg() (*config.Environment, error) { +func (o *packageEnvOpts) getEnvCfg(ctx context.Context) (*config.Environment, error) { if o.envCfg != nil { return o.envCfg, nil } - cfg, err := o.cfgStore.GetEnvironment(o.appName, o.name) + cfg, err := o.cfgStore.GetEnvironment(ctx, o.appName, o.name) if err != nil { return nil, fmt.Errorf("get environment %q in application %q: %w", o.name, o.appName, err) } @@ -270,9 +271,9 @@ func (o *packageEnvOpts) getEnvCfg() (*config.Environment, error) { return o.envCfg, nil } -func (o *packageEnvOpts) validateOrAskName() error { +func (o *packageEnvOpts) validateOrAskName(ctx context.Context) error { if o.name != "" { - if _, err := o.getEnvCfg(); err != nil { + if _, err := o.getEnvCfg(ctx); err != nil { log.Errorf("It seems like environment %s is not added in application %s yet. Have you run %s?\n", o.name, o.appName, color.HighlightCode("copilot env init")) return err @@ -280,7 +281,7 @@ func (o *packageEnvOpts) validateOrAskName() error { return nil } - name, err := o.sel.LocalEnvironment("Select an environment manifest from your workspace", "") + name, err := o.sel.LocalEnvironment(ctx, "Select an environment manifest from your workspace", "") if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -354,7 +355,7 @@ func buildEnvPkgCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", envFlagDescription) diff --git a/internal/pkg/cli/env_package_test.go b/internal/pkg/cli/env_package_test.go index 3f536c0477f..15659ebfba5 100644 --- a/internal/pkg/cli/env_package_test.go +++ b/internal/pkg/cli/env_package_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -48,7 +49,7 @@ func TestPackageEnvOpts_Ask(t *testing.T) { }, mockedCmd: func(ctrl *gomock.Controller, vars packageEnvVars) *packageEnvOpts { cfgStore := mocks.NewMockstore(ctrl) - cfgStore.EXPECT().GetApplication(gomock.Any()).Return(nil, errors.New("some error")) + cfgStore.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, errors.New("some error")) return &packageEnvOpts{ packageEnvVars: vars, cfgStore: cfgStore, @@ -64,8 +65,8 @@ func TestPackageEnvOpts_Ask(t *testing.T) { }, mockedCmd: func(ctrl *gomock.Controller, vars packageEnvVars) *packageEnvOpts { cfgStore := mocks.NewMockstore(ctrl) - cfgStore.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{}, nil) - cfgStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) + cfgStore.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{}, nil) + cfgStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return &packageEnvOpts{ packageEnvVars: vars, cfgStore: cfgStore, @@ -80,9 +81,9 @@ func TestPackageEnvOpts_Ask(t *testing.T) { }, mockedCmd: func(ctrl *gomock.Controller, vars packageEnvVars) *packageEnvOpts { cfgStore := mocks.NewMockstore(ctrl) - cfgStore.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{}, nil) + cfgStore.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{}, nil) sel := mocks.NewMockwsEnvironmentSelector(ctrl) - sel.EXPECT().LocalEnvironment(gomock.Any(), gomock.Any()).Return("", errors.New("no environments found")) + sel.EXPECT().LocalEnvironment(ctx, gomock.Any(), gomock.Any()).Return("", errors.New("no environments found")) return &packageEnvOpts{ packageEnvVars: vars, cfgStore: cfgStore, @@ -98,9 +99,9 @@ func TestPackageEnvOpts_Ask(t *testing.T) { }, mockedCmd: func(ctrl *gomock.Controller, vars packageEnvVars) *packageEnvOpts { cfgStore := mocks.NewMockstore(ctrl) - cfgStore.EXPECT().GetApplication(vars.appName).Return(&config.Application{}, nil) + cfgStore.EXPECT().GetApplication(ctx, vars.appName).Return(&config.Application{}, nil) sel := mocks.NewMockwsEnvironmentSelector(ctrl) - sel.EXPECT().LocalEnvironment("Select an environment manifest from your workspace", "").Return("test", nil) + sel.EXPECT().LocalEnvironment(ctx, "Select an environment manifest from your workspace", "").Return("test", nil) return &packageEnvOpts{ packageEnvVars: vars, cfgStore: cfgStore, @@ -118,7 +119,7 @@ func TestPackageEnvOpts_Ask(t *testing.T) { cmd := tc.mockedCmd(ctrl, tc.in) // WHEN - actual := cmd.Ask() + actual := cmd.Ask(context.Background()) // THEN if tc.wanted == nil { @@ -182,7 +183,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate(gomock.Any()).Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, errors.New("some error")) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, errors.New("some error")) return &packageEnvOpts{ packageEnvVars: packageEnvVars{ @@ -205,7 +206,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate(gomock.Any()).Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(errors.New("mock error")) @@ -218,7 +219,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, envCfg: &config.Environment{Name: "test"}, @@ -233,7 +234,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate(gomock.Any()).Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(nil) deployer.EXPECT().UploadArtifacts().Return(nil, errors.New("some error")) @@ -248,7 +249,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, envCfg: &config.Environment{Name: "test"}, @@ -263,7 +264,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate(gomock.Any()).Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(nil) deployer.EXPECT().GenerateCloudFormationTemplate(gomock.Any()).Return(nil, errors.New("some error")) @@ -277,7 +278,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, envCfg: &config.Environment{Name: "test"}, @@ -293,7 +294,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate(gomock.Any()).Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(nil) deployer.EXPECT().GenerateCloudFormationTemplate(gomock.Any()).Return(&deploy.GenerateCloudFormationTemplateOutput{}, nil) @@ -308,7 +309,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, envCfg: &config.Environment{Name: "test"}, @@ -325,7 +326,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate(gomock.Any()).Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) packager := mocks.NewMockenvPackager(ctrl) packager.EXPECT().Validate(gomock.Any()).Return(nil) packager.EXPECT().GenerateCloudFormationTemplate(gomock.Any()).Return(&deploy.GenerateCloudFormationTemplateOutput{ @@ -342,7 +343,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return packager, nil }, envCfg: &config.Environment{Name: "test"}, @@ -358,7 +359,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate("name: test\ntype: Environment\n").Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(nil) deployer.EXPECT().UploadArtifacts().Return(&deploy.UploadEnvArtifactsOutput{ @@ -392,7 +393,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, fs: fs, @@ -411,7 +412,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate(gomock.Any()).Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(nil) deployer.EXPECT().GenerateCloudFormationTemplate(gomock.Any()).Return(&deploy.GenerateCloudFormationTemplateOutput{}, nil) @@ -426,7 +427,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, envCfg: &config.Environment{Name: "test"}, @@ -444,7 +445,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate("name: test\ntype: Environment\n").Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(nil) deployer.EXPECT().GenerateCloudFormationTemplate(&deploy.DeployEnvironmentInput{ @@ -477,7 +478,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, fs: fs, @@ -511,7 +512,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { interop := mocks.NewMockinterpolator(ctrl) interop.EXPECT().Interpolate("name: test\ntype: Environment\n").Return("name: test\ntype: Environment\n", nil) caller := mocks.NewMockidentityService(ctrl) - caller.EXPECT().Get().Return(identity.Caller{}, nil) + caller.EXPECT().Get(ctx).Return(identity.Caller{}, nil) deployer := mocks.NewMockenvPackager(ctrl) deployer.EXPECT().Validate(gomock.Any()).Return(nil) deployer.EXPECT().GenerateCloudFormationTemplate(&deploy.DeployEnvironmentInput{ @@ -544,7 +545,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { newInterpolator: func(_, _ string) interpolator { return interop }, - newEnvPackager: func() (envPackager, error) { + newEnvPackager: func(_ context.Context) (envPackager, error) { return deployer, nil }, fs: fs, @@ -585,7 +586,7 @@ func TestPackageEnvOpts_Execute(t *testing.T) { cmd.allowEnvDowngrade = true // downgrade logic is tested in env deploy // WHEN - actual := cmd.Execute() + actual := cmd.Execute(context.Background()) // THEN if tc.wantedErr == nil { diff --git a/internal/pkg/cli/env_show.go b/internal/pkg/cli/env_show.go index fb1abbab456..a92f060e2b4 100644 --- a/internal/pkg/cli/env_show.go +++ b/internal/pkg/cli/env_show.go @@ -41,7 +41,7 @@ type showEnvOpts struct { store store describer envDescriber sel configSelector - initEnvDescriber func() error + initEnvDescriber func(ctx context.Context) error } func newShowEnvOpts(vars showEnvVars) (*showEnvOpts, error) { @@ -63,8 +63,8 @@ func newShowEnvOpts(vars showEnvVars) (*showEnvOpts, error) { w: log.OutputWriter, sel: selector.NewConfigSelector(prompt.New(), store), } - opts.initEnvDescriber = func() error { - d, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + opts.initEnvDescriber = func(ctx context.Context) error { + d, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: opts.appName, Env: opts.name, ConfigStore: store, @@ -86,16 +86,16 @@ func (o *showEnvOpts) Validate() error { } // Ask validates required fields that users passed in, otherwise it prompts for them. -func (o *showEnvOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *showEnvOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - return o.validateOrAskEnv() + return o.validateOrAskEnv(ctx) } // Execute shows the environments through the prompt. -func (o *showEnvOpts) Execute() error { - if err := o.initEnvDescriber(); err != nil { +func (o *showEnvOpts) Execute(ctx context.Context) error { + if err := o.initEnvDescriber(ctx); err != nil { return err } if o.shouldOutputManifest { @@ -118,11 +118,11 @@ func (o *showEnvOpts) Execute() error { return nil } -func (o *showEnvOpts) validateOrAskApp() error { +func (o *showEnvOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - return o.validateApp() + return o.validateApp(ctx) } - app, err := o.sel.Application(envShowAppNamePrompt, envShowAppNameHelpPrompt) + app, err := o.sel.Application(ctx, envShowAppNamePrompt, envShowAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -130,18 +130,18 @@ func (o *showEnvOpts) validateOrAskApp() error { return nil } -func (o *showEnvOpts) validateApp() error { - if _, err := o.store.GetApplication(o.appName); err != nil { +func (o *showEnvOpts) validateApp(ctx context.Context) error { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return fmt.Errorf("validate application name %q: %v", o.appName, err) } return nil } -func (o *showEnvOpts) validateOrAskEnv() error { +func (o *showEnvOpts) validateOrAskEnv(ctx context.Context) error { if o.name != "" { - return o.validateEnv() + return o.validateEnv(ctx) } - env, err := o.sel.Environment(fmt.Sprintf(envShowNamePrompt, color.HighlightUserInput(o.appName)), envShowHelpPrompt, o.appName) + env, err := o.sel.Environment(ctx, fmt.Sprintf(envShowNamePrompt, color.HighlightUserInput(o.appName)), envShowHelpPrompt, o.appName) if err != nil { return fmt.Errorf("select environment for application %s: %w", o.appName, err) } @@ -149,8 +149,8 @@ func (o *showEnvOpts) validateOrAskEnv() error { return nil } -func (o *showEnvOpts) validateEnv() error { - if _, err := o.store.GetEnvironment(o.appName, o.name); err != nil { +func (o *showEnvOpts) validateEnv(ctx context.Context) error { + if _, err := o.store.GetEnvironment(ctx, o.appName, o.name); err != nil { return fmt.Errorf("validate environment name %q in application %q: %v", o.name, o.appName, err) } return nil @@ -183,7 +183,7 @@ func buildEnvShowCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/env_show_test.go b/internal/pkg/cli/env_show_test.go index ac5bbad18ff..71b1742fc7b 100644 --- a/internal/pkg/cli/env_show_test.go +++ b/internal/pkg/cli/env_show_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" @@ -43,8 +44,8 @@ func TestEnvShow_Ask(t *testing.T) { inputEnv: "my-env", setupMocks: func(m showEnvMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(nil, nil) - m.storeSvc.EXPECT().GetEnvironment("my-app", "my-env").Return(nil, nil) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(nil, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(nil, nil) }, wantedApp: "my-app", @@ -54,7 +55,7 @@ func TestEnvShow_Ask(t *testing.T) { inputApp: "my-app", setupMocks: func(m showEnvMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(nil, mockErr) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(nil, mockErr) }, wantedError: errors.New(`validate application name "my-app": some error`), }, @@ -63,8 +64,8 @@ func TestEnvShow_Ask(t *testing.T) { inputEnv: "my-env", setupMocks: func(m showEnvMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(nil, nil) - m.storeSvc.EXPECT().GetEnvironment("my-app", "my-env").Return(nil, mockErr) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(nil, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(nil, mockErr) }, wantedError: errors.New(`validate environment name "my-env" in application "my-app": some error`), }, @@ -73,7 +74,7 @@ func TestEnvShow_Ask(t *testing.T) { inputEnv: "", setupMocks: func(m showEnvMocks) { - m.sel.EXPECT().Application(envShowAppNamePrompt, envShowAppNameHelpPrompt).Return("", mockErr) + m.sel.EXPECT().Application(ctx, envShowAppNamePrompt, envShowAppNameHelpPrompt).Return("", mockErr) }, wantedError: fmt.Errorf("select application: some error"), @@ -83,8 +84,8 @@ func TestEnvShow_Ask(t *testing.T) { inputEnv: "", setupMocks: func(m showEnvMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(nil, nil) - m.sel.EXPECT().Environment(fmt.Sprintf(envShowNamePrompt, color.HighlightUserInput("my-app")), envShowHelpPrompt, "my-app").Return("", mockErr) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(nil, nil) + m.sel.EXPECT().Environment(ctx, fmt.Sprintf(envShowNamePrompt, color.HighlightUserInput("my-app")), envShowHelpPrompt, "my-app").Return("", mockErr) }, wantedError: fmt.Errorf("select environment for application my-app: some error"), @@ -95,8 +96,8 @@ func TestEnvShow_Ask(t *testing.T) { setupMocks: func(m showEnvMocks) { gomock.InOrder( - m.sel.EXPECT().Application(envShowAppNamePrompt, envShowAppNameHelpPrompt).Return("my-app", nil), - m.sel.EXPECT().Environment(fmt.Sprintf(envShowNamePrompt, color.HighlightUserInput("my-app")), envShowHelpPrompt, "my-app").Return("my-env", nil), + m.sel.EXPECT().Application(ctx, envShowAppNamePrompt, envShowAppNameHelpPrompt).Return("my-app", nil), + m.sel.EXPECT().Environment(ctx, fmt.Sprintf(envShowNamePrompt, color.HighlightUserInput("my-app")), envShowHelpPrompt, "my-app").Return("my-env", nil), ) }, @@ -129,7 +130,7 @@ func TestEnvShow_Ask(t *testing.T) { store: mockStore, } // WHEN - err := showEnvs.Ask() + err := showEnvs.Ask(context.Background()) // THEN if tc.wantedError != nil { require.EqualError(t, err, tc.wantedError.Error()) @@ -297,12 +298,12 @@ Resources }, store: mockStoreReader, describer: mockEnvDescriber, - initEnvDescriber: func() error { return nil }, + initEnvDescriber: func(_ context.Context) error { return nil }, w: b, } // WHEN - err := showEnvs.Execute() + err := showEnvs.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/identity.go b/internal/pkg/cli/identity.go index d6812393f9a..3cd803b15ac 100644 --- a/internal/pkg/cli/identity.go +++ b/internal/pkg/cli/identity.go @@ -3,8 +3,12 @@ package cli -import "github.com/aproint/copilot-cli/internal/pkg/aws/identity" +import ( + "context" + + "github.com/aproint/copilot-cli/internal/pkg/aws/identity" +) type identityService interface { - Get() (identity.Caller, error) + Get(ctx context.Context) (identity.Caller, error) } diff --git a/internal/pkg/cli/init.go b/internal/pkg/cli/init.go index 20fe426142c..02a9e1816ef 100644 --- a/internal/pkg/cli/init.go +++ b/internal/pkg/cli/init.go @@ -160,8 +160,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { identity: id, fs: fs, newInterpolator: newManifestInterpolator, - newEnvVersionGetter: func(appName, envName string) (versionGetter, error) { - return describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + newEnvVersionGetter: func(ctx context.Context, appName, envName string) (versionGetter, error) { + return describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: appName, Env: envName, ConfigStore: configStore, @@ -183,8 +183,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { sessProvider: sessProvider, templateVersion: version.LatestTemplateVersion(), } - deploySvcCmd.newSvcDeployer = func() (workloadDeployer, error) { - return newSvcDeployer(deploySvcCmd) + deploySvcCmd.newSvcDeployer = func(ctx context.Context) (workloadDeployer, error) { + return newSvcDeployer(ctx, deploySvcCmd) } deployJobCmd := &deployJobOpts{ deployWkldVars: deployWkldVars{ @@ -197,8 +197,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { sessProvider: sessProvider, templateVersion: version.LatestTemplateVersion(), } - deployJobCmd.newJobDeployer = func() (workloadDeployer, error) { - return newJobDeployer(deployJobCmd) + deployJobCmd.newJobDeployer = func(ctx context.Context) (workloadDeployer, error) { + return newJobDeployer(ctx, deployJobCmd) } cmd := exec.NewCmd() @@ -212,8 +212,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { initEnvCmd.manifestWriter = ws initEnvCmd.envLister = ws deployEnvCmd.ws = ws - deployEnvCmd.newEnvDeployer = func() (envDeployer, error) { - return newEnvDeployer(deployEnvCmd, ws) + deployEnvCmd.newEnvDeployer = func(ctx context.Context) (envDeployer, error) { + return newEnvDeployer(ctx, deployEnvCmd, ws) } deploySvcCmd.ws = ws deploySvcCmd.sel = sel @@ -289,8 +289,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { return dockerfile.New(fs, s) }, templateVersion: version.LatestTemplateVersion(), - initEnvDescriber: func(appName string, envName string) (envDescriber, error) { - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + initEnvDescriber: func(ctx context.Context, appName string, envName string) (envDescriber, error) { + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: appName, Env: envName, ConfigStore: configStore, @@ -337,8 +337,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { opts.df = dockerfile.New(opts.fs, opts.dockerfilePath) return opts.df } - opts.initEnvDescriber = func(appName string, envName string) (envDescriber, error) { - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + opts.initEnvDescriber = func(ctx context.Context, appName string, envName string) (envDescriber, error) { + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: appName, Env: envName, ConfigStore: opts.store, @@ -373,7 +373,7 @@ func newInitOpts(vars initVars) (*initOpts, error) { } // Run executes "app init", "env init", "svc init" and "svc deploy". -func (o *initOpts) Run() error { +func (o *initOpts) Run(ctx context.Context) error { if !workspace.IsInGitRepository(afero.NewOsFs()) { log.Warningln("It's best to run this command in the root of your Git repository.") } @@ -382,31 +382,31 @@ to help you get set up with a containerized application on AWS. An application i containerized services that operate together.`)) log.Infoln() - if err := o.loadApp(); err != nil { + if err := o.loadApp(ctx); err != nil { return err } - if err := o.loadWkld(); err != nil { + if err := o.loadWkld(ctx); err != nil { return err } o.logWorkloadTypeAck() log.Infoln() - if err := o.initAppCmd.Execute(); err != nil { + if err := o.initAppCmd.Execute(ctx); err != nil { return fmt.Errorf("execute app init: %w", err) } if err := o.useExistingWorkspaceForCMDs(o); err != nil { return fmt.Errorf("set up workspace client for commands: %w", err) } - if err := o.initWlCmd.Execute(); err != nil { + if err := o.initWlCmd.Execute(ctx); err != nil { return fmt.Errorf("execute %s init: %w", o.wkldType, err) } - if err := o.deployEnv(); err != nil { + if err := o.deployEnv(ctx); err != nil { return err } - return o.deploy() + return o.deploy(ctx) } func (o *initOpts) logWorkloadTypeAck() { @@ -418,15 +418,15 @@ func (o *initOpts) logWorkloadTypeAck() { log.Infof("Ok great, we'll set up a %s named %s in application %s.\n", color.HighlightUserInput(o.initWkldVars.wkldType), color.HighlightUserInput(o.initWkldVars.name), color.HighlightUserInput(o.initWkldVars.appName)) } -func (o *initOpts) deploy() error { +func (o *initOpts) deploy(ctx context.Context) error { if manifestinfo.IsTypeAJob(o.initWkldVars.wkldType) { - return o.deployJob() + return o.deployJob(ctx) } - return o.deploySvc() + return o.deploySvc(ctx) } -func (o *initOpts) loadApp() error { - if err := o.initAppCmd.Ask(); err != nil { +func (o *initOpts) loadApp(ctx context.Context) error { + if err := o.initAppCmd.Ask(ctx); err != nil { return fmt.Errorf("ask app init: %w", err) } if err := o.initAppCmd.Validate(); err != nil { @@ -435,7 +435,7 @@ func (o *initOpts) loadApp() error { return nil } -func (o *initOpts) loadWkld() error { +func (o *initOpts) loadWkld(ctx context.Context) error { err := o.loadWkldCmd() if err != nil { return err @@ -443,7 +443,7 @@ func (o *initOpts) loadWkld() error { if err := o.initWlCmd.Validate(); err != nil { return fmt.Errorf("validate %s: %w", o.wkldType, err) } - if err := o.initWlCmd.Ask(); err != nil { + if err := o.initWlCmd.Ask(ctx); err != nil { return fmt.Errorf("ask %s: %w", o.wkldType, err) } return nil @@ -476,7 +476,7 @@ func (o *initOpts) askWorkload() (string, error) { } // deployEnv prompts the user to deploy a test environment if the application doesn't already have one. -func (o *initOpts) deployEnv() error { +func (o *initOpts) deployEnv(ctx context.Context) error { log.Infoln("All right, you're all set for local development.") if err := o.askShouldDeploy(); err != nil { return err @@ -492,7 +492,7 @@ func (o *initOpts) deployEnv() error { initEnvCmd.name = o.initVars.envName } - if err := o.askEnvNameAndMaybeInit(); err != nil { + if err := o.askEnvNameAndMaybeInit(ctx); err != nil { return err } @@ -502,7 +502,7 @@ func (o *initOpts) deployEnv() error { deployEnvCmd.name = *o.envName } - if err := o.deployEnvCmd.Execute(); err != nil { + if err := o.deployEnvCmd.Execute(ctx); err != nil { var errEmptyChangeSet *awscfn.ErrChangeSetEmpty if !errors.As(err, &errEmptyChangeSet) { return err @@ -511,7 +511,7 @@ func (o *initOpts) deployEnv() error { return nil } -func (o *initOpts) deploySvc() error { +func (o *initOpts) deploySvc(ctx context.Context) error { if !aws.ToBool(o.shouldDeploy) { return nil } @@ -522,10 +522,10 @@ func (o *initOpts) deploySvc() error { deployOpts.envName = *o.envName } - if err := o.deploySvcCmd.Ask(); err != nil { + if err := o.deploySvcCmd.Ask(ctx); err != nil { return err } - if err := o.deploySvcCmd.Execute(); err != nil { + if err := o.deploySvcCmd.Execute(ctx); err != nil { return err } if err := o.deploySvcCmd.RecommendActions(); err != nil { @@ -534,7 +534,7 @@ func (o *initOpts) deploySvc() error { return nil } -func (o *initOpts) deployJob() error { +func (o *initOpts) deployJob(ctx context.Context) error { if !aws.ToBool(o.shouldDeploy) { return nil } @@ -545,10 +545,10 @@ func (o *initOpts) deployJob() error { deployOpts.envName = *o.envName } - if err := o.deployJobCmd.Ask(); err != nil { + if err := o.deployJobCmd.Ask(ctx); err != nil { return err } - if err := o.deployJobCmd.Execute(); err != nil { + if err := o.deployJobCmd.Execute(ctx); err != nil { return err } if err := o.deployJobCmd.RecommendActions(); err != nil { @@ -569,10 +569,10 @@ func (o *initOpts) askShouldDeploy() error { return nil } -func (o *initOpts) askEnvNameAndMaybeInit() error { +func (o *initOpts) askEnvNameAndMaybeInit(ctx context.Context) error { if o.initVars.envName == "" { // Select one of existing envs or create a new one. - selectedEnv, err := o.sel.Environment(initExistingEnvSelectPrompt, initExistingEnvSelectHelp, *o.appName, prompt.Option{Value: envPromptCreateNew}) + selectedEnv, err := o.sel.Environment(ctx, initExistingEnvSelectPrompt, initExistingEnvSelectHelp, *o.appName, prompt.Option{Value: envPromptCreateNew}) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -594,7 +594,7 @@ func (o *initOpts) askEnvNameAndMaybeInit() error { } // If the environment doesn't exist, initialize it. If it does exist, return early. - _, err := o.store.GetEnvironment(*o.appName, o.initVars.envName) + _, err := o.store.GetEnvironment(ctx, *o.appName, o.initVars.envName) // nil error means environment exists and we don't need to init. if err == nil { return nil @@ -607,7 +607,7 @@ func (o *initOpts) askEnvNameAndMaybeInit() error { } log.Infof("Environment %s does not yet exist in application %s; initializing it.\n", o.initVars.envName, *o.appName) - if err := o.initEnvCmd.Execute(); err != nil { + if err := o.initEnvCmd.Execute(ctx); err != nil { return err } log.Successf("Provisioned bootstrap resources for environment %s.\n", o.initVars.envName) @@ -636,7 +636,7 @@ func BuildInitCmd() *cobra.Command { } } - if err := opts.Run(); err != nil { + if err := opts.Run(cmd.Context()); err != nil { return err } diff --git a/internal/pkg/cli/init_test.go b/internal/pkg/cli/init_test.go index befb8f76874..2a3f907854c 100644 --- a/internal/pkg/cli/init_test.go +++ b/internal/pkg/cli/init_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -37,14 +38,14 @@ func TestInitOpts_Run(t *testing.T) { "returns prompt error for application": { inWlType: "Load Balanced Web Service", expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(errors.New("my error")) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(errors.New("my error")) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Times(0) }, wantedError: "ask app init: my error", }, "returns validation error for application": { expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(errors.New("my error")) }, wantedError: "my error", @@ -52,17 +53,17 @@ func TestInitOpts_Run(t *testing.T) { "returns prompt error for service": { inWlType: "Backend Service", expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Times(1).Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(errors.New("my error")) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(errors.New("my error")) }, wantedError: "ask Backend Service: my error", }, "returns validation error for service": { inWlType: "Load Balanced Web Service", expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(errors.New("my error")) }, @@ -71,61 +72,61 @@ func TestInitOpts_Run(t *testing.T) { "returns execute error for application": { expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(errors.New("my error")) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Times(0) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(errors.New("my error")) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Times(0) }, wantedError: "execute app init: my error", }, "returns execute error for service": { inWlType: "Load Balanced Web Service", expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(errors.New("my error")) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(errors.New("my error")) }, wantedError: "execute Load Balanced Web Service init: my error", }, "fail to deploy an environment": { expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(manifestinfo.LoadBalancedWebServiceType, nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(ctx, initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Confirm(initShouldDeployPrompt, initShouldDeployHelpPrompt, gomock.Any()). Return(true, nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Get(envInitNamePrompt, envInitNameHelpPrompt, gomock.Any(), gomock.Any()).Return("test2", nil) - opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(mockAppName, "test2").Return(nil, &config.ErrNoSuchEnvironment{ + opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(ctx, mockAppName, "test2").Return(nil, &config.ErrNoSuchEnvironment{ ApplicationName: mockAppName, EnvironmentName: "test2", }) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Return(errors.New("some error")) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Return(errors.New("some error")) }, wantedError: "some error", }, "fail to get env name": { expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(manifestinfo.LoadBalancedWebServiceType, nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Confirm(initShouldDeployPrompt, initShouldDeployHelpPrompt, gomock.Any()). Return(true, nil) - opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) + opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(ctx, initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Get(envInitNamePrompt, envInitNameHelpPrompt, gomock.Any(), gomock.Any()).Return("", errors.New("some error")) }, wantedError: "get environment name: some error", @@ -133,24 +134,24 @@ func TestInitOpts_Run(t *testing.T) { "deploys environment": { expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(manifestinfo.LoadBalancedWebServiceType, nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Confirm(initShouldDeployPrompt, initShouldDeployHelpPrompt, gomock.Any()). Return(true, nil) - opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) + opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(ctx, initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Get(envInitNamePrompt, envInitNameHelpPrompt, gomock.Any(), gomock.Any()).Return("test2", nil) - opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(mockAppName, "test2").Return(nil, &config.ErrNoSuchEnvironment{ + opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(ctx, mockAppName, "test2").Return(nil, &config.ErrNoSuchEnvironment{ ApplicationName: mockAppName, EnvironmentName: "test2", }) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().RecommendActions().Return(nil) }, }, @@ -158,40 +159,40 @@ func TestInitOpts_Run(t *testing.T) { inEnvName: "test2", expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(manifestinfo.LoadBalancedWebServiceType, nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Confirm(initShouldDeployPrompt, initShouldDeployHelpPrompt, gomock.Any()). Return(true, nil) - opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(mockAppName, "test2").Return(&config.Environment{}, nil) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Times(0) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(ctx, mockAppName, "test2").Return(&config.Environment{}, nil) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Times(0) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().RecommendActions().Return(nil) }, }, "should not error out if environment change set is empty": { expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(manifestinfo.LoadBalancedWebServiceType, nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Confirm(initShouldDeployPrompt, initShouldDeployHelpPrompt, gomock.Any()). Return(true, nil) - opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) + opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(ctx, initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return(envPromptCreateNew, nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Get(envInitNamePrompt, envInitNameHelpPrompt, gomock.Any(), gomock.Any()).Return("test2", nil) - opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(mockAppName, "test2").Return(&config.Environment{}, nil) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Times(0) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Return(fmt.Errorf("wrap: %w", &awscfn.ErrChangeSetEmpty{})) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(ctx, mockAppName, "test2").Return(&config.Environment{}, nil) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Times(0) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Return(fmt.Errorf("wrap: %w", &awscfn.ErrChangeSetEmpty{})) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().RecommendActions().Return(nil) }, }, @@ -223,32 +224,32 @@ func TestInitOpts_Run(t *testing.T) { Hint: jobTypeHint, }, }, gomock.Any()) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Confirm(initShouldDeployPrompt, initShouldDeployHelpPrompt, gomock.Any()). Return(true, nil) - opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return("test2", nil) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Times(0) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.sel.(*climocks.MockconfigSelector).EXPECT().Environment(ctx, initExistingEnvSelectPrompt, initExistingEnvSelectHelp, mockAppName, prompt.Option{Value: envPromptCreateNew}).Return("test2", nil) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Times(0) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().RecommendActions().Return(nil) }, }, "should not deploy the svc if shouldDeploy is false": { expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(manifestinfo.LoadBalancedWebServiceType, nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.prompt.(*climocks.Mockprompter).EXPECT().Confirm(initShouldDeployPrompt, initShouldDeployHelpPrompt, gomock.Any()). Return(false, nil) @@ -258,12 +259,12 @@ func TestInitOpts_Run(t *testing.T) { inShouldDeploy: aws.Bool(false), expect: func(opts *initOpts) { opts.prompt.(*climocks.Mockprompter).EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(manifestinfo.LoadBalancedWebServiceType, nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) }, }, "should skip prompting if all flags and --deploy explicitly specified": { @@ -272,17 +273,17 @@ func TestInitOpts_Run(t *testing.T) { inWlType: manifestinfo.LoadBalancedWebServiceType, inAppName: mockAppName, expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(mockAppName, "test2").Return(nil, &config.ErrNoSuchEnvironment{ApplicationName: mockAppName, EnvironmentName: "test2"}) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(ctx, mockAppName, "test2").Return(nil, &config.ErrNoSuchEnvironment{ApplicationName: mockAppName, EnvironmentName: "test2"}) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().RecommendActions().Return(nil) }, }, @@ -292,17 +293,17 @@ func TestInitOpts_Run(t *testing.T) { inWlType: manifestinfo.LoadBalancedWebServiceType, inAppName: mockAppName, expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Times(0) - opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(mockAppName, "test2").Return(nil, nil) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Times(0) + opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(ctx, mockAppName, "test2").Return(nil, nil) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().RecommendActions().Return(nil) }, }, @@ -312,17 +313,17 @@ func TestInitOpts_Run(t *testing.T) { inWlType: manifestinfo.LoadBalancedWebServiceType, inAppName: mockAppName, expect: func(opts *initOpts) { - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask().Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Return(nil) opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Validate().Return(nil) - opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute().Return(nil) - opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute().Times(0) - opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(mockAppName, "test2").Return(nil, fmt.Errorf("some error")) - opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute().Times(0) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask().Times(0) - opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute().Times(0) + opts.initAppCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initWlCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Return(nil) + opts.initEnvCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Times(0) + opts.store.(*climocks.Mockstore).EXPECT().GetEnvironment(ctx, mockAppName, "test2").Return(nil, fmt.Errorf("some error")) + opts.deployEnvCmd.(*climocks.Mockcmd).EXPECT().Execute(gomock.Any()).Times(0) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Ask(gomock.Any()).Times(0) + opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().Execute(gomock.Any()).Times(0) opts.deploySvcCmd.(*climocks.MockactionCommand).EXPECT().RecommendActions().Times(0) }, wantedError: "some error", @@ -366,7 +367,7 @@ func TestInitOpts_Run(t *testing.T) { tc.expect(opts) // WHEN - err := opts.Run() + err := opts.Run(context.Background()) // THEN if tc.wantedError != "" { diff --git a/internal/pkg/cli/interfaces.go b/internal/pkg/cli/interfaces.go index 3e28add545a..3b665200477 100644 --- a/internal/pkg/cli/interfaces.go +++ b/internal/pkg/cli/interfaces.go @@ -43,10 +43,10 @@ type cmd interface { Validate() error // Ask prompts for flag values that are required but not passed in. - Ask() error + Ask(context.Context) error // Execute runs the command after collecting all required options. - Execute() error + Execute(context.Context) error } // actionCommand is the interface that every command that creates a resource implements. @@ -59,26 +59,26 @@ type actionCommand interface { // SSM store interfaces. type serviceStore interface { - CreateService(svc *config.Workload) error - GetService(appName, svcName string) (*config.Workload, error) - ListServices(appName string) ([]*config.Workload, error) - DeleteService(appName, svcName string) error + CreateService(ctx context.Context, svc *config.Workload) error + GetService(ctx context.Context, appName, svcName string) (*config.Workload, error) + ListServices(ctx context.Context, appName string) ([]*config.Workload, error) + DeleteService(ctx context.Context, appName, svcName string) error } type jobStore interface { - CreateJob(job *config.Workload) error - GetJob(appName, jobName string) (*config.Workload, error) - ListJobs(appName string) ([]*config.Workload, error) - DeleteJob(appName, jobName string) error + CreateJob(ctx context.Context, job *config.Workload) error + GetJob(ctx context.Context, appName, jobName string) (*config.Workload, error) + ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) + DeleteJob(ctx context.Context, appName, jobName string) error } type wlStore interface { - ListWorkloads(appName string) ([]*config.Workload, error) - GetWorkload(appName, name string) (*config.Workload, error) + ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) + GetWorkload(ctx context.Context, appName, name string) (*config.Workload, error) } type workloadListWriter interface { - Write(appName string) error + Write(ctx context.Context, appName string) error } type applicationStore interface { @@ -90,23 +90,23 @@ type applicationStore interface { } type applicationCreator interface { - CreateApplication(app *config.Application) error + CreateApplication(ctx context.Context, app *config.Application) error } type applicationUpdater interface { - UpdateApplication(app *config.Application) error + UpdateApplication(ctx context.Context, app *config.Application) error } type applicationGetter interface { - GetApplication(appName string) (*config.Application, error) + GetApplication(ctx context.Context, appName string) (*config.Application, error) } type applicationLister interface { - ListApplications() ([]*config.Application, error) + ListApplications(ctx context.Context) ([]*config.Application, error) } type applicationDeleter interface { - DeleteApplication(name string) error + DeleteApplication(ctx context.Context, name string) error } type environmentStore interface { @@ -118,15 +118,15 @@ type environmentStore interface { } type environmentCreator interface { - CreateEnvironment(env *config.Environment) error + CreateEnvironment(ctx context.Context, env *config.Environment) error } type environmentGetter interface { - GetEnvironment(appName string, environmentName string) (*config.Environment, error) + GetEnvironment(ctx context.Context, appName string, environmentName string) (*config.Environment, error) } type environmentLister interface { - ListEnvironments(appName string) ([]*config.Environment, error) + ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) } type wsEnvironmentsLister interface { @@ -134,7 +134,7 @@ type wsEnvironmentsLister interface { } type environmentDeleter interface { - DeleteEnvironment(appName, environmentName string) error + DeleteEnvironment(ctx context.Context, appName, environmentName string) error } type store interface { @@ -146,11 +146,11 @@ type store interface { } type deployedEnvironmentLister interface { - ListEnvironmentsDeployedTo(appName, svcName string) ([]string, error) - ListDeployedServices(appName, envName string) ([]string, error) - ListDeployedJobs(appName string, envName string) ([]string, error) - IsServiceDeployed(appName, envName string, svcName string) (bool, error) - ListSNSTopics(appName string, envName string) ([]deploy.Topic, error) + ListEnvironmentsDeployedTo(ctx context.Context, appName, svcName string) ([]string, error) + ListDeployedServices(ctx context.Context, appName, envName string) ([]string, error) + ListDeployedJobs(ctx context.Context, appName string, envName string) ([]string, error) + IsServiceDeployed(ctx context.Context, appName, envName string, svcName string) (bool, error) + ListSNSTopics(ctx context.Context, appName string, envName string) ([]deploy.Topic, error) } // Secretsmanager interface. @@ -379,7 +379,7 @@ type stackDescriber interface { type environmentDeployer interface { CreateAndRenderEnvironment(conf cloudformation.StackConfiguration, bucketARN string) error DeleteEnvironment(appName, envName, cfnExecRoleARN string) error - GetEnvironment(appName, envName string) (*config.Environment, error) + GetEnvironment(ctx context.Context, appName, envName string) (*config.Environment, error) Template(stackName string) (string, error) UpdateEnvironmentTemplate(appName, envName, templateBody, cfnExecRoleARN string) error } @@ -498,21 +498,21 @@ type deployedPipelineLister interface { } type executor interface { - Execute() error + Execute(context.Context) error } type executeAsker interface { - Ask() error + Ask(context.Context) error executor } type appSelector interface { - Application(prompt, help string, additionalOpts ...string) (string, error) + Application(ctx context.Context, prompt, help string, additionalOpts ...string) (string, error) } type appEnvSelector interface { appSelector - Environment(prompt, help, app string, additionalOpts ...prompt.Option) (string, error) + Environment(ctx context.Context, prompt, help, app string, additionalOpts ...prompt.Option) (string, error) } type cfnSelector interface { @@ -521,20 +521,20 @@ type cfnSelector interface { type configSelector interface { appEnvSelector - Service(prompt, help, app string) (string, error) - Job(prompt, help, app string) (string, error) - Workload(prompt, help, app string) (string, error) + Service(ctx context.Context, prompt, help, app string) (string, error) + Job(ctx context.Context, prompt, help, app string) (string, error) + Workload(ctx context.Context, prompt, help, app string) (string, error) } type deploySelector interface { appSelector - DeployedService(prompt, help string, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedService, error) - DeployedJob(prompt, help string, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedJob, error) - DeployedWorkload(prompt, help string, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedWorkload, error) + DeployedService(ctx context.Context, prompt, help string, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedService, error) + DeployedJob(ctx context.Context, prompt, help string, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedJob, error) + DeployedWorkload(ctx context.Context, prompt, help string, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedWorkload, error) } type pipelineEnvSelector interface { - Environments(prompt, help, app string, finalMsgFunc func(int) prompt.PromptConfig) ([]string, error) + Environments(ctx context.Context, prompt, help, app string, finalMsgFunc func(int) prompt.PromptConfig) ([]string, error) } type wsPipelineSelector interface { @@ -542,7 +542,7 @@ type wsPipelineSelector interface { } type wsEnvironmentSelector interface { - LocalEnvironment(msg, help string) (wl string, err error) + LocalEnvironment(ctx context.Context, msg, help string) (wl string, err error) } type codePipelineSelector interface { @@ -552,10 +552,10 @@ type codePipelineSelector interface { type wsSelector interface { appEnvSelector - Service(prompt, help string) (string, error) - Job(prompt, help string) (string, error) - Workload(msg, help string) (string, error) - Workloads(msg, help string) ([]string, error) + Service(ctx context.Context, prompt, help string) (string, error) + Job(ctx context.Context, prompt, help string) (string, error) + Workload(ctx context.Context, msg, help string) (string, error) + Workloads(ctx context.Context, msg, help string) ([]string, error) } type staticSourceSelector interface { @@ -575,7 +575,7 @@ type dockerfileSelector interface { } type topicSelector interface { - Topics(prompt, help, app string) ([]deploy.Topic, error) + Topics(ctx context.Context, prompt, help, app string) ([]deploy.Topic, error) } type ec2Selector interface { @@ -597,15 +597,15 @@ type serviceResumer interface { } type jobInitializer interface { - Job(props *initialize.JobProps) (string, error) + Job(ctx context.Context, props *initialize.JobProps) (string, error) } type svcInitializer interface { - Service(props *initialize.ServiceProps) (string, error) + Service(ctx context.Context, props *initialize.ServiceProps) (string, error) } type wkldInitializerWithoutManifest interface { - AddWorkloadToApp(appName, name, workloadType string) error + AddWorkloadToApp(ctx context.Context, appName, name, workloadType string) error } type roleDeleter interface { diff --git a/internal/pkg/cli/job_delete.go b/internal/pkg/cli/job_delete.go index c39b2d66d80..c87ec77a123 100644 --- a/internal/pkg/cli/job_delete.go +++ b/internal/pkg/cli/job_delete.go @@ -102,22 +102,22 @@ func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { // Validate returns an error if the user inputs are invalid. func (o *deleteJobOpts) Validate() error { if o.name != "" { - if _, err := o.store.GetJob(o.appName, o.name); err != nil { + if _, err := o.store.GetJob(context.Background(), o.appName, o.name); err != nil { return err } } if o.envName != "" { - return o.validateEnvName() + return o.validateEnvName(context.Background()) } return nil } // Ask prompts the user for any required flags. -func (o *deleteJobOpts) Ask() error { - if err := o.askAppName(); err != nil { +func (o *deleteJobOpts) Ask(ctx context.Context) error { + if err := o.askAppName(ctx); err != nil { return err } - if err := o.askJobName(); err != nil { + if err := o.askJobName(ctx); err != nil { return err } @@ -154,8 +154,8 @@ func (o *deleteJobOpts) Ask() error { // Execute deletes the job's CloudFormation stack. // If the job is being removed from the application, Execute will // also delete the ECR repository and the SSM parameter. -func (o *deleteJobOpts) Execute() error { - envs, err := o.appEnvironments() +func (o *deleteJobOpts) Execute(ctx context.Context) error { + envs, err := o.appEnvironments(ctx) if err != nil { return err } @@ -173,10 +173,10 @@ func (o *deleteJobOpts) Execute() error { if err := o.emptyECRRepos(envs); err != nil { return err } - if err := o.removeJobFromApp(); err != nil { + if err := o.removeJobFromApp(ctx); err != nil { return err } - if err := o.deleteSSMParam(); err != nil { + if err := o.deleteSSMParam(ctx); err != nil { return err } @@ -185,27 +185,27 @@ func (o *deleteJobOpts) Execute() error { return nil } -func (o *deleteJobOpts) validateEnvName() error { - if _, err := o.targetEnv(); err != nil { +func (o *deleteJobOpts) validateEnvName(ctx context.Context) error { + if _, err := o.targetEnv(ctx); err != nil { return err } return nil } -func (o *deleteJobOpts) targetEnv() (*config.Environment, error) { - env, err := o.store.GetEnvironment(o.appName, o.envName) +func (o *deleteJobOpts) targetEnv(ctx context.Context) (*config.Environment, error) { + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return nil, fmt.Errorf("get environment %s from config store: %w", o.envName, err) } return env, nil } -func (o *deleteJobOpts) askAppName() error { +func (o *deleteJobOpts) askAppName(ctx context.Context) error { if o.appName != "" { return nil } - name, err := o.sel.Application(jobDeleteAppNamePrompt, "") + name, err := o.sel.Application(ctx, jobDeleteAppNamePrompt, "") if err != nil { return fmt.Errorf("select application name: %w", err) } @@ -213,12 +213,12 @@ func (o *deleteJobOpts) askAppName() error { return nil } -func (o *deleteJobOpts) askJobName() error { +func (o *deleteJobOpts) askJobName(ctx context.Context) error { if o.name != "" { return nil } - name, err := o.sel.Job(jobDeleteJobNamePrompt, "", o.appName) + name, err := o.sel.Job(ctx, jobDeleteJobNamePrompt, "", o.appName) if err != nil { return fmt.Errorf("select job: %w", err) } @@ -226,17 +226,17 @@ func (o *deleteJobOpts) askJobName() error { return nil } -func (o *deleteJobOpts) appEnvironments() ([]*config.Environment, error) { +func (o *deleteJobOpts) appEnvironments(ctx context.Context) ([]*config.Environment, error) { var envs []*config.Environment var err error if o.envName != "" { - env, err := o.targetEnv() + env, err := o.targetEnv(ctx) if err != nil { return nil, err } envs = append(envs, env) } else { - envs, err = o.store.ListEnvironments(o.appName) + envs, err = o.store.ListEnvironments(ctx, o.appName) if err != nil { return nil, fmt.Errorf("list environments: %w", err) } @@ -316,8 +316,8 @@ func (o *deleteJobOpts) emptyECRRepos(envs []*config.Environment) error { return nil } -func (o *deleteJobOpts) removeJobFromApp() error { - proj, err := o.store.GetApplication(o.appName) +func (o *deleteJobOpts) removeJobFromApp(ctx context.Context) error { + proj, err := o.store.GetApplication(ctx, o.appName) if err != nil { return err } @@ -330,8 +330,8 @@ func (o *deleteJobOpts) removeJobFromApp() error { return nil } -func (o *deleteJobOpts) deleteSSMParam() error { - if err := o.store.DeleteJob(o.appName, o.name); err != nil { +func (o *deleteJobOpts) deleteSSMParam(ctx context.Context) error { + if err := o.store.DeleteJob(ctx, o.appName, o.name); err != nil { return fmt.Errorf("delete job %s in application %s from config store: %w", o.name, o.appName, err) } @@ -370,7 +370,7 @@ func buildJobDeleteCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } diff --git a/internal/pkg/cli/job_delete_test.go b/internal/pkg/cli/job_delete_test.go index cf2d355e5cb..81c5f15602f 100644 --- a/internal/pkg/cli/job_delete_test.go +++ b/internal/pkg/cli/job_delete_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -38,9 +39,9 @@ func TestDeleteJobOpts_Validate(t *testing.T) { inEnvName: "test", inName: "resizer", setupMocks: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("phonetool", "test"). + m.EXPECT().GetEnvironment(ctx, "phonetool", "test"). Return(&config.Environment{Name: "test"}, nil) - m.EXPECT().GetJob("phonetool", "resizer").Times(1).Return(&config.Workload{ + m.EXPECT().GetJob(ctx, "phonetool", "resizer").Times(1).Return(&config.Workload{ Name: "resizer", }, nil) }, @@ -50,7 +51,7 @@ func TestDeleteJobOpts_Validate(t *testing.T) { inAppName: "phonetool", inEnvName: "test", setupMocks: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("phonetool", "test"). + m.EXPECT().GetEnvironment(ctx, "phonetool", "test"). Return(&config.Environment{Name: "test"}, nil) }, want: nil, @@ -59,7 +60,7 @@ func TestDeleteJobOpts_Validate(t *testing.T) { inAppName: "phonetool", inName: "resizer", setupMocks: func(m *mocks.Mockstore) { - m.EXPECT().GetJob("phonetool", "resizer").Times(1).Return(&config.Workload{ + m.EXPECT().GetJob(ctx, "phonetool", "resizer").Times(1).Return(&config.Workload{ Name: "resizer", }, nil) }, @@ -69,7 +70,7 @@ func TestDeleteJobOpts_Validate(t *testing.T) { inAppName: "phonetool", inEnvName: "test", setupMocks: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("phonetool", "test").Return(nil, errors.New("unknown env")) + m.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(nil, errors.New("unknown env")) }, want: errors.New("get environment test from config store: unknown env"), }, @@ -77,7 +78,7 @@ func TestDeleteJobOpts_Validate(t *testing.T) { inAppName: "phonetool", inName: "resizer", setupMocks: func(m *mocks.Mockstore) { - m.EXPECT().GetJob("phonetool", "resizer").Times(1).Return(nil, mockError) + m.EXPECT().GetJob(ctx, "phonetool", "resizer").Times(1).Return(nil, mockError) }, want: errors.New("some error"), }, @@ -135,7 +136,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: testJobName, skipConfirmation: true, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Application("Which application's job would you like to delete?", "").Return(testAppName, nil) + m.EXPECT().Application(ctx, "Which application's job would you like to delete?", "").Return(testAppName, nil) }, mockPrompt: func(m *mocks.Mockprompter) {}, @@ -146,7 +147,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: "", skipConfirmation: true, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job("Which job would you like to delete?", "", testAppName).Return(testJobName, nil) + m.EXPECT().Job(ctx, "Which job would you like to delete?", "", testAppName).Return(testJobName, nil) }, mockPrompt: func(m *mocks.Mockprompter) {}, @@ -157,7 +158,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: "", skipConfirmation: true, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job("Which job would you like to delete?", "", testAppName).Return("", mockError) + m.EXPECT().Job(ctx, "Which job would you like to delete?", "", testAppName).Return("", mockError) }, mockPrompt: func(m *mocks.Mockprompter) {}, @@ -168,7 +169,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: "", skipConfirmation: true, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job("Which job would you like to delete?", "", testAppName).Return("", mockError) + m.EXPECT().Job(ctx, "Which job would you like to delete?", "", testAppName).Return("", mockError) }, mockPrompt: func(m *mocks.Mockprompter) {}, @@ -179,7 +180,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: testJobName, skipConfirmation: true, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockPrompt: func(m *mocks.Mockprompter) {}, @@ -190,7 +191,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: testJobName, skipConfirmation: false, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Confirm( @@ -207,7 +208,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: testJobName, skipConfirmation: false, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Confirm( @@ -224,7 +225,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { inName: testJobName, skipConfirmation: false, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Confirm( @@ -242,7 +243,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { envName: "test", skipConfirmation: false, mockSel: func(m *mocks.MockconfigSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, mockPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Confirm( @@ -277,7 +278,7 @@ func TestDeleteJobOpts_Ask(t *testing.T) { sel: mockSel, } - got := opts.Ask() + got := opts.Ask(context.Background()) if got != nil { require.Equal(t, test.wantedError, got) @@ -332,7 +333,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { setupMocks: func(mocks deleteJobMocks) { gomock.InOrder( // appEnvironments - mocks.store.EXPECT().ListEnvironments(gomock.Eq(mockAppName)).Times(1).Return(mockEnvs, nil), + mocks.store.EXPECT().ListEnvironments(ctx, gomock.Eq(mockAppName)).Times(1).Return(mockEnvs, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks @@ -346,11 +347,11 @@ func TestDeleteJobOpts_Execute(t *testing.T) { // emptyECRRepos mocks.ecr.EXPECT().ClearRepository(mockRepo).Return(nil), // removeJobFromApp - mocks.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil), + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil), mocks.appCFN.EXPECT().RemoveJobFromApp(mockApp, mockJobName).Return(nil), // deleteSSMParam - mocks.store.EXPECT().DeleteJob(mockAppName, mockJobName).Return(nil), + mocks.store.EXPECT().DeleteJob(ctx, mockAppName, mockJobName).Return(nil), ) }, wantedError: nil, @@ -365,7 +366,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { setupMocks: func(mocks deleteJobMocks) { gomock.InOrder( // appEnvironments - mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), + mocks.store.EXPECT().GetEnvironment(ctx, mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks mocks.jobCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(nil), @@ -381,7 +382,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { mocks.appCFN.EXPECT().RemoveJobFromApp(gomock.Any(), gomock.Any()).Return(nil).Times(0), // It should **not** deleteSSMParam - mocks.store.EXPECT().DeleteJob(gomock.Any(), gomock.Any()).Return(nil).Times(0), + mocks.store.EXPECT().DeleteJob(ctx, gomock.Any(), gomock.Any()).Return(nil).Times(0), ) }, wantedError: nil, @@ -393,7 +394,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { setupMocks: func(mocks deleteJobMocks) { gomock.InOrder( // appEnvironments - mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), + mocks.store.EXPECT().GetEnvironment(ctx, mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), // deleteStacks mocks.jobCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(testError), @@ -408,7 +409,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { setupMocks: func(mocks deleteJobMocks) { gomock.InOrder( // appEnvironments - mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), + mocks.store.EXPECT().GetEnvironment(ctx, mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), // deleteStacks mocks.jobCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(nil), @@ -475,7 +476,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if test.wantedError != nil { diff --git a/internal/pkg/cli/job_deploy.go b/internal/pkg/cli/job_deploy.go index 9a7c53c7565..47124134522 100644 --- a/internal/pkg/cli/job_deploy.go +++ b/internal/pkg/cli/job_deploy.go @@ -45,7 +45,7 @@ type deployJobOpts struct { cmd execRunner jobVersionGetter versionGetter sessProvider *sessions.Provider - newJobDeployer func() (workloadDeployer, error) + newJobDeployer func(context.Context) (workloadDeployer, error) envFeaturesDescriber versionCompatibilityChecker sel wsSelector prompt prompter @@ -90,14 +90,14 @@ func newJobDeployOpts(vars deployWkldVars) (*deployJobOpts, error) { templateVersion: version.LatestTemplateVersion(), diffWriter: os.Stdout, } - opts.newJobDeployer = func() (workloadDeployer, error) { + opts.newJobDeployer = func(ctx context.Context) (workloadDeployer, error) { // NOTE: Defined as a struct member to facilitate unit testing. - return newJobDeployer(opts) + return newJobDeployer(ctx, opts) } return opts, nil } -func newJobDeployer(o *deployJobOpts) (workloadDeployer, error) { +func newJobDeployer(ctx context.Context, o *deployJobOpts) (workloadDeployer, error) { ovrdr, err := deploy.NewOverrider(o.ws.WorkloadOverridesPath(o.name), o.appName, o.envName, afero.NewOsFs(), o.sessProvider) if err != nil { return nil, err @@ -105,6 +105,7 @@ func newJobDeployer(o *deployJobOpts) (workloadDeployer, error) { content := o.appliedDynamicMft.Manifest() in := deploy.WorkloadDeployerInput{ + Ctx: ctx, SessionProvider: o.sessProvider, Name: o.name, App: o.targetApp, @@ -137,12 +138,12 @@ func (o *deployJobOpts) Validate() error { return errNoAppInWorkspace } if o.name != "" { - if err := o.validateJobName(); err != nil { + if err := o.validateJobName(context.Background()); err != nil { return err } } if o.envName != "" { - if err := o.validateEnvName(); err != nil { + if err := o.validateEnvName(context.Background()); err != nil { return err } } @@ -150,20 +151,20 @@ func (o *deployJobOpts) Validate() error { } // Ask prompts the user for any required fields that are not provided. -func (o *deployJobOpts) Ask() error { - if err := o.askJobName(); err != nil { +func (o *deployJobOpts) Ask(ctx context.Context) error { + if err := o.askJobName(ctx); err != nil { return err } - if err := o.askEnvName(); err != nil { + if err := o.askEnvName(ctx); err != nil { return err } return nil } // Execute builds and pushes the container image for the job. -func (o *deployJobOpts) Execute() error { +func (o *deployJobOpts) Execute(ctx context.Context) error { if !o.clientConfigured { - if err := o.configureClients(); err != nil { + if err := o.configureClients(ctx); err != nil { return err } } @@ -189,7 +190,7 @@ func (o *deployJobOpts) Execute() error { if err := validateWorkloadManifestCompatibilityWithEnv(o.ws, o.envFeaturesDescriber, mft, o.envName); err != nil { return err } - deployer, err := o.newJobDeployer() + deployer, err := o.newJobDeployer(ctx) if err != nil { return err } @@ -281,14 +282,14 @@ After fixing the deployment, you can: return nil } -func (o *deployJobOpts) configureClients() error { +func (o *deployJobOpts) configureClients(ctx context.Context) error { o.gitShortCommit = imageTagFromGit(o.cmd) // Best effort assign git tag. - env, err := o.store.GetEnvironment(o.appName, o.envName) + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return err } o.targetEnv = env - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { return err } @@ -306,13 +307,13 @@ func (o *deployJobOpts) configureClients() error { o.envConfig = envConfig // client to retrieve caller identity. - caller, err := identity.New(defaultConfig).Get() + caller, err := identity.New(defaultConfig).Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } o.rootUserARN = caller.RootUserARN - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: o.appName, Env: o.envName, ConfigStore: o.store, @@ -322,7 +323,7 @@ func (o *deployJobOpts) configureClients() error { } o.envFeaturesDescriber = envDescriber - wkldDescriber, err := describe.NewWorkloadStackDescriber(describe.NewWorkloadConfig{ + wkldDescriber, err := describe.NewWorkloadStackDescriber(ctx, describe.NewWorkloadConfig{ App: o.appName, Env: o.envName, Name: o.name, @@ -340,7 +341,7 @@ func (o *deployJobOpts) RecommendActions() error { return nil } -func (o *deployJobOpts) validateJobName() error { +func (o *deployJobOpts) validateJobName(ctx context.Context) error { names, err := o.ws.ListJobs() if err != nil { return fmt.Errorf("list jobs in the workspace: %w", err) @@ -353,19 +354,19 @@ func (o *deployJobOpts) validateJobName() error { return fmt.Errorf("job %s not found in the workspace", color.HighlightUserInput(o.name)) } -func (o *deployJobOpts) validateEnvName() error { - if _, err := o.store.GetEnvironment(o.appName, o.envName); err != nil { +func (o *deployJobOpts) validateEnvName(ctx context.Context) error { + if _, err := o.store.GetEnvironment(ctx, o.appName, o.envName); err != nil { return fmt.Errorf("get environment %s configuration: %w", o.envName, err) } return nil } -func (o *deployJobOpts) askJobName() error { +func (o *deployJobOpts) askJobName(ctx context.Context) error { if o.name != "" { return nil } - name, err := o.sel.Job("Select a job from your workspace", "") + name, err := o.sel.Job(ctx, "Select a job from your workspace", "") if err != nil { return fmt.Errorf("select job: %w", err) } @@ -373,12 +374,12 @@ func (o *deployJobOpts) askJobName() error { return nil } -func (o *deployJobOpts) askEnvName() error { +func (o *deployJobOpts) askEnvName(ctx context.Context) error { if o.envName != "" { return nil } - name, err := o.sel.Environment("Select an environment", "", o.appName) + name, err := o.sel.Environment(ctx, "Select an environment", "", o.appName) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -403,7 +404,7 @@ func buildJobDeployCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/job_deploy_test.go b/internal/pkg/cli/job_deploy_test.go index 8dc77e1e953..ee1c34b7eab 100644 --- a/internal/pkg/cli/job_deploy_test.go +++ b/internal/pkg/cli/job_deploy_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "strings" @@ -59,7 +60,7 @@ func TestJobDeployOpts_Validate(t *testing.T) { inEnvName: "test", mockWs: func(m *mocks.MockwsWlDirReader) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("phonetool", "test"). + m.EXPECT().GetEnvironment(ctx, "phonetool", "test"). Return(nil, errors.New("unknown env")) }, @@ -73,7 +74,7 @@ func TestJobDeployOpts_Validate(t *testing.T) { m.EXPECT().ListJobs().Return([]string{"resizer"}, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("phonetool", "test"). + m.EXPECT().GetEnvironment(ctx, "phonetool", "test"). Return(&config.Environment{Name: "test"}, nil) }, }, @@ -130,8 +131,8 @@ func TestJobDeployOpts_Ask(t *testing.T) { inAppName: "phonetool", inImageTag: "latest", wantedCalls: func(m *mocks.MockwsSelector) { - m.EXPECT().Job("Select a job from your workspace", "").Return("resizer", nil) - m.EXPECT().Environment("Select an environment", "", "phonetool").Return("prod-iad", nil) + m.EXPECT().Job(ctx, "Select a job from your workspace", "").Return("resizer", nil) + m.EXPECT().Environment(ctx, "Select an environment", "", "phonetool").Return("prod-iad", nil) }, wantedJobName: "resizer", @@ -144,8 +145,8 @@ func TestJobDeployOpts_Ask(t *testing.T) { inJobName: "resizer", inImageTag: "latest", wantedCalls: func(m *mocks.MockwsSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any()).Times(0) - m.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedJobName: "resizer", @@ -173,7 +174,7 @@ func TestJobDeployOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError == nil { @@ -470,7 +471,7 @@ func TestJobDeployOpts_Execute(t *testing.T) { clientConfigured: true, }, ws: m.mockWsReader, - newJobDeployer: func() (workloadDeployer, error) { + newJobDeployer: func(_ context.Context) (workloadDeployer, error) { return m.mockDeployer, nil }, newInterpolator: func(app, env string) interpolator { @@ -490,7 +491,7 @@ func TestJobDeployOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedError == nil { diff --git a/internal/pkg/cli/job_init.go b/internal/pkg/cli/job_init.go index 3957451cc32..a22a6a20620 100644 --- a/internal/pkg/cli/job_init.go +++ b/internal/pkg/cli/job_init.go @@ -82,7 +82,7 @@ type initJobOpts struct { wsAppName string initParser func(path string) dockerfileParser - initEnvDescriber func(appName, envName string) (envDescriber, error) + initEnvDescriber func(ctx context.Context, appName, envName string) (envDescriber, error) newAppVersionGetter func(appName string) (versionGetter, error) // Overridden in tests. @@ -128,8 +128,8 @@ func newInitJobOpts(vars initJobVars) (*initJobOpts, error) { initParser: func(path string) dockerfileParser { return dockerfile.New(fs, path) }, - initEnvDescriber: func(appName string, envName string) (envDescriber, error) { - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + initEnvDescriber: func(ctx context.Context, appName string, envName string) (envDescriber, error) { + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: appName, Env: envName, ConfigStore: store, @@ -176,7 +176,7 @@ func (o *initJobOpts) Validate() error { } // Ask prompts for fields that are required but not passed in. -func (o *initJobOpts) Ask() error { +func (o *initJobOpts) Ask(ctx context.Context) error { if o.wkldType != "" { if err := validateJobType(o.wkldType); err != nil { return err @@ -194,7 +194,7 @@ func (o *initJobOpts) Ask() error { if err := validateJobName(o.name); err != nil { return err } - if err := o.validateDuplicateJob(); err != nil { + if err := o.validateDuplicateJob(ctx); err != nil { return err } if !o.wsPendingCreation { @@ -237,14 +237,14 @@ func (o *initJobOpts) Ask() error { } // envsWithPrivateSubnetsOnly returns the list of environments names deployed that contains only private subnets. -func envsWithPrivateSubnetsOnly(store store, initEnvDescriber func(string, string) (envDescriber, error), appName string) ([]string, error) { - envs, err := store.ListEnvironments(appName) +func envsWithPrivateSubnetsOnly(ctx context.Context, store store, initEnvDescriber func(context.Context, string, string) (envDescriber, error), appName string) ([]string, error) { + envs, err := store.ListEnvironments(ctx, appName) if err != nil { return nil, fmt.Errorf("list environments for application %s: %w", appName, err) } var privateOnlyEnvs []string for _, env := range envs { - envDescriber, err := initEnvDescriber(appName, env.Name) + envDescriber, err := initEnvDescriber(ctx, appName, env.Name) if err != nil { return nil, err } @@ -266,7 +266,7 @@ func envsWithPrivateSubnetsOnly(store store, initEnvDescriber func(string, strin } // Execute writes the job's manifest file, creates an ECR repo, and stores the name in SSM. -func (o *initJobOpts) Execute() error { +func (o *initJobOpts) Execute(ctx context.Context) error { if !o.allowAppDowngrade { appVersionGetter, err := o.newAppVersionGetter(o.appName) if err != nil { @@ -295,11 +295,11 @@ func (o *initJobOpts) Execute() error { o.platform = &platform } } - envs, err := envsWithPrivateSubnetsOnly(o.store, o.initEnvDescriber, o.appName) + envs, err := envsWithPrivateSubnetsOnly(ctx, o.store, o.initEnvDescriber, o.appName) if err != nil { return err } - manifestPath, err := o.init.Job(&initialize.JobProps{ + manifestPath, err := o.init.Job(ctx, &initialize.JobProps{ WorkloadProps: initialize.WorkloadProps{ App: o.appName, Name: o.name, @@ -335,8 +335,8 @@ func (o *initJobOpts) RecommendActions() error { return nil } -func (o *initJobOpts) validateDuplicateJob() error { - _, err := o.store.GetJob(o.appName, o.name) +func (o *initJobOpts) validateDuplicateJob(ctx context.Context) error { + _, err := o.store.GetJob(ctx, o.appName, o.name) if err == nil { log.Errorf(`It seems like you are trying to init a job that already exists. To recreate the job, please run: @@ -477,7 +477,7 @@ func buildJobInitCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/job_init_test.go b/internal/pkg/cli/job_init_test.go index 42434235041..1aeea93707f 100644 --- a/internal/pkg/cli/job_init_test.go +++ b/internal/pkg/cli/job_init_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "path/filepath" @@ -57,7 +58,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inImage: "mockImage", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(nil, errors.New("some error")) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(nil, errors.New("some error")) }, wantedErr: fmt.Errorf("get application phonetool configuration: some error"), }, @@ -66,7 +67,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inDockerfilePath: "./hello/Dockerfile", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("open %s: file does not exist", filepath.FromSlash("hello/Dockerfile")), }, @@ -75,7 +76,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inTimeout: "30 minutes", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("timeout value 30 minutes is invalid: %s", errDurationInvalid), }, @@ -84,7 +85,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inTimeout: "30m45.5s", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("timeout value 30m45.5s is invalid: %s", errDurationBadUnits), }, @@ -93,7 +94,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inTimeout: "3ms", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("timeout value 3ms is invalid: %s", errDurationBadUnits), }, @@ -102,7 +103,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inTimeout: "0s", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: errors.New("timeout value 0s is invalid: duration must be 1s or greater"), }, @@ -111,7 +112,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inRetries: -3, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: errors.New("number of retries must be non-negative"), }, @@ -121,7 +122,7 @@ func TestJobInitOpts_Validate(t *testing.T) { inImage: "mockImage", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("--dockerfile and --image cannot be specified together"), }, @@ -222,7 +223,7 @@ func TestJobInitOpts_Ask(t *testing.T) { setupMocks: func(m initJobMocks) { m.mockPrompt.EXPECT().Get(gomock.Eq("What do you want to name this job?"), gomock.Any(), gomock.Any(), gomock.Any()). Return(wantedJobName, nil) - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(&config.Workload{}, nil) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(&config.Workload{}, nil) }, wantedErr: fmt.Errorf("job cuteness-aggregator already exists"), }, @@ -234,7 +235,7 @@ func TestJobInitOpts_Ask(t *testing.T) { setupMocks: func(m initJobMocks) { m.mockPrompt.EXPECT().Get(gomock.Eq("What do you want to name this job?"), gomock.Any(), gomock.Any(), gomock.Any()). Return(wantedJobName, nil) - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, mockError) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, mockError) }, wantedErr: fmt.Errorf("validate if job exists: mock error"), }, @@ -251,7 +252,7 @@ func TestJobInitOpts_Ask(t *testing.T) { gomock.Any(), gomock.Any(), ).Return(wantedJobName, nil) - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) }, @@ -264,7 +265,7 @@ func TestJobInitOpts_Ask(t *testing.T) { inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, mockError) }, @@ -275,7 +276,7 @@ func TestJobInitOpts_Ask(t *testing.T) { inJobName: wantedJobName, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return([]byte(` type: Backend Service`), nil) }, @@ -288,7 +289,7 @@ type: Backend Service`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return([]byte(`name: cuteness-aggregator type: Scheduled Job`), nil) }, @@ -303,7 +304,7 @@ type: Scheduled Job`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) }, @@ -315,7 +316,7 @@ type: Scheduled Job`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockDockerEngine.EXPECT().CheckDockerEngineRunning().Return(errors.New("some error")) }, @@ -328,7 +329,7 @@ type: Scheduled Job`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("mockImage", nil) @@ -343,7 +344,7 @@ type: Scheduled Job`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("mockImage", nil) @@ -358,7 +359,7 @@ type: Scheduled Job`), nil) inDockerfilePath: "", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("", mockError) @@ -381,7 +382,7 @@ type: Scheduled Job`), nil) inDockerfilePath: "", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("mockImage", nil) @@ -404,7 +405,7 @@ type: Scheduled Job`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockDockerfileSel.EXPECT().Dockerfile( gomock.Eq(fmt.Sprintf(fmtWkldInitDockerfilePrompt, color.HighlightUserInput(wantedJobName))), @@ -425,7 +426,7 @@ type: Scheduled Job`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockDockerfileSel.EXPECT().Dockerfile( gomock.Eq(fmt.Sprintf(fmtWkldInitDockerfilePrompt, color.HighlightUserInput(wantedJobName))), @@ -446,7 +447,7 @@ type: Scheduled Job`), nil) inJobSchedule: "", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{}) m.mockScheduleSel.EXPECT().Schedule( gomock.Eq(jobInitSchedulePrompt), @@ -465,7 +466,7 @@ type: Scheduled Job`), nil) inJobSchedule: "", setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) m.mockScheduleSel.EXPECT().Schedule( gomock.Any(), @@ -484,7 +485,7 @@ type: Scheduled Job`), nil) inJobSchedule: wantedCronSchedule, setupMocks: func(m initJobMocks) { - m.mockStore.EXPECT().GetJob(mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) + m.mockStore.EXPECT().GetJob(ctx, mockAppName, wantedJobName).Return(nil, &config.ErrNoSuchJob{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedJobName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedJobName}) }, @@ -529,7 +530,7 @@ type: Scheduled Job`), nil) } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedErr != nil { @@ -604,7 +605,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockJobInit: func(m *mocks.MockjobInitializer) { - m.EXPECT().Job(&initialize.JobProps{ + m.EXPECT().Job(ctx, &initialize.JobProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "mailer", @@ -623,7 +624,7 @@ network: }).Return("manifest/path", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, }, "fail to init job": { @@ -632,10 +633,10 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "").Return(nil, nil) }, mockJobInit: func(m *mocks.MockjobInitializer) { - m.EXPECT().Job(gomock.Any()).Return("", errors.New("some error")) + m.EXPECT().Job(ctx, gomock.Any()).Return("", errors.New("some error")) }, wantedErr: errors.New("some error"), }, @@ -662,7 +663,7 @@ network: m.EXPECT().GetPlatform().Times(0) }, mockJobInit: func(m *mocks.MockjobInitializer) { - m.EXPECT().Job(&initialize.JobProps{ + m.EXPECT().Job(ctx, &initialize.JobProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "mailer", @@ -681,7 +682,7 @@ network: }).Return("manifest/path", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, }, "doesn't complain if docker is unavailable": { @@ -706,7 +707,7 @@ network: m.EXPECT().GetPlatform().Times(0) }, mockJobInit: func(m *mocks.MockjobInitializer) { - m.EXPECT().Job(&initialize.JobProps{ + m.EXPECT().Job(ctx, &initialize.JobProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "mailer", @@ -725,7 +726,7 @@ network: }).Return("manifest/path", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, }, "return error if platform detection fails": { @@ -757,7 +758,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockJobInit: func(m *mocks.MockjobInitializer) { - m.EXPECT().Job(&initialize.JobProps{ + m.EXPECT().Job(ctx, &initialize.JobProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "mailer", @@ -777,7 +778,7 @@ network: }).Return("manifest/path", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return([]*config.Environment{ + m.EXPECT().ListEnvironments(ctx, "sample").Return([]*config.Environment{ { App: "sample", Name: "test", @@ -835,13 +836,13 @@ network: dockerEngine: mockDockerEngine, manifestExists: tc.inManifestExists, store: mockStore, - initEnvDescriber: func(string, string) (envDescriber, error) { + initEnvDescriber: func(_ context.Context, appName, envName string) (envDescriber, error) { return mockEnvDescriber, nil }, } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedErr == nil { diff --git a/internal/pkg/cli/job_list.go b/internal/pkg/cli/job_list.go index 23866028983..2a39b107f51 100644 --- a/internal/pkg/cli/job_list.go +++ b/internal/pkg/cli/job_list.go @@ -63,12 +63,12 @@ func (o *listJobOpts) Validate() error { } // Ask asks for fields that are required but not passed in. -func (o *listJobOpts) Ask() error { +func (o *listJobOpts) Ask(ctx context.Context) error { if o.appName != "" { return nil } - name, err := o.sel.Application(jobListAppNamePrompt, wkldAppNameHelpPrompt) + name, err := o.sel.Application(ctx, jobListAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application name: %w", err) } @@ -77,8 +77,8 @@ func (o *listJobOpts) Ask() error { } // Execute lists the jobs in the workspace or application. -func (o *listJobOpts) Execute() error { - if err := o.list.Write(o.appName); err != nil { +func (o *listJobOpts) Execute(ctx context.Context) error { + if err := o.list.Write(ctx, o.appName); err != nil { return err } return nil @@ -97,10 +97,10 @@ func buildJobListCmd() *cobra.Command { if err != nil { return err } - if err := opts.Ask(); err != nil { + if err := opts.Ask(cmd.Context()); err != nil { return err } - return opts.Execute() + return opts.Execute(cmd.Context()) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/job_list_test.go b/internal/pkg/cli/job_list_test.go index a83b8f66301..1a394030443 100644 --- a/internal/pkg/cli/job_list_test.go +++ b/internal/pkg/cli/job_list_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "testing" @@ -33,7 +34,7 @@ func TestListJobOpts_Execute(t *testing.T) { }, mocking: func() { mockLister.EXPECT(). - Write("coolapp"). + Write(ctx, "coolapp"). Return(nil) }, }, @@ -46,7 +47,7 @@ func TestListJobOpts_Execute(t *testing.T) { }, mocking: func() { mockLister.EXPECT(). - Write(gomock.Eq("coolapp")). + Write(ctx, gomock.Eq("coolapp")). Return(mockError) }, expectedErr: fmt.Errorf("error"), @@ -55,7 +56,7 @@ func TestListJobOpts_Execute(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { tc.mocking() - err := tc.opts.Execute() + err := tc.opts.Execute(context.Background()) if tc.expectedErr != nil { require.EqualError(t, tc.expectedErr, err.Error()) @@ -76,13 +77,13 @@ func TestListJobOpts_Ask(t *testing.T) { }{ "with no flags set": { mockSel: func(m *mocks.MockappSelector) { - m.EXPECT().Application(jobListAppNamePrompt, wkldAppNameHelpPrompt).Return("myapp", nil) + m.EXPECT().Application(ctx, jobListAppNamePrompt, wkldAppNameHelpPrompt).Return("myapp", nil) }, wantedApp: "myapp", }, "with app flag set": { mockSel: func(m *mocks.MockappSelector) { - m.EXPECT().Application(gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Times(0) }, inApp: "myapp", wantedApp: "myapp", @@ -104,7 +105,7 @@ func TestListJobOpts_Ask(t *testing.T) { sel: mockSel, } - err := listApps.Ask() + err := listApps.Ask(context.Background()) require.NoError(t, err) require.Equal(t, tc.wantedApp, listApps.appName, "expected application names to match") diff --git a/internal/pkg/cli/job_logs.go b/internal/pkg/cli/job_logs.go index 38addd90e4d..a09745053aa 100644 --- a/internal/pkg/cli/job_logs.go +++ b/internal/pkg/cli/job_logs.go @@ -64,8 +64,8 @@ func newJobLogOpts(vars jobLogsVars) (*jobLogsOpts, error) { sel: selector.NewDeploySelect(prompt.New(), configStore, deployStore), }, } - opts.initRuntimeClients = func() error { - env, err := opts.getTargetEnv() + opts.initRuntimeClients = func(ctx context.Context) error { + env, err := opts.getTargetEnv(ctx) if err != nil { return fmt.Errorf("get environment: %w", err) } @@ -74,6 +74,7 @@ func newJobLogOpts(vars jobLogsVars) (*jobLogsOpts, error) { return err } opts.logsSvc = logging.NewJobLogger(&logging.NewWorkloadLoggerOpts{ + Ctx: ctx, Cfg: cfg, App: opts.appName, Env: opts.envName, @@ -86,17 +87,18 @@ func newJobLogOpts(vars jobLogsVars) (*jobLogsOpts, error) { // Validate returns an error if the values provided by flags are invalid. func (o *jobLogsOpts) Validate() error { + ctx := context.Background() if o.appName != "" { - if _, err := o.configStore.GetApplication(o.appName); err != nil { + if _, err := o.configStore.GetApplication(ctx, o.appName); err != nil { return err } if o.envName != "" { - if _, err := o.configStore.GetEnvironment(o.appName, o.envName); err != nil { + if _, err := o.configStore.GetEnvironment(ctx, o.appName, o.envName); err != nil { return err } } if o.name != "" { - if _, err := o.configStore.GetJob(o.appName, o.name); err != nil { + if _, err := o.configStore.GetJob(ctx, o.appName, o.name); err != nil { return err } } @@ -142,16 +144,16 @@ func (o *jobLogsOpts) Validate() error { } // Ask asks for fields that are required but not passed in. -func (o *jobLogsOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *jobLogsOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - return o.validateAndAskJobEnvName() + return o.validateAndAskJobEnvName(ctx) } // Execute outputs logs of the job. -func (o *jobLogsOpts) Execute() error { - if err := o.initRuntimeClients(); err != nil { +func (o *jobLogsOpts) Execute(ctx context.Context) error { + if err := o.initRuntimeClients(ctx); err != nil { return err } eventsWriter := logging.WriteHumanLogs @@ -185,11 +187,11 @@ func (o *jobLogsOpts) Execute() error { return nil } -func (o *jobLogsOpts) getTargetEnv() (*config.Environment, error) { +func (o *jobLogsOpts) getTargetEnv(ctx context.Context) (*config.Environment, error) { if o.targetEnv != nil { return o.targetEnv, nil } - env, err := o.configStore.GetEnvironment(o.appName, o.envName) + env, err := o.configStore.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return nil, err } @@ -197,12 +199,12 @@ func (o *jobLogsOpts) getTargetEnv() (*config.Environment, error) { return o.targetEnv, nil } -func (o *jobLogsOpts) validateOrAskApp() error { +func (o *jobLogsOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.configStore.GetApplication(o.appName) + _, err := o.configStore.GetApplication(ctx, o.appName) return err } - app, err := o.sel.Application(jobAppNamePrompt, wkldAppNameHelpPrompt) + app, err := o.sel.Application(ctx, jobAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -210,18 +212,18 @@ func (o *jobLogsOpts) validateOrAskApp() error { return nil } -func (o *jobLogsOpts) validateAndAskJobEnvName() error { +func (o *jobLogsOpts) validateAndAskJobEnvName(ctx context.Context) error { if o.envName != "" { - if _, err := o.getTargetEnv(); err != nil { + if _, err := o.getTargetEnv(ctx); err != nil { return err } } if o.name != "" { - if _, err := o.configStore.GetJob(o.appName, o.name); err != nil { + if _, err := o.configStore.GetJob(ctx, o.appName, o.name); err != nil { return err } } - deployedJob, err := o.sel.DeployedJob(jobLogNamePrompt, jobLogNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.name)) + deployedJob, err := o.sel.DeployedJob(ctx, jobLogNamePrompt, jobLogNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.name)) if err != nil { return fmt.Errorf("select deployed jobs for application %s: %w", o.appName, err) } @@ -254,7 +256,7 @@ func buildJobLogsCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", svcFlagDescription) diff --git a/internal/pkg/cli/job_logs_test.go b/internal/pkg/cli/job_logs_test.go index f9a24c44890..19b542902f8 100644 --- a/internal/pkg/cli/job_logs_test.go +++ b/internal/pkg/cli/job_logs_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -55,7 +56,7 @@ func TestJobLogs_Validate(t *testing.T) { inputApp: "my-app", mockstore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication("my-app").Return(nil, errors.New("some error")) + m.EXPECT().GetApplication(ctx, "my-app").Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("some error"), @@ -64,8 +65,8 @@ func TestJobLogs_Validate(t *testing.T) { inputApp: "my-app", inputEnvName: "test", mockstore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication("my-app").Return(&config.Application{}, nil) - m.EXPECT().GetEnvironment("my-app", "test").Return(nil, errors.New("some error")) + m.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{}, nil) + m.EXPECT().GetEnvironment(ctx, "my-app", "test").Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("some error"), @@ -75,8 +76,8 @@ func TestJobLogs_Validate(t *testing.T) { inputSvc: "frontend", mockstore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication("my-app").Return(&config.Application{}, nil) - m.EXPECT().GetJob("my-app", "frontend").Return(nil, errors.New("some error")) + m.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{}, nil) + m.EXPECT().GetJob(ctx, "my-app", "frontend").Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("some error"), @@ -199,10 +200,10 @@ func TestJobLogs_Ask(t *testing.T) { inputEnvName: inputEnv, setupMocks: func(m wkldLogsMock) { gomock.InOrder( - m.configStore.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil), - m.configStore.EXPECT().GetEnvironment("my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), - m.configStore.EXPECT().GetJob("my-app", "my-job").Return(&config.Workload{}, nil), - m.sel.EXPECT().DeployedJob(jobLogNamePrompt, jobLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil), + m.configStore.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), + m.configStore.EXPECT().GetJob(ctx, "my-app", "my-job").Return(&config.Workload{}, nil), + m.sel.EXPECT().DeployedJob(ctx, jobLogNamePrompt, jobLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(&selector.DeployedJob{ Env: "my-env", Name: "my-job", @@ -217,11 +218,11 @@ func TestJobLogs_Ask(t *testing.T) { inputJob: inputJob, inputEnvName: inputEnv, setupMocks: func(m wkldLogsMock) { - m.sel.EXPECT().Application(jobAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) - m.configStore.EXPECT().GetApplication(gomock.Any()).Times(0) - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetJob(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedJob(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedJob{ + m.sel.EXPECT().Application(ctx, jobAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetJob(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedJob(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedJob{ Env: "my-env", Name: "my-job", }, nil).AnyTimes() @@ -233,7 +234,7 @@ func TestJobLogs_Ask(t *testing.T) { "returns error if fail to select app": { setupMocks: func(m wkldLogsMock) { gomock.InOrder( - m.sel.EXPECT().Application(jobAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")), + m.sel.EXPECT().Application(ctx, jobAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")), ) }, wantedError: fmt.Errorf("select application: some error"), @@ -241,10 +242,10 @@ func TestJobLogs_Ask(t *testing.T) { "prompt for job and env": { inputApp: "my-app", setupMocks: func(m wkldLogsMock) { - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.configStore.EXPECT().GetJob(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedJob(jobLogNamePrompt, jobLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.configStore.EXPECT().GetJob(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedJob(ctx, jobLogNamePrompt, jobLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(&selector.DeployedJob{ Env: "my-env", Name: "my-job", @@ -257,10 +258,10 @@ func TestJobLogs_Ask(t *testing.T) { "return error if fail to select deployed job": { inputApp: inputApp, setupMocks: func(m wkldLogsMock) { - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.configStore.EXPECT().GetJob(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedJob(jobLogNamePrompt, jobLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.configStore.EXPECT().GetJob(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedJob(ctx, jobLogNamePrompt, jobLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("select deployed jobs for application my-app: some error"), @@ -297,7 +298,7 @@ func TestJobLogs_Ask(t *testing.T) { } // WHEN - err := jobLogs.Ask() + err := jobLogs.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -427,13 +428,13 @@ func TestJobLogs_Execute(t *testing.T) { wkldLogOpts: wkldLogOpts{ startTime: &tc.startTime, endTime: &tc.endTime, - initRuntimeClients: func() error { return nil }, + initRuntimeClients: func(_ context.Context) error { return nil }, logsSvc: tc.mocklogsSvc(ctrl), }, } // WHEN - err := svcLogs.Execute() + err := svcLogs.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/job_override.go b/internal/pkg/cli/job_override.go index ec6b42fbd8b..2d76c72a18a 100644 --- a/internal/pkg/cli/job_override.go +++ b/internal/pkg/cli/job_override.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "slices" @@ -20,15 +21,15 @@ func newOverrideJobOpts(vars overrideWorkloadVars) (*overrideWorkloadOpts, error return cmd, nil } -func (o *overrideWorkloadOpts) validateOrAskJobName() error { +func (o *overrideWorkloadOpts) validateOrAskJobName(ctx context.Context) error { if o.name == "" { - return o.askJobName() + return o.askJobName(ctx) } return o.validateJobName() } -func (o *overrideWorkloadOpts) askJobName() error { - name, err := o.wsPrompt.Job("Which job's resources would you like to override?", "") +func (o *overrideWorkloadOpts) askJobName(ctx context.Context) error { + name, err := o.wsPrompt.Job(ctx, "Which job's resources would you like to override?", "") if err != nil { return fmt.Errorf("select job name from workspace: %v", err) } @@ -64,7 +65,7 @@ or add new resources to the job's template.`, if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", jobFlagDescription) diff --git a/internal/pkg/cli/job_override_test.go b/internal/pkg/cli/job_override_test.go index 023acf2a925..9ca993d3fc4 100644 --- a/internal/pkg/cli/job_override_test.go +++ b/internal/pkg/cli/job_override_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "testing" @@ -50,7 +51,7 @@ func TestOverrideJob_Ask(t *testing.T) { name: "", initMocks: func(ctrl *gomock.Controller, cmd *overrideWorkloadOpts) { mockPrompt := mocks.NewMockwsSelector(ctrl) - mockPrompt.EXPECT().Job(gomock.Any(), gomock.Any()) + mockPrompt.EXPECT().Job(ctx, gomock.Any(), gomock.Any()) cmd.wsPrompt = mockPrompt }, }, @@ -71,7 +72,7 @@ func TestOverrideJob_Ask(t *testing.T) { cfnPrompt: mockCfnPrompt, packageCmd: func(_ stringWriteCloser) (executor, error) { mockCmd := mocks.NewMockexecutor(ctrl) - mockCmd.EXPECT().Execute().AnyTimes() + mockCmd.EXPECT().Execute(gomock.Any()).AnyTimes() return mockCmd, nil }, spinner: &spinnerTestDouble{}, @@ -81,7 +82,7 @@ func TestOverrideJob_Ask(t *testing.T) { tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { diff --git a/internal/pkg/cli/job_package.go b/internal/pkg/cli/job_package.go index 97685f6ceb0..8f1fd219338 100644 --- a/internal/pkg/cli/job_package.go +++ b/internal/pkg/cli/job_package.go @@ -120,7 +120,7 @@ func (o *packageJobOpts) Validate() error { } } if o.envName != "" { - if _, err := o.store.GetEnvironment(o.appName, o.envName); err != nil { + if _, err := o.store.GetEnvironment(context.Background(), o.appName, o.envName); err != nil { return err } } @@ -128,20 +128,20 @@ func (o *packageJobOpts) Validate() error { } // Ask prompts the user for any missing required fields. -func (o *packageJobOpts) Ask() error { - if err := o.askJobName(); err != nil { +func (o *packageJobOpts) Ask(ctx context.Context) error { + if err := o.askJobName(ctx); err != nil { return err } - if err := o.askEnvName(); err != nil { + if err := o.askEnvName(ctx); err != nil { return err } return nil } // Execute prints the CloudFormation template of the application for the environment. -func (o *packageJobOpts) Execute() error { +func (o *packageJobOpts) Execute(ctx context.Context) error { o.newPackageCmd(o) - return o.packageCmd.Execute() + return o.packageCmd.Execute(ctx) } // RecommendActions suggests recommended actions before the packaged template is used for deployment. @@ -149,12 +149,12 @@ func (o *packageJobOpts) RecommendActions() error { return o.packageCmd.RecommendActions() } -func (o *packageJobOpts) askJobName() error { +func (o *packageJobOpts) askJobName(ctx context.Context) error { if o.name != "" { return nil } - name, err := o.sel.Job(jobPackageJobNamePrompt, "") + name, err := o.sel.Job(ctx, jobPackageJobNamePrompt, "") if err != nil { return fmt.Errorf("select job: %w", err) } @@ -162,12 +162,12 @@ func (o *packageJobOpts) askJobName() error { return nil } -func (o *packageJobOpts) askEnvName() error { +func (o *packageJobOpts) askEnvName(ctx context.Context) error { if o.envName != "" { return nil } - name, err := o.sel.Environment(jobPackageEnvNamePrompt, "", o.appName) + name, err := o.sel.Environment(ctx, jobPackageEnvNamePrompt, "", o.appName) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -197,7 +197,7 @@ func buildJobPackageCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", jobFlagDescription) diff --git a/internal/pkg/cli/job_package_test.go b/internal/pkg/cli/job_package_test.go index acb8b35c4f1..204c233e8ab 100644 --- a/internal/pkg/cli/job_package_test.go +++ b/internal/pkg/cli/job_package_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "testing" @@ -35,7 +36,7 @@ func TestPackageJobOpts_Validate(t *testing.T) { "invalid workspace": { setupMocks: func() { mockWorkspace.EXPECT().ListJobs().Times(0) - mockStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) + mockStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) }, wantedErrorS: "could not find an application attached to this workspace, please run `app init` first", }, @@ -44,7 +45,7 @@ func TestPackageJobOpts_Validate(t *testing.T) { inJobName: "resizer", setupMocks: func() { mockWorkspace.EXPECT().ListJobs().Return(nil, errors.New("some error")) - mockStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) + mockStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) }, wantedErrorS: "list jobs in the workspace: some error", @@ -54,7 +55,7 @@ func TestPackageJobOpts_Validate(t *testing.T) { inJobName: "resizer", setupMocks: func() { mockWorkspace.EXPECT().ListJobs().Return([]string{"other-job"}, nil) - mockStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) + mockStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) }, wantedErrorS: "job 'resizer' does not exist in the workspace", @@ -65,7 +66,7 @@ func TestPackageJobOpts_Validate(t *testing.T) { setupMocks: func() { mockWorkspace.EXPECT().ListJobs().Times(0) - mockStore.EXPECT().GetEnvironment("phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{ + mockStore.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(nil, &config.ErrNoSuchEnvironment{ ApplicationName: "phonetool", EnvironmentName: "test", }) @@ -131,8 +132,8 @@ func TestPackageJobOpts_Ask(t *testing.T) { }{ "prompt for all options": { expectSelector: func(m *mocks.MockwsSelector) { - m.EXPECT().Job(jobPackageJobNamePrompt, "").Return("resizer", nil) - m.EXPECT().Environment(jobPackageEnvNamePrompt, "", testAppName).Return("test", nil) + m.EXPECT().Job(ctx, jobPackageJobNamePrompt, "").Return("resizer", nil) + m.EXPECT().Environment(ctx, jobPackageEnvNamePrompt, "", testAppName).Return("test", nil) }, expectPrompt: func(m *mocks.Mockprompter) {}, @@ -143,8 +144,8 @@ func TestPackageJobOpts_Ask(t *testing.T) { inEnvName: "test", expectSelector: func(m *mocks.MockwsSelector) { - m.EXPECT().Job(jobPackageJobNamePrompt, "").Return("resizer", nil) - m.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, jobPackageJobNamePrompt, "").Return("resizer", nil) + m.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, expectPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) @@ -157,8 +158,8 @@ func TestPackageJobOpts_Ask(t *testing.T) { inJobName: "resizer", expectSelector: func(m *mocks.MockwsSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any()).Times(0) - m.EXPECT().Environment(jobPackageEnvNamePrompt, "", testAppName).Return("test", nil) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, jobPackageEnvNamePrompt, "", testAppName).Return("test", nil) }, expectPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) @@ -172,8 +173,8 @@ func TestPackageJobOpts_Ask(t *testing.T) { inEnvName: "test", expectSelector: func(m *mocks.MockwsSelector) { - m.EXPECT().Job(gomock.Any(), gomock.Any()).Times(0) - m.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Job(ctx, gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, expectPrompt: func(m *mocks.Mockprompter) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) @@ -209,7 +210,7 @@ func TestPackageJobOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN require.Equal(t, tc.wantedJobName, opts.name) @@ -242,7 +243,7 @@ func TestPackageJobOpts_Execute(t *testing.T) { mockDependencies: func(ctrl *gomock.Controller, opts *packageJobOpts) { opts.newPackageCmd = func(opts *packageJobOpts) { mockCmd := mocks.NewMockactionCommand(ctrl) - mockCmd.EXPECT().Execute().Return(nil) + mockCmd.EXPECT().Execute(gomock.Any()).Return(nil) opts.packageCmd = mockCmd } }, @@ -263,7 +264,7 @@ func TestPackageJobOpts_Execute(t *testing.T) { tc.mockDependencies(ctrl, opts) // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN require.Equal(t, tc.wantedErr, err) diff --git a/internal/pkg/cli/job_run.go b/internal/pkg/cli/job_run.go index a4e919fe8bd..133569cf6bb 100644 --- a/internal/pkg/cli/job_run.go +++ b/internal/pkg/cli/job_run.go @@ -40,8 +40,8 @@ type jobRunOpts struct { targetEnv *config.Environment sessProvider *sessions.Provider - newRunner func() (runner, error) - newEnvCompatibilityChecker func() (versionCompatibilityChecker, error) + newRunner func(ctx context.Context) (runner, error) + newEnvCompatibilityChecker func(ctx context.Context) (versionCompatibilityChecker, error) } func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { @@ -67,8 +67,8 @@ func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { sessProvider: sessProvider, } - opts.newRunner = func() (runner, error) { - cfg, err := opts.envConfig() + opts.newRunner = func(ctx context.Context) (runner, error) { + cfg, err := opts.envConfig(ctx) if err != nil { return nil, err } @@ -82,8 +82,8 @@ func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { StateMachine: stepfunctions.New(cfg), }), nil } - opts.newEnvCompatibilityChecker = func() (versionCompatibilityChecker, error) { - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + opts.newEnvCompatibilityChecker = func(ctx context.Context) (versionCompatibilityChecker, error) { + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: opts.appName, Env: opts.envName, ConfigStore: opts.configStore, @@ -103,25 +103,25 @@ func (o *jobRunOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *jobRunOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *jobRunOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - if err := o.askJobName(); err != nil { + if err := o.askJobName(ctx); err != nil { return err } - if err := o.askEnvName(); err != nil { + if err := o.askEnvName(ctx); err != nil { return err } return nil } // Execute runs the "job run" command. -func (o *jobRunOpts) Execute() error { - if err := o.validateEnvCompatible(); err != nil { +func (o *jobRunOpts) Execute(ctx context.Context) error { + if err := o.validateEnvCompatible(ctx); err != nil { return err } - runner, err := o.newRunner() + runner, err := o.newRunner(ctx) if err != nil { return err } @@ -132,12 +132,12 @@ func (o *jobRunOpts) Execute() error { return nil } -func (o *jobRunOpts) validateOrAskApp() error { +func (o *jobRunOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.configStore.GetApplication(o.appName) + _, err := o.configStore.GetApplication(ctx, o.appName) return err } - app, err := o.sel.Application(jobAppNamePrompt, wkldAppNameHelpPrompt) + app, err := o.sel.Application(ctx, jobAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -145,15 +145,15 @@ func (o *jobRunOpts) validateOrAskApp() error { return nil } -func (o *jobRunOpts) askJobName() error { +func (o *jobRunOpts) askJobName(ctx context.Context) error { if o.jobName != "" { - if _, err := o.configStore.GetJob(o.appName, o.jobName); err != nil { + if _, err := o.configStore.GetJob(ctx, o.appName, o.jobName); err != nil { return err } return nil } - name, err := o.sel.Job("Which job would you like to invoke?", "", o.appName) + name, err := o.sel.Job(ctx, "Which job would you like to invoke?", "", o.appName) if err != nil { return fmt.Errorf("select job: %w", err) } @@ -161,15 +161,15 @@ func (o *jobRunOpts) askJobName() error { return nil } -func (o *jobRunOpts) askEnvName() error { +func (o *jobRunOpts) askEnvName(ctx context.Context) error { if o.envName != "" { - if _, err := o.getTargetEnv(); err != nil { + if _, err := o.getTargetEnv(ctx); err != nil { return err } return nil } - name, err := o.sel.Environment("Which environment?", "", o.appName) + name, err := o.sel.Environment(ctx, "Which environment?", "", o.appName) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -177,11 +177,11 @@ func (o *jobRunOpts) askEnvName() error { return nil } -func (o *jobRunOpts) getTargetEnv() (*config.Environment, error) { +func (o *jobRunOpts) getTargetEnv(ctx context.Context) (*config.Environment, error) { if o.targetEnv != nil { return o.targetEnv, nil } - env, err := o.configStore.GetEnvironment(o.appName, o.envName) + env, err := o.configStore.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return nil, err } @@ -189,16 +189,16 @@ func (o *jobRunOpts) getTargetEnv() (*config.Environment, error) { return o.targetEnv, nil } -func (o *jobRunOpts) envConfig() (aws.Config, error) { - env, err := o.getTargetEnv() +func (o *jobRunOpts) envConfig(ctx context.Context) (aws.Config, error) { + env, err := o.getTargetEnv(ctx) if err != nil { return aws.Config{}, err } return o.sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) } -func (o *jobRunOpts) validateEnvCompatible() error { - envStack, err := o.newEnvCompatibilityChecker() +func (o *jobRunOpts) validateEnvCompatible(ctx context.Context) error { + envStack, err := o.newEnvCompatibilityChecker(ctx) if err != nil { return err } @@ -220,7 +220,7 @@ func buildJobRunCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/job_run_test.go b/internal/pkg/cli/job_run_test.go index c09ed50e7a9..32d9d931c2c 100644 --- a/internal/pkg/cli/job_run_test.go +++ b/internal/pkg/cli/job_run_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -44,9 +45,9 @@ func TestJobRun_Ask(t *testing.T) { inputEnvName: inputEnv, setupMocks: func(m jobRunMock) { gomock.InOrder( - m.configStore.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil), - m.configStore.EXPECT().GetJob("my-app", "my-job").Return(&config.Workload{}, nil), - m.configStore.EXPECT().GetEnvironment("my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), + m.configStore.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil), + m.configStore.EXPECT().GetJob(ctx, "my-app", "my-job").Return(&config.Workload{}, nil), + m.configStore.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), ) }, wantedApp: inputApp, @@ -58,12 +59,12 @@ func TestJobRun_Ask(t *testing.T) { inputEnvName: inputEnv, setupMocks: func(m jobRunMock) { gomock.InOrder( - m.sel.EXPECT().Application(jobAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil), - m.configStore.EXPECT().GetApplication(gomock.Any()).Times(0), - m.configStore.EXPECT().GetJob(gomock.Any(), gomock.Any()).AnyTimes(), - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes(), - m.sel.EXPECT().Job(gomock.Any(), gomock.Any(), gomock.Any()).Return("my-job", nil).AnyTimes(), - m.sel.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any()).Return("my-env", nil).AnyTimes(), + m.sel.EXPECT().Application(ctx, jobAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil), + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).Times(0), + m.configStore.EXPECT().GetJob(ctx, gomock.Any(), gomock.Any()).AnyTimes(), + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes(), + m.sel.EXPECT().Job(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return("my-job", nil).AnyTimes(), + m.sel.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return("my-env", nil).AnyTimes(), ) }, wantedApp: inputApp, @@ -73,7 +74,7 @@ func TestJobRun_Ask(t *testing.T) { "returns error if fail to select app": { setupMocks: func(m jobRunMock) { gomock.InOrder( - m.sel.EXPECT().Application(jobAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")), + m.sel.EXPECT().Application(ctx, jobAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")), ) }, wantedError: fmt.Errorf("select application: some error"), @@ -82,11 +83,11 @@ func TestJobRun_Ask(t *testing.T) { inputApp: inputApp, setupMocks: func(m jobRunMock) { gomock.InOrder( - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes(), - m.configStore.EXPECT().GetJob(gomock.Any(), gomock.Any()).Times(0), - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0), - m.sel.EXPECT().Job("Which job would you like to invoke?", "", "my-app").Return("my-job", nil), - m.sel.EXPECT().Environment("Which environment?", "", "my-app").Return("my-env", nil), + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes(), + m.configStore.EXPECT().GetJob(ctx, gomock.Any(), gomock.Any()).Times(0), + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0), + m.sel.EXPECT().Job(ctx, "Which job would you like to invoke?", "", "my-app").Return("my-job", nil), + m.sel.EXPECT().Environment(ctx, "Which environment?", "", "my-app").Return("my-env", nil), ) }, wantedApp: inputApp, @@ -98,10 +99,10 @@ func TestJobRun_Ask(t *testing.T) { inputJob: inputJob, setupMocks: func(m jobRunMock) { gomock.InOrder( - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes(), - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0), - m.configStore.EXPECT().GetJob(gomock.Any(), gomock.Any()).AnyTimes(), - m.sel.EXPECT().Environment("Which environment?", "", "my-app").Return("", errors.New("some error")), + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes(), + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0), + m.configStore.EXPECT().GetJob(ctx, gomock.Any(), gomock.Any()).AnyTimes(), + m.sel.EXPECT().Environment(ctx, "Which environment?", "", "my-app").Return("", errors.New("some error")), ) }, wantedError: fmt.Errorf("select environment: some error"), @@ -111,10 +112,10 @@ func TestJobRun_Ask(t *testing.T) { inputEnvName: inputEnv, setupMocks: func(m jobRunMock) { gomock.InOrder( - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes(), - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes(), - m.configStore.EXPECT().GetJob(gomock.Any(), gomock.Any()).Times(0), - m.sel.EXPECT().Job("Which job would you like to invoke?", "", "my-app").Return("", errors.New("some error")), + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes(), + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes(), + m.configStore.EXPECT().GetJob(ctx, gomock.Any(), gomock.Any()).Times(0), + m.sel.EXPECT().Job(ctx, "Which job would you like to invoke?", "", "my-app").Return("", errors.New("some error")), ) }, wantedError: fmt.Errorf("select job: some error"), @@ -143,7 +144,7 @@ func TestJobRun_Ask(t *testing.T) { sel: mockSel, } - err := jobRun.Ask() + err := jobRun.Ask(context.Background()) if tc.wantedError != nil { require.EqualError(t, err, tc.wantedError.Error()) @@ -234,15 +235,15 @@ func TestJobRun_Execute(t *testing.T) { envName: tc.envName, jobName: tc.jobName, }, - newRunner: func() (runner, error) { + newRunner: func(_ context.Context) (runner, error) { return tc.mockjobRunner(ctrl), nil }, - newEnvCompatibilityChecker: func() (versionCompatibilityChecker, error) { + newEnvCompatibilityChecker: func(_ context.Context) (versionCompatibilityChecker, error) { return tc.mockEnvChecker(ctrl), nil }, } - err := jobRunOpts.Execute() + err := jobRunOpts.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/list/list.go b/internal/pkg/cli/list/list.go index 6f7e2296017..34b1aabac95 100644 --- a/internal/pkg/cli/list/list.go +++ b/internal/pkg/cli/list/list.go @@ -4,6 +4,7 @@ package list import ( + "context" "encoding/json" "fmt" "io" @@ -28,9 +29,9 @@ const ( // Store wraps the methods required for interacting with config stores. type Store interface { - GetApplication(appName string) (*config.Application, error) - ListJobs(appName string) ([]*config.Workload, error) - ListServices(appName string) ([]*config.Workload, error) + GetApplication(ctx context.Context, appName string) (*config.Application, error) + ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) + ListServices(ctx context.Context, appName string) ([]*config.Workload, error) } // Workspace wraps the methods required to interact with a local workspace. @@ -73,11 +74,11 @@ type JobJSONOutput struct { } // Jobs lists all jobs, either locally or in the workspace, and writes the output to a writer. -func (l *JobListWriter) Write(appName string) error { - if _, err := l.Store.GetApplication(appName); err != nil { +func (l *JobListWriter) Write(ctx context.Context, appName string) error { + if _, err := l.Store.GetApplication(ctx, appName); err != nil { return fmt.Errorf("get application: %w", err) } - wklds, err := l.Store.ListJobs(appName) + wklds, err := l.Store.ListJobs(ctx, appName) if err != nil { return fmt.Errorf("get %s names: %w", jobWorkloadType, err) } @@ -101,11 +102,11 @@ func (l *JobListWriter) Write(appName string) error { } // Write lists all services, either locally or in the workspace, and writes the output to a writer. -func (l *SvcListWriter) Write(appName string) error { - if _, err := l.Store.GetApplication(appName); err != nil { +func (l *SvcListWriter) Write(ctx context.Context, appName string) error { + if _, err := l.Store.GetApplication(ctx, appName); err != nil { return fmt.Errorf("get application: %w", err) } - wklds, err := l.Store.ListServices(appName) + wklds, err := l.Store.ListServices(ctx, appName) if err != nil { return fmt.Errorf("get %s names: %w", svcWorkloadType, err) } diff --git a/internal/pkg/cli/list/list_test.go b/internal/pkg/cli/list/list_test.go index 4dc20c493f7..e24e771bf39 100644 --- a/internal/pkg/cli/list/list_test.go +++ b/internal/pkg/cli/list/list_test.go @@ -5,6 +5,7 @@ package list import ( "bytes" + "context" "fmt" "testing" @@ -43,11 +44,11 @@ farmer Scheduled Job `, mocking: func() { mockStore.EXPECT(). - GetApplication(gomock.Eq("barnyard")). + GetApplication(context.Background(), gomock.Eq("barnyard")). Return(&config.Application{}, nil) mockStore. EXPECT(). - ListJobs(gomock.Eq("barnyard")). + ListJobs(context.Background(), gomock.Eq("barnyard")). Return([]*config.Workload{ {Name: "badgoose", Type: "Scheduled Job"}, {Name: "farmer", Type: "Scheduled Job"}, @@ -62,11 +63,11 @@ farmer Scheduled Job `, mocking: func() { mockStore.EXPECT(). - GetApplication(gomock.Eq("barnyard")). + GetApplication(context.Background(), gomock.Eq("barnyard")). Return(&config.Application{}, nil) mockStore. EXPECT(). - ListJobs(gomock.Eq("barnyard")). + ListJobs(context.Background(), gomock.Eq("barnyard")). Return([]*config.Workload{ {Name: "badgoose", Type: "Scheduled Job"}, {Name: "farmer", Type: "Scheduled Job"}, @@ -80,11 +81,11 @@ farmer Scheduled Job mocking: func() { mockStore.EXPECT(). - GetApplication(gomock.Eq("barnyard")). + GetApplication(context.Background(), gomock.Eq("barnyard")). Return(nil, mockError) mockStore. EXPECT(). - ListJobs(gomock.Eq("barnyard")). + ListJobs(context.Background(), gomock.Eq("barnyard")). Times(0) }, }, @@ -95,9 +96,9 @@ farmer Scheduled Job wantedContent: "Name Type\n---- ----\nbadgoose Scheduled Job\n", mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListJobs("barnyard"). + mockStore.EXPECT().ListJobs(context.Background(), "barnyard"). Return([]*config.Workload{ {Name: "badgoose", Type: "Scheduled Job"}, {Name: "farmer", Type: "Scheduled Job"}, @@ -111,9 +112,9 @@ farmer Scheduled Job wantedError: fmt.Errorf("get job names: error"), mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListJobs("barnyard"). + mockStore.EXPECT().ListJobs(context.Background(), "barnyard"). Return(nil, mockError) }, }, @@ -124,9 +125,9 @@ farmer Scheduled Job wantedContent: "Name Type\n---- ----\n", mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListJobs("barnyard"). + mockStore.EXPECT().ListJobs(context.Background(), "barnyard"). Return([]*config.Workload{ {Name: "badgoose", Type: "Scheduled Job"}, {Name: "farmer", Type: "Scheduled Job"}, @@ -142,9 +143,9 @@ farmer Scheduled Job wantedContent: "{\"jobs\":null}\n", mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListJobs("barnyard"). + mockStore.EXPECT().ListJobs(context.Background(), "barnyard"). Return([]*config.Workload{ {Name: "badgoose", Type: "Scheduled Job"}, {Name: "farmer", Type: "Scheduled Job"}, @@ -168,7 +169,7 @@ farmer Scheduled Job } // WHEN - err := list.Write(tc.inputAppName) + err := list.Write(context.Background(), tc.inputAppName) if tc.wantedError != nil { require.EqualError(t, tc.wantedError, err.Error()) @@ -204,11 +205,11 @@ func TestList_SvcListWriter(t *testing.T) { wantedContent: "Name Type\n---- ----\ntrough Backend Service\ngaggle Load Balanced Web Service\n", mocking: func() { mockStore.EXPECT(). - GetApplication(gomock.Eq("barnyard")). + GetApplication(context.Background(), gomock.Eq("barnyard")). Return(&config.Application{}, nil) mockStore. EXPECT(). - ListServices(gomock.Eq("barnyard")). + ListServices(context.Background(), gomock.Eq("barnyard")). Return([]*config.Workload{ {Name: "trough", Type: "Backend Service"}, {Name: "gaggle", Type: "Load Balanced Web Service"}, @@ -223,11 +224,11 @@ func TestList_SvcListWriter(t *testing.T) { `, mocking: func() { mockStore.EXPECT(). - GetApplication(gomock.Eq("barnyard")). + GetApplication(context.Background(), gomock.Eq("barnyard")). Return(&config.Application{}, nil) mockStore. EXPECT(). - ListServices(gomock.Eq("barnyard")). + ListServices(context.Background(), gomock.Eq("barnyard")). Return([]*config.Workload{ {Name: "trough", Type: "Backend Service"}, {Name: "gaggle", Type: "Load Balanced Web Service"}, @@ -241,11 +242,11 @@ func TestList_SvcListWriter(t *testing.T) { mocking: func() { mockStore.EXPECT(). - GetApplication(gomock.Eq("barnyard")). + GetApplication(context.Background(), gomock.Eq("barnyard")). Return(nil, mockError) mockStore. EXPECT(). - ListServices(gomock.Eq("barnyard")). + ListServices(context.Background(), gomock.Eq("barnyard")). Times(0) }, }, @@ -256,9 +257,9 @@ func TestList_SvcListWriter(t *testing.T) { wantedContent: "Name Type\n---- ----\ntrough Backend Service\n", mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListServices("barnyard"). + mockStore.EXPECT().ListServices(context.Background(), "barnyard"). Return([]*config.Workload{ {Name: "trough", Type: "Backend Service"}, {Name: "gaggle", Type: "Load Balanced Web Service"}, @@ -272,9 +273,9 @@ func TestList_SvcListWriter(t *testing.T) { wantedError: fmt.Errorf("get service names: error"), mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListServices("barnyard"). + mockStore.EXPECT().ListServices(context.Background(), "barnyard"). Return(nil, mockError) }, }, @@ -285,9 +286,9 @@ func TestList_SvcListWriter(t *testing.T) { wantedContent: "Name Type\n---- ----\n", mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListServices("barnyard"). + mockStore.EXPECT().ListServices(context.Background(), "barnyard"). Return([]*config.Workload{ {Name: "trough", Type: "Backend Service"}, {Name: "gaggle", Type: "Load Balanced Web Service"}, @@ -303,9 +304,9 @@ func TestList_SvcListWriter(t *testing.T) { wantedContent: "{\"services\":null}\n", mocking: func() { - mockStore.EXPECT().GetApplication("barnyard"). + mockStore.EXPECT().GetApplication(context.Background(), "barnyard"). Return(&config.Application{}, nil) - mockStore.EXPECT().ListServices("barnyard"). + mockStore.EXPECT().ListServices(context.Background(), "barnyard"). Return([]*config.Workload{ {Name: "trough", Type: "Backend Service"}, {Name: "gaggle", Type: "Load Balanced Web Service"}, @@ -329,7 +330,7 @@ func TestList_SvcListWriter(t *testing.T) { } // WHEN - err := list.Write(tc.inputAppName) + err := list.Write(context.Background(), tc.inputAppName) if tc.wantedError != nil { require.EqualError(t, tc.wantedError, err.Error()) diff --git a/internal/pkg/cli/list/mocks/mock_list.go b/internal/pkg/cli/list/mocks/mock_list.go index f6f1579c91e..a99b3036568 100644 --- a/internal/pkg/cli/list/mocks/mock_list.go +++ b/internal/pkg/cli/list/mocks/mock_list.go @@ -5,6 +5,7 @@ package mocks import ( + context "context" reflect "reflect" config "github.com/aproint/copilot-cli/internal/pkg/config" @@ -35,48 +36,48 @@ func (m *MockStore) EXPECT() *MockStoreMockRecorder { } // GetApplication mocks base method. -func (m *MockStore) GetApplication(appName string) (*config.Application, error) { +func (m *MockStore) GetApplication(ctx context.Context, appName string) (*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetApplication", appName) + ret := m.ctrl.Call(m, "GetApplication", ctx, appName) ret0, _ := ret[0].(*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // GetApplication indicates an expected call of GetApplication. -func (mr *MockStoreMockRecorder) GetApplication(appName interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) GetApplication(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockStore)(nil).GetApplication), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockStore)(nil).GetApplication), ctx, appName) } // ListJobs mocks base method. -func (m *MockStore) ListJobs(appName string) ([]*config.Workload, error) { +func (m *MockStore) ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListJobs", appName) + ret := m.ctrl.Call(m, "ListJobs", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListJobs indicates an expected call of ListJobs. -func (mr *MockStoreMockRecorder) ListJobs(appName interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) ListJobs(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockStore)(nil).ListJobs), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockStore)(nil).ListJobs), ctx, appName) } // ListServices mocks base method. -func (m *MockStore) ListServices(appName string) ([]*config.Workload, error) { +func (m *MockStore) ListServices(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", appName) + ret := m.ctrl.Call(m, "ListServices", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockStoreMockRecorder) ListServices(appName interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) ListServices(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockStore)(nil).ListServices), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockStore)(nil).ListServices), ctx, appName) } // MockWorkspace is a mock of Workspace interface. diff --git a/internal/pkg/cli/mocks/mock_identity.go b/internal/pkg/cli/mocks/mock_identity.go index 1c535e00b6f..b00f4f531a4 100644 --- a/internal/pkg/cli/mocks/mock_identity.go +++ b/internal/pkg/cli/mocks/mock_identity.go @@ -5,6 +5,7 @@ package mocks import ( + context "context" reflect "reflect" identity "github.com/aproint/copilot-cli/internal/pkg/aws/identity" @@ -35,16 +36,16 @@ func (m *MockidentityService) EXPECT() *MockidentityServiceMockRecorder { } // Get mocks base method. -func (m *MockidentityService) Get() (identity.Caller, error) { +func (m *MockidentityService) Get(ctx context.Context) (identity.Caller, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get") + ret := m.ctrl.Call(m, "Get", ctx) ret0, _ := ret[0].(identity.Caller) ret1, _ := ret[1].(error) return ret0, ret1 } // Get indicates an expected call of Get. -func (mr *MockidentityServiceMockRecorder) Get() *gomock.Call { +func (mr *MockidentityServiceMockRecorder) Get(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockidentityService)(nil).Get)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockidentityService)(nil).Get), ctx) } diff --git a/internal/pkg/cli/mocks/mock_interfaces.go b/internal/pkg/cli/mocks/mock_interfaces.go index bc2b0ecdb09..f9ce710d8ed 100644 --- a/internal/pkg/cli/mocks/mock_interfaces.go +++ b/internal/pkg/cli/mocks/mock_interfaces.go @@ -64,31 +64,31 @@ func (m *Mockcmd) EXPECT() *MockcmdMockRecorder { } // Ask mocks base method. -func (m *Mockcmd) Ask() error { +func (m *Mockcmd) Ask(arg0 context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Ask") + ret := m.ctrl.Call(m, "Ask", arg0) ret0, _ := ret[0].(error) return ret0 } // Ask indicates an expected call of Ask. -func (mr *MockcmdMockRecorder) Ask() *gomock.Call { +func (mr *MockcmdMockRecorder) Ask(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ask", reflect.TypeOf((*Mockcmd)(nil).Ask)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ask", reflect.TypeOf((*Mockcmd)(nil).Ask), arg0) } // Execute mocks base method. -func (m *Mockcmd) Execute() error { +func (m *Mockcmd) Execute(arg0 context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Execute") + ret := m.ctrl.Call(m, "Execute", arg0) ret0, _ := ret[0].(error) return ret0 } // Execute indicates an expected call of Execute. -func (mr *MockcmdMockRecorder) Execute() *gomock.Call { +func (mr *MockcmdMockRecorder) Execute(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*Mockcmd)(nil).Execute)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*Mockcmd)(nil).Execute), arg0) } // Validate mocks base method. @@ -129,31 +129,31 @@ func (m *MockactionCommand) EXPECT() *MockactionCommandMockRecorder { } // Ask mocks base method. -func (m *MockactionCommand) Ask() error { +func (m *MockactionCommand) Ask(arg0 context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Ask") + ret := m.ctrl.Call(m, "Ask", arg0) ret0, _ := ret[0].(error) return ret0 } // Ask indicates an expected call of Ask. -func (mr *MockactionCommandMockRecorder) Ask() *gomock.Call { +func (mr *MockactionCommandMockRecorder) Ask(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ask", reflect.TypeOf((*MockactionCommand)(nil).Ask)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ask", reflect.TypeOf((*MockactionCommand)(nil).Ask), arg0) } // Execute mocks base method. -func (m *MockactionCommand) Execute() error { +func (m *MockactionCommand) Execute(arg0 context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Execute") + ret := m.ctrl.Call(m, "Execute", arg0) ret0, _ := ret[0].(error) return ret0 } // Execute indicates an expected call of Execute. -func (mr *MockactionCommandMockRecorder) Execute() *gomock.Call { +func (mr *MockactionCommandMockRecorder) Execute(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockactionCommand)(nil).Execute)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockactionCommand)(nil).Execute), arg0) } // RecommendActions mocks base method. @@ -208,61 +208,61 @@ func (m *MockserviceStore) EXPECT() *MockserviceStoreMockRecorder { } // CreateService mocks base method. -func (m *MockserviceStore) CreateService(svc *config.Workload) error { +func (m *MockserviceStore) CreateService(ctx context.Context, svc *config.Workload) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateService", svc) + ret := m.ctrl.Call(m, "CreateService", ctx, svc) ret0, _ := ret[0].(error) return ret0 } // CreateService indicates an expected call of CreateService. -func (mr *MockserviceStoreMockRecorder) CreateService(svc interface{}) *gomock.Call { +func (mr *MockserviceStoreMockRecorder) CreateService(ctx, svc interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateService", reflect.TypeOf((*MockserviceStore)(nil).CreateService), svc) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateService", reflect.TypeOf((*MockserviceStore)(nil).CreateService), ctx, svc) } // DeleteService mocks base method. -func (m *MockserviceStore) DeleteService(appName, svcName string) error { +func (m *MockserviceStore) DeleteService(ctx context.Context, appName, svcName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteService", appName, svcName) + ret := m.ctrl.Call(m, "DeleteService", ctx, appName, svcName) ret0, _ := ret[0].(error) return ret0 } // DeleteService indicates an expected call of DeleteService. -func (mr *MockserviceStoreMockRecorder) DeleteService(appName, svcName interface{}) *gomock.Call { +func (mr *MockserviceStoreMockRecorder) DeleteService(ctx, appName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteService", reflect.TypeOf((*MockserviceStore)(nil).DeleteService), appName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteService", reflect.TypeOf((*MockserviceStore)(nil).DeleteService), ctx, appName, svcName) } // GetService mocks base method. -func (m *MockserviceStore) GetService(appName, svcName string) (*config.Workload, error) { +func (m *MockserviceStore) GetService(ctx context.Context, appName, svcName string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetService", appName, svcName) + ret := m.ctrl.Call(m, "GetService", ctx, appName, svcName) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetService indicates an expected call of GetService. -func (mr *MockserviceStoreMockRecorder) GetService(appName, svcName interface{}) *gomock.Call { +func (mr *MockserviceStoreMockRecorder) GetService(ctx, appName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockserviceStore)(nil).GetService), appName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockserviceStore)(nil).GetService), ctx, appName, svcName) } // ListServices mocks base method. -func (m *MockserviceStore) ListServices(appName string) ([]*config.Workload, error) { +func (m *MockserviceStore) ListServices(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", appName) + ret := m.ctrl.Call(m, "ListServices", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockserviceStoreMockRecorder) ListServices(appName interface{}) *gomock.Call { +func (mr *MockserviceStoreMockRecorder) ListServices(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockserviceStore)(nil).ListServices), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockserviceStore)(nil).ListServices), ctx, appName) } // MockjobStore is a mock of jobStore interface. @@ -289,61 +289,61 @@ func (m *MockjobStore) EXPECT() *MockjobStoreMockRecorder { } // CreateJob mocks base method. -func (m *MockjobStore) CreateJob(job *config.Workload) error { +func (m *MockjobStore) CreateJob(ctx context.Context, job *config.Workload) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateJob", job) + ret := m.ctrl.Call(m, "CreateJob", ctx, job) ret0, _ := ret[0].(error) return ret0 } // CreateJob indicates an expected call of CreateJob. -func (mr *MockjobStoreMockRecorder) CreateJob(job interface{}) *gomock.Call { +func (mr *MockjobStoreMockRecorder) CreateJob(ctx, job interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateJob", reflect.TypeOf((*MockjobStore)(nil).CreateJob), job) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateJob", reflect.TypeOf((*MockjobStore)(nil).CreateJob), ctx, job) } // DeleteJob mocks base method. -func (m *MockjobStore) DeleteJob(appName, jobName string) error { +func (m *MockjobStore) DeleteJob(ctx context.Context, appName, jobName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteJob", appName, jobName) + ret := m.ctrl.Call(m, "DeleteJob", ctx, appName, jobName) ret0, _ := ret[0].(error) return ret0 } // DeleteJob indicates an expected call of DeleteJob. -func (mr *MockjobStoreMockRecorder) DeleteJob(appName, jobName interface{}) *gomock.Call { +func (mr *MockjobStoreMockRecorder) DeleteJob(ctx, appName, jobName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteJob", reflect.TypeOf((*MockjobStore)(nil).DeleteJob), appName, jobName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteJob", reflect.TypeOf((*MockjobStore)(nil).DeleteJob), ctx, appName, jobName) } // GetJob mocks base method. -func (m *MockjobStore) GetJob(appName, jobName string) (*config.Workload, error) { +func (m *MockjobStore) GetJob(ctx context.Context, appName, jobName string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetJob", appName, jobName) + ret := m.ctrl.Call(m, "GetJob", ctx, appName, jobName) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetJob indicates an expected call of GetJob. -func (mr *MockjobStoreMockRecorder) GetJob(appName, jobName interface{}) *gomock.Call { +func (mr *MockjobStoreMockRecorder) GetJob(ctx, appName, jobName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJob", reflect.TypeOf((*MockjobStore)(nil).GetJob), appName, jobName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJob", reflect.TypeOf((*MockjobStore)(nil).GetJob), ctx, appName, jobName) } // ListJobs mocks base method. -func (m *MockjobStore) ListJobs(appName string) ([]*config.Workload, error) { +func (m *MockjobStore) ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListJobs", appName) + ret := m.ctrl.Call(m, "ListJobs", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListJobs indicates an expected call of ListJobs. -func (mr *MockjobStoreMockRecorder) ListJobs(appName interface{}) *gomock.Call { +func (mr *MockjobStoreMockRecorder) ListJobs(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockjobStore)(nil).ListJobs), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockjobStore)(nil).ListJobs), ctx, appName) } // MockwlStore is a mock of wlStore interface. @@ -370,33 +370,33 @@ func (m *MockwlStore) EXPECT() *MockwlStoreMockRecorder { } // GetWorkload mocks base method. -func (m *MockwlStore) GetWorkload(appName, name string) (*config.Workload, error) { +func (m *MockwlStore) GetWorkload(ctx context.Context, appName, name string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetWorkload", appName, name) + ret := m.ctrl.Call(m, "GetWorkload", ctx, appName, name) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetWorkload indicates an expected call of GetWorkload. -func (mr *MockwlStoreMockRecorder) GetWorkload(appName, name interface{}) *gomock.Call { +func (mr *MockwlStoreMockRecorder) GetWorkload(ctx, appName, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkload", reflect.TypeOf((*MockwlStore)(nil).GetWorkload), appName, name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkload", reflect.TypeOf((*MockwlStore)(nil).GetWorkload), ctx, appName, name) } // ListWorkloads mocks base method. -func (m *MockwlStore) ListWorkloads(appName string) ([]*config.Workload, error) { +func (m *MockwlStore) ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListWorkloads", appName) + ret := m.ctrl.Call(m, "ListWorkloads", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListWorkloads indicates an expected call of ListWorkloads. -func (mr *MockwlStoreMockRecorder) ListWorkloads(appName interface{}) *gomock.Call { +func (mr *MockwlStoreMockRecorder) ListWorkloads(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockwlStore)(nil).ListWorkloads), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockwlStore)(nil).ListWorkloads), ctx, appName) } // MockworkloadListWriter is a mock of workloadListWriter interface. @@ -423,17 +423,17 @@ func (m *MockworkloadListWriter) EXPECT() *MockworkloadListWriterMockRecorder { } // Write mocks base method. -func (m *MockworkloadListWriter) Write(appName string) error { +func (m *MockworkloadListWriter) Write(ctx context.Context, appName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Write", appName) + ret := m.ctrl.Call(m, "Write", ctx, appName) ret0, _ := ret[0].(error) return ret0 } // Write indicates an expected call of Write. -func (mr *MockworkloadListWriterMockRecorder) Write(appName interface{}) *gomock.Call { +func (mr *MockworkloadListWriterMockRecorder) Write(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockworkloadListWriter)(nil).Write), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockworkloadListWriter)(nil).Write), ctx, appName) } // MockapplicationStore is a mock of applicationStore interface. @@ -460,75 +460,75 @@ func (m *MockapplicationStore) EXPECT() *MockapplicationStoreMockRecorder { } // CreateApplication mocks base method. -func (m *MockapplicationStore) CreateApplication(app *config.Application) error { +func (m *MockapplicationStore) CreateApplication(ctx context.Context, app *config.Application) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateApplication", app) + ret := m.ctrl.Call(m, "CreateApplication", ctx, app) ret0, _ := ret[0].(error) return ret0 } // CreateApplication indicates an expected call of CreateApplication. -func (mr *MockapplicationStoreMockRecorder) CreateApplication(app interface{}) *gomock.Call { +func (mr *MockapplicationStoreMockRecorder) CreateApplication(ctx, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplication", reflect.TypeOf((*MockapplicationStore)(nil).CreateApplication), app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplication", reflect.TypeOf((*MockapplicationStore)(nil).CreateApplication), ctx, app) } // DeleteApplication mocks base method. -func (m *MockapplicationStore) DeleteApplication(name string) error { +func (m *MockapplicationStore) DeleteApplication(ctx context.Context, name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteApplication", name) + ret := m.ctrl.Call(m, "DeleteApplication", ctx, name) ret0, _ := ret[0].(error) return ret0 } // DeleteApplication indicates an expected call of DeleteApplication. -func (mr *MockapplicationStoreMockRecorder) DeleteApplication(name interface{}) *gomock.Call { +func (mr *MockapplicationStoreMockRecorder) DeleteApplication(ctx, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplication", reflect.TypeOf((*MockapplicationStore)(nil).DeleteApplication), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplication", reflect.TypeOf((*MockapplicationStore)(nil).DeleteApplication), ctx, name) } // GetApplication mocks base method. -func (m *MockapplicationStore) GetApplication(appName string) (*config.Application, error) { +func (m *MockapplicationStore) GetApplication(ctx context.Context, appName string) (*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetApplication", appName) + ret := m.ctrl.Call(m, "GetApplication", ctx, appName) ret0, _ := ret[0].(*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // GetApplication indicates an expected call of GetApplication. -func (mr *MockapplicationStoreMockRecorder) GetApplication(appName interface{}) *gomock.Call { +func (mr *MockapplicationStoreMockRecorder) GetApplication(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockapplicationStore)(nil).GetApplication), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockapplicationStore)(nil).GetApplication), ctx, appName) } // ListApplications mocks base method. -func (m *MockapplicationStore) ListApplications() ([]*config.Application, error) { +func (m *MockapplicationStore) ListApplications(ctx context.Context) ([]*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListApplications") + ret := m.ctrl.Call(m, "ListApplications", ctx) ret0, _ := ret[0].([]*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // ListApplications indicates an expected call of ListApplications. -func (mr *MockapplicationStoreMockRecorder) ListApplications() *gomock.Call { +func (mr *MockapplicationStoreMockRecorder) ListApplications(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockapplicationStore)(nil).ListApplications)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockapplicationStore)(nil).ListApplications), ctx) } // UpdateApplication mocks base method. -func (m *MockapplicationStore) UpdateApplication(app *config.Application) error { +func (m *MockapplicationStore) UpdateApplication(ctx context.Context, app *config.Application) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateApplication", app) + ret := m.ctrl.Call(m, "UpdateApplication", ctx, app) ret0, _ := ret[0].(error) return ret0 } // UpdateApplication indicates an expected call of UpdateApplication. -func (mr *MockapplicationStoreMockRecorder) UpdateApplication(app interface{}) *gomock.Call { +func (mr *MockapplicationStoreMockRecorder) UpdateApplication(ctx, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateApplication", reflect.TypeOf((*MockapplicationStore)(nil).UpdateApplication), app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateApplication", reflect.TypeOf((*MockapplicationStore)(nil).UpdateApplication), ctx, app) } // MockapplicationCreator is a mock of applicationCreator interface. @@ -555,17 +555,17 @@ func (m *MockapplicationCreator) EXPECT() *MockapplicationCreatorMockRecorder { } // CreateApplication mocks base method. -func (m *MockapplicationCreator) CreateApplication(app *config.Application) error { +func (m *MockapplicationCreator) CreateApplication(ctx context.Context, app *config.Application) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateApplication", app) + ret := m.ctrl.Call(m, "CreateApplication", ctx, app) ret0, _ := ret[0].(error) return ret0 } // CreateApplication indicates an expected call of CreateApplication. -func (mr *MockapplicationCreatorMockRecorder) CreateApplication(app interface{}) *gomock.Call { +func (mr *MockapplicationCreatorMockRecorder) CreateApplication(ctx, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplication", reflect.TypeOf((*MockapplicationCreator)(nil).CreateApplication), app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplication", reflect.TypeOf((*MockapplicationCreator)(nil).CreateApplication), ctx, app) } // MockapplicationUpdater is a mock of applicationUpdater interface. @@ -592,17 +592,17 @@ func (m *MockapplicationUpdater) EXPECT() *MockapplicationUpdaterMockRecorder { } // UpdateApplication mocks base method. -func (m *MockapplicationUpdater) UpdateApplication(app *config.Application) error { +func (m *MockapplicationUpdater) UpdateApplication(ctx context.Context, app *config.Application) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateApplication", app) + ret := m.ctrl.Call(m, "UpdateApplication", ctx, app) ret0, _ := ret[0].(error) return ret0 } // UpdateApplication indicates an expected call of UpdateApplication. -func (mr *MockapplicationUpdaterMockRecorder) UpdateApplication(app interface{}) *gomock.Call { +func (mr *MockapplicationUpdaterMockRecorder) UpdateApplication(ctx, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateApplication", reflect.TypeOf((*MockapplicationUpdater)(nil).UpdateApplication), app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateApplication", reflect.TypeOf((*MockapplicationUpdater)(nil).UpdateApplication), ctx, app) } // MockapplicationGetter is a mock of applicationGetter interface. @@ -629,18 +629,18 @@ func (m *MockapplicationGetter) EXPECT() *MockapplicationGetterMockRecorder { } // GetApplication mocks base method. -func (m *MockapplicationGetter) GetApplication(appName string) (*config.Application, error) { +func (m *MockapplicationGetter) GetApplication(ctx context.Context, appName string) (*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetApplication", appName) + ret := m.ctrl.Call(m, "GetApplication", ctx, appName) ret0, _ := ret[0].(*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // GetApplication indicates an expected call of GetApplication. -func (mr *MockapplicationGetterMockRecorder) GetApplication(appName interface{}) *gomock.Call { +func (mr *MockapplicationGetterMockRecorder) GetApplication(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockapplicationGetter)(nil).GetApplication), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockapplicationGetter)(nil).GetApplication), ctx, appName) } // MockapplicationLister is a mock of applicationLister interface. @@ -667,18 +667,18 @@ func (m *MockapplicationLister) EXPECT() *MockapplicationListerMockRecorder { } // ListApplications mocks base method. -func (m *MockapplicationLister) ListApplications() ([]*config.Application, error) { +func (m *MockapplicationLister) ListApplications(ctx context.Context) ([]*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListApplications") + ret := m.ctrl.Call(m, "ListApplications", ctx) ret0, _ := ret[0].([]*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // ListApplications indicates an expected call of ListApplications. -func (mr *MockapplicationListerMockRecorder) ListApplications() *gomock.Call { +func (mr *MockapplicationListerMockRecorder) ListApplications(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockapplicationLister)(nil).ListApplications)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockapplicationLister)(nil).ListApplications), ctx) } // MockapplicationDeleter is a mock of applicationDeleter interface. @@ -705,17 +705,17 @@ func (m *MockapplicationDeleter) EXPECT() *MockapplicationDeleterMockRecorder { } // DeleteApplication mocks base method. -func (m *MockapplicationDeleter) DeleteApplication(name string) error { +func (m *MockapplicationDeleter) DeleteApplication(ctx context.Context, name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteApplication", name) + ret := m.ctrl.Call(m, "DeleteApplication", ctx, name) ret0, _ := ret[0].(error) return ret0 } // DeleteApplication indicates an expected call of DeleteApplication. -func (mr *MockapplicationDeleterMockRecorder) DeleteApplication(name interface{}) *gomock.Call { +func (mr *MockapplicationDeleterMockRecorder) DeleteApplication(ctx, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplication", reflect.TypeOf((*MockapplicationDeleter)(nil).DeleteApplication), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplication", reflect.TypeOf((*MockapplicationDeleter)(nil).DeleteApplication), ctx, name) } // MockenvironmentStore is a mock of environmentStore interface. @@ -742,76 +742,76 @@ func (m *MockenvironmentStore) EXPECT() *MockenvironmentStoreMockRecorder { } // CreateEnvironment mocks base method. -func (m *MockenvironmentStore) CreateEnvironment(env *config.Environment) error { +func (m *MockenvironmentStore) CreateEnvironment(ctx context.Context, env *config.Environment) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateEnvironment", env) + ret := m.ctrl.Call(m, "CreateEnvironment", ctx, env) ret0, _ := ret[0].(error) return ret0 } // CreateEnvironment indicates an expected call of CreateEnvironment. -func (mr *MockenvironmentStoreMockRecorder) CreateEnvironment(env interface{}) *gomock.Call { +func (mr *MockenvironmentStoreMockRecorder) CreateEnvironment(ctx, env interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEnvironment", reflect.TypeOf((*MockenvironmentStore)(nil).CreateEnvironment), env) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEnvironment", reflect.TypeOf((*MockenvironmentStore)(nil).CreateEnvironment), ctx, env) } // DeleteEnvironment mocks base method. -func (m *MockenvironmentStore) DeleteEnvironment(appName, environmentName string) error { +func (m *MockenvironmentStore) DeleteEnvironment(ctx context.Context, appName, environmentName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "DeleteEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(error) return ret0 } // DeleteEnvironment indicates an expected call of DeleteEnvironment. -func (mr *MockenvironmentStoreMockRecorder) DeleteEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockenvironmentStoreMockRecorder) DeleteEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEnvironment", reflect.TypeOf((*MockenvironmentStore)(nil).DeleteEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEnvironment", reflect.TypeOf((*MockenvironmentStore)(nil).DeleteEnvironment), ctx, appName, environmentName) } // GetApplication mocks base method. -func (m *MockenvironmentStore) GetApplication(appName string) (*config.Application, error) { +func (m *MockenvironmentStore) GetApplication(ctx context.Context, appName string) (*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetApplication", appName) + ret := m.ctrl.Call(m, "GetApplication", ctx, appName) ret0, _ := ret[0].(*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // GetApplication indicates an expected call of GetApplication. -func (mr *MockenvironmentStoreMockRecorder) GetApplication(appName interface{}) *gomock.Call { +func (mr *MockenvironmentStoreMockRecorder) GetApplication(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockenvironmentStore)(nil).GetApplication), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockenvironmentStore)(nil).GetApplication), ctx, appName) } // GetEnvironment mocks base method. -func (m *MockenvironmentStore) GetEnvironment(appName, environmentName string) (*config.Environment, error) { +func (m *MockenvironmentStore) GetEnvironment(ctx context.Context, appName, environmentName string) (*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "GetEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // GetEnvironment indicates an expected call of GetEnvironment. -func (mr *MockenvironmentStoreMockRecorder) GetEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockenvironmentStoreMockRecorder) GetEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockenvironmentStore)(nil).GetEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockenvironmentStore)(nil).GetEnvironment), ctx, appName, environmentName) } // ListEnvironments mocks base method. -func (m *MockenvironmentStore) ListEnvironments(appName string) ([]*config.Environment, error) { +func (m *MockenvironmentStore) ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironments", appName) + ret := m.ctrl.Call(m, "ListEnvironments", ctx, appName) ret0, _ := ret[0].([]*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironments indicates an expected call of ListEnvironments. -func (mr *MockenvironmentStoreMockRecorder) ListEnvironments(appName interface{}) *gomock.Call { +func (mr *MockenvironmentStoreMockRecorder) ListEnvironments(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockenvironmentStore)(nil).ListEnvironments), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockenvironmentStore)(nil).ListEnvironments), ctx, appName) } // MockenvironmentCreator is a mock of environmentCreator interface. @@ -838,17 +838,17 @@ func (m *MockenvironmentCreator) EXPECT() *MockenvironmentCreatorMockRecorder { } // CreateEnvironment mocks base method. -func (m *MockenvironmentCreator) CreateEnvironment(env *config.Environment) error { +func (m *MockenvironmentCreator) CreateEnvironment(ctx context.Context, env *config.Environment) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateEnvironment", env) + ret := m.ctrl.Call(m, "CreateEnvironment", ctx, env) ret0, _ := ret[0].(error) return ret0 } // CreateEnvironment indicates an expected call of CreateEnvironment. -func (mr *MockenvironmentCreatorMockRecorder) CreateEnvironment(env interface{}) *gomock.Call { +func (mr *MockenvironmentCreatorMockRecorder) CreateEnvironment(ctx, env interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEnvironment", reflect.TypeOf((*MockenvironmentCreator)(nil).CreateEnvironment), env) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEnvironment", reflect.TypeOf((*MockenvironmentCreator)(nil).CreateEnvironment), ctx, env) } // MockenvironmentGetter is a mock of environmentGetter interface. @@ -875,18 +875,18 @@ func (m *MockenvironmentGetter) EXPECT() *MockenvironmentGetterMockRecorder { } // GetEnvironment mocks base method. -func (m *MockenvironmentGetter) GetEnvironment(appName, environmentName string) (*config.Environment, error) { +func (m *MockenvironmentGetter) GetEnvironment(ctx context.Context, appName, environmentName string) (*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "GetEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // GetEnvironment indicates an expected call of GetEnvironment. -func (mr *MockenvironmentGetterMockRecorder) GetEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockenvironmentGetterMockRecorder) GetEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockenvironmentGetter)(nil).GetEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockenvironmentGetter)(nil).GetEnvironment), ctx, appName, environmentName) } // MockenvironmentLister is a mock of environmentLister interface. @@ -913,18 +913,18 @@ func (m *MockenvironmentLister) EXPECT() *MockenvironmentListerMockRecorder { } // ListEnvironments mocks base method. -func (m *MockenvironmentLister) ListEnvironments(appName string) ([]*config.Environment, error) { +func (m *MockenvironmentLister) ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironments", appName) + ret := m.ctrl.Call(m, "ListEnvironments", ctx, appName) ret0, _ := ret[0].([]*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironments indicates an expected call of ListEnvironments. -func (mr *MockenvironmentListerMockRecorder) ListEnvironments(appName interface{}) *gomock.Call { +func (mr *MockenvironmentListerMockRecorder) ListEnvironments(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockenvironmentLister)(nil).ListEnvironments), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockenvironmentLister)(nil).ListEnvironments), ctx, appName) } // MockwsEnvironmentsLister is a mock of wsEnvironmentsLister interface. @@ -989,17 +989,17 @@ func (m *MockenvironmentDeleter) EXPECT() *MockenvironmentDeleterMockRecorder { } // DeleteEnvironment mocks base method. -func (m *MockenvironmentDeleter) DeleteEnvironment(appName, environmentName string) error { +func (m *MockenvironmentDeleter) DeleteEnvironment(ctx context.Context, appName, environmentName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "DeleteEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(error) return ret0 } // DeleteEnvironment indicates an expected call of DeleteEnvironment. -func (mr *MockenvironmentDeleterMockRecorder) DeleteEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockenvironmentDeleterMockRecorder) DeleteEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEnvironment", reflect.TypeOf((*MockenvironmentDeleter)(nil).DeleteEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEnvironment", reflect.TypeOf((*MockenvironmentDeleter)(nil).DeleteEnvironment), ctx, appName, environmentName) } // Mockstore is a mock of store interface. @@ -1026,279 +1026,279 @@ func (m *Mockstore) EXPECT() *MockstoreMockRecorder { } // CreateApplication mocks base method. -func (m *Mockstore) CreateApplication(app *config.Application) error { +func (m *Mockstore) CreateApplication(ctx context.Context, app *config.Application) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateApplication", app) + ret := m.ctrl.Call(m, "CreateApplication", ctx, app) ret0, _ := ret[0].(error) return ret0 } // CreateApplication indicates an expected call of CreateApplication. -func (mr *MockstoreMockRecorder) CreateApplication(app interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) CreateApplication(ctx, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplication", reflect.TypeOf((*Mockstore)(nil).CreateApplication), app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplication", reflect.TypeOf((*Mockstore)(nil).CreateApplication), ctx, app) } // CreateEnvironment mocks base method. -func (m *Mockstore) CreateEnvironment(env *config.Environment) error { +func (m *Mockstore) CreateEnvironment(ctx context.Context, env *config.Environment) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateEnvironment", env) + ret := m.ctrl.Call(m, "CreateEnvironment", ctx, env) ret0, _ := ret[0].(error) return ret0 } // CreateEnvironment indicates an expected call of CreateEnvironment. -func (mr *MockstoreMockRecorder) CreateEnvironment(env interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) CreateEnvironment(ctx, env interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEnvironment", reflect.TypeOf((*Mockstore)(nil).CreateEnvironment), env) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEnvironment", reflect.TypeOf((*Mockstore)(nil).CreateEnvironment), ctx, env) } // CreateJob mocks base method. -func (m *Mockstore) CreateJob(job *config.Workload) error { +func (m *Mockstore) CreateJob(ctx context.Context, job *config.Workload) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateJob", job) + ret := m.ctrl.Call(m, "CreateJob", ctx, job) ret0, _ := ret[0].(error) return ret0 } // CreateJob indicates an expected call of CreateJob. -func (mr *MockstoreMockRecorder) CreateJob(job interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) CreateJob(ctx, job interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateJob", reflect.TypeOf((*Mockstore)(nil).CreateJob), job) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateJob", reflect.TypeOf((*Mockstore)(nil).CreateJob), ctx, job) } // CreateService mocks base method. -func (m *Mockstore) CreateService(svc *config.Workload) error { +func (m *Mockstore) CreateService(ctx context.Context, svc *config.Workload) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateService", svc) + ret := m.ctrl.Call(m, "CreateService", ctx, svc) ret0, _ := ret[0].(error) return ret0 } // CreateService indicates an expected call of CreateService. -func (mr *MockstoreMockRecorder) CreateService(svc interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) CreateService(ctx, svc interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateService", reflect.TypeOf((*Mockstore)(nil).CreateService), svc) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateService", reflect.TypeOf((*Mockstore)(nil).CreateService), ctx, svc) } // DeleteApplication mocks base method. -func (m *Mockstore) DeleteApplication(name string) error { +func (m *Mockstore) DeleteApplication(ctx context.Context, name string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteApplication", name) + ret := m.ctrl.Call(m, "DeleteApplication", ctx, name) ret0, _ := ret[0].(error) return ret0 } // DeleteApplication indicates an expected call of DeleteApplication. -func (mr *MockstoreMockRecorder) DeleteApplication(name interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) DeleteApplication(ctx, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplication", reflect.TypeOf((*Mockstore)(nil).DeleteApplication), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplication", reflect.TypeOf((*Mockstore)(nil).DeleteApplication), ctx, name) } // DeleteEnvironment mocks base method. -func (m *Mockstore) DeleteEnvironment(appName, environmentName string) error { +func (m *Mockstore) DeleteEnvironment(ctx context.Context, appName, environmentName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "DeleteEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(error) return ret0 } // DeleteEnvironment indicates an expected call of DeleteEnvironment. -func (mr *MockstoreMockRecorder) DeleteEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) DeleteEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEnvironment", reflect.TypeOf((*Mockstore)(nil).DeleteEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEnvironment", reflect.TypeOf((*Mockstore)(nil).DeleteEnvironment), ctx, appName, environmentName) } // DeleteJob mocks base method. -func (m *Mockstore) DeleteJob(appName, jobName string) error { +func (m *Mockstore) DeleteJob(ctx context.Context, appName, jobName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteJob", appName, jobName) + ret := m.ctrl.Call(m, "DeleteJob", ctx, appName, jobName) ret0, _ := ret[0].(error) return ret0 } // DeleteJob indicates an expected call of DeleteJob. -func (mr *MockstoreMockRecorder) DeleteJob(appName, jobName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) DeleteJob(ctx, appName, jobName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteJob", reflect.TypeOf((*Mockstore)(nil).DeleteJob), appName, jobName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteJob", reflect.TypeOf((*Mockstore)(nil).DeleteJob), ctx, appName, jobName) } // DeleteService mocks base method. -func (m *Mockstore) DeleteService(appName, svcName string) error { +func (m *Mockstore) DeleteService(ctx context.Context, appName, svcName string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteService", appName, svcName) + ret := m.ctrl.Call(m, "DeleteService", ctx, appName, svcName) ret0, _ := ret[0].(error) return ret0 } // DeleteService indicates an expected call of DeleteService. -func (mr *MockstoreMockRecorder) DeleteService(appName, svcName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) DeleteService(ctx, appName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteService", reflect.TypeOf((*Mockstore)(nil).DeleteService), appName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteService", reflect.TypeOf((*Mockstore)(nil).DeleteService), ctx, appName, svcName) } // GetApplication mocks base method. -func (m *Mockstore) GetApplication(appName string) (*config.Application, error) { +func (m *Mockstore) GetApplication(ctx context.Context, appName string) (*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetApplication", appName) + ret := m.ctrl.Call(m, "GetApplication", ctx, appName) ret0, _ := ret[0].(*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // GetApplication indicates an expected call of GetApplication. -func (mr *MockstoreMockRecorder) GetApplication(appName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) GetApplication(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*Mockstore)(nil).GetApplication), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*Mockstore)(nil).GetApplication), ctx, appName) } // GetEnvironment mocks base method. -func (m *Mockstore) GetEnvironment(appName, environmentName string) (*config.Environment, error) { +func (m *Mockstore) GetEnvironment(ctx context.Context, appName, environmentName string) (*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "GetEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // GetEnvironment indicates an expected call of GetEnvironment. -func (mr *MockstoreMockRecorder) GetEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) GetEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*Mockstore)(nil).GetEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*Mockstore)(nil).GetEnvironment), ctx, appName, environmentName) } // GetJob mocks base method. -func (m *Mockstore) GetJob(appName, jobName string) (*config.Workload, error) { +func (m *Mockstore) GetJob(ctx context.Context, appName, jobName string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetJob", appName, jobName) + ret := m.ctrl.Call(m, "GetJob", ctx, appName, jobName) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetJob indicates an expected call of GetJob. -func (mr *MockstoreMockRecorder) GetJob(appName, jobName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) GetJob(ctx, appName, jobName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJob", reflect.TypeOf((*Mockstore)(nil).GetJob), appName, jobName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJob", reflect.TypeOf((*Mockstore)(nil).GetJob), ctx, appName, jobName) } // GetService mocks base method. -func (m *Mockstore) GetService(appName, svcName string) (*config.Workload, error) { +func (m *Mockstore) GetService(ctx context.Context, appName, svcName string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetService", appName, svcName) + ret := m.ctrl.Call(m, "GetService", ctx, appName, svcName) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetService indicates an expected call of GetService. -func (mr *MockstoreMockRecorder) GetService(appName, svcName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) GetService(ctx, appName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*Mockstore)(nil).GetService), appName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*Mockstore)(nil).GetService), ctx, appName, svcName) } // GetWorkload mocks base method. -func (m *Mockstore) GetWorkload(appName, name string) (*config.Workload, error) { +func (m *Mockstore) GetWorkload(ctx context.Context, appName, name string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetWorkload", appName, name) + ret := m.ctrl.Call(m, "GetWorkload", ctx, appName, name) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetWorkload indicates an expected call of GetWorkload. -func (mr *MockstoreMockRecorder) GetWorkload(appName, name interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) GetWorkload(ctx, appName, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkload", reflect.TypeOf((*Mockstore)(nil).GetWorkload), appName, name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkload", reflect.TypeOf((*Mockstore)(nil).GetWorkload), ctx, appName, name) } // ListApplications mocks base method. -func (m *Mockstore) ListApplications() ([]*config.Application, error) { +func (m *Mockstore) ListApplications(ctx context.Context) ([]*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListApplications") + ret := m.ctrl.Call(m, "ListApplications", ctx) ret0, _ := ret[0].([]*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // ListApplications indicates an expected call of ListApplications. -func (mr *MockstoreMockRecorder) ListApplications() *gomock.Call { +func (mr *MockstoreMockRecorder) ListApplications(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*Mockstore)(nil).ListApplications)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*Mockstore)(nil).ListApplications), ctx) } // ListEnvironments mocks base method. -func (m *Mockstore) ListEnvironments(appName string) ([]*config.Environment, error) { +func (m *Mockstore) ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironments", appName) + ret := m.ctrl.Call(m, "ListEnvironments", ctx, appName) ret0, _ := ret[0].([]*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironments indicates an expected call of ListEnvironments. -func (mr *MockstoreMockRecorder) ListEnvironments(appName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) ListEnvironments(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*Mockstore)(nil).ListEnvironments), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*Mockstore)(nil).ListEnvironments), ctx, appName) } // ListJobs mocks base method. -func (m *Mockstore) ListJobs(appName string) ([]*config.Workload, error) { +func (m *Mockstore) ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListJobs", appName) + ret := m.ctrl.Call(m, "ListJobs", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListJobs indicates an expected call of ListJobs. -func (mr *MockstoreMockRecorder) ListJobs(appName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) ListJobs(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*Mockstore)(nil).ListJobs), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*Mockstore)(nil).ListJobs), ctx, appName) } // ListServices mocks base method. -func (m *Mockstore) ListServices(appName string) ([]*config.Workload, error) { +func (m *Mockstore) ListServices(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", appName) + ret := m.ctrl.Call(m, "ListServices", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockstoreMockRecorder) ListServices(appName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) ListServices(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*Mockstore)(nil).ListServices), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*Mockstore)(nil).ListServices), ctx, appName) } // ListWorkloads mocks base method. -func (m *Mockstore) ListWorkloads(appName string) ([]*config.Workload, error) { +func (m *Mockstore) ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListWorkloads", appName) + ret := m.ctrl.Call(m, "ListWorkloads", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListWorkloads indicates an expected call of ListWorkloads. -func (mr *MockstoreMockRecorder) ListWorkloads(appName interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) ListWorkloads(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*Mockstore)(nil).ListWorkloads), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*Mockstore)(nil).ListWorkloads), ctx, appName) } // UpdateApplication mocks base method. -func (m *Mockstore) UpdateApplication(app *config.Application) error { +func (m *Mockstore) UpdateApplication(ctx context.Context, app *config.Application) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateApplication", app) + ret := m.ctrl.Call(m, "UpdateApplication", ctx, app) ret0, _ := ret[0].(error) return ret0 } // UpdateApplication indicates an expected call of UpdateApplication. -func (mr *MockstoreMockRecorder) UpdateApplication(app interface{}) *gomock.Call { +func (mr *MockstoreMockRecorder) UpdateApplication(ctx, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateApplication", reflect.TypeOf((*Mockstore)(nil).UpdateApplication), app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateApplication", reflect.TypeOf((*Mockstore)(nil).UpdateApplication), ctx, app) } // MockdeployedEnvironmentLister is a mock of deployedEnvironmentLister interface. @@ -1325,78 +1325,78 @@ func (m *MockdeployedEnvironmentLister) EXPECT() *MockdeployedEnvironmentListerM } // IsServiceDeployed mocks base method. -func (m *MockdeployedEnvironmentLister) IsServiceDeployed(appName, envName, svcName string) (bool, error) { +func (m *MockdeployedEnvironmentLister) IsServiceDeployed(ctx context.Context, appName, envName, svcName string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsServiceDeployed", appName, envName, svcName) + ret := m.ctrl.Call(m, "IsServiceDeployed", ctx, appName, envName, svcName) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // IsServiceDeployed indicates an expected call of IsServiceDeployed. -func (mr *MockdeployedEnvironmentListerMockRecorder) IsServiceDeployed(appName, envName, svcName interface{}) *gomock.Call { +func (mr *MockdeployedEnvironmentListerMockRecorder) IsServiceDeployed(ctx, appName, envName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsServiceDeployed", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).IsServiceDeployed), appName, envName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsServiceDeployed", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).IsServiceDeployed), ctx, appName, envName, svcName) } // ListDeployedJobs mocks base method. -func (m *MockdeployedEnvironmentLister) ListDeployedJobs(appName, envName string) ([]string, error) { +func (m *MockdeployedEnvironmentLister) ListDeployedJobs(ctx context.Context, appName, envName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployedJobs", appName, envName) + ret := m.ctrl.Call(m, "ListDeployedJobs", ctx, appName, envName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListDeployedJobs indicates an expected call of ListDeployedJobs. -func (mr *MockdeployedEnvironmentListerMockRecorder) ListDeployedJobs(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployedEnvironmentListerMockRecorder) ListDeployedJobs(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedJobs", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListDeployedJobs), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedJobs", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListDeployedJobs), ctx, appName, envName) } // ListDeployedServices mocks base method. -func (m *MockdeployedEnvironmentLister) ListDeployedServices(appName, envName string) ([]string, error) { +func (m *MockdeployedEnvironmentLister) ListDeployedServices(ctx context.Context, appName, envName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployedServices", appName, envName) + ret := m.ctrl.Call(m, "ListDeployedServices", ctx, appName, envName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListDeployedServices indicates an expected call of ListDeployedServices. -func (mr *MockdeployedEnvironmentListerMockRecorder) ListDeployedServices(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployedEnvironmentListerMockRecorder) ListDeployedServices(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedServices", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListDeployedServices), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedServices", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListDeployedServices), ctx, appName, envName) } // ListEnvironmentsDeployedTo mocks base method. -func (m *MockdeployedEnvironmentLister) ListEnvironmentsDeployedTo(appName, svcName string) ([]string, error) { +func (m *MockdeployedEnvironmentLister) ListEnvironmentsDeployedTo(ctx context.Context, appName, svcName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironmentsDeployedTo", appName, svcName) + ret := m.ctrl.Call(m, "ListEnvironmentsDeployedTo", ctx, appName, svcName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironmentsDeployedTo indicates an expected call of ListEnvironmentsDeployedTo. -func (mr *MockdeployedEnvironmentListerMockRecorder) ListEnvironmentsDeployedTo(appName, svcName interface{}) *gomock.Call { +func (mr *MockdeployedEnvironmentListerMockRecorder) ListEnvironmentsDeployedTo(ctx, appName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironmentsDeployedTo", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListEnvironmentsDeployedTo), appName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironmentsDeployedTo", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListEnvironmentsDeployedTo), ctx, appName, svcName) } // ListSNSTopics mocks base method. -func (m *MockdeployedEnvironmentLister) ListSNSTopics(appName, envName string) ([]deploy0.Topic, error) { +func (m *MockdeployedEnvironmentLister) ListSNSTopics(ctx context.Context, appName, envName string) ([]deploy0.Topic, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListSNSTopics", appName, envName) + ret := m.ctrl.Call(m, "ListSNSTopics", ctx, appName, envName) ret0, _ := ret[0].([]deploy0.Topic) ret1, _ := ret[1].(error) return ret0, ret1 } // ListSNSTopics indicates an expected call of ListSNSTopics. -func (mr *MockdeployedEnvironmentListerMockRecorder) ListSNSTopics(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployedEnvironmentListerMockRecorder) ListSNSTopics(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSNSTopics", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListSNSTopics), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSNSTopics", reflect.TypeOf((*MockdeployedEnvironmentLister)(nil).ListSNSTopics), ctx, appName, envName) } // MocksecretsManager is a mock of secretsManager interface. @@ -3988,18 +3988,18 @@ func (mr *MockenvironmentDeployerMockRecorder) DeleteEnvironment(appName, envNam } // GetEnvironment mocks base method. -func (m *MockenvironmentDeployer) GetEnvironment(appName, envName string) (*config.Environment, error) { +func (m *MockenvironmentDeployer) GetEnvironment(ctx context.Context, appName, envName string) (*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnvironment", appName, envName) + ret := m.ctrl.Call(m, "GetEnvironment", ctx, appName, envName) ret0, _ := ret[0].(*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // GetEnvironment indicates an expected call of GetEnvironment. -func (mr *MockenvironmentDeployerMockRecorder) GetEnvironment(appName, envName interface{}) *gomock.Call { +func (mr *MockenvironmentDeployerMockRecorder) GetEnvironment(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockenvironmentDeployer)(nil).GetEnvironment), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockenvironmentDeployer)(nil).GetEnvironment), ctx, appName, envName) } // Template mocks base method. @@ -4957,18 +4957,18 @@ func (mr *MockdeployerMockRecorder) GetAppResourcesByRegion(app, region interfac } // GetEnvironment mocks base method. -func (m *Mockdeployer) GetEnvironment(appName, envName string) (*config.Environment, error) { +func (m *Mockdeployer) GetEnvironment(ctx context.Context, appName, envName string) (*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnvironment", appName, envName) + ret := m.ctrl.Call(m, "GetEnvironment", ctx, appName, envName) ret0, _ := ret[0].(*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // GetEnvironment indicates an expected call of GetEnvironment. -func (mr *MockdeployerMockRecorder) GetEnvironment(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployerMockRecorder) GetEnvironment(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*Mockdeployer)(nil).GetEnvironment), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*Mockdeployer)(nil).GetEnvironment), ctx, appName, envName) } // GetRegionalAppResources mocks base method. @@ -5497,17 +5497,17 @@ func (m *Mockexecutor) EXPECT() *MockexecutorMockRecorder { } // Execute mocks base method. -func (m *Mockexecutor) Execute() error { +func (m *Mockexecutor) Execute(arg0 context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Execute") + ret := m.ctrl.Call(m, "Execute", arg0) ret0, _ := ret[0].(error) return ret0 } // Execute indicates an expected call of Execute. -func (mr *MockexecutorMockRecorder) Execute() *gomock.Call { +func (mr *MockexecutorMockRecorder) Execute(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*Mockexecutor)(nil).Execute)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*Mockexecutor)(nil).Execute), arg0) } // MockexecuteAsker is a mock of executeAsker interface. @@ -5534,31 +5534,31 @@ func (m *MockexecuteAsker) EXPECT() *MockexecuteAskerMockRecorder { } // Ask mocks base method. -func (m *MockexecuteAsker) Ask() error { +func (m *MockexecuteAsker) Ask(arg0 context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Ask") + ret := m.ctrl.Call(m, "Ask", arg0) ret0, _ := ret[0].(error) return ret0 } // Ask indicates an expected call of Ask. -func (mr *MockexecuteAskerMockRecorder) Ask() *gomock.Call { +func (mr *MockexecuteAskerMockRecorder) Ask(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ask", reflect.TypeOf((*MockexecuteAsker)(nil).Ask)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ask", reflect.TypeOf((*MockexecuteAsker)(nil).Ask), arg0) } // Execute mocks base method. -func (m *MockexecuteAsker) Execute() error { +func (m *MockexecuteAsker) Execute(arg0 context.Context) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Execute") + ret := m.ctrl.Call(m, "Execute", arg0) ret0, _ := ret[0].(error) return ret0 } // Execute indicates an expected call of Execute. -func (mr *MockexecuteAskerMockRecorder) Execute() *gomock.Call { +func (mr *MockexecuteAskerMockRecorder) Execute(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockexecuteAsker)(nil).Execute)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockexecuteAsker)(nil).Execute), arg0) } // MockappSelector is a mock of appSelector interface. @@ -5585,9 +5585,9 @@ func (m *MockappSelector) EXPECT() *MockappSelectorMockRecorder { } // Application mocks base method. -func (m *MockappSelector) Application(prompt, help string, additionalOpts ...string) (string, error) { +func (m *MockappSelector) Application(ctx context.Context, prompt, help string, additionalOpts ...string) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help} + varargs := []interface{}{ctx, prompt, help} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -5598,9 +5598,9 @@ func (m *MockappSelector) Application(prompt, help string, additionalOpts ...str } // Application indicates an expected call of Application. -func (mr *MockappSelectorMockRecorder) Application(prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockappSelectorMockRecorder) Application(ctx, prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Application", reflect.TypeOf((*MockappSelector)(nil).Application), varargs...) } @@ -5628,9 +5628,9 @@ func (m *MockappEnvSelector) EXPECT() *MockappEnvSelectorMockRecorder { } // Application mocks base method. -func (m *MockappEnvSelector) Application(prompt, help string, additionalOpts ...string) (string, error) { +func (m *MockappEnvSelector) Application(ctx context.Context, prompt, help string, additionalOpts ...string) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help} + varargs := []interface{}{ctx, prompt, help} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -5641,16 +5641,16 @@ func (m *MockappEnvSelector) Application(prompt, help string, additionalOpts ... } // Application indicates an expected call of Application. -func (mr *MockappEnvSelectorMockRecorder) Application(prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockappEnvSelectorMockRecorder) Application(ctx, prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Application", reflect.TypeOf((*MockappEnvSelector)(nil).Application), varargs...) } // Environment mocks base method. -func (m *MockappEnvSelector) Environment(prompt, help, app string, additionalOpts ...prompt.Option) (string, error) { +func (m *MockappEnvSelector) Environment(ctx context.Context, prompt, help, app string, additionalOpts ...prompt.Option) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help, app} + varargs := []interface{}{ctx, prompt, help, app} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -5661,9 +5661,9 @@ func (m *MockappEnvSelector) Environment(prompt, help, app string, additionalOpt } // Environment indicates an expected call of Environment. -func (mr *MockappEnvSelectorMockRecorder) Environment(prompt, help, app interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockappEnvSelectorMockRecorder) Environment(ctx, prompt, help, app interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help, app}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help, app}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Environment", reflect.TypeOf((*MockappEnvSelector)(nil).Environment), varargs...) } @@ -5729,9 +5729,9 @@ func (m *MockconfigSelector) EXPECT() *MockconfigSelectorMockRecorder { } // Application mocks base method. -func (m *MockconfigSelector) Application(prompt, help string, additionalOpts ...string) (string, error) { +func (m *MockconfigSelector) Application(ctx context.Context, prompt, help string, additionalOpts ...string) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help} + varargs := []interface{}{ctx, prompt, help} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -5742,16 +5742,16 @@ func (m *MockconfigSelector) Application(prompt, help string, additionalOpts ... } // Application indicates an expected call of Application. -func (mr *MockconfigSelectorMockRecorder) Application(prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockconfigSelectorMockRecorder) Application(ctx, prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Application", reflect.TypeOf((*MockconfigSelector)(nil).Application), varargs...) } // Environment mocks base method. -func (m *MockconfigSelector) Environment(prompt, help, app string, additionalOpts ...prompt.Option) (string, error) { +func (m *MockconfigSelector) Environment(ctx context.Context, prompt, help, app string, additionalOpts ...prompt.Option) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help, app} + varargs := []interface{}{ctx, prompt, help, app} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -5762,55 +5762,55 @@ func (m *MockconfigSelector) Environment(prompt, help, app string, additionalOpt } // Environment indicates an expected call of Environment. -func (mr *MockconfigSelectorMockRecorder) Environment(prompt, help, app interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockconfigSelectorMockRecorder) Environment(ctx, prompt, help, app interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help, app}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help, app}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Environment", reflect.TypeOf((*MockconfigSelector)(nil).Environment), varargs...) } // Job mocks base method. -func (m *MockconfigSelector) Job(prompt, help, app string) (string, error) { +func (m *MockconfigSelector) Job(ctx context.Context, prompt, help, app string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Job", prompt, help, app) + ret := m.ctrl.Call(m, "Job", ctx, prompt, help, app) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Job indicates an expected call of Job. -func (mr *MockconfigSelectorMockRecorder) Job(prompt, help, app interface{}) *gomock.Call { +func (mr *MockconfigSelectorMockRecorder) Job(ctx, prompt, help, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Job", reflect.TypeOf((*MockconfigSelector)(nil).Job), prompt, help, app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Job", reflect.TypeOf((*MockconfigSelector)(nil).Job), ctx, prompt, help, app) } // Service mocks base method. -func (m *MockconfigSelector) Service(prompt, help, app string) (string, error) { +func (m *MockconfigSelector) Service(ctx context.Context, prompt, help, app string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Service", prompt, help, app) + ret := m.ctrl.Call(m, "Service", ctx, prompt, help, app) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Service indicates an expected call of Service. -func (mr *MockconfigSelectorMockRecorder) Service(prompt, help, app interface{}) *gomock.Call { +func (mr *MockconfigSelectorMockRecorder) Service(ctx, prompt, help, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Service", reflect.TypeOf((*MockconfigSelector)(nil).Service), prompt, help, app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Service", reflect.TypeOf((*MockconfigSelector)(nil).Service), ctx, prompt, help, app) } // Workload mocks base method. -func (m *MockconfigSelector) Workload(prompt, help, app string) (string, error) { +func (m *MockconfigSelector) Workload(ctx context.Context, prompt, help, app string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Workload", prompt, help, app) + ret := m.ctrl.Call(m, "Workload", ctx, prompt, help, app) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Workload indicates an expected call of Workload. -func (mr *MockconfigSelectorMockRecorder) Workload(prompt, help, app interface{}) *gomock.Call { +func (mr *MockconfigSelectorMockRecorder) Workload(ctx, prompt, help, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Workload", reflect.TypeOf((*MockconfigSelector)(nil).Workload), prompt, help, app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Workload", reflect.TypeOf((*MockconfigSelector)(nil).Workload), ctx, prompt, help, app) } // MockdeploySelector is a mock of deploySelector interface. @@ -5837,9 +5837,9 @@ func (m *MockdeploySelector) EXPECT() *MockdeploySelectorMockRecorder { } // Application mocks base method. -func (m *MockdeploySelector) Application(prompt, help string, additionalOpts ...string) (string, error) { +func (m *MockdeploySelector) Application(ctx context.Context, prompt, help string, additionalOpts ...string) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help} + varargs := []interface{}{ctx, prompt, help} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -5850,16 +5850,16 @@ func (m *MockdeploySelector) Application(prompt, help string, additionalOpts ... } // Application indicates an expected call of Application. -func (mr *MockdeploySelectorMockRecorder) Application(prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockdeploySelectorMockRecorder) Application(ctx, prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Application", reflect.TypeOf((*MockdeploySelector)(nil).Application), varargs...) } // DeployedJob mocks base method. -func (m *MockdeploySelector) DeployedJob(prompt, help, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedJob, error) { +func (m *MockdeploySelector) DeployedJob(ctx context.Context, prompt, help, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedJob, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help, app} + varargs := []interface{}{ctx, prompt, help, app} for _, a := range opts { varargs = append(varargs, a) } @@ -5870,16 +5870,16 @@ func (m *MockdeploySelector) DeployedJob(prompt, help, app string, opts ...selec } // DeployedJob indicates an expected call of DeployedJob. -func (mr *MockdeploySelectorMockRecorder) DeployedJob(prompt, help, app interface{}, opts ...interface{}) *gomock.Call { +func (mr *MockdeploySelectorMockRecorder) DeployedJob(ctx, prompt, help, app interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help, app}, opts...) + varargs := append([]interface{}{ctx, prompt, help, app}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeployedJob", reflect.TypeOf((*MockdeploySelector)(nil).DeployedJob), varargs...) } // DeployedService mocks base method. -func (m *MockdeploySelector) DeployedService(prompt, help, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedService, error) { +func (m *MockdeploySelector) DeployedService(ctx context.Context, prompt, help, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedService, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help, app} + varargs := []interface{}{ctx, prompt, help, app} for _, a := range opts { varargs = append(varargs, a) } @@ -5890,16 +5890,16 @@ func (m *MockdeploySelector) DeployedService(prompt, help, app string, opts ...s } // DeployedService indicates an expected call of DeployedService. -func (mr *MockdeploySelectorMockRecorder) DeployedService(prompt, help, app interface{}, opts ...interface{}) *gomock.Call { +func (mr *MockdeploySelectorMockRecorder) DeployedService(ctx, prompt, help, app interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help, app}, opts...) + varargs := append([]interface{}{ctx, prompt, help, app}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeployedService", reflect.TypeOf((*MockdeploySelector)(nil).DeployedService), varargs...) } // DeployedWorkload mocks base method. -func (m *MockdeploySelector) DeployedWorkload(prompt, help, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedWorkload, error) { +func (m *MockdeploySelector) DeployedWorkload(ctx context.Context, prompt, help, app string, opts ...selector.GetDeployedWorkloadOpts) (*selector.DeployedWorkload, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help, app} + varargs := []interface{}{ctx, prompt, help, app} for _, a := range opts { varargs = append(varargs, a) } @@ -5910,9 +5910,9 @@ func (m *MockdeploySelector) DeployedWorkload(prompt, help, app string, opts ... } // DeployedWorkload indicates an expected call of DeployedWorkload. -func (mr *MockdeploySelectorMockRecorder) DeployedWorkload(prompt, help, app interface{}, opts ...interface{}) *gomock.Call { +func (mr *MockdeploySelectorMockRecorder) DeployedWorkload(ctx, prompt, help, app interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help, app}, opts...) + varargs := append([]interface{}{ctx, prompt, help, app}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeployedWorkload", reflect.TypeOf((*MockdeploySelector)(nil).DeployedWorkload), varargs...) } @@ -5940,18 +5940,18 @@ func (m *MockpipelineEnvSelector) EXPECT() *MockpipelineEnvSelectorMockRecorder } // Environments mocks base method. -func (m *MockpipelineEnvSelector) Environments(prompt, help, app string, finalMsgFunc func(int) prompt.PromptConfig) ([]string, error) { +func (m *MockpipelineEnvSelector) Environments(ctx context.Context, prompt, help, app string, finalMsgFunc func(int) prompt.PromptConfig) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Environments", prompt, help, app, finalMsgFunc) + ret := m.ctrl.Call(m, "Environments", ctx, prompt, help, app, finalMsgFunc) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // Environments indicates an expected call of Environments. -func (mr *MockpipelineEnvSelectorMockRecorder) Environments(prompt, help, app, finalMsgFunc interface{}) *gomock.Call { +func (mr *MockpipelineEnvSelectorMockRecorder) Environments(ctx, prompt, help, app, finalMsgFunc interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Environments", reflect.TypeOf((*MockpipelineEnvSelector)(nil).Environments), prompt, help, app, finalMsgFunc) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Environments", reflect.TypeOf((*MockpipelineEnvSelector)(nil).Environments), ctx, prompt, help, app, finalMsgFunc) } // MockwsPipelineSelector is a mock of wsPipelineSelector interface. @@ -6016,18 +6016,18 @@ func (m *MockwsEnvironmentSelector) EXPECT() *MockwsEnvironmentSelectorMockRecor } // LocalEnvironment mocks base method. -func (m *MockwsEnvironmentSelector) LocalEnvironment(msg, help string) (string, error) { +func (m *MockwsEnvironmentSelector) LocalEnvironment(ctx context.Context, msg, help string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LocalEnvironment", msg, help) + ret := m.ctrl.Call(m, "LocalEnvironment", ctx, msg, help) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // LocalEnvironment indicates an expected call of LocalEnvironment. -func (mr *MockwsEnvironmentSelectorMockRecorder) LocalEnvironment(msg, help interface{}) *gomock.Call { +func (mr *MockwsEnvironmentSelectorMockRecorder) LocalEnvironment(ctx, msg, help interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LocalEnvironment", reflect.TypeOf((*MockwsEnvironmentSelector)(nil).LocalEnvironment), msg, help) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LocalEnvironment", reflect.TypeOf((*MockwsEnvironmentSelector)(nil).LocalEnvironment), ctx, msg, help) } // MockcodePipelineSelector is a mock of codePipelineSelector interface. @@ -6054,9 +6054,9 @@ func (m *MockcodePipelineSelector) EXPECT() *MockcodePipelineSelectorMockRecorde } // Application mocks base method. -func (m *MockcodePipelineSelector) Application(prompt, help string, additionalOpts ...string) (string, error) { +func (m *MockcodePipelineSelector) Application(ctx context.Context, prompt, help string, additionalOpts ...string) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help} + varargs := []interface{}{ctx, prompt, help} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -6067,9 +6067,9 @@ func (m *MockcodePipelineSelector) Application(prompt, help string, additionalOp } // Application indicates an expected call of Application. -func (mr *MockcodePipelineSelectorMockRecorder) Application(prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockcodePipelineSelectorMockRecorder) Application(ctx, prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Application", reflect.TypeOf((*MockcodePipelineSelector)(nil).Application), varargs...) } @@ -6112,9 +6112,9 @@ func (m *MockwsSelector) EXPECT() *MockwsSelectorMockRecorder { } // Application mocks base method. -func (m *MockwsSelector) Application(prompt, help string, additionalOpts ...string) (string, error) { +func (m *MockwsSelector) Application(ctx context.Context, prompt, help string, additionalOpts ...string) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help} + varargs := []interface{}{ctx, prompt, help} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -6125,16 +6125,16 @@ func (m *MockwsSelector) Application(prompt, help string, additionalOpts ...stri } // Application indicates an expected call of Application. -func (mr *MockwsSelectorMockRecorder) Application(prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockwsSelectorMockRecorder) Application(ctx, prompt, help interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Application", reflect.TypeOf((*MockwsSelector)(nil).Application), varargs...) } // Environment mocks base method. -func (m *MockwsSelector) Environment(prompt, help, app string, additionalOpts ...prompt.Option) (string, error) { +func (m *MockwsSelector) Environment(ctx context.Context, prompt, help, app string, additionalOpts ...prompt.Option) (string, error) { m.ctrl.T.Helper() - varargs := []interface{}{prompt, help, app} + varargs := []interface{}{ctx, prompt, help, app} for _, a := range additionalOpts { varargs = append(varargs, a) } @@ -6145,70 +6145,70 @@ func (m *MockwsSelector) Environment(prompt, help, app string, additionalOpts .. } // Environment indicates an expected call of Environment. -func (mr *MockwsSelectorMockRecorder) Environment(prompt, help, app interface{}, additionalOpts ...interface{}) *gomock.Call { +func (mr *MockwsSelectorMockRecorder) Environment(ctx, prompt, help, app interface{}, additionalOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{prompt, help, app}, additionalOpts...) + varargs := append([]interface{}{ctx, prompt, help, app}, additionalOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Environment", reflect.TypeOf((*MockwsSelector)(nil).Environment), varargs...) } // Job mocks base method. -func (m *MockwsSelector) Job(prompt, help string) (string, error) { +func (m *MockwsSelector) Job(ctx context.Context, prompt, help string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Job", prompt, help) + ret := m.ctrl.Call(m, "Job", ctx, prompt, help) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Job indicates an expected call of Job. -func (mr *MockwsSelectorMockRecorder) Job(prompt, help interface{}) *gomock.Call { +func (mr *MockwsSelectorMockRecorder) Job(ctx, prompt, help interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Job", reflect.TypeOf((*MockwsSelector)(nil).Job), prompt, help) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Job", reflect.TypeOf((*MockwsSelector)(nil).Job), ctx, prompt, help) } // Service mocks base method. -func (m *MockwsSelector) Service(prompt, help string) (string, error) { +func (m *MockwsSelector) Service(ctx context.Context, prompt, help string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Service", prompt, help) + ret := m.ctrl.Call(m, "Service", ctx, prompt, help) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Service indicates an expected call of Service. -func (mr *MockwsSelectorMockRecorder) Service(prompt, help interface{}) *gomock.Call { +func (mr *MockwsSelectorMockRecorder) Service(ctx, prompt, help interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Service", reflect.TypeOf((*MockwsSelector)(nil).Service), prompt, help) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Service", reflect.TypeOf((*MockwsSelector)(nil).Service), ctx, prompt, help) } // Workload mocks base method. -func (m *MockwsSelector) Workload(msg, help string) (string, error) { +func (m *MockwsSelector) Workload(ctx context.Context, msg, help string) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Workload", msg, help) + ret := m.ctrl.Call(m, "Workload", ctx, msg, help) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Workload indicates an expected call of Workload. -func (mr *MockwsSelectorMockRecorder) Workload(msg, help interface{}) *gomock.Call { +func (mr *MockwsSelectorMockRecorder) Workload(ctx, msg, help interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Workload", reflect.TypeOf((*MockwsSelector)(nil).Workload), msg, help) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Workload", reflect.TypeOf((*MockwsSelector)(nil).Workload), ctx, msg, help) } // Workloads mocks base method. -func (m *MockwsSelector) Workloads(msg, help string) ([]string, error) { +func (m *MockwsSelector) Workloads(ctx context.Context, msg, help string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Workloads", msg, help) + ret := m.ctrl.Call(m, "Workloads", ctx, msg, help) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // Workloads indicates an expected call of Workloads. -func (mr *MockwsSelectorMockRecorder) Workloads(msg, help interface{}) *gomock.Call { +func (mr *MockwsSelectorMockRecorder) Workloads(ctx, msg, help interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Workloads", reflect.TypeOf((*MockwsSelector)(nil).Workloads), msg, help) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Workloads", reflect.TypeOf((*MockwsSelector)(nil).Workloads), ctx, msg, help) } // MockstaticSourceSelector is a mock of staticSourceSelector interface. @@ -6392,18 +6392,18 @@ func (m *MocktopicSelector) EXPECT() *MocktopicSelectorMockRecorder { } // Topics mocks base method. -func (m *MocktopicSelector) Topics(prompt, help, app string) ([]deploy0.Topic, error) { +func (m *MocktopicSelector) Topics(ctx context.Context, prompt, help, app string) ([]deploy0.Topic, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Topics", prompt, help, app) + ret := m.ctrl.Call(m, "Topics", ctx, prompt, help, app) ret0, _ := ret[0].([]deploy0.Topic) ret1, _ := ret[1].(error) return ret0, ret1 } // Topics indicates an expected call of Topics. -func (mr *MocktopicSelectorMockRecorder) Topics(prompt, help, app interface{}) *gomock.Call { +func (mr *MocktopicSelectorMockRecorder) Topics(ctx, prompt, help, app interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Topics", reflect.TypeOf((*MocktopicSelector)(nil).Topics), prompt, help, app) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Topics", reflect.TypeOf((*MocktopicSelector)(nil).Topics), ctx, prompt, help, app) } // Mockec2Selector is a mock of ec2Selector interface. @@ -6611,18 +6611,18 @@ func (m *MockjobInitializer) EXPECT() *MockjobInitializerMockRecorder { } // Job mocks base method. -func (m *MockjobInitializer) Job(props *initialize.JobProps) (string, error) { +func (m *MockjobInitializer) Job(ctx context.Context, props *initialize.JobProps) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Job", props) + ret := m.ctrl.Call(m, "Job", ctx, props) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Job indicates an expected call of Job. -func (mr *MockjobInitializerMockRecorder) Job(props interface{}) *gomock.Call { +func (mr *MockjobInitializerMockRecorder) Job(ctx, props interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Job", reflect.TypeOf((*MockjobInitializer)(nil).Job), props) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Job", reflect.TypeOf((*MockjobInitializer)(nil).Job), ctx, props) } // MocksvcInitializer is a mock of svcInitializer interface. @@ -6649,18 +6649,18 @@ func (m *MocksvcInitializer) EXPECT() *MocksvcInitializerMockRecorder { } // Service mocks base method. -func (m *MocksvcInitializer) Service(props *initialize.ServiceProps) (string, error) { +func (m *MocksvcInitializer) Service(ctx context.Context, props *initialize.ServiceProps) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Service", props) + ret := m.ctrl.Call(m, "Service", ctx, props) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // Service indicates an expected call of Service. -func (mr *MocksvcInitializerMockRecorder) Service(props interface{}) *gomock.Call { +func (mr *MocksvcInitializerMockRecorder) Service(ctx, props interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Service", reflect.TypeOf((*MocksvcInitializer)(nil).Service), props) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Service", reflect.TypeOf((*MocksvcInitializer)(nil).Service), ctx, props) } // MockwkldInitializerWithoutManifest is a mock of wkldInitializerWithoutManifest interface. @@ -6687,17 +6687,17 @@ func (m *MockwkldInitializerWithoutManifest) EXPECT() *MockwkldInitializerWithou } // AddWorkloadToApp mocks base method. -func (m *MockwkldInitializerWithoutManifest) AddWorkloadToApp(appName, name, workloadType string) error { +func (m *MockwkldInitializerWithoutManifest) AddWorkloadToApp(ctx context.Context, appName, name, workloadType string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddWorkloadToApp", appName, name, workloadType) + ret := m.ctrl.Call(m, "AddWorkloadToApp", ctx, appName, name, workloadType) ret0, _ := ret[0].(error) return ret0 } // AddWorkloadToApp indicates an expected call of AddWorkloadToApp. -func (mr *MockwkldInitializerWithoutManifestMockRecorder) AddWorkloadToApp(appName, name, workloadType interface{}) *gomock.Call { +func (mr *MockwkldInitializerWithoutManifestMockRecorder) AddWorkloadToApp(ctx, appName, name, workloadType interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddWorkloadToApp", reflect.TypeOf((*MockwkldInitializerWithoutManifest)(nil).AddWorkloadToApp), appName, name, workloadType) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddWorkloadToApp", reflect.TypeOf((*MockwkldInitializerWithoutManifest)(nil).AddWorkloadToApp), ctx, appName, name, workloadType) } // MockroleDeleter is a mock of roleDeleter interface. diff --git a/internal/pkg/cli/override.go b/internal/pkg/cli/override.go index 72fd436802b..624122be313 100644 --- a/internal/pkg/cli/override.go +++ b/internal/pkg/cli/override.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "io" "path/filepath" @@ -87,16 +88,16 @@ func (o *overrideOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *overrideOpts) Ask() error { +func (o *overrideOpts) Ask(ctx context.Context) error { if err := o.validateOrAskIaCTool(); err != nil { return err } - return o.askResourcesToOverride() + return o.askResourcesToOverride(ctx) } // Execute writes IaC override files to the local workspace. // This method assumes that the IaC tool chosen by the user is valid. -func (o *overrideOpts) Execute() error { +func (o *overrideOpts) Execute(_ context.Context) error { dir := o.dir() switch o.iacTool { case cdkIaCTool: @@ -126,7 +127,7 @@ func (o *overrideOpts) validateAppName() error { if o.appName == "" { return errNoAppInWorkspace } - _, err := o.cfgStore.GetApplication(o.appName) + _, err := o.cfgStore.GetApplication(context.Background(), o.appName) if err != nil { return fmt.Errorf("get application %q configuration: %v", o.appName, err) } @@ -180,7 +181,7 @@ func (o *overrideOpts) validateIaCTool() error { strings.Join(applyAll(validIaCTools, strconv.Quote), ", ")) } -func (o *overrideOpts) askResourcesToOverride() error { +func (o *overrideOpts) askResourcesToOverride(ctx context.Context) error { if o.skipResources || o.iacTool == yamlPatch { return nil } @@ -194,7 +195,7 @@ func (o *overrideOpts) askResourcesToOverride() error { o.spinner.Stop("") return err } - if err := pkgCmd.Execute(); err != nil { + if err := pkgCmd.Execute(ctx); err != nil { o.spinner.Stop("") return fmt.Errorf("generate CloudFormation template for %q: %v", o.name, err) } diff --git a/internal/pkg/cli/pipeline_delete.go b/internal/pkg/cli/pipeline_delete.go index eddb2bb28ff..cf5f1cf87c6 100644 --- a/internal/pkg/cli/pipeline_delete.go +++ b/internal/pkg/cli/pipeline_delete.go @@ -111,13 +111,13 @@ func (o *deletePipelineOpts) Validate() error { } // Ask prompts for and validates required fields. -func (o *deletePipelineOpts) Ask() error { +func (o *deletePipelineOpts) Ask(ctx context.Context) error { if o.appName != "" { - if _, err := o.store.GetApplication(o.appName); err != nil { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return err } } else { - if err := o.askAppName(); err != nil { + if err := o.askAppName(ctx); err != nil { return err } } @@ -154,7 +154,7 @@ func (o *deletePipelineOpts) Ask() error { } // Execute deletes the secret and pipeline stack. -func (o *deletePipelineOpts) Execute() error { +func (o *deletePipelineOpts) Execute(_ context.Context) error { if err := o.getSecret(); err != nil { return err } @@ -202,8 +202,8 @@ func getDeployedPipelineInfo(lister deployedPipelineLister, app, name string) (d return deploy.Pipeline{}, fmt.Errorf("cannot find pipeline named %s", name) } -func (o *deletePipelineOpts) askAppName() error { - app, err := o.sel.Application(pipelineDeleteAppNamePrompt, pipelineDeleteAppNameHelpPrompt) +func (o *deletePipelineOpts) askAppName(ctx context.Context) error { + app, err := o.sel.Application(ctx, pipelineDeleteAppNamePrompt, pipelineDeleteAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -307,7 +307,7 @@ func buildPipelineDeleteCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/pipeline_delete_test.go b/internal/pkg/cli/pipeline_delete_test.go index 6a99c8f29c6..5e24bbd1b10 100644 --- a/internal/pkg/cli/pipeline_delete_test.go +++ b/internal/pkg/cli/pipeline_delete_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -52,7 +53,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { skipConfirmation: true, callMocks: func(m deletePipelineMocks) { - m.sel.EXPECT().Application(pipelineDeleteAppNamePrompt, pipelineDeleteAppNameHelpPrompt).Return(testAppName, nil) + m.sel.EXPECT().Application(ctx, pipelineDeleteAppNamePrompt, pipelineDeleteAppNameHelpPrompt).Return(testAppName, nil) m.deployedPipelineLister.EXPECT().ListDeployedPipelines(testAppName).Return([]deploy.Pipeline{ { Name: testPipelineName, @@ -69,7 +70,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { inAppName: "badAppName", callMocks: func(m deletePipelineMocks) { - m.store.EXPECT().GetApplication("badAppName").Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "badAppName").Return(nil, errors.New("some error")) }, wantedError: errors.New("some error"), @@ -80,7 +81,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { inPipelineName: "badPipelineName", callMocks: func(m deletePipelineMocks) { - m.store.EXPECT().GetApplication(testAppName).Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, testAppName).Return(nil, nil) m.deployedPipelineLister.EXPECT().ListDeployedPipelines(testAppName).Return([]deploy.Pipeline{}, nil) }, @@ -92,7 +93,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { inAppName: testAppName, callMocks: func(m deletePipelineMocks) { - m.store.EXPECT().GetApplication(testAppName).Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, testAppName).Return(nil, nil) m.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), testAppName).Return(deploy.Pipeline{ Name: testPipelineName, IsLegacy: true, @@ -107,7 +108,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { inAppName: testAppName, callMocks: func(m deletePipelineMocks) { - m.store.EXPECT().GetApplication(testAppName).Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, testAppName).Return(nil, nil) m.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), testAppName).Return(deploy.Pipeline{}, errors.New("some error")) }, @@ -120,7 +121,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { inPipelineName: testPipelineName, callMocks: func(m deletePipelineMocks) { - m.store.EXPECT().GetApplication(testAppName).Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, testAppName).Return(nil, nil) m.deployedPipelineLister.EXPECT().ListDeployedPipelines(testAppName).Return([]deploy.Pipeline{ { Name: testPipelineName, @@ -137,7 +138,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { inAppName: testAppName, inPipelineName: testPipelineName, callMocks: func(m deletePipelineMocks) { - m.store.EXPECT().GetApplication(testAppName).Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, testAppName).Return(nil, nil) m.deployedPipelineLister.EXPECT().ListDeployedPipelines(testAppName).Return([]deploy.Pipeline{ { Name: testPipelineName, @@ -194,7 +195,7 @@ func TestDeletePipelineOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -404,7 +405,7 @@ func TestDeletePipelineOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/pipeline_deploy.go b/internal/pkg/cli/pipeline_deploy.go index 26c37f4120b..3d05b75e6a4 100644 --- a/internal/pkg/cli/pipeline_deploy.go +++ b/internal/pkg/cli/pipeline_deploy.go @@ -202,7 +202,7 @@ func (o *deployPipelineOpts) Validate() error { } // Ask prompts the user for any unprovided required fields and validates them. -func (o *deployPipelineOpts) Ask() error { +func (o *deployPipelineOpts) Ask(ctx context.Context) error { if o.wsAppName == "" { return errNoAppInWorkspace } @@ -210,7 +210,7 @@ func (o *deployPipelineOpts) Ask() error { if o.appName != "" && o.appName != o.wsAppName { return fmt.Errorf("cannot specify app %s because the workspace is already registered with app %s", o.appName, o.wsAppName) } - appConfig, err := o.store.GetApplication(o.wsAppName) + appConfig, err := o.store.GetApplication(ctx, o.wsAppName) if err != nil { return fmt.Errorf("get application %s configuration: %w", o.wsAppName, err) } @@ -243,7 +243,7 @@ func validatePipelineVersion(vg versionGetter, name, templateVersion string) err } // Execute creates a new pipeline or updates the current pipeline if it already exists. -func (o *deployPipelineOpts) Execute() error { +func (o *deployPipelineOpts) Execute(ctx context.Context) error { if !o.allowDowngrade { isLegacy, err := o.isLegacy(o.name) if err != nil { @@ -287,7 +287,7 @@ func (o *deployPipelineOpts) Execute() error { } // Convert environments to deployment stages. - stages, err := o.convertStages(pipeline.Stages) + stages, err := o.convertStages(ctx, pipeline.Stages) if err != nil { return fmt.Errorf("convert environments to deployment stage: %w", err) } @@ -461,14 +461,14 @@ func (o *deployPipelineOpts) getPipelineMft() (*manifest.Pipeline, error) { return pipelineMft, nil } -func (o *deployPipelineOpts) convertStages(manifestStages []manifest.PipelineStage) ([]deploy.PipelineStage, error) { +func (o *deployPipelineOpts) convertStages(ctx context.Context, manifestStages []manifest.PipelineStage) ([]deploy.PipelineStage, error) { var stages []deploy.PipelineStage - workloads, err := o.getLocalWorkloads() + workloads, err := o.getLocalWorkloads(ctx) if err != nil { return nil, err } for _, stage := range manifestStages { - env, err := o.store.GetEnvironment(o.appName, stage.Name) + env, err := o.store.GetEnvironment(ctx, o.appName, stage.Name) if err != nil { return nil, fmt.Errorf("get environment %s in application %s: %w", stage.Name, o.appName, err) } @@ -480,12 +480,12 @@ func (o *deployPipelineOpts) convertStages(manifestStages []manifest.PipelineSta return stages, nil } -func (o deployPipelineOpts) getLocalWorkloads() ([]string, error) { +func (o deployPipelineOpts) getLocalWorkloads(ctx context.Context) ([]string, error) { var localWklds []string - if err := o.newSvcListCmd(o.svcBuffer, o.appName).Execute(); err != nil { + if err := o.newSvcListCmd(o.svcBuffer, o.appName).Execute(ctx); err != nil { return nil, fmt.Errorf("get local services: %w", err) } - if err := o.newJobListCmd(o.jobBuffer, o.appName).Execute(); err != nil { + if err := o.newJobListCmd(o.jobBuffer, o.appName).Execute(ctx); err != nil { return nil, fmt.Errorf("get local jobs: %w", err) } svcOutput, jobOutput := &list.ServiceJSONOutput{}, &list.JobJSONOutput{} @@ -628,7 +628,7 @@ func buildPipelineDeployCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, "", appFlagDescription) diff --git a/internal/pkg/cli/pipeline_deploy_test.go b/internal/pkg/cli/pipeline_deploy_test.go index 37db0a7e36b..66cdfa3d324 100644 --- a/internal/pkg/cli/pipeline_deploy_test.go +++ b/internal/pkg/cli/pipeline_deploy_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "io" @@ -79,7 +80,7 @@ func TestDeployPipelineOpts_Ask(t *testing.T) { inWsAppName: testAppName, inAppName: testAppName, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication(testAppName).Return(nil, errors.New("some error")) + m.EXPECT().GetApplication(ctx, testAppName).Return(nil, errors.New("some error")) }, mockWs: func(m *mocks.MockwsPipelineReader) {}, mockSel: func(m *mocks.MockwsPipelineSelector) {}, @@ -93,7 +94,7 @@ func TestDeployPipelineOpts_Ask(t *testing.T) { mockSel: func(m *mocks.MockwsPipelineSelector) {}, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication(testAppName).Return(nil, nil) + m.EXPECT().GetApplication(ctx, testAppName).Return(nil, nil) }, mockWs: func(m *mocks.MockwsPipelineReader) { m.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{pipeline}, nil) @@ -104,7 +105,7 @@ func TestDeployPipelineOpts_Ask(t *testing.T) { inAppName: testAppName, inWsAppName: testAppName, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication(testAppName).Return(nil, nil) + m.EXPECT().GetApplication(ctx, testAppName).Return(nil, nil) }, mockSel: func(m *mocks.MockwsPipelineSelector) { m.EXPECT().WsPipeline(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) @@ -118,7 +119,7 @@ func TestDeployPipelineOpts_Ask(t *testing.T) { inAppName: testAppName, inPipelineName: testPipelineName, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication(testAppName).Return(&config.Application{ + m.EXPECT().GetApplication(ctx, testAppName).Return(&config.Application{ Name: testAppName, }, nil) }, @@ -157,7 +158,7 @@ func TestDeployPipelineOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -246,11 +247,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -282,11 +283,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -324,11 +325,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -361,11 +362,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -395,11 +396,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -443,11 +444,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -547,7 +548,7 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Return(errors.New("some error")), + m.actionCmd.EXPECT().Execute(gomock.Any()).Return(errors.New("some error")), ) }, expectedError: fmt.Errorf("convert environments to deployment stage: get local services: some error"), @@ -562,11 +563,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, errors.New("some error")), @@ -584,11 +585,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -616,11 +617,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -652,11 +653,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -714,11 +715,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -751,11 +752,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -779,11 +780,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil), @@ -805,11 +806,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil) m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil) m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil) - m.actionCmd.EXPECT().Execute().Times(2) + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2) // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1) - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1) + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1) + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1) // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil) @@ -835,11 +836,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { m.versionGetter.EXPECT().Version().Return(mockTemplateVersion, nil) m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil) m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil) - m.actionCmd.EXPECT().Execute().Times(2) + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2) // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1) - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1) + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1) + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1) // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil) @@ -875,11 +876,11 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { callMocks: func(m deployPipelineMocks) { m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil) m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil) - m.actionCmd.EXPECT().Execute().Times(2) + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2) // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1) - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1) + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1) + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1) // getArtifactBuckets m.deployer.EXPECT().GetRegionalAppResources(gomock.Any()).Return(mockResources, nil) @@ -968,7 +969,7 @@ func TestDeployPipelineOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.expectedError != nil { diff --git a/internal/pkg/cli/pipeline_init.go b/internal/pkg/cli/pipeline_init.go index 8c3fde20ab0..23d4cf2046d 100644 --- a/internal/pkg/cli/pipeline_init.go +++ b/internal/pkg/cli/pipeline_init.go @@ -99,7 +99,7 @@ var ( type pipelineInitializer interface { writeManifest() error - writeBuildspec() error + writeBuildspec(ctx context.Context) error } type workloadPipelineInitializer struct { @@ -121,8 +121,8 @@ func (ini *workloadPipelineInitializer) writeManifest() error { return ini.cmd.createPipelineManifest(stages) } -func (ini *workloadPipelineInitializer) writeBuildspec() error { - if err := ini.cmd.createBuildspec(workloadsPipelineBuildspecTemplatePath); err != nil { +func (ini *workloadPipelineInitializer) writeBuildspec(ctx context.Context) error { + if err := ini.cmd.createBuildspec(ctx, workloadsPipelineBuildspecTemplatePath); err != nil { return err } log.Debugln(`The buildspec contains the commands to push your container images, and generate CloudFormation templates. @@ -148,8 +148,8 @@ func (ini *envPipelineInitializer) writeManifest() error { return ini.cmd.createPipelineManifest(stages) } -func (ini *envPipelineInitializer) writeBuildspec() error { - if err := ini.cmd.createBuildspec(environmentsPipelineBuildspecTemplatePath); err != nil { +func (ini *envPipelineInitializer) writeBuildspec(ctx context.Context) error { + if err := ini.cmd.createBuildspec(ctx, environmentsPipelineBuildspecTemplatePath); err != nil { return err } log.Debugln(`The buildspec contains the commands to generate CloudFormation templates for your environments.`) @@ -256,7 +256,7 @@ func (o *initPipelineOpts) Validate() error { } // Ask prompts for required fields that are not passed in and validates them. -func (o *initPipelineOpts) Ask() error { +func (o *initPipelineOpts) Ask(ctx context.Context) error { // This command must be executed in the app's workspace because the pipeline manifest and buildspec will be created and stored. if err := validateWorkspaceApp(o.wsAppName, o.appName, o.store); err != nil { return err @@ -288,11 +288,11 @@ func (o *initPipelineOpts) Ask() error { } if len(o.environments) == 0 { - if err := o.askEnvs(); err != nil { + if err := o.askEnvs(ctx); err != nil { return err } } - if err := o.validateEnvs(); err != nil { + if err := o.validateEnvs(ctx); err != nil { return err } @@ -300,7 +300,7 @@ func (o *initPipelineOpts) Ask() error { } // Execute writes the pipeline manifest file. -func (o *initPipelineOpts) Execute() error { +func (o *initPipelineOpts) Execute(ctx context.Context) error { if o.provider == manifest.GithubV1ProviderName { if err := o.storeGitHubAccessToken(); err != nil { return err @@ -311,7 +311,7 @@ func (o *initPipelineOpts) Execute() error { if err := ini.writeManifest(); err != nil { return err } - if err := ini.writeBuildspec(); err != nil { + if err := ini.writeBuildspec(ctx); err != nil { return err } return nil @@ -443,10 +443,10 @@ func (o *initPipelineOpts) validateURL(url string) error { } // To avoid duplicating calls to GetEnvironment, validate and get config in the same step. -func (o *initPipelineOpts) validateEnvs() error { +func (o *initPipelineOpts) validateEnvs(ctx context.Context) error { var envConfigs []*config.Environment for _, env := range o.environments { - config, err := o.store.GetEnvironment(o.appName, env) + config, err := o.store.GetEnvironment(ctx, o.appName, env) if err != nil { return fmt.Errorf("validate environment %s: %w", env, err) } @@ -456,8 +456,8 @@ func (o *initPipelineOpts) validateEnvs() error { return nil } -func (o *initPipelineOpts) askEnvs() error { - envs, err := o.sel.Environments(pipelineSelectEnvPrompt, pipelineSelectEnvHelpPrompt, o.appName, func(order int) prompt.PromptConfig { +func (o *initPipelineOpts) askEnvs(ctx context.Context) error { + envs, err := o.sel.Environments(ctx, pipelineSelectEnvPrompt, pipelineSelectEnvHelpPrompt, o.appName, func(order int) prompt.PromptConfig { return prompt.WithFinalMessage(fmt.Sprintf("%s stage:", humanize.Ordinal(order))) }) if err != nil { @@ -766,8 +766,8 @@ Update the file to add stages, change the tracked branch, add test commands or m return nil } -func (o *initPipelineOpts) createBuildspec(buildSpecTemplatePath string) error { - artifactBuckets, err := o.artifactBuckets() +func (o *initPipelineOpts) createBuildspec(ctx context.Context, buildSpecTemplatePath string) error { + artifactBuckets, err := o.artifactBuckets(ctx) if err != nil { return err } @@ -840,8 +840,8 @@ func (o *initPipelineOpts) pipelineProvider() (manifest.Provider, error) { return manifest.NewProvider(config) } -func (o *initPipelineOpts) artifactBuckets() ([]artifactBucket, error) { - app, err := o.store.GetApplication(o.appName) +func (o *initPipelineOpts) artifactBuckets(ctx context.Context) ([]artifactBucket, error) { + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { return nil, fmt.Errorf("get application %s: %w", o.appName, err) } @@ -890,10 +890,10 @@ func buildPipelineInitCmd() *cobra.Command { if err := opts.Validate(); err != nil { return err } - if err := opts.Ask(); err != nil { + if err := opts.Ask(cmd.Context()); err != nil { return err } - if err := opts.Execute(); err != nil { + if err := opts.Execute(cmd.Context()); err != nil { return err } log.Infoln() diff --git a/internal/pkg/cli/pipeline_init_test.go b/internal/pkg/cli/pipeline_init_test.go index 8bc0d33ddcb..b2f758d2681 100644 --- a/internal/pkg/cli/pipeline_init_test.go +++ b/internal/pkg/cli/pipeline_init_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -78,7 +79,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inWsAppName: "ghost-app", inAppName: "ghost-app", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication("ghost-app").Return(nil, mockError) + m.store.EXPECT().GetApplication(ctx, "ghost-app").Return(nil, mockError) }, expectedError: fmt.Errorf("get application ghost-app configuration: some error"), }, @@ -86,7 +87,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inWsAppName: mockAppName, inRepoURL: "https://gitlab.company.com/group/project.git", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) }, expectedError: errors.New("repository https://gitlab.company.com/group/project.git must be from a supported provider: GitHub, CodeCommit or Bitbucket"), }, @@ -94,7 +95,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inWsAppName: mockAppName, inRepoURL: "thisisnotevenagithub.comrepository", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) }, expectedError: errors.New("unable to parse the GitHub repository owner and name from thisisnotevenagithub.comrepository: please pass the repository URL with the format `--url https://github.com/{owner}/{repositoryName}`"), }, @@ -102,7 +103,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inWsAppName: mockAppName, inRepoURL: "git-codecommitus-west-2amazonaws.com", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) }, expectedError: errors.New("unknown CodeCommit URL format: git-codecommitus-west-2amazonaws.com"), }, @@ -110,7 +111,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inWsAppName: mockAppName, inRepoURL: "codecommit::us-mess-2://repo-man", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) }, expectedError: errors.New("unable to parse the AWS region from codecommit::us-mess-2://repo-man"), }, @@ -118,7 +119,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inWsAppName: mockAppName, inRepoURL: "codecommit::us-west-2://repo-man", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.sessProvider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: "us-east-1"}, nil) }, expectedError: errors.New("repository repo-man is in us-west-2, but app my-app is in us-east-1; they must be in the same region"), @@ -127,7 +128,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inWsAppName: mockAppName, inRepoURL: "bitbucket.org", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) }, expectedError: errors.New("unable to parse the Bitbucket repository name from bitbucket.org"), }, @@ -138,10 +139,10 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inName: wantedName, buffer: *bytes.NewBufferString("devBranch"), setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() m.runner.EXPECT().Run(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - m.store.EXPECT().GetEnvironment("my-app", "test").Return( + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return( &config.Environment{ Name: "test", }, nil) @@ -157,10 +158,10 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inEnvironments: []string{"test"}, inName: wantedName, setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() m.runner.EXPECT().Run(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - m.store.EXPECT().GetEnvironment("my-app", "test").Return( + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return( &config.Environment{ Name: "test", }, nil) @@ -176,7 +177,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: githubAnotherURL, inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication("my-app").Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(mockApp, nil) }, expectedError: fmt.Errorf("pipeline name 1234 is invalid: %w", errBasicNameRegexNotMatched), @@ -186,7 +187,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: githubAnotherURL, inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return("", errors.New("mock error")) }, @@ -200,7 +201,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inName: "mock-pipeline", inType: "RandomType", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) }, expectedError: errors.New(`invalid pipeline type "RandomType"; must be one of "Workloads" or "Environments"`), }, @@ -209,7 +210,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: githubAnotherURL, inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().Get(gomock.Eq("What would you like to name this pipeline?"), gomock.Any(), gomock.Any(), gomock.Any()). Return(wantedName, nil) m.prompt.EXPECT().SelectOption(gomock.Eq("What type of continuous delivery pipeline is this?"), gomock.Any(), gomock.Any()). @@ -224,8 +225,8 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inGitBranch: "main", inEnvironments: []string{"prod"}, setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) - m.store.EXPECT().GetEnvironment(mockAppName, "prod"). + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetEnvironment(ctx, mockAppName, "prod"). Return(&config.Environment{Name: "prod"}, nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.workspace.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{}, nil) @@ -240,7 +241,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: "unsupported.org/repositories/repoName", inEnvironments: []string{"test"}, setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, @@ -253,9 +254,9 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inEnvironments: []string{"test", "prod"}, inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment("my-app", "test").Return(nil, mockError) + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return(nil, mockError) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.workspace.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{}, nil) }, @@ -269,13 +270,13 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: "https://github.com/badGoose/chaOS", inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment("my-app", "test").Return( + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return( &config.Environment{ Name: "test", }, nil) - m.store.EXPECT().GetEnvironment("my-app", "prod").Return( + m.store.EXPECT().GetEnvironment(ctx, "my-app", "prod").Return( &config.Environment{ Name: "prod", }, nil) @@ -290,14 +291,14 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: "https://git-codecommit.us-west-2.amazonaws.com/v1/repos/repo-man", inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.sessProvider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: "us-west-2"}, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment("my-app", "test").Return( + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return( &config.Environment{ Name: "test", }, nil) - m.store.EXPECT().GetEnvironment("my-app", "prod").Return( + m.store.EXPECT().GetEnvironment(ctx, "my-app", "prod").Return( &config.Environment{ Name: "prod", }, nil) @@ -310,14 +311,14 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inGitHubAccessToken: githubToken, buffer: *bytes.NewBufferString("archer\tgit@github.com:goodGoose/bhaOS (fetch)\narcher\thttps://github.com/badGoose/chaOS (push)\narcher\tcodecommit::us-west-2://repo-man (fetch)\n"), setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.runner.EXPECT().Run(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) m.runner.EXPECT().Run(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - m.store.EXPECT().GetEnvironment("my-app", "test").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return(&config.Environment{ Name: "test", Region: "us-west-2", }, nil) - m.store.EXPECT().GetEnvironment("my-app", "prod").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "my-app", "prod").Return(&config.Environment{ Name: "prod", Region: "us-west-2", }, nil) @@ -326,7 +327,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { m.prompt.EXPECT().SelectOne(pipelineSelectURLPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(githubAnotherURL, nil).Times(1) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.workspace.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{}, nil) - m.sel.EXPECT().Environments(pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return([]string{"test", "prod"}, nil) + m.sel.EXPECT().Environments(ctx, pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return([]string{"test", "prod"}, nil) }, }, "returns error if fail to list environments": { @@ -335,11 +336,11 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: githubAnotherURL, inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.workspace.EXPECT().ListPipelines().Return(nil, nil) - m.sel.EXPECT().Environments(pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return(nil, errors.New("some error")) + m.sel.EXPECT().Environments(ctx, pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return(nil, errors.New("some error")) }, expectedError: fmt.Errorf("select environments: some error"), @@ -351,7 +352,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inEnvironments: []string{}, buffer: *bytes.NewBufferString("archer\tgit@github.com:goodGoose/bhaOS (fetch)\narcher\thttps://github.com/badGoose/chaOS (push)\n"), setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.runner.EXPECT().Run(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) m.prompt.EXPECT().SelectOne(pipelineSelectURLPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return("", mockError).Times(1) }, @@ -365,16 +366,16 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inGitBranch: "main", inEnvironments: []string{}, setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.workspace.EXPECT().ListPipelines().Return(nil, nil) - m.sel.EXPECT().Environments(pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return([]string{"test", "prod"}, nil) - m.store.EXPECT().GetEnvironment("my-app", "test").Return(&config.Environment{ + m.sel.EXPECT().Environments(ctx, pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return([]string{"test", "prod"}, nil) + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return(&config.Environment{ Name: "test", Region: "us-west-2", }, nil) - m.store.EXPECT().GetEnvironment("my-app", "prod").Return(nil, errors.New("some error")) + m.store.EXPECT().GetEnvironment(ctx, "my-app", "prod").Return(nil, errors.New("some error")) }, expectedError: fmt.Errorf("validate environment prod: some error"), @@ -385,17 +386,17 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inGitBranch: "main", buffer: *bytes.NewBufferString("archer\tgit@github.com:goodGoose/bhaOS (fetch)\n"), setupMocks: func(m pipelineInitMocks) { - m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) + m.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() m.runner.EXPECT().Run(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) m.pipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) m.workspace.EXPECT().ListPipelines().Return(nil, nil) - m.sel.EXPECT().Environments(pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return([]string{"test", "prod"}, nil) - m.store.EXPECT().GetEnvironment("my-app", "test").Return(&config.Environment{ + m.sel.EXPECT().Environments(ctx, pipelineSelectEnvPrompt, gomock.Any(), "my-app", gomock.Any()).Return([]string{"test", "prod"}, nil) + m.store.EXPECT().GetEnvironment(ctx, "my-app", "test").Return(&config.Environment{ Name: "test", Region: "us-west-2", }, nil) - m.store.EXPECT().GetEnvironment("my-app", "prod").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "my-app", "prod").Return(&config.Environment{ Name: "prod", Region: "us-west-2", }, nil) @@ -444,7 +445,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.expectedError != nil { @@ -504,7 +505,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -535,7 +536,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -566,7 +567,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -598,7 +599,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -629,7 +630,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(environmentsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -663,7 +664,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -709,7 +710,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.secretsmanager.EXPECT().CreateSecret("github-token-badgoose-goose", "hunter2").Return("some-arn", nil) m.workspace.EXPECT().WritePipelineManifest(gomock.Any(), wantedName).Return(wantedManifestFile, nil) m.workspace.EXPECT().Rel(wantedManifestFile).Return(wantedManifestRelPath, nil) - m.store.EXPECT().GetApplication("badgoose").Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(nil, errors.New("some error")) }, expectedError: errors.New("get application badgoose: some error"), }, @@ -728,7 +729,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.secretsmanager.EXPECT().CreateSecret("github-token-badgoose-goose", "hunter2").Return("some-arn", nil) m.workspace.EXPECT().WritePipelineManifest(gomock.Any(), wantedName).Return(wantedManifestFile, nil) m.workspace.EXPECT().Rel(wantedManifestFile).Return(wantedManifestRelPath, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -754,7 +755,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.workspace.EXPECT().WritePipelineBuildspec(gomock.Any(), wantedName).Times(0) m.workspace.EXPECT().Rel(wantedManifestFile).Return(wantedManifestRelPath, nil) m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -787,7 +788,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -820,7 +821,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { m.parser.EXPECT().Parse(workloadsPipelineBuildspecTemplatePath, gomock.Any(), gomock.Any()).Return(&template.Content{ Buffer: bytes.NewBufferString("hello"), }, nil) - m.store.EXPECT().GetApplication("badgoose").Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, "badgoose").Return(&config.Application{ Name: "badgoose", }, nil) m.cfnClient.EXPECT().GetRegionalAppResources(&config.Application{ @@ -874,7 +875,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { // WHEN require.NoError(t, opts.parseRepoDetails()) - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.expectedError != nil { diff --git a/internal/pkg/cli/pipeline_list.go b/internal/pkg/cli/pipeline_list.go index 5a78e560143..dc813fd3f98 100644 --- a/internal/pkg/cli/pipeline_list.go +++ b/internal/pkg/cli/pipeline_list.go @@ -89,17 +89,17 @@ func newListPipelinesOpts(vars listPipelineVars) (*listPipelineOpts, error) { } // Ask asks for and validates fields that are required but not passed in. -func (o *listPipelineOpts) Ask() error { +func (o *listPipelineOpts) Ask(ctx context.Context) error { if o.shouldShowLocalPipelines { return validateWorkspaceApp(o.wsAppName, o.appName, o.store) } if o.appName != "" { - if _, err := o.store.GetApplication(o.appName); err != nil { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return fmt.Errorf("validate application: %w", err) } } else { - app, err := o.sel.Application(pipelineListAppNamePrompt, pipelineListAppNameHelper) + app, err := o.sel.Application(ctx, pipelineListAppNamePrompt, pipelineListAppNameHelper) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -110,7 +110,7 @@ func (o *listPipelineOpts) Ask() error { } // Execute writes the pipelines. -func (o *listPipelineOpts) Execute() error { +func (o *listPipelineOpts) Execute(_ context.Context) error { ctx, cancel := context.WithTimeout(context.Background(), pipelineListTimeout) defer cancel() @@ -287,10 +287,10 @@ func buildPipelineListCmd() *cobra.Command { if err != nil { return err } - if err := opts.Ask(); err != nil { + if err := opts.Ask(cmd.Context()); err != nil { return err } - return opts.Execute() + return opts.Execute(cmd.Context()) }), } diff --git a/internal/pkg/cli/pipeline_list_test.go b/internal/pkg/cli/pipeline_list_test.go index 43ca87b9abc..cc46bc95aff 100644 --- a/internal/pkg/cli/pipeline_list_test.go +++ b/internal/pkg/cli/pipeline_list_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -40,7 +41,7 @@ func TestPipelineList_Ask(t *testing.T) { }{ "success with no flags set": { setupMocks: func(m pipelineListMocks) { - m.sel.EXPECT().Application(pipelineListAppNamePrompt, pipelineListAppNameHelper).Return("my-app", nil) + m.sel.EXPECT().Application(ctx, pipelineListAppNamePrompt, pipelineListAppNameHelper).Return("my-app", nil) }, wantedApp: "my-app", wantedErr: nil, @@ -48,14 +49,14 @@ func TestPipelineList_Ask(t *testing.T) { "success with app flag set": { inputApp: "my-app", setupMocks: func(m pipelineListMocks) { - m.store.EXPECT().GetApplication("my-app").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(nil, nil) }, wantedApp: "my-app", wantedErr: nil, }, "error if fail to select app": { setupMocks: func(m pipelineListMocks) { - m.sel.EXPECT().Application(pipelineListAppNamePrompt, pipelineListAppNameHelper).Return("", errors.New("some error")) + m.sel.EXPECT().Application(ctx, pipelineListAppNamePrompt, pipelineListAppNameHelper).Return("", errors.New("some error")) }, wantedApp: "my-app", wantedErr: fmt.Errorf("select application: some error"), @@ -63,7 +64,7 @@ func TestPipelineList_Ask(t *testing.T) { "error if passed-in app doesn't exist": { inputApp: "my-app", setupMocks: func(m pipelineListMocks) { - m.store.EXPECT().GetApplication("my-app").Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(nil, errors.New("some error")) }, wantedApp: "", wantedErr: errors.New("validate application: some error"), @@ -71,7 +72,7 @@ func TestPipelineList_Ask(t *testing.T) { "using workspace successful": { inWsAppName: "my-app", setupMocks: func(m pipelineListMocks) { - m.store.EXPECT().GetApplication("my-app").Return(nil, nil) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(nil, nil) }, shouldShowLocalPipelines: true, }, @@ -117,7 +118,7 @@ func TestPipelineList_Ask(t *testing.T) { wsAppName: tc.inWsAppName, } - err := opts.Ask() + err := opts.Ask(context.Background()) if tc.wantedErr != nil { require.EqualError(t, err, tc.wantedErr.Error()) @@ -264,7 +265,7 @@ my-pipeline-repo } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.expectedErr != nil { diff --git a/internal/pkg/cli/pipeline_override.go b/internal/pkg/cli/pipeline_override.go index d6d51b08ed0..8db70c16c26 100644 --- a/internal/pkg/cli/pipeline_override.go +++ b/internal/pkg/cli/pipeline_override.go @@ -67,21 +67,21 @@ func (o *overridePipelineOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *overridePipelineOpts) Ask() error { +func (o *overridePipelineOpts) Ask(ctx context.Context) error { if o.name == "" { if err := o.askPipelineName(); err != nil { return err } } - return o.overrideOpts.Ask() + return o.overrideOpts.Ask(ctx) } // Execute writes IaC override files to the local workspace. -func (o *overridePipelineOpts) Execute() error { +func (o *overridePipelineOpts) Execute(ctx context.Context) error { o.overrideOpts.dir = func() string { return o.ws.PipelineOverridesPath(o.name) } - return o.overrideOpts.Execute() + return o.overrideOpts.Execute(ctx) } @@ -141,7 +141,7 @@ or add new resources to the Pipeline's AWS CloudFormation template.`, if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", pipelineFlagDescription) diff --git a/internal/pkg/cli/pipeline_override_test.go b/internal/pkg/cli/pipeline_override_test.go index fe1fff4b3e1..fd1cba9160b 100644 --- a/internal/pkg/cli/pipeline_override_test.go +++ b/internal/pkg/cli/pipeline_override_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "path/filepath" @@ -32,7 +33,7 @@ func TestOverridePipeline_Validate(t *testing.T) { appName: "demo", initMocks: func(ctrl *gomock.Controller, cmd *overridePipelineOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).Return(nil, errors.New("some error")) + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, errors.New("some error")) cmd.cfgStore = mockSSM }, wanted: errors.New(`get application "demo" configuration: some error`), @@ -76,7 +77,7 @@ func TestOverridePipeline_Validate(t *testing.T) { "skip validating if pipeline name is empty": { initMocks: func(ctrl *gomock.Controller, cmd *overridePipelineOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() cmd.cfgStore = mockSSM }, }, @@ -84,7 +85,7 @@ func TestOverridePipeline_Validate(t *testing.T) { name: "pipeline-testing", initMocks: func(ctrl *gomock.Controller, cmd *overridePipelineOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() cmd.cfgStore = mockSSM mockWS := mocks.NewMockwsPipelineReader(ctrl) mockWS.EXPECT().ListPipelines().Return(nil, errors.New("some error")) @@ -97,7 +98,7 @@ func TestOverridePipeline_Validate(t *testing.T) { name: "pipeline-testing", initMocks: func(ctrl *gomock.Controller, cmd *overridePipelineOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() cmd.cfgStore = mockSSM mockWS := mocks.NewMockwsPipelineReader(ctrl) mockWS.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{{Name: "pipeline-production", Path: "path"}}, nil) @@ -152,7 +153,7 @@ func TestOverridePipeline_Ask(t *testing.T) { cfgStore: mocks.NewMockstore(ctrl), packageCmd: func(_ stringWriteCloser) (executor, error) { mockCmd := mocks.NewMockexecutor(ctrl) - mockCmd.EXPECT().Execute().AnyTimes() + mockCmd.EXPECT().Execute(gomock.Any()).AnyTimes() return mockCmd, nil }, }, @@ -160,7 +161,7 @@ func TestOverridePipeline_Ask(t *testing.T) { } // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN require.NoError(t, err) @@ -205,7 +206,7 @@ func TestOverridePipeline_Ask(t *testing.T) { cfnPrompt: mockCfnPrompt, packageCmd: func(_ stringWriteCloser) (executor, error) { mockCmd := mocks.NewMockexecutor(ctrl) - mockCmd.EXPECT().Execute().AnyTimes() + mockCmd.EXPECT().Execute(gomock.Any()).AnyTimes() return mockCmd, nil }, spinner: &spinnerTestDouble{}, @@ -216,7 +217,7 @@ func TestOverridePipeline_Ask(t *testing.T) { } // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { @@ -252,7 +253,7 @@ func TestOverridePipeline_Ask(t *testing.T) { "should return a wrapped error if package command fails to execute": { initMocks: func(ctrl *gomock.Controller, cmd *overridePipelineOpts) { mockPkgCmd := mocks.NewMockexecutor(ctrl) - mockPkgCmd.EXPECT().Execute().Return(errors.New("some error")) + mockPkgCmd.EXPECT().Execute(gomock.Any()).Return(errors.New("some error")) cmd.packageCmd = func(_ stringWriteCloser) (executor, error) { return mockPkgCmd, nil } @@ -262,7 +263,7 @@ func TestOverridePipeline_Ask(t *testing.T) { "should prompt for CloudFormation resources in a template": { initMocks: func(ctrl *gomock.Controller, cmd *overridePipelineOpts) { mockPkgCmd := mocks.NewMockexecutor(ctrl) - mockPkgCmd.EXPECT().Execute().Return(nil) + mockPkgCmd.EXPECT().Execute(gomock.Any()).Return(nil) mockPrompt := mocks.NewMockcfnSelector(ctrl) template := ` Resources: @@ -298,7 +299,7 @@ func TestOverridePipeline_Ask(t *testing.T) { tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { @@ -372,7 +373,7 @@ func TestOverridePipeline_Execute(t *testing.T) { tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Execute() + err := cmd.Execute(context.Background()) // THEN if tc.wanted != nil { diff --git a/internal/pkg/cli/pipeline_package.go b/internal/pkg/cli/pipeline_package.go index 3b56c165591..593f616f74a 100644 --- a/internal/pkg/cli/pipeline_package.go +++ b/internal/pkg/cli/pipeline_package.go @@ -117,7 +117,7 @@ func newPackagePipelineOpts(vars packagePipelineVars) (*packagePipelineOpts, err return opts, nil } -func (o *packagePipelineOpts) Execute() error { +func (o *packagePipelineOpts) Execute(ctx context.Context) error { pipelines, err := o.ws.ListPipelines() if err != nil { return fmt.Errorf("list all pipelines in the workspace: %w", err) @@ -158,12 +158,12 @@ func (o *packagePipelineOpts) Execute() error { return fmt.Errorf("convert manifest path to relative path: %w", err) } - stages, err := o.convertStages(pipelineMft.Stages) + stages, err := o.convertStages(ctx, pipelineMft.Stages) if err != nil { return fmt.Errorf("convert environments to deployment stage: %w", err) } - appConfig, err := o.store.GetApplication(o.appName) + appConfig, err := o.store.GetApplication(ctx, o.appName) if err != nil { return fmt.Errorf("get application %s configuration: %w", o.appName, err) } @@ -245,14 +245,14 @@ func (o *packagePipelineOpts) isLegacy(inputName string) (bool, error) { return false, nil } -func (o *packagePipelineOpts) convertStages(manifestStages []manifest.PipelineStage) ([]deploy.PipelineStage, error) { +func (o *packagePipelineOpts) convertStages(ctx context.Context, manifestStages []manifest.PipelineStage) ([]deploy.PipelineStage, error) { var stages []deploy.PipelineStage - workloads, err := o.getLocalWorkloads() + workloads, err := o.getLocalWorkloads(ctx) if err != nil { return nil, err } for _, stage := range manifestStages { - env, err := o.store.GetEnvironment(o.appName, stage.Name) + env, err := o.store.GetEnvironment(ctx, o.appName, stage.Name) if err != nil { return nil, fmt.Errorf("get environment %s in application %s: %w", stage.Name, o.appName, err) } @@ -264,12 +264,12 @@ func (o *packagePipelineOpts) convertStages(manifestStages []manifest.PipelineSt return stages, nil } -func (o packagePipelineOpts) getLocalWorkloads() ([]string, error) { +func (o packagePipelineOpts) getLocalWorkloads(ctx context.Context) ([]string, error) { var localWklds []string - if err := o.newSvcListCmd(o.svcBuffer, o.appName).Execute(); err != nil { + if err := o.newSvcListCmd(o.svcBuffer, o.appName).Execute(ctx); err != nil { return nil, fmt.Errorf("get local services: %w", err) } - if err := o.newJobListCmd(o.jobBuffer, o.appName).Execute(); err != nil { + if err := o.newJobListCmd(o.jobBuffer, o.appName).Execute(ctx); err != nil { return nil, fmt.Errorf("get local jobs: %w", err) } svcOutput, jobOutput := &list.ServiceJSONOutput{}, &list.JobJSONOutput{} diff --git a/internal/pkg/cli/pipeline_package_test.go b/internal/pkg/cli/pipeline_package_test.go index 9c371c10232..a71c2056b54 100644 --- a/internal/pkg/cli/pipeline_package_test.go +++ b/internal/pkg/cli/pipeline_package_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "io" @@ -171,7 +172,7 @@ func TestPipelinePackageOpts_Execute(t *testing.T) { m.ws.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{pipeline}, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Return(someError), + m.actionCmd.EXPECT().Execute(gomock.Any()).Return(someError), ) }, expectedError: fmt.Errorf("convert environments to deployment stage: get local services: some error"), @@ -182,13 +183,13 @@ func TestPipelinePackageOpts_Execute(t *testing.T) { m.ws.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{pipeline}, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetApplication(appName).Return(nil, someError), + m.store.EXPECT().GetApplication(ctx, appName).Return(nil, someError), ) }, expectedError: fmt.Errorf("get application %v configuration: some error", appName), @@ -199,13 +200,13 @@ func TestPipelinePackageOpts_Execute(t *testing.T) { m.ws.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{pipeline}, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetApplication(appName).Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, appName).Return(&config.Application{ Name: appName, }, nil), @@ -221,13 +222,13 @@ func TestPipelinePackageOpts_Execute(t *testing.T) { m.ws.EXPECT().ListPipelines().Return([]workspace.PipelineManifest{pipeline}, nil), m.ws.EXPECT().ReadPipelineManifest(pipelineManifestPath).Return(mockPipelineManifest, nil), m.ws.EXPECT().Rel(pipelineManifestPath).Return(relativePath, nil), - m.actionCmd.EXPECT().Execute().Times(2), + m.actionCmd.EXPECT().Execute(gomock.Any()).Times(2), // convertStages - m.store.EXPECT().GetEnvironment(appName, "chicken").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetEnvironment(appName, "wings").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "chicken").Return(mockEnv, nil).Times(1), + m.store.EXPECT().GetEnvironment(ctx, appName, "wings").Return(mockEnv, nil).Times(1), - m.store.EXPECT().GetApplication(appName).Return(&config.Application{ + m.store.EXPECT().GetApplication(ctx, appName).Return(&config.Application{ Name: appName, }, nil), @@ -296,7 +297,7 @@ func TestPipelinePackageOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.expectedError != nil { diff --git a/internal/pkg/cli/pipeline_show.go b/internal/pkg/cli/pipeline_show.go index 3f9bb1b3828..3189f1f95f3 100644 --- a/internal/pkg/cli/pipeline_show.go +++ b/internal/pkg/cli/pipeline_show.go @@ -101,13 +101,13 @@ func (o *showPipelineOpts) Validate() error { } // Ask prompts for fields that are required but not passed in, and validates those that are. -func (o *showPipelineOpts) Ask() error { +func (o *showPipelineOpts) Ask(ctx context.Context) error { if o.appName != "" { - if _, err := o.store.GetApplication(o.appName); err != nil { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return fmt.Errorf("validate application name: %w", err) } } else { - if err := o.askAppName(); err != nil { + if err := o.askAppName(ctx); err != nil { return err } } @@ -127,7 +127,7 @@ func (o *showPipelineOpts) Ask() error { } // Execute shows details about the pipeline. -func (o *showPipelineOpts) Execute() error { +func (o *showPipelineOpts) Execute(_ context.Context) error { err := o.initDescriber(o.shouldOutputResources) if err != nil { return err @@ -163,8 +163,8 @@ func (o *showPipelineOpts) getTargetPipeline() (deploy.Pipeline, error) { return pipeline, nil } -func (o *showPipelineOpts) askAppName() error { - name, err := o.sel.Application(pipelineShowAppNamePrompt, pipelineShowAppNameHelpPrompt) +func (o *showPipelineOpts) askAppName(ctx context.Context) error { + name, err := o.sel.Application(ctx, pipelineShowAppNamePrompt, pipelineShowAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -187,7 +187,7 @@ func buildPipelineShowCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", pipelineFlagDescription) diff --git a/internal/pkg/cli/pipeline_show_test.go b/internal/pkg/cli/pipeline_show_test.go index e8d4be87c1d..433985ada36 100644 --- a/internal/pkg/cli/pipeline_show_test.go +++ b/internal/pkg/cli/pipeline_show_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -46,7 +47,7 @@ func TestPipelineShow_Ask(t *testing.T) { inAppName: mockAppName, setupMocks: func(mocks showPipelineMocks) { gomock.InOrder( - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil), mocks.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), mockAppName).Return(deploy.Pipeline{ @@ -62,7 +63,7 @@ func TestPipelineShow_Ask(t *testing.T) { "error if problem selecting app": { setupMocks: func(mocks showPipelineMocks) { gomock.InOrder( - mocks.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Return("", mockError)) + mocks.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Return("", mockError)) }, expectedErr: fmt.Errorf("select application: %w", mockError), }, @@ -71,7 +72,7 @@ func TestPipelineShow_Ask(t *testing.T) { inAppName: mockAppName, setupMocks: func(mocks showPipelineMocks) { - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil) mocks.deployedPipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{ @@ -87,7 +88,7 @@ func TestPipelineShow_Ask(t *testing.T) { "prompt if no app name AND no pipeline name": { setupMocks: func(mocks showPipelineMocks) { gomock.InOrder( - mocks.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Return(mockAppName, nil)) + mocks.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Return(mockAppName, nil)) mocks.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), mockAppName).Return(deploy.Pipeline{ Name: mockPipelineName, }, nil) @@ -101,7 +102,7 @@ func TestPipelineShow_Ask(t *testing.T) { inAppName: mockAppName, setupMocks: func(mocks showPipelineMocks) { - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil) mocks.deployedPipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, nil) @@ -114,7 +115,7 @@ func TestPipelineShow_Ask(t *testing.T) { inAppName: mockAppName, setupMocks: func(mocks showPipelineMocks) { - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil) mocks.deployedPipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{}, errors.New("some error")) @@ -127,7 +128,7 @@ func TestPipelineShow_Ask(t *testing.T) { inPipelineName: "", setupMocks: func(mocks showPipelineMocks) { gomock.InOrder( - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil), mocks.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), mockAppName).Return(deploy.Pipeline{}, mockError), @@ -175,7 +176,7 @@ func TestPipelineShow_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.expectedErr != nil { @@ -255,7 +256,7 @@ func TestPipelineShow_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.expectedErr != nil { diff --git a/internal/pkg/cli/pipeline_status.go b/internal/pkg/cli/pipeline_status.go index 1559031e744..af1f51da3ec 100644 --- a/internal/pkg/cli/pipeline_status.go +++ b/internal/pkg/cli/pipeline_status.go @@ -98,13 +98,13 @@ func (o *pipelineStatusOpts) Validate() error { } // Ask prompts for fields that are required but not passed in, and validates those that are. -func (o *pipelineStatusOpts) Ask() error { +func (o *pipelineStatusOpts) Ask(ctx context.Context) error { if o.appName != "" { - if _, err := o.store.GetApplication(o.appName); err != nil { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return fmt.Errorf("validate application name: %w", err) } } else { - if err := o.askAppName(); err != nil { + if err := o.askAppName(ctx); err != nil { return err } } @@ -124,7 +124,7 @@ func (o *pipelineStatusOpts) Ask() error { } // Execute displays the status of the pipeline. -func (o *pipelineStatusOpts) Execute() error { +func (o *pipelineStatusOpts) Execute(_ context.Context) error { err := o.initDescriber(o) if err != nil { return fmt.Errorf("describe status of pipeline: %w", err) @@ -159,8 +159,8 @@ func (o *pipelineStatusOpts) getTargetPipeline() (deploy.Pipeline, error) { return pipeline, nil } -func (o *pipelineStatusOpts) askAppName() error { - name, err := o.sel.Application(pipelineStatusAppNamePrompt, pipelineStatusAppNameHelpPrompt) +func (o *pipelineStatusOpts) askAppName(ctx context.Context) error { + name, err := o.sel.Application(ctx, pipelineStatusAppNamePrompt, pipelineStatusAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -184,7 +184,7 @@ Shows status of the pipeline "my-repo-my-branch". if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", pipelineFlagDescription) diff --git a/internal/pkg/cli/pipeline_status_test.go b/internal/pkg/cli/pipeline_status_test.go index 9ef697a34c2..7fac16ccbbe 100644 --- a/internal/pkg/cli/pipeline_status_test.go +++ b/internal/pkg/cli/pipeline_status_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -49,7 +50,7 @@ func TestPipelineStatus_Ask(t *testing.T) { testAppName: mockAppName, setupMocks: func(mocks pipelineStatusMocks) { gomock.InOrder( - mocks.store.EXPECT().GetApplication(mockAppName).Return(nil, mockError), + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(nil, mockError), ) }, expectedApp: "", @@ -58,7 +59,7 @@ func TestPipelineStatus_Ask(t *testing.T) { "prompts for app name if not passed in with flag and name not passed in": { setupMocks: func(mocks pipelineStatusMocks) { gomock.InOrder( - mocks.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Return(mockAppName, nil), + mocks.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Return(mockAppName, nil), mocks.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), mockAppName).Return(deploy.Pipeline{ Name: mockPipelineName, }, nil), @@ -72,7 +73,7 @@ func TestPipelineStatus_Ask(t *testing.T) { "errors if fail to select app name": { setupMocks: func(mocks pipelineStatusMocks) { gomock.InOrder( - mocks.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Return("", errors.New("some error"))) + mocks.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Return("", errors.New("some error"))) }, expectedApp: "", expectedErr: errors.New("select application: some error"), @@ -81,7 +82,7 @@ func TestPipelineStatus_Ask(t *testing.T) { testAppName: mockAppName, setupMocks: func(mocks pipelineStatusMocks) { gomock.InOrder( - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil), mocks.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), mockAppName).Return(deploy.Pipeline{ @@ -98,7 +99,7 @@ func TestPipelineStatus_Ask(t *testing.T) { testPipelineName: "", setupMocks: func(mocks pipelineStatusMocks) { gomock.InOrder( - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil), mocks.sel.EXPECT().DeployedPipeline(gomock.Any(), gomock.Any(), mockAppName).Return(deploy.Pipeline{}, mockError), @@ -113,7 +114,7 @@ func TestPipelineStatus_Ask(t *testing.T) { setupMocks: func(mocks pipelineStatusMocks) { gomock.InOrder( - mocks.store.EXPECT().GetApplication(mockAppName).Return(&config.Application{ + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(&config.Application{ Name: "dinder", }, nil), mocks.deployedPipelineLister.EXPECT().ListDeployedPipelines(mockAppName).Return([]deploy.Pipeline{ @@ -166,7 +167,7 @@ func TestPipelineStatus_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.expectedErr != nil { @@ -242,7 +243,7 @@ func TestPipelineStatus_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.expectedError != nil { diff --git a/internal/pkg/cli/run_local.go b/internal/pkg/cli/run_local.go index 3dec311562e..de6eb751436 100644 --- a/internal/pkg/cli/run_local.go +++ b/internal/pkg/cli/run_local.go @@ -137,7 +137,7 @@ type runLocalOpts struct { newRecursiveWatcher func() (recursiveWatcher, error) buildContainerImages func(mft manifest.DynamicWorkload) (map[string]string, error) - configureClients func() error + configureClients func(ctx context.Context) error labeledTermPrinter func(fw syncbuffer.FileWriter, bufs []*syncbuffer.LabeledSyncBuffer, opts ...syncbuffer.LabeledTermPrinterOption) clideploy.LabeledTermPrinter unmarshal func([]byte) (manifest.DynamicWorkload, error) newInterpolator func(app, env string) interpolator @@ -180,7 +180,7 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { labeledTermPrinter: labeledTermPrinter, prog: termprogress.NewSpinner(log.DiagnosticWriter), } - o.configureClients = func() error { + o.configureClients = func(ctx context.Context) error { defaultConfigEnvRegion, err := o.sessProvider.DefaultConfigWithRegion(context.Background(), o.targetEnv.Region) if err != nil { return fmt.Errorf("create default config with region %s: %w", o.targetEnv.Region, err) @@ -224,7 +224,7 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { rg: resourcegroups.New(envManagerConfig), rds: rds.NewFromConfig(envManagerConfig), } - envDesc, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + envDesc, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: o.appName, Env: o.envName, ConfigStore: store, @@ -313,7 +313,7 @@ func (o *runLocalOpts) Validate() error { return errNoAppInWorkspace } // Ensure that the application name provided exists in the workspace - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(context.Background(), o.appName) if err != nil { return fmt.Errorf("get application %s: %w", o.appName, err) } @@ -322,30 +322,30 @@ func (o *runLocalOpts) Validate() error { } // Ask prompts the user for any unprovided required fields and validates them. -func (o *runLocalOpts) Ask() error { - return o.validateAndAskWkldEnvName() +func (o *runLocalOpts) Ask(ctx context.Context) error { + return o.validateAndAskWkldEnvName(ctx) } -func (o *runLocalOpts) validateAndAskWkldEnvName() error { +func (o *runLocalOpts) validateAndAskWkldEnvName(ctx context.Context) error { if o.envName != "" { - env, err := o.store.GetEnvironment(o.appName, o.envName) + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return err } o.targetEnv = env } if o.wkldName != "" { - if _, err := o.store.GetWorkload(o.appName, o.wkldName); err != nil { + if _, err := o.store.GetWorkload(ctx, o.appName, o.wkldName); err != nil { return err } } - deployedWorkload, err := o.sel.DeployedWorkload(workloadAskPrompt, "", o.appName, selector.WithEnv(o.envName), selector.WithName(o.wkldName)) + deployedWorkload, err := o.sel.DeployedWorkload(ctx, workloadAskPrompt, "", o.appName, selector.WithEnv(o.envName), selector.WithName(o.wkldName)) if err != nil { return fmt.Errorf("select a deployed workload from application %s: %w", o.appName, err) } if o.envName == "" { - env, err := o.store.GetEnvironment(o.appName, deployedWorkload.Env) + env, err := o.store.GetEnvironment(ctx, o.appName, deployedWorkload.Env) if err != nil { return fmt.Errorf("get environment %q configuration: %w", o.envName, err) } @@ -359,13 +359,11 @@ func (o *runLocalOpts) validateAndAskWkldEnvName() error { } // Execute builds and runs the workload images locally. -func (o *runLocalOpts) Execute() error { - if err := o.configureClients(); err != nil { +func (o *runLocalOpts) Execute(ctx context.Context) error { + if err := o.configureClients(ctx); err != nil { return err } - ctx := context.Background() - task, err := o.prepareTask(ctx) if err != nil { return err @@ -1229,7 +1227,7 @@ func BuildRunLocalCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), Annotations: map[string]string{ "group": group.Develop, diff --git a/internal/pkg/cli/run_local_test.go b/internal/pkg/cli/run_local_test.go index b3b28a78b4a..49b59f76030 100644 --- a/internal/pkg/cli/run_local_test.go +++ b/internal/pkg/cli/run_local_test.go @@ -52,7 +52,7 @@ func TestRunLocalOpts_Validate(t *testing.T) { "fail to read the application from SSM store": { inAppName: "testApp", setupMocks: func(m *runLocalAskMocks) { - m.store.EXPECT().GetApplication("testApp").Return(nil, testError) + m.store.EXPECT().GetApplication(ctx, "testApp").Return(nil, testError) }, wantError: fmt.Errorf("get application testApp: %w", testError), }, @@ -109,7 +109,7 @@ func TestRunLocalOpts_Ask(t *testing.T) { inputAppName: testAppName, inputEnvName: testEnvName, setupMocks: func(m *runLocalAskMocks) { - m.store.EXPECT().GetEnvironment(testAppName, testEnvName).Return(nil, testError) + m.store.EXPECT().GetEnvironment(ctx, testAppName, testEnvName).Return(nil, testError) }, wantedError: testError, }, @@ -117,8 +117,8 @@ func TestRunLocalOpts_Ask(t *testing.T) { inputAppName: testAppName, inputWkldName: testWkldName, setupMocks: func(m *runLocalAskMocks) { - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetWorkload(testAppName, testWkldName).Return(nil, testError) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetWorkload(ctx, testAppName, testWkldName).Return(nil, testError) }, wantedError: testError, }, @@ -127,9 +127,9 @@ func TestRunLocalOpts_Ask(t *testing.T) { inputWkldName: testWkldName, inputEnvName: testEnvName, setupMocks: func(m *runLocalAskMocks) { - m.store.EXPECT().GetEnvironment(testAppName, testEnvName).Return(&config.Environment{Name: "testEnv"}, nil) - m.store.EXPECT().GetWorkload(testAppName, testWkldName).Return(&config.Workload{Name: "testWkld"}, nil) - m.sel.EXPECT().DeployedWorkload(workloadAskPrompt, "", testAppName, gomock.Any()).Return(&selector.DeployedWorkload{ + m.store.EXPECT().GetEnvironment(ctx, testAppName, testEnvName).Return(&config.Environment{Name: "testEnv"}, nil) + m.store.EXPECT().GetWorkload(ctx, testAppName, testWkldName).Return(&config.Workload{Name: "testWkld"}, nil) + m.sel.EXPECT().DeployedWorkload(ctx, workloadAskPrompt, "", testAppName, gomock.Any()).Return(&selector.DeployedWorkload{ Env: "testEnv", Name: "testWkld", Type: "testWkldType", @@ -142,14 +142,14 @@ func TestRunLocalOpts_Ask(t *testing.T) { "prompt for workload and environment": { inputAppName: testAppName, setupMocks: func(m *runLocalAskMocks) { - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetWorkload(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedWorkload(workloadAskPrompt, "", testAppName, gomock.Any()).Return(&selector.DeployedWorkload{ + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetWorkload(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedWorkload(ctx, workloadAskPrompt, "", testAppName, gomock.Any()).Return(&selector.DeployedWorkload{ Env: "testEnv", Name: "testWkld", Type: "testWkldType", }, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(1) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(1) }, wantedEnvName: testEnvName, wantedWkldName: testWkldName, @@ -158,7 +158,7 @@ func TestRunLocalOpts_Ask(t *testing.T) { "return error while failed to select workload": { inputAppName: testAppName, setupMocks: func(m *runLocalAskMocks) { - m.sel.EXPECT().DeployedWorkload(workloadAskPrompt, "", testAppName, gomock.Any()). + m.sel.EXPECT().DeployedWorkload(ctx, workloadAskPrompt, "", testAppName, gomock.Any()). Return(nil, testError) }, wantedError: fmt.Errorf("select a deployed workload from application %s: %w", testAppName, testError), @@ -185,7 +185,7 @@ func TestRunLocalOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError == nil { @@ -1177,7 +1177,7 @@ ecs exec: all containers failed to retrieve credentials`), unmarshal: func(b []byte) (manifest.DynamicWorkload, error) { return m.mockMft, nil }, - configureClients: func() error { + configureClients: func(_ context.Context) error { return nil }, buildContainerImages: func(mft manifest.DynamicWorkload) (map[string]string, error) { @@ -1212,7 +1212,7 @@ ecs exec: all containers failed to retrieve credentials`), releaseStdout: func() {}, } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedError == nil { diff --git a/internal/pkg/cli/secret_init.go b/internal/pkg/cli/secret_init.go index f58373b75d1..5415bea0964 100644 --- a/internal/pkg/cli/secret_init.go +++ b/internal/pkg/cli/secret_init.go @@ -67,7 +67,7 @@ type secretInitOpts struct { envCompatibilityChecker map[string]versionCompatibilityChecker secretPutters map[string]secretPutter - configureClientsForEnv func(envName string) error + configureClientsForEnv func(ctx context.Context, envName string) error readFile func() ([]byte, error) } @@ -98,8 +98,8 @@ func newSecretInitOpts(vars secretInitVars) (*secretInitOpts, error) { selector: selector.NewAppEnvSelector(prompter, store), } - opts.configureClientsForEnv = func(envName string) error { - checker, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + opts.configureClientsForEnv = func(ctx context.Context, envName string) error { + checker, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: opts.appName, Env: envName, ConfigStore: opts.store, @@ -109,7 +109,7 @@ func newSecretInitOpts(vars secretInitVars) (*secretInitOpts, error) { } opts.envCompatibilityChecker[envName] = checker - env, err := opts.targetEnv(envName) + env, err := opts.targetEnv(ctx, envName) if err != nil { return err } @@ -140,6 +140,7 @@ func newSecretInitOpts(vars secretInitVars) (*secretInitOpts, error) { // Validate returns an error if the flag values passed by the user are invalid. func (o *secretInitOpts) Validate() error { + ctx := context.Background() if o.inputFilePath != "" && o.name != "" { return errors.New("cannot specify `--cli-input-yaml` with `--name`") } @@ -149,13 +150,13 @@ func (o *secretInitOpts) Validate() error { } if o.appName != "" { - _, err := o.store.GetApplication(o.appName) + _, err := o.store.GetApplication(ctx, o.appName) if err != nil { return fmt.Errorf("get application %s: %w", o.appName, err) } if o.values != nil { for env := range o.values { - if _, err := o.targetEnv(env); err != nil { + if _, err := o.targetEnv(ctx, env); err != nil { return err } } @@ -177,7 +178,7 @@ func (o *secretInitOpts) Validate() error { } // Ask prompts the user for any required or important fields that are not provided. -func (o *secretInitOpts) Ask() error { +func (o *secretInitOpts) Ask(ctx context.Context) error { if o.overwrite { log.Warningf("You have specified %s flag. Please note that overwriting an existing secret may break your deployed service.\n", color.HighlightCode(fmt.Sprintf("--%s", overwriteFlag))) } @@ -186,20 +187,20 @@ func (o *secretInitOpts) Ask() error { return nil } - if err := o.askForAppName(); err != nil { + if err := o.askForAppName(ctx); err != nil { return err } if err := o.askForSecretName(); err != nil { return err } - if err := o.askForSecretValues(); err != nil { + if err := o.askForSecretValues(ctx); err != nil { return err } return nil } // Execute creates or updates the secrets. -func (o *secretInitOpts) Execute() error { +func (o *secretInitOpts) Execute(ctx context.Context) error { if o.inputFilePath != "" { secrets, err := o.parseSecretsInputFile() if err != nil { @@ -208,7 +209,7 @@ func (o *secretInitOpts) Execute() error { o.secretValues = secrets - if err := o.configureClientsAndUpgradeForEnvironments(secrets); err != nil { + if err := o.configureClientsAndUpgradeForEnvironments(ctx, secrets); err != nil { return err } @@ -231,13 +232,13 @@ func (o *secretInitOpts) Execute() error { o.secretValues = map[string]map[string]string{ o.name: o.values, } - if err := o.configureClientsAndUpgradeForEnvironments(o.secretValues); err != nil { + if err := o.configureClientsAndUpgradeForEnvironments(ctx, o.secretValues); err != nil { return err } return o.putSecret(o.name, o.values) } -func (o *secretInitOpts) configureClientsAndUpgradeForEnvironments(secrets map[string]map[string]string) error { +func (o *secretInitOpts) configureClientsAndUpgradeForEnvironments(ctx context.Context, secrets map[string]map[string]string) error { envNames := make(map[string]struct{}) for _, values := range secrets { for envName := range values { @@ -246,7 +247,7 @@ func (o *secretInitOpts) configureClientsAndUpgradeForEnvironments(secrets map[s } for envName := range envNames { - if err := o.configureClientsForEnv(envName); err != nil { + if err := o.configureClientsForEnv(ctx, envName); err != nil { return err } if err := validateMinEnvVersion(o.ws, o.envCompatibilityChecker[envName], o.appName, envName, template.SecretInitMinEnvVersion, "secret init"); err != nil { @@ -340,12 +341,12 @@ func (o *secretInitOpts) parseSecretsInputFile() (map[string]map[string]string, return f.Secrets, nil } -func (o *secretInitOpts) askForAppName() error { +func (o *secretInitOpts) askForAppName(ctx context.Context) error { if o.appName != "" { return nil } - app, err := o.selector.Application(secretInitAppPrompt, secretInitAppPromptHelp) + app, err := o.selector.Application(ctx, secretInitAppPrompt, secretInitAppPromptHelp) if err != nil { return fmt.Errorf("ask for an application to add the secret to: %w", err) } @@ -370,12 +371,12 @@ func (o *secretInitOpts) askForSecretName() error { return nil } -func (o *secretInitOpts) askForSecretValues() error { +func (o *secretInitOpts) askForSecretValues(ctx context.Context) error { if o.values != nil { return nil } - envs, err := o.store.ListEnvironments(o.appName) + envs, err := o.store.ListEnvironments(ctx, o.appName) if err != nil { return fmt.Errorf("list environments in app %s: %w", o.appName, err) } @@ -460,8 +461,8 @@ func (e *errBatchPutSecretsFailed) Error() string { return strings.Join(out, "\n") } -func (o *secretInitOpts) targetEnv(envName string) (*config.Environment, error) { - env, err := o.store.GetEnvironment(o.appName, envName) +func (o *secretInitOpts) targetEnv(ctx context.Context, envName string) (*config.Environment, error) { + env, err := o.store.GetEnvironment(ctx, o.appName, envName) if err != nil { return nil, fmt.Errorf("get environment %s in application %s: %w", envName, o.appName, err) } @@ -489,11 +490,11 @@ Create secrets from input.yml. For the format of the YAML file, please see https if err := opts.Validate(); err != nil { return err } - if err := opts.Ask(); err != nil { + if err := opts.Ask(cmd.Context()); err != nil { return err } - err = opts.Execute() + err = opts.Execute(cmd.Context()) if opts.shouldShowOverwriteHint { log.Warningf("If you want to overwrite an existing secret, use the %s flag.\n", color.HighlightCode(fmt.Sprintf("--%s", overwriteFlag))) } diff --git a/internal/pkg/cli/secret_init_test.go b/internal/pkg/cli/secret_init_test.go index 793d5b9c73d..87add4e8c84 100644 --- a/internal/pkg/cli/secret_init_test.go +++ b/internal/pkg/cli/secret_init_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "path/filepath" @@ -60,15 +61,15 @@ func TestSecretInitOpts_Validate(t *testing.T) { inOverwrite: true, setupMocks: func(m secretInitMocks) { - m.mockStore.EXPECT().GetApplication("dragon_slaying").Return(&config.Application{}, nil) - m.mockStore.EXPECT().GetEnvironment("dragon_slaying", "good_village").Return(&config.Environment{}, nil) - m.mockStore.EXPECT().GetEnvironment("dragon_slaying", "bad_village").Return(&config.Environment{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "dragon_slaying").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetEnvironment(ctx, "dragon_slaying", "good_village").Return(&config.Environment{}, nil) + m.mockStore.EXPECT().GetEnvironment(ctx, "dragon_slaying", "bad_village").Return(&config.Environment{}, nil) }, }, "error getting app": { inApp: "dragon_befriending", setupMocks: func(m secretInitMocks) { - m.mockStore.EXPECT().GetApplication("dragon_befriending").Return(&config.Application{}, errors.New("some error")) + m.mockStore.EXPECT().GetApplication(ctx, "dragon_befriending").Return(&config.Application{}, errors.New("some error")) }, wantedError: errors.New("get application dragon_befriending: some error"), }, @@ -81,10 +82,10 @@ func TestSecretInitOpts_Validate(t *testing.T) { }, inApp: "dragon_slaying", setupMocks: func(m secretInitMocks) { - m.mockStore.EXPECT().GetApplication("dragon_slaying").Return(&config.Application{}, nil) - m.mockStore.EXPECT().GetEnvironment("dragon_slaying", "good_village").Return(&config.Environment{}, nil).MinTimes(0).MaxTimes(1) - m.mockStore.EXPECT().GetEnvironment("dragon_slaying", "bad_village").Return(&config.Environment{}, nil).MinTimes(0).MaxTimes(1) - m.mockStore.EXPECT().GetEnvironment("dragon_slaying", "neutral_village").Return(nil, errors.New("some error")) + m.mockStore.EXPECT().GetApplication(ctx, "dragon_slaying").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetEnvironment(ctx, "dragon_slaying", "good_village").Return(&config.Environment{}, nil).MinTimes(0).MaxTimes(1) + m.mockStore.EXPECT().GetEnvironment(ctx, "dragon_slaying", "bad_village").Return(&config.Environment{}, nil).MinTimes(0).MaxTimes(1) + m.mockStore.EXPECT().GetEnvironment(ctx, "dragon_slaying", "neutral_village").Return(nil, errors.New("some error")) }, wantedError: errors.New("get environment neutral_village in application dragon_slaying: some error"), }, @@ -183,13 +184,13 @@ func TestSecretInitOpts_Ask(t *testing.T) { inName: wantedName, inValues: wantedValues, setupMocks: func(m secretInitAskMocks) { - m.mockSelector.EXPECT().Application(secretInitAppPrompt, gomock.Any()).Return(wantedApp, nil) + m.mockSelector.EXPECT().Application(ctx, secretInitAppPrompt, gomock.Any()).Return(wantedApp, nil) }, wantedVars: wantedVars, }, "error prompting to select an app": { setupMocks: func(m secretInitAskMocks) { - m.mockSelector.EXPECT().Application(secretInitAppPrompt, gomock.Any()).Return("", errors.New("some error")) + m.mockSelector.EXPECT().Application(ctx, secretInitAppPrompt, gomock.Any()).Return("", errors.New("some error")) }, wantedError: errors.New("ask for an application to add the secret to: some error"), }, @@ -198,7 +199,7 @@ func TestSecretInitOpts_Ask(t *testing.T) { inName: wantedName, inValues: wantedValues, setupMocks: func(m secretInitAskMocks) { - m.mockSelector.EXPECT().Application(gomock.Any(), gomock.Any()).Times(0) + m.mockSelector.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Times(0) }, wantedVars: secretInitVars{ appName: wantedApp, @@ -237,7 +238,7 @@ func TestSecretInitOpts_Ask(t *testing.T) { inAppName: wantedApp, inName: wantedName, setupMocks: func(m secretInitAskMocks) { - m.mockStore.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.mockStore.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", }, @@ -261,7 +262,7 @@ func TestSecretInitOpts_Ask(t *testing.T) { inAppName: wantedApp, inName: wantedName, setupMocks: func(m secretInitAskMocks) { - m.mockStore.EXPECT().ListEnvironments("my-app").Return(nil, errors.New("some error")) + m.mockStore.EXPECT().ListEnvironments(ctx, "my-app").Return(nil, errors.New("some error")) }, wantedError: errors.New("list environments in app my-app: some error"), }, @@ -269,7 +270,7 @@ func TestSecretInitOpts_Ask(t *testing.T) { inAppName: wantedApp, inName: wantedName, setupMocks: func(m secretInitAskMocks) { - m.mockStore.EXPECT().ListEnvironments("my-app").Return([]*config.Environment{ + m.mockStore.EXPECT().ListEnvironments(ctx, "my-app").Return([]*config.Environment{ { Name: "test", }, @@ -291,7 +292,7 @@ func TestSecretInitOpts_Ask(t *testing.T) { inAppName: wantedApp, inName: wantedName, setupMocks: func(m secretInitAskMocks) { - m.mockStore.EXPECT().ListEnvironments(wantedApp).Return([]*config.Environment{}, nil) + m.mockStore.EXPECT().ListEnvironments(ctx, wantedApp).Return([]*config.Environment{}, nil) }, wantedError: errors.New("no environment is found in app my-app"), }, @@ -328,7 +329,7 @@ func TestSecretInitOpts_Ask(t *testing.T) { tc.setupMocks(m) - err := opts.Ask() + err := opts.Ask(context.Background()) if tc.wantedError == nil { require.NoError(t, err) require.Equal(t, tc.wantedVars, opts.secretInitVars) @@ -587,13 +588,13 @@ db-host: }, } - opts.configureClientsForEnv = func(envName string) error { + opts.configureClientsForEnv = func(_ context.Context, envName string) error { opts.secretPutters[envName] = m.mockSecretPutter opts.envCompatibilityChecker[envName] = m.mockEnvCompatibilityChecker return nil } - err := opts.Execute() + err := opts.Execute(context.Background()) if tc.wantedError == nil { require.NoError(t, err) } else { diff --git a/internal/pkg/cli/storage_init.go b/internal/pkg/cli/storage_init.go index cfc6fe62177..aeec406c54b 100644 --- a/internal/pkg/cli/storage_init.go +++ b/internal/pkg/cli/storage_init.go @@ -275,14 +275,14 @@ func (o *initStorageOpts) validateServerlessVersion() error { } // Ask asks for fields that are required but not passed in. -func (o *initStorageOpts) Ask() error { +func (o *initStorageOpts) Ask(ctx context.Context) error { if o.addIngressFrom != "" { return nil } if err := o.validateOrAskStorageType(); err != nil { return err } - if err := o.askWorkload(); err != nil { + if err := o.askWorkload(ctx); err != nil { return err } // Storage name needs to be asked after workload because for Aurora the default storage name uses the workload name. @@ -436,14 +436,14 @@ func (o *initStorageOpts) askStorageNameWithDefault(friendlyText, defaultName st return nil } -func (o *initStorageOpts) askWorkload() error { +func (o *initStorageOpts) askWorkload(ctx context.Context) error { if o.workloadName != "" { return nil } if o.lifecycle == lifecycleWorkloadLevel { - return o.askLocalWorkload() + return o.askLocalWorkload(ctx) } - workload, err := o.configSel.Workload(storageInitSvcPrompt, "", o.appName) + workload, err := o.configSel.Workload(ctx, storageInitSvcPrompt, "", o.appName) if err != nil { return fmt.Errorf("select a workload from app %s: %w", o.appName, err) } @@ -451,8 +451,8 @@ func (o *initStorageOpts) askWorkload() error { return nil } -func (o *initStorageOpts) askLocalWorkload() error { - workload, err := o.sel.Workload(storageInitSvcPrompt, "") +func (o *initStorageOpts) askLocalWorkload(ctx context.Context) error { + workload, err := o.sel.Workload(ctx, storageInitSvcPrompt, "") if err != nil { return fmt.Errorf("retrieve local workload names: %w", err) } @@ -738,7 +738,7 @@ func (o *initStorageOpts) validateOrAskAuroraInitialDBName() error { } // Execute deploys a new environment with CloudFormation and adds it to SSM. -func (o *initStorageOpts) Execute() error { +func (o *initStorageOpts) Execute(ctx context.Context) error { o.consumeFlags() if err := o.checkWorkloadExists(); err != nil { return err @@ -746,7 +746,7 @@ func (o *initStorageOpts) Execute() error { if err := o.readWorkloadType(); err != nil { return err } - addonBlobs, err := o.addonBlobs() + addonBlobs, err := o.addonBlobs(ctx) if err != nil { return err } @@ -825,7 +825,7 @@ func (b *addonBlob) recommendedAction() string { return fmt.Sprintf("Check that %s has the following snippet:\n%s", displayPath(b.path), color.HighlightCodeBlock(string(data))) } -func (o *initStorageOpts) addonBlobs() ([]addonBlob, error) { +func (o *initStorageOpts) addonBlobs(ctx context.Context) ([]addonBlob, error) { type option struct { lifecycle string storageType string @@ -837,13 +837,13 @@ func (o *initStorageOpts) addonBlobs() ([]addonBlob, error) { case option{lifecycleWorkloadLevel, dynamoDBStorageType}: return o.wkldDDBAddonBlobs() case option{lifecycleWorkloadLevel, rdsStorageType}: - return o.wkldRDSAddonBlobs() + return o.wkldRDSAddonBlobs(ctx) case option{lifecycleEnvironmentLevel, s3StorageType}: return o.envS3AddonBlobs() case option{lifecycleEnvironmentLevel, dynamoDBStorageType}: return o.envDDBAddonBlobs() case option{lifecycleEnvironmentLevel, rdsStorageType}: - return o.envRDSAddonBlobs() + return o.envRDSAddonBlobs(ctx) } return nil, fmt.Errorf("storage type %s is not supported yet", o.storageType) } @@ -953,8 +953,8 @@ func (o *initStorageOpts) s3Props() *addon.S3Props { } } -func (o *initStorageOpts) wkldRDSAddonBlobs() ([]addonBlob, error) { - props, err := o.rdsProps() +func (o *initStorageOpts) wkldRDSAddonBlobs(ctx context.Context) ([]addonBlob, error) { + props, err := o.rdsProps(ctx) if err != nil { return nil, err } @@ -986,14 +986,14 @@ func (o *initStorageOpts) wkldRDSAddonBlobs() ([]addonBlob, error) { }), nil } -func (o *initStorageOpts) envRDSAddonBlobs() ([]addonBlob, error) { +func (o *initStorageOpts) envRDSAddonBlobs(ctx context.Context) ([]addonBlob, error) { if o.workloadType == manifestinfo.RequestDrivenWebServiceType { - return o.envRDSForRDWSAddonBlobs() + return o.envRDSForRDWSAddonBlobs(ctx) } if o.addIngressFrom != "" { return nil, nil } - props, err := o.rdsProps() + props, err := o.rdsProps(ctx) if err != nil { return nil, err } @@ -1010,7 +1010,7 @@ func (o *initStorageOpts) envRDSAddonBlobs() ([]addonBlob, error) { return []addonBlob{tmplBlob, paramBlob}, nil } -func (o *initStorageOpts) envRDSForRDWSAddonBlobs() ([]addonBlob, error) { +func (o *initStorageOpts) envRDSForRDWSAddonBlobs(ctx context.Context) ([]addonBlob, error) { rdwsIngressTmplBlob := addonBlob{ path: o.ws.WorkloadAddonFilePath(o.workloadName, fmt.Sprintf("%s-ingress.yml", o.storageName)), description: blobDescriptionTemplate, @@ -1027,7 +1027,7 @@ func (o *initStorageOpts) envRDSForRDWSAddonBlobs() ([]addonBlob, error) { if o.addIngressFrom != "" { return []addonBlob{rdwsIngressTmplBlob, rdwsIngressParamBlob}, nil } - props, err := o.rdsProps() + props, err := o.rdsProps(ctx) if err != nil { return nil, err } @@ -1047,8 +1047,8 @@ func (o *initStorageOpts) envRDSForRDWSAddonBlobs() ([]addonBlob, error) { return []addonBlob{tmplBlob, paramBlob}, nil } -func (o *initStorageOpts) rdsProps() (addon.RDSProps, error) { - envs, err := o.environmentNames() +func (o *initStorageOpts) rdsProps(ctx context.Context) (addon.RDSProps, error) { + envs, err := o.environmentNames(ctx) if err != nil { return addon.RDSProps{}, err } @@ -1061,9 +1061,9 @@ func (o *initStorageOpts) rdsProps() (addon.RDSProps, error) { }, nil } -func (o *initStorageOpts) environmentNames() ([]string, error) { +func (o *initStorageOpts) environmentNames(ctx context.Context) ([]string, error) { var envNames []string - envs, err := o.store.ListEnvironments(o.appName) + envs, err := o.store.ListEnvironments(ctx, o.appName) if err != nil { return nil, fmt.Errorf("list environments: %w", err) } @@ -1225,7 +1225,7 @@ Storage resources are addons, either for a workload or the environments.`, if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.storageName, nameFlag, nameFlagShort, "", storageFlagDescription) diff --git a/internal/pkg/cli/storage_init_test.go b/internal/pkg/cli/storage_init_test.go index 9d011ac5d81..ee962cdbac0 100644 --- a/internal/pkg/cli/storage_init_test.go +++ b/internal/pkg/cli/storage_init_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -234,7 +235,7 @@ func TestStorageInitOpts_Ask(t *testing.T) { inStorageType: s3StorageType, inLifecycle: lifecycleWorkloadLevel, mock: func(m *mockStorageInitAsk) { - m.sel.EXPECT().Workload(gomock.Eq(storageInitSvcPrompt), gomock.Any()).Return(wantedSvcName, nil) + m.sel.EXPECT().Workload(ctx, gomock.Eq(storageInitSvcPrompt), gomock.Any()).Return(wantedSvcName, nil) m.ws.EXPECT().WorkloadExists(wantedSvcName).Return(true, nil) }, wantedVars: &initStorageVars{ @@ -249,7 +250,7 @@ func TestStorageInitOpts_Ask(t *testing.T) { inStorageType: s3StorageType, inLifecycle: lifecycleEnvironmentLevel, mock: func(m *mockStorageInitAsk) { - m.configSel.EXPECT().Workload(gomock.Eq(storageInitSvcPrompt), gomock.Any(), wantedAppName).Return(wantedSvcName, nil) + m.configSel.EXPECT().Workload(ctx, gomock.Eq(storageInitSvcPrompt), gomock.Any(), wantedAppName).Return(wantedSvcName, nil) m.ws.EXPECT().HasEnvironments().Return(true, nil) }, wantedVars: &initStorageVars{ @@ -264,7 +265,7 @@ func TestStorageInitOpts_Ask(t *testing.T) { inStorageType: s3StorageType, inLifecycle: lifecycleWorkloadLevel, mock: func(m *mockStorageInitAsk) { - m.sel.EXPECT().Workload(gomock.Eq(storageInitSvcPrompt), gomock.Any()).Return("", errors.New("some error")) + m.sel.EXPECT().Workload(ctx, gomock.Eq(storageInitSvcPrompt), gomock.Any()).Return("", errors.New("some error")) }, wantedErr: fmt.Errorf("retrieve local workload names: some error"), }, @@ -272,7 +273,7 @@ func TestStorageInitOpts_Ask(t *testing.T) { inStorageName: wantedBucketName, inStorageType: s3StorageType, mock: func(m *mockStorageInitAsk) { - m.configSel.EXPECT().Workload(gomock.Eq(storageInitSvcPrompt), gomock.Any(), wantedAppName).Return("", errors.New("some error")) + m.configSel.EXPECT().Workload(ctx, gomock.Eq(storageInitSvcPrompt), gomock.Any(), wantedAppName).Return("", errors.New("some error")) }, wantedErr: fmt.Errorf("select a workload from app %s: some error", wantedAppName), }, @@ -509,7 +510,7 @@ func TestStorageInitOpts_Ask(t *testing.T) { } tc.mock(&m) // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedErr != nil { @@ -928,7 +929,7 @@ func TestStorageInitOpts_AskDDB(t *testing.T) { ws: m.ws, } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedErr != nil { @@ -1144,7 +1145,7 @@ func TestStorageInitOpts_AskRDS(t *testing.T) { } tc.mock(&m) // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedErr != nil { @@ -1249,7 +1250,7 @@ func TestStorageInitOpts_Execute(t *testing.T) { m.EXPECT().Write(gomock.Any(), "mockPath").Return("/frontend/addons/mycluster.yml", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments(gomock.Any()).Times(1) + m.EXPECT().ListEnvironments(ctx, gomock.Any()).Times(1) }, }, "happy calls for wkld RDS with a RDWS": { @@ -1269,7 +1270,7 @@ func TestStorageInitOpts_Execute(t *testing.T) { m.EXPECT().Write(gomock.Any(), "mockParamsPath").Return("/frontend/addons/addons.parameters.yml", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments(gomock.Any()).Times(1) + m.EXPECT().ListEnvironments(ctx, gomock.Any()).Times(1) }, }, "happy calls for env S3": { @@ -1339,7 +1340,7 @@ func TestStorageInitOpts_Execute(t *testing.T) { m.EXPECT().Write(gomock.Any(), "mockEnvParametersPath").Return("mockEnvParametersPath", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments(gomock.Any()).Times(1) + m.EXPECT().ListEnvironments(ctx, gomock.Any()).Times(1) }, }, "happy calls for env RDS with RDWS": { @@ -1364,7 +1365,7 @@ func TestStorageInitOpts_Execute(t *testing.T) { m.EXPECT().Write(gomock.Any(), "mockWkldParamsPath").Return("mockWkldParamsPath", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments(gomock.Any()).Times(1) + m.EXPECT().ListEnvironments(ctx, gomock.Any()).Times(1) }, }, "add ingress for env DDB": { @@ -1431,7 +1432,7 @@ func TestStorageInitOpts_Execute(t *testing.T) { m.EXPECT().Write(gomock.Any(), gomock.Not(gomock.Eq("mockWkldPath"))).Return("mockEnvTemplatePath", nil).Times(2) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments(gomock.Any()).Times(1) + m.EXPECT().ListEnvironments(ctx, gomock.Any()).Times(1) }, }, "do not error out if addon exists": { @@ -1446,7 +1447,7 @@ func TestStorageInitOpts_Execute(t *testing.T) { m.EXPECT().Write(gomock.Any(), "mockPath").Return("/frontend/addons/my-bucket.yml", nil).Return("", fileExistsError) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments(gomock.Any()).AnyTimes() + m.EXPECT().ListEnvironments(ctx, gomock.Any()).AnyTimes() }, }, "unexpected read workload manifest error handled": { @@ -1513,7 +1514,7 @@ func TestStorageInitOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedErr != nil { diff --git a/internal/pkg/cli/svc_delete.go b/internal/pkg/cli/svc_delete.go index 911a9fc00e8..8a526e6b181 100644 --- a/internal/pkg/cli/svc_delete.go +++ b/internal/pkg/cli/svc_delete.go @@ -112,29 +112,29 @@ func (o *deleteSvcOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *deleteSvcOpts) Ask() error { +func (o *deleteSvcOpts) Ask(ctx context.Context) error { if o.appName != "" { - if _, err := o.store.GetApplication(o.appName); err != nil { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return err } } else { - if err := o.askAppName(); err != nil { + if err := o.askAppName(ctx); err != nil { return err } } if o.name != "" { - if _, err := o.store.GetService(o.appName, o.name); err != nil { + if _, err := o.store.GetService(ctx, o.appName, o.name); err != nil { return err } } else { - if err := o.askSvcName(); err != nil { + if err := o.askSvcName(ctx); err != nil { return err } } if o.envName != "" { - if err := o.validateEnvName(); err != nil { + if err := o.validateEnvName(ctx); err != nil { return err } } @@ -171,13 +171,13 @@ func (o *deleteSvcOpts) Ask() error { // Execute deletes the service's CloudFormation stack. // If the service is being removed from the application, Execute will // also delete the ECR repository and the SSM parameter. -func (o *deleteSvcOpts) Execute() error { - wkld, err := o.store.GetWorkload(o.appName, o.name) +func (o *deleteSvcOpts) Execute(ctx context.Context) error { + wkld, err := o.store.GetWorkload(ctx, o.appName, o.name) if err != nil { return fmt.Errorf("get workload: %w", err) } - envs, err := o.appEnvironments() + envs, err := o.appEnvironments(ctx) if err != nil { return err } @@ -195,10 +195,10 @@ func (o *deleteSvcOpts) Execute() error { if err := o.emptyECRRepos(envs); err != nil { return err } - if err := o.removeSvcFromApp(); err != nil { + if err := o.removeSvcFromApp(ctx); err != nil { return err } - if err := o.deleteSSMParam(); err != nil { + if err := o.deleteSSMParam(ctx); err != nil { return err } @@ -208,8 +208,8 @@ func (o *deleteSvcOpts) Execute() error { return nil } -func (o *deleteSvcOpts) validateEnvName() error { - if _, err := o.targetEnv(); err != nil { +func (o *deleteSvcOpts) validateEnvName(ctx context.Context) error { + if _, err := o.targetEnv(ctx); err != nil { return err } return nil @@ -223,16 +223,16 @@ func (o *deleteSvcOpts) needsAppCleanup() bool { return o.envName == "" } -func (o *deleteSvcOpts) targetEnv() (*config.Environment, error) { - env, err := o.store.GetEnvironment(o.appName, o.envName) +func (o *deleteSvcOpts) targetEnv(ctx context.Context) (*config.Environment, error) { + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return nil, fmt.Errorf("get environment %s from config store: %w", o.envName, err) } return env, nil } -func (o *deleteSvcOpts) askAppName() error { - name, err := o.sel.Application(svcAppNamePrompt, wkldAppNameHelpPrompt) +func (o *deleteSvcOpts) askAppName(ctx context.Context) error { + name, err := o.sel.Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application name: %w", err) } @@ -240,8 +240,8 @@ func (o *deleteSvcOpts) askAppName() error { return nil } -func (o *deleteSvcOpts) askSvcName() error { - name, err := o.sel.Service(svcDeleteNamePrompt, "", o.appName) +func (o *deleteSvcOpts) askSvcName(ctx context.Context) error { + name, err := o.sel.Service(ctx, svcDeleteNamePrompt, "", o.appName) if err != nil { return fmt.Errorf("select service: %w", err) } @@ -249,17 +249,17 @@ func (o *deleteSvcOpts) askSvcName() error { return nil } -func (o *deleteSvcOpts) appEnvironments() ([]*config.Environment, error) { +func (o *deleteSvcOpts) appEnvironments(ctx context.Context) ([]*config.Environment, error) { var envs []*config.Environment var err error if o.envName != "" { - env, err := o.targetEnv() + env, err := o.targetEnv(ctx) if err != nil { return nil, err } envs = append(envs, env) } else { - envs, err = o.store.ListEnvironments(o.appName) + envs, err = o.store.ListEnvironments(ctx, o.appName) if err != nil { return nil, fmt.Errorf("list environments: %w", err) } @@ -315,8 +315,8 @@ func (o *deleteSvcOpts) emptyECRRepos(envs []*config.Environment) error { return nil } -func (o *deleteSvcOpts) removeSvcFromApp() error { - proj, err := o.store.GetApplication(o.appName) +func (o *deleteSvcOpts) removeSvcFromApp(ctx context.Context) error { + proj, err := o.store.GetApplication(ctx, o.appName) if err != nil { return err } @@ -329,8 +329,8 @@ func (o *deleteSvcOpts) removeSvcFromApp() error { return nil } -func (o *deleteSvcOpts) deleteSSMParam() error { - if err := o.store.DeleteService(o.appName, o.name); err != nil { +func (o *deleteSvcOpts) deleteSSMParam(ctx context.Context) error { + if err := o.store.DeleteService(ctx, o.appName, o.name); err != nil { return fmt.Errorf("delete service %s in application %s from config store: %w", o.name, o.appName, err) } @@ -369,7 +369,7 @@ func buildSvcDeleteCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } diff --git a/internal/pkg/cli/svc_delete_test.go b/internal/pkg/cli/svc_delete_test.go index 095c7018108..9b2ca673425 100644 --- a/internal/pkg/cli/svc_delete_test.go +++ b/internal/pkg/cli/svc_delete_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -111,9 +112,9 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: testSvcName, skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.store.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{}, nil) - m.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{}, nil) + m.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() }, wantedName: testSvcName, }, @@ -122,8 +123,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: testSvcName, skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.store.EXPECT().GetApplication(gomock.Any()).Return(nil, &config.ErrNoSuchApplication{}) - m.sel.EXPECT().Application(gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, &config.ErrNoSuchApplication{}) + m.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Times(0) }, wantedError: &config.ErrNoSuchApplication{}, }, @@ -132,9 +133,9 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: testSvcName, skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return(testAppName, nil) - m.store.EXPECT().GetApplication(gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return(testAppName, nil) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() }, wantedName: testSvcName, }, @@ -143,9 +144,9 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: testSvcName, skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Return(&config.Workload{}, nil) - m.sel.EXPECT().Service(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Return(&config.Workload{}, nil) + m.sel.EXPECT().Service(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedName: testSvcName, }, @@ -154,8 +155,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: testSvcName, skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.store.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{}, nil) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{}, nil) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) }, wantedError: errors.New("some error"), }, @@ -164,9 +165,9 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: "", skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.sel.EXPECT().Service("Which service would you like to delete?", "", testAppName).Return(testSvcName, nil) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.sel.EXPECT().Service(ctx, "Which service would you like to delete?", "", testAppName).Return(testSvcName, nil) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedName: testSvcName, }, @@ -175,8 +176,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: "", skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.sel.EXPECT().Service("Which service would you like to delete?", "", testAppName).Return("", mockError) - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.sel.EXPECT().Service(ctx, "Which service would you like to delete?", "", testAppName).Return("", mockError) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedError: fmt.Errorf("select service: %w", mockError), }, @@ -185,8 +186,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { inName: "", skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { - m.sel.EXPECT().Service("Which service would you like to delete?", "", testAppName).Return("", mockError) - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.sel.EXPECT().Service(ctx, "Which service would you like to delete?", "", testAppName).Return("", mockError) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedError: fmt.Errorf("select service: %w", mockError), }, @@ -196,8 +197,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { skipConfirmation: true, setUpMocks: func(m *svcDeleteAskMocks) { m.prompt.EXPECT().Confirm(gomock.Any(), gomock.Any(), gomock.Any).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedName: testSvcName, }, @@ -211,8 +212,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { svcDeleteConfirmHelp, gomock.Any(), ).Times(1).Return(true, mockError) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedError: fmt.Errorf("svc delete confirmation prompt: %w", mockError), @@ -227,8 +228,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { svcDeleteConfirmHelp, gomock.Any(), ).Times(1).Return(false, nil) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedError: errSvcDeleteCancelled, }, @@ -242,8 +243,8 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { svcDeleteConfirmHelp, gomock.Any(), ).Times(1).Return(true, nil) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedName: testSvcName, }, @@ -253,14 +254,14 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { envName: "test", skipConfirmation: false, setUpMocks: func(m *svcDeleteAskMocks) { - m.store.EXPECT().GetEnvironment(testAppName, "test").Return(&config.Environment{}, nil) + m.store.EXPECT().GetEnvironment(ctx, testAppName, "test").Return(&config.Environment{}, nil) m.prompt.EXPECT().Confirm( fmt.Sprintf(fmtSvcDeleteFromEnvConfirmPrompt, testSvcName, "test"), fmt.Sprintf(svcDeleteFromEnvConfirmHelp, "test"), gomock.Any(), ).Times(1).Return(true, nil) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedName: testSvcName, }, @@ -293,7 +294,7 @@ func TestDeleteSvcOpts_Ask(t *testing.T) { store: m.store, } - got := opts.Ask() + got := opts.Ask(context.Background()) if got != nil { require.Equal(t, test.wantedError, got) @@ -355,12 +356,12 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { }, setupMocks: func(mocks deleteSvcMocks) { gomock.InOrder( - mocks.store.EXPECT().GetWorkload(mockAppName, mockSvcName).Return(&config.Workload{ + mocks.store.EXPECT().GetWorkload(ctx, mockAppName, mockSvcName).Return(&config.Workload{ Type: manifestinfo.LoadBalancedWebServiceType, }, nil), // appEnvironments - mocks.store.EXPECT().ListEnvironments(gomock.Eq(mockAppName)).Times(1).Return(mockEnvs, nil), + mocks.store.EXPECT().ListEnvironments(ctx, gomock.Eq(mockAppName)).Times(1).Return(mockEnvs, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks @@ -372,11 +373,11 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { mocks.ecr.EXPECT().ClearRepository(mockRepo).Return(nil), // removeSvcFromApp - mocks.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil), + mocks.store.EXPECT().GetApplication(ctx, mockAppName).Return(mockApp, nil), mocks.appCFN.EXPECT().RemoveServiceFromApp(mockApp, mockSvcName).Return(nil), // deleteSSMParam - mocks.store.EXPECT().DeleteService(mockAppName, mockSvcName).Return(nil), + mocks.store.EXPECT().DeleteService(ctx, mockAppName, mockSvcName).Return(nil), ) }, wantedError: nil, @@ -397,12 +398,12 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { }, setupMocks: func(mocks deleteSvcMocks) { gomock.InOrder( - mocks.store.EXPECT().GetWorkload(mockAppName, mockSvcName).Return(&config.Workload{ + mocks.store.EXPECT().GetWorkload(ctx, mockAppName, mockSvcName).Return(&config.Workload{ Type: manifestinfo.LoadBalancedWebServiceType, }, nil), // appEnvironments - mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), + mocks.store.EXPECT().GetEnvironment(ctx, mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks @@ -415,7 +416,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { mocks.appCFN.EXPECT().RemoveServiceFromApp(gomock.Any(), gomock.Any()).Return(nil).Times(0), // It should **not** deleteSSMParam - mocks.store.EXPECT().DeleteService(gomock.Any(), gomock.Any()).Return(nil).Times(0), + mocks.store.EXPECT().DeleteService(ctx, gomock.Any(), gomock.Any()).Return(nil).Times(0), ) }, wantedError: nil, @@ -429,7 +430,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { }, setupMocks: func(mocks deleteSvcMocks) { gomock.InOrder( - mocks.store.EXPECT().GetWorkload(mockAppName, mockSvcName).Return(nil, errors.New("some error")), + mocks.store.EXPECT().GetWorkload(ctx, mockAppName, mockSvcName).Return(nil, errors.New("some error")), ) }, wantedError: errors.New("get workload: some error"), @@ -447,10 +448,10 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { }, setupMocks: func(mocks deleteSvcMocks) { gomock.InOrder( - mocks.store.EXPECT().GetWorkload(mockAppName, mockSvcName).Return(&config.Workload{ + mocks.store.EXPECT().GetWorkload(ctx, mockAppName, mockSvcName).Return(&config.Workload{ Type: manifestinfo.LoadBalancedWebServiceType, }, nil), - mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), + mocks.store.EXPECT().GetEnvironment(ctx, mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), ) }, @@ -469,12 +470,12 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { }, setupMocks: func(mocks deleteSvcMocks) { gomock.InOrder( - mocks.store.EXPECT().GetWorkload(mockAppName, mockSvcName).Return(&config.Workload{ + mocks.store.EXPECT().GetWorkload(ctx, mockAppName, mockSvcName).Return(&config.Workload{ Type: manifestinfo.LoadBalancedWebServiceType, }, nil), // appEnvironments - mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), + mocks.store.EXPECT().GetEnvironment(ctx, mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks @@ -514,7 +515,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { } // WHEN - err := tc.opts.Execute() + err := tc.opts.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/svc_deploy.go b/internal/pkg/cli/svc_deploy.go index 9af714f216c..a9b172a3b9d 100644 --- a/internal/pkg/cli/svc_deploy.go +++ b/internal/pkg/cli/svc_deploy.go @@ -67,7 +67,7 @@ type deploySvcOpts struct { newInterpolator func(app, env string) interpolator cmd execRunner sessProvider *sessions.Provider - newSvcDeployer func() (workloadDeployer, error) + newSvcDeployer func(context.Context) (workloadDeployer, error) svcVersionGetter versionGetter envFeaturesDescriber versionCompatibilityChecker diffWriter io.Writer @@ -122,15 +122,15 @@ func newSvcDeployOpts(vars deployWkldVars) (*deploySvcOpts, error) { diffWriter: os.Stdout, templateVersion: version.LatestTemplateVersion(), } - opts.newSvcDeployer = func() (workloadDeployer, error) { + opts.newSvcDeployer = func(ctx context.Context) (workloadDeployer, error) { // NOTE: Defined as a struct member to facilitate unit testing. - return newSvcDeployer(opts) + return newSvcDeployer(ctx, opts) } return opts, err } -func newSvcDeployer(o *deploySvcOpts) (workloadDeployer, error) { - targetApp, err := o.getTargetApp() +func newSvcDeployer(ctx context.Context, o *deploySvcOpts) (workloadDeployer, error) { + targetApp, err := o.getTargetApp(ctx) if err != nil { return nil, err } @@ -142,6 +142,7 @@ func newSvcDeployer(o *deploySvcOpts) (workloadDeployer, error) { content := o.appliedDynamicMft.Manifest() var deployer workloadDeployer in := clideploy.WorkloadDeployerInput{ + Ctx: ctx, SessionProvider: o.sessProvider, Name: o.name, App: targetApp, @@ -185,9 +186,9 @@ func (o *deploySvcOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *deploySvcOpts) Ask() error { +func (o *deploySvcOpts) Ask(ctx context.Context) error { if o.appName != "" { - if _, err := o.getTargetApp(); err != nil { + if _, err := o.getTargetApp(ctx); err != nil { return err } } else { @@ -195,20 +196,20 @@ func (o *deploySvcOpts) Ask() error { return errNoAppInWorkspace } - if err := o.validateOrAskSvcName(); err != nil { + if err := o.validateOrAskSvcName(ctx); err != nil { return err } - if err := o.validateOrAskEnvName(); err != nil { + if err := o.validateOrAskEnvName(ctx); err != nil { return err } return nil } // Execute builds and pushes the container image for the service, -func (o *deploySvcOpts) Execute() error { +func (o *deploySvcOpts) Execute(ctx context.Context) error { if !o.clientConfigured { - if err := o.configureClients(); err != nil { + if err := o.configureClients(ctx); err != nil { return err } } @@ -237,7 +238,7 @@ func (o *deploySvcOpts) Execute() error { if err := validateWorkloadManifestCompatibilityWithEnv(o.ws, o.envFeaturesDescriber, mft, o.envName); err != nil { return err } - deployer, err := o.newSvcDeployer() + deployer, err := o.newSvcDeployer(ctx) if err != nil { return err } @@ -253,7 +254,7 @@ func (o *deploySvcOpts) Execute() error { if err != nil { return fmt.Errorf("upload deploy resources for service %s: %w", o.name, err) } - targetApp, err := o.getTargetApp() + targetApp, err := o.getTargetApp(ctx) if err != nil { return err } @@ -379,7 +380,7 @@ func (o *deploySvcOpts) RecommendActions() error { return nil } -func (o *deploySvcOpts) validateSvcName() error { +func (o *deploySvcOpts) validateSvcName(ctx context.Context) error { names, err := o.ws.ListServices() if err != nil { return fmt.Errorf("list services in the workspace: %w", err) @@ -392,26 +393,26 @@ func (o *deploySvcOpts) validateSvcName() error { return fmt.Errorf("service %s not found in the workspace", color.HighlightUserInput(o.name)) } -func (o *deploySvcOpts) validateEnvName() error { - if _, err := o.store.GetEnvironment(o.appName, o.envName); err != nil { +func (o *deploySvcOpts) validateEnvName(ctx context.Context) error { + if _, err := o.store.GetEnvironment(ctx, o.appName, o.envName); err != nil { return fmt.Errorf("get environment %s configuration: %w", o.envName, err) } return nil } -func (o *deploySvcOpts) validateOrAskSvcName() error { +func (o *deploySvcOpts) validateOrAskSvcName(ctx context.Context) error { if o.name != "" { - if err := o.validateSvcName(); err != nil { + if err := o.validateSvcName(ctx); err != nil { return err } } else { - name, err := o.sel.Service("Select a service in your workspace", "") + name, err := o.sel.Service(ctx, "Select a service in your workspace", "") if err != nil { return fmt.Errorf("select service: %w", err) } o.name = name } - svc, err := o.store.GetService(o.appName, o.name) + svc, err := o.store.GetService(ctx, o.appName, o.name) if err != nil { return fmt.Errorf("get service %s configuration: %w", o.name, err) } @@ -419,12 +420,12 @@ func (o *deploySvcOpts) validateOrAskSvcName() error { return nil } -func (o *deploySvcOpts) validateOrAskEnvName() error { +func (o *deploySvcOpts) validateOrAskEnvName(ctx context.Context) error { if o.envName != "" { - return o.validateEnvName() + return o.validateEnvName(ctx) } - name, err := o.sel.Environment("Select an environment", "", o.appName) + name, err := o.sel.Environment(ctx, "Select an environment", "", o.appName) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -432,9 +433,9 @@ func (o *deploySvcOpts) validateOrAskEnvName() error { return nil } -func (o *deploySvcOpts) configureClients() error { +func (o *deploySvcOpts) configureClients(ctx context.Context) error { o.gitShortCommit = imageTagFromGit(o.cmd) // Best effort assign git tag. - env, err := o.store.GetEnvironment(o.appName, o.envName) + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return fmt.Errorf("get environment %s configuration: %w", o.envName, err) } @@ -452,13 +453,13 @@ func (o *deploySvcOpts) configureClients() error { o.envConfig = envConfig // client to retrieve caller identity. - caller, err := identity.New(defaultConfig).Get() + caller, err := identity.New(defaultConfig).Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } o.rootUserARN = caller.RootUserARN - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: o.appName, Env: o.envName, ConfigStore: o.store, @@ -468,7 +469,7 @@ func (o *deploySvcOpts) configureClients() error { } o.envFeaturesDescriber = envDescriber - wkldDescriber, err := describe.NewWorkloadStackDescriber(describe.NewWorkloadConfig{ + wkldDescriber, err := describe.NewWorkloadStackDescriber(ctx, describe.NewWorkloadConfig{ App: o.appName, Env: o.envName, Name: o.name, @@ -575,7 +576,7 @@ func validateWkldVersion(vg versionGetter, name, templateVersion string) error { } func (o *deploySvcOpts) uriRecommendedActions() ([]string, error) { - describer, err := describe.NewReachableService(o.appName, o.name, o.store) + describer, err := describe.NewReachableService(context.Background(), o.appName, o.name, o.store) if err != nil { var errNotAccessible *describe.ErrNonAccessibleServiceType if errors.As(err, &errNotAccessible) { @@ -625,11 +626,11 @@ func (o *deploySvcOpts) publishRecommendedActions() []string { } } -func (o *deploySvcOpts) getTargetApp() (*config.Application, error) { +func (o *deploySvcOpts) getTargetApp(ctx context.Context) (*config.Application, error) { if o.targetApp != nil { return o.targetApp, nil } - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { return nil, fmt.Errorf("get application %s configuration: %w", o.appName, err) } @@ -716,7 +717,7 @@ func buildSvcDeployCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/svc_deploy_test.go b/internal/pkg/cli/svc_deploy_test.go index d078b39a081..3c50bc67d06 100644 --- a/internal/pkg/cli/svc_deploy_test.go +++ b/internal/pkg/cli/svc_deploy_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "strings" @@ -50,19 +51,19 @@ func TestSvcDeployOpts_Ask(t *testing.T) { inEnvName: "prod-iad", inSvcName: "frontend", setupMocks: func(m *svcDeployAskMocks) { - m.store.EXPECT().GetApplication("phonetool") - m.store.EXPECT().GetEnvironment("phonetool", "prod-iad").Return(&config.Environment{Name: "prod-iad"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool") + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "prod-iad").Return(&config.Environment{Name: "prod-iad"}, nil) m.ws.EXPECT().ListServices().Return([]string{"frontend"}, nil) - m.store.EXPECT().GetService("phonetool", "frontend").Return(&config.Workload{}, nil) - m.sel.EXPECT().Service(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, "phonetool", "frontend").Return(&config.Workload{}, nil) + m.sel.EXPECT().Service(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedSvcName: "frontend", wantedEnvName: "prod-iad", }, "error instead of prompting for application name if not provided": { setupMocks: func(m *svcDeployAskMocks) { - m.store.EXPECT().GetApplication(gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) }, wantedError: errNoAppInWorkspace, }, @@ -70,10 +71,10 @@ func TestSvcDeployOpts_Ask(t *testing.T) { inAppName: "phonetool", inEnvName: "prod-iad", setupMocks: func(m *svcDeployAskMocks) { - m.sel.EXPECT().Service("Select a service in your workspace", "").Return("frontend", nil) - m.store.EXPECT().GetApplication(gomock.Any()).Times(1) - m.store.EXPECT().GetEnvironment("phonetool", "prod-iad").Return(&config.Environment{Name: "prod-iad"}, nil) - m.store.EXPECT().GetService("phonetool", "frontend").Return(&config.Workload{}, nil) + m.sel.EXPECT().Service(ctx, "Select a service in your workspace", "").Return("frontend", nil) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Times(1) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "prod-iad").Return(&config.Environment{Name: "prod-iad"}, nil) + m.store.EXPECT().GetService(ctx, "phonetool", "frontend").Return(&config.Workload{}, nil) }, wantedSvcName: "frontend", wantedEnvName: "prod-iad", @@ -82,10 +83,10 @@ func TestSvcDeployOpts_Ask(t *testing.T) { inAppName: "phonetool", inSvcName: "frontend", setupMocks: func(m *svcDeployAskMocks) { - m.sel.EXPECT().Environment(gomock.Any(), gomock.Any(), "phonetool").Return("prod-iad", nil) - m.store.EXPECT().GetApplication("phonetool") + m.sel.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), "phonetool").Return("prod-iad", nil) + m.store.EXPECT().GetApplication(ctx, "phonetool") m.ws.EXPECT().ListServices().Return([]string{"frontend"}, nil) - m.store.EXPECT().GetService("phonetool", "frontend").Return(&config.Workload{}, nil) + m.store.EXPECT().GetService(ctx, "phonetool", "frontend").Return(&config.Workload{}, nil) }, wantedSvcName: "frontend", wantedEnvName: "prod-iad", @@ -116,7 +117,7 @@ func TestSvcDeployOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError == nil { @@ -504,7 +505,7 @@ func TestSvcDeployOpts_Execute(t *testing.T) { clientConfigured: true, }, svcType: tc.inSvcType, - newSvcDeployer: func() (workloadDeployer, error) { + newSvcDeployer: func(_ context.Context) (workloadDeployer, error) { return m.mockDeployer, nil }, newInterpolator: func(app, env string) interpolator { @@ -524,7 +525,7 @@ func TestSvcDeployOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedError == nil { diff --git a/internal/pkg/cli/svc_exec.go b/internal/pkg/cli/svc_exec.go index 246b0221f59..fce031afe8c 100644 --- a/internal/pkg/cli/svc_exec.go +++ b/internal/pkg/cli/svc_exec.go @@ -92,26 +92,26 @@ func (o *svcExecOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *svcExecOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *svcExecOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - if err := o.validateAndAskSvcEnvName(); err != nil { + if err := o.validateAndAskSvcEnvName(ctx); err != nil { return err } return nil } // Execute executes a command in a running container. -func (o *svcExecOpts) Execute() error { - wkld, err := o.store.GetWorkload(o.appName, o.name) +func (o *svcExecOpts) Execute(ctx context.Context) error { + wkld, err := o.store.GetWorkload(ctx, o.appName, o.name) if err != nil { return fmt.Errorf("get workload: %w", err) } if wkld.Type == manifestinfo.RequestDrivenWebServiceType { return fmt.Errorf("executing a command in a running container part of a service is not supported for services with type: '%s'", manifestinfo.RequestDrivenWebServiceType) } - cfg, err := o.envConfig() + cfg, err := o.envConfig(ctx) if err != nil { return err } @@ -141,12 +141,12 @@ func (o *svcExecOpts) Execute() error { return nil } -func (o *svcExecOpts) validateOrAskApp() error { +func (o *svcExecOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.store.GetApplication(o.appName) + _, err := o.store.GetApplication(ctx, o.appName) return err } - app, err := o.sel.Application(svcAppNamePrompt, wkldAppNameHelpPrompt) + app, err := o.sel.Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -154,22 +154,22 @@ func (o *svcExecOpts) validateOrAskApp() error { return nil } -func (o *svcExecOpts) validateAndAskSvcEnvName() error { +func (o *svcExecOpts) validateAndAskSvcEnvName(ctx context.Context) error { if o.envName != "" { - if _, err := o.store.GetEnvironment(o.appName, o.envName); err != nil { + if _, err := o.store.GetEnvironment(ctx, o.appName, o.envName); err != nil { return err } } if o.name != "" { - if _, err := o.store.GetService(o.appName, o.name); err != nil { + if _, err := o.store.GetService(ctx, o.appName, o.name); err != nil { return err } } // Note: we let prompter handle the case when there is only option for user to choose from. // This is naturally the case when `o.envName != "" && o.name != ""`. - deployedService, err := o.sel.DeployedService(svcExecNamePrompt, svcExecNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.name)) + deployedService, err := o.sel.DeployedService(ctx, svcExecNamePrompt, svcExecNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.name)) if err != nil { return fmt.Errorf("select deployed service for application %s: %w", o.appName, err) } @@ -178,8 +178,8 @@ func (o *svcExecOpts) validateAndAskSvcEnvName() error { return nil } -func (o *svcExecOpts) envConfig() (aws.Config, error) { - env, err := o.store.GetEnvironment(o.appName, o.envName) +func (o *svcExecOpts) envConfig(ctx context.Context) (aws.Config, error) { + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return aws.Config{}, fmt.Errorf("get environment %s: %w", o.envName, err) } @@ -291,7 +291,7 @@ func buildSvcExecCmd() *cobra.Command { opts.skipConfirmation = aws.Bool(true) } } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/svc_exec_test.go b/internal/pkg/cli/svc_exec_test.go index e64d5412229..0304af68ad8 100644 --- a/internal/pkg/cli/svc_exec_test.go +++ b/internal/pkg/cli/svc_exec_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -272,10 +273,10 @@ func TestSvcExec_Ask(t *testing.T) { inputEnv: inputEnv, inputSvc: inputSvc, setupMocks: func(m execSvcMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil) - m.storeSvc.EXPECT().GetEnvironment("my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil) - m.storeSvc.EXPECT().GetService("my-app", "my-svc").Return(&config.Workload{}, nil) - m.sel.EXPECT().DeployedService(svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil) + m.storeSvc.EXPECT().GetService(ctx, "my-app", "my-svc").Return(&config.Workload{}, nil) + m.sel.EXPECT().DeployedService(ctx, svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -289,12 +290,12 @@ func TestSvcExec_Ask(t *testing.T) { inputEnv: inputEnv, inputSvc: inputSvc, setupMocks: func(m execSvcMocks) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) - m.storeSvc.EXPECT().GetApplication(gomock.Any()).Times(0) + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) + m.storeSvc.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) // Don't care about the other calls. - m.storeSvc.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.storeSvc.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedService{ + m.storeSvc.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.storeSvc.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", }, nil).AnyTimes() @@ -305,22 +306,22 @@ func TestSvcExec_Ask(t *testing.T) { }, "returns error when fail to select apps": { setupMocks: func(m execSvcMocks) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) }, wantedError: fmt.Errorf("select application: some error"), }, "prompt for svc and env": { inputApp: inputApp, setupMocks: func(m execSvcMocks) { - m.storeSvc.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.storeSvc.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.storeSvc.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.storeSvc.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", }, nil) // Don't care about the other calls. - m.storeSvc.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.storeSvc.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedApp: inputApp, wantedEnv: inputEnv, @@ -329,10 +330,10 @@ func TestSvcExec_Ask(t *testing.T) { "returns error when fail to select services": { inputApp: inputApp, setupMocks: func(m execSvcMocks) { - m.sel.EXPECT().DeployedService(svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.sel.EXPECT().DeployedService(ctx, svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(nil, fmt.Errorf("some error")) // Don't care about the other calls. - m.storeSvc.EXPECT().GetApplication(gomock.Any()).AnyTimes() + m.storeSvc.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() }, wantedError: fmt.Errorf("select deployed service for application my-app: some error"), @@ -340,8 +341,8 @@ func TestSvcExec_Ask(t *testing.T) { "success": { setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil), - m.sel.EXPECT().DeployedService(svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil), + m.sel.EXPECT().DeployedService(ctx, svcExecNamePrompt, svcExecNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -380,7 +381,7 @@ func TestSvcExec_Ask(t *testing.T) { } // WHEN - err := execSvcs.Ask() + err := execSvcs.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -421,7 +422,7 @@ func TestSvcExec_Execute(t *testing.T) { "return error if fail to get workload": { setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(nil, mockError), + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(nil, mockError), ) }, wantedError: fmt.Errorf("get workload: some error"), @@ -429,7 +430,7 @@ func TestSvcExec_Execute(t *testing.T) { "return error if service type is Request-Driven Web Service": { setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(&mockRDWSWl, nil), + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(&mockRDWSWl, nil), ) }, wantedError: fmt.Errorf("executing a command in a running container part of a service is not supported for services with type: 'Request-Driven Web Service'"), @@ -437,8 +438,8 @@ func TestSvcExec_Execute(t *testing.T) { "return error if fail to get environment": { setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(&mockWl, nil), - m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(nil, mockError), + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(&mockWl, nil), + m.storeSvc.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(nil, mockError), ) }, wantedError: fmt.Errorf("get environment mockEnv: some error"), @@ -446,8 +447,8 @@ func TestSvcExec_Execute(t *testing.T) { "return error if fail to describe service": { setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(&mockWl, nil), - m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(&mockWl, nil), + m.storeSvc.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), @@ -459,8 +460,8 @@ func TestSvcExec_Execute(t *testing.T) { "return error if no running task found": { setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(&mockWl, nil), - m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(&mockWl, nil), + m.storeSvc.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), @@ -475,8 +476,8 @@ func TestSvcExec_Execute(t *testing.T) { taskID: "mockTaskID1", setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(&mockWl, nil), - m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(&mockWl, nil), + m.storeSvc.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), @@ -496,8 +497,8 @@ func TestSvcExec_Execute(t *testing.T) { containerName: "hello", setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(&mockWl, nil), - m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(&mockWl, nil), + m.storeSvc.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), @@ -523,8 +524,8 @@ func TestSvcExec_Execute(t *testing.T) { "success": { setupMocks: func(m execSvcMocks) { gomock.InOrder( - m.storeSvc.EXPECT().GetWorkload("mockApp", "mockSvc").Return(&mockWl, nil), - m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ + m.storeSvc.EXPECT().GetWorkload(ctx, "mockApp", "mockSvc").Return(&mockWl, nil), + m.storeSvc.EXPECT().GetEnvironment(ctx, "mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), @@ -594,7 +595,7 @@ func TestSvcExec_Execute(t *testing.T) { } // WHEN - err := execSvcs.Execute() + err := execSvcs.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/svc_init.go b/internal/pkg/cli/svc_init.go index b2e71b96392..fecbbba650f 100644 --- a/internal/pkg/cli/svc_init.go +++ b/internal/pkg/cli/svc_init.go @@ -175,7 +175,7 @@ type initSvcOpts struct { wsRoot string dockerfile func(path string) dockerfileParser - initEnvDescriber func(appName, envName string) (envDescriber, error) + initEnvDescriber func(ctx context.Context, appName, envName string) (envDescriber, error) newAppVersionGetter func(appName string) (versionGetter, error) // Overridden in tests. @@ -229,8 +229,8 @@ func newInitSvcOpts(vars initSvcVars) (*initSvcOpts, error) { newAppVersionGetter: func(appName string) (versionGetter, error) { return describe.NewAppDescriber(appName) }, - initEnvDescriber: func(appName string, envName string) (envDescriber, error) { - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + initEnvDescriber: func(ctx context.Context, appName string, envName string) (envDescriber, error) { + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: appName, Env: envName, ConfigStore: store, @@ -321,13 +321,13 @@ func (o *initSvcOpts) validateSourcePaths(sources []string) error { } // Ask prompts for and validates any required flags. -func (o *initSvcOpts) Ask() error { +func (o *initSvcOpts) Ask(ctx context.Context) error { // NOTE: we optimize the case where `name` is given as a flag while `wkldType` is not. // In this case, we can try reading the manifest, and set `wkldType` to the value found in the manifest // without having to validate it. We can then short circuit the rest of the prompts for an optimal UX. if o.name != "" && o.wkldType == "" { // Best effort to validate the service name without type. - if err := o.validateSvc(); err != nil { + if err := o.validateSvc(ctx); err != nil { return err } shouldSkipAsking, err := o.manifestAlreadyExists() @@ -352,7 +352,7 @@ func (o *initSvcOpts) Ask() error { return err } } - if err := o.validateSvc(); err != nil { + if err := o.validateSvc(ctx); err != nil { return err } if err := o.askIngressType(); err != nil { @@ -365,11 +365,11 @@ func (o *initSvcOpts) Ask() error { if shouldSkipAsking { return nil } - return o.askSvcDetails() + return o.askSvcDetails(ctx) } // Execute writes the service's manifest file and stores the service in SSM. -func (o *initSvcOpts) Execute() error { +func (o *initSvcOpts) Execute(ctx context.Context) error { if !o.allowAppDowngrade { appVersionGetter, err := o.newAppVersionGetter(o.appName) if err != nil { @@ -399,12 +399,12 @@ func (o *initSvcOpts) Execute() error { } } // Environments that are deployed and have​ only private subnets. - envs, err := envsWithPrivateSubnetsOnly(o.store, o.initEnvDescriber, o.appName) + envs, err := envsWithPrivateSubnetsOnly(ctx, o.store, o.initEnvDescriber, o.appName) if err != nil { return err } - o.manifestPath, err = o.init.Service(&initialize.ServiceProps{ + o.manifestPath, err = o.init.Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: o.appName, Name: o.name, @@ -451,7 +451,7 @@ You can specify multiple paths where your service will receive traffic by settin return nil } -func (o *initSvcOpts) askSvcDetails() error { +func (o *initSvcOpts) askSvcDetails(ctx context.Context) error { if o.wkldType == manifestinfo.StaticSiteType { return o.askStaticSite() } @@ -467,7 +467,7 @@ func (o *initSvcOpts) askSvcDetails() error { if err := o.askSvcPort(); err != nil { return err } - return o.askSvcPublishers() + return o.askSvcPublishers(ctx) } func (o *initSvcOpts) askSvcType() error { @@ -484,15 +484,15 @@ func (o *initSvcOpts) askSvcType() error { return nil } -func (o *initSvcOpts) validateSvc() error { +func (o *initSvcOpts) validateSvc(ctx context.Context) error { if err := validateSvcName(o.name, o.wkldType); err != nil { return err } - return o.validateDuplicateSvc() + return o.validateDuplicateSvc(ctx) } -func (o *initSvcOpts) validateDuplicateSvc() error { - _, err := o.store.GetService(o.appName, o.name) +func (o *initSvcOpts) validateDuplicateSvc(ctx context.Context) error { + _, err := o.store.GetService(ctx, o.appName, o.name) if err == nil { // Skip error if service already exists in workspace if !o.wsPendingCreation { @@ -800,7 +800,7 @@ func legitimizePlatform(engine dockerEngine, wkldType string) (manifest.Platform return manifest.PlatformString(redirectedPlatform), nil } -func (o *initSvcOpts) askSvcPublishers() (err error) { +func (o *initSvcOpts) askSvcPublishers(ctx context.Context) (err error) { if o.wkldType != manifestinfo.WorkerServiceType { return nil } @@ -823,7 +823,7 @@ func (o *initSvcOpts) askSvcPublishers() (err error) { return nil } - topics, err := o.topicSel.Topics(svcInitPublisherPrompt, svcInitPublisherHelpPrompt, o.appName) + topics, err := o.topicSel.Topics(ctx, svcInitPublisherPrompt, svcInitPublisherHelpPrompt, o.appName) if err != nil { return fmt.Errorf("select publisher: %w", err) } @@ -849,7 +849,7 @@ func validateWorkspaceApp(wsApp, inputApp string, store store) error { if inputApp != "" && inputApp != wsApp { return fmt.Errorf("cannot specify app %s because the workspace is already registered with app %s", inputApp, wsApp) } - if _, err := store.GetApplication(wsApp); err != nil { + if _, err := store.GetApplication(context.Background(), wsApp); err != nil { return fmt.Errorf("get application %s configuration: %w", wsApp, err) } return nil @@ -940,10 +940,10 @@ This command is also run as part of "copilot init".`, return err } log.Warningln("It's best to run this command in the root of your workspace.") - if err := opts.Ask(); err != nil { + if err := opts.Ask(cmd.Context()); err != nil { return err } - if err := opts.Execute(); err != nil { + if err := opts.Execute(cmd.Context()); err != nil { return err } if err := opts.RecommendActions(); err != nil { diff --git a/internal/pkg/cli/svc_init_test.go b/internal/pkg/cli/svc_init_test.go index 408c618c233..ad7819ecec8 100644 --- a/internal/pkg/cli/svc_init_test.go +++ b/internal/pkg/cli/svc_init_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "path/filepath" @@ -67,7 +68,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inImage: "mockImage", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(nil, errors.New("some error")) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(nil, errors.New("some error")) }, wantedErr: fmt.Errorf("get application phonetool configuration: some error"), }, @@ -77,7 +78,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inImage: "mockImage", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("--dockerfile and --image cannot be specified together"), }, @@ -87,7 +88,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inSvcType: manifestinfo.RequestDrivenWebServiceType, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("image amazon/amazon-ecs-sample is not supported by App Runner: value must be an ECR or ECR Public image URI"), }, @@ -96,7 +97,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inDockerfilePath: "./hello/Dockerfile", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: fmt.Errorf("open %s: file does not exist", filepath.FromSlash("hello/Dockerfile")), }, @@ -106,7 +107,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inSubscribeTags: []string{"name:svc"}, inNoSubscribe: true, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: errors.New("validate subscribe configuration: cannot specify both --no-subscribe and --subscribe-topics"), }, @@ -117,7 +118,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inIngressType: "invalid", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, mockFileSystem: func(mockFS afero.Fs) { mockFS.MkdirAll("hello", 0755) @@ -131,7 +132,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inSources: []string{"goodbye", "hello/there"}, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: errors.New(`'--sources' must be specified with '--type "Static Site"'`), }, @@ -148,7 +149,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { }, setupMocks: func(m *initSvcMocks) { m.mockCachedWSRoot = "mockRoot" - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedErr: errors.New(`source "non-existent path" must be a valid path relative to the workspace "mockRoot": open mockRoot/non-existent path: file does not exist`), }, @@ -158,7 +159,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inDockerfilePath: "./hello/Dockerfile", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, mockFileSystem: func(mockFS afero.Fs) { mockFS.MkdirAll("hello", 0755) @@ -172,7 +173,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inIngressType: "Internet", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, mockFileSystem: func(mockFS afero.Fs) { mockFS.MkdirAll("hello", 0755) @@ -186,7 +187,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { inSvcPort: 3000, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, mockFileSystem: func(mockFS afero.Fs) { mockFS.MkdirAll("hello", 0755) @@ -206,7 +207,7 @@ func TestSvcInitOpts_Validate(t *testing.T) { }, setupMocks: func(m *initSvcMocks) { m.mockCachedWSRoot = "groot" - m.mockStore.EXPECT().GetApplication("phonetool").Return(&config.Application{}, nil) + m.mockStore.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{}, nil) }, wantedAssets: []manifest.FileUpload{ { @@ -320,7 +321,7 @@ func TestSvcInitOpts_Ask(t *testing.T) { setupMocks: func(m *initSvcMocks) { m.mockPrompt.EXPECT().Get(gomock.Eq("What do you want to name this service?"), gomock.Any(), gomock.Any(), gomock.Any()). Return(wantedSvcName, nil) - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) }, wantedErr: nil, @@ -346,7 +347,7 @@ func TestSvcInitOpts_Ask(t *testing.T) { setupMocks: func(m *initSvcMocks) { m.mockPrompt.EXPECT().Get(gomock.Eq("What do you want to name this service?"), gomock.Any(), gomock.Any(), gomock.Any()). Return(wantedSvcName, nil) - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(&config.Workload{}, nil) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(&config.Workload{}, nil) m.mockSvcLister.EXPECT().ListWorkloads().Return([]string{}, nil) }, wantedErr: fmt.Errorf("service frontend already exists"), @@ -360,7 +361,7 @@ func TestSvcInitOpts_Ask(t *testing.T) { setupMocks: func(m *initSvcMocks) { m.mockPrompt.EXPECT().Get(gomock.Eq("What do you want to name this service?"), gomock.Any(), gomock.Any(), gomock.Any()). Return(wantedSvcName, nil) - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(&config.Workload{}, nil) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(&config.Workload{}, nil) m.mockSvcLister.EXPECT().ListWorkloads().Return([]string{wantedSvcName}, nil) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return([]byte(` type: Load Balanced Web Service`), nil) @@ -375,7 +376,7 @@ type: Load Balanced Web Service`), nil) setupMocks: func(m *initSvcMocks) { m.mockPrompt.EXPECT().Get(gomock.Eq("What do you want to name this service?"), gomock.Any(), gomock.Any(), gomock.Any()). Return(wantedSvcName, nil) - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, mockError) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, mockError) }, wantedErr: fmt.Errorf("validate if service exists: mock error"), }, @@ -384,7 +385,7 @@ type: Load Balanced Web Service`), nil) inSvcName: wantedSvcName, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return([]byte(` type: Backend Service`), nil) }, @@ -395,7 +396,7 @@ type: Backend Service`), nil) inSvcName: wantedSvcName, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return([]byte(` type: Worker Service`), nil) }, @@ -412,7 +413,7 @@ type: Worker Service`), nil) inSvcName: badAppRunnerSvcName, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, badAppRunnerSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, badAppRunnerSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(badAppRunnerSvcName).Return([]byte(` type: Request-Driven Web Service`), nil) }, @@ -422,7 +423,7 @@ type: Request-Driven Web Service`), nil) inSvcName: wantedSvcName, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, mockError) }, @@ -469,7 +470,7 @@ type: Request-Driven Web Service`), nil) }, }), gomock.Any()). Return(wantedSvcType, nil) - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}).Times(2) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}).Times(2) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}).Times(2) }, wantedErr: nil, @@ -481,7 +482,7 @@ type: Request-Driven Web Service`), nil) setupMocks: func(m *initSvcMocks) { m.mockPrompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return(appRunnerSvcType, nil) - m.mockStore.EXPECT().GetService(mockAppName, badAppRunnerSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, badAppRunnerSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(badAppRunnerSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: badAppRunnerSvcName}) }, wantedErr: fmt.Errorf("service name iamoverfortycharacterlongandaninvalidrdwsname is invalid: value must not exceed 40 characters"), @@ -493,7 +494,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: wantedDockerfilePath, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().SelectOption(gomock.Eq(svcInitIngressTypePrompt), gomock.Any(), gomock.Eq([]prompt.Option{ { @@ -512,7 +513,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: wantedDockerfilePath, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockPrompt.EXPECT().SelectOption(gomock.Eq(svcInitIngressTypePrompt), gomock.Any(), gomock.Eq([]prompt.Option{ { Value: "Environment", @@ -532,7 +533,7 @@ type: Request-Driven Web Service`), nil) inIngressType: ingressTypeInternet, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) }, }, @@ -544,7 +545,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: "", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) }, }, @@ -554,7 +555,7 @@ type: Request-Driven Web Service`), nil) inSvcPort: wantedSvcPort, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockDockerEngine.EXPECT().CheckDockerEngineRunning().Return(errors.New("some error")) }, @@ -566,7 +567,7 @@ type: Request-Driven Web Service`), nil) inSvcPort: wantedSvcPort, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("mockImage", nil) @@ -581,7 +582,7 @@ type: Request-Driven Web Service`), nil) inSvcPort: wantedSvcPort, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("mockImage", nil) @@ -597,7 +598,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: "", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("", mockError) @@ -618,7 +619,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: "", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().Get(wkldInitImagePrompt, wkldInitImagePromptHelp, gomock.Any(), gomock.Any()). Return("mockImage", nil) @@ -641,7 +642,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: "", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockSel.EXPECT().Dockerfile( gomock.Eq(fmt.Sprintf(fmtWkldInitDockerfilePrompt, wantedSvcName)), @@ -661,7 +662,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: "", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockSel.EXPECT().Dockerfile( gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), @@ -676,7 +677,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: wantedDockerfilePath, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockDockerfile.EXPECT().GetExposedPorts().Return(nil, errors.New("no expose")) }, @@ -688,7 +689,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: wantedDockerfilePath, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().Get(gomock.Eq(fmt.Sprintf(svcInitSvcPortPrompt, "port")), gomock.Any(), gomock.Any(), gomock.Any()). Return(defaultSvcPortString, nil) @@ -702,7 +703,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: wantedDockerfilePath, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().Get(gomock.Eq(fmt.Sprintf(svcInitSvcPortPrompt, "port")), gomock.Any(), gomock.Any(), gomock.Any()). Return("", errors.New("some error")) @@ -716,7 +717,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: wantedDockerfilePath, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockPrompt.EXPECT().Get(gomock.Eq(fmt.Sprintf(svcInitSvcPortPrompt, "port")), gomock.Any(), gomock.Any(), gomock.Any()). Return("100000", errors.New("some error")) @@ -730,7 +731,7 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: wantedDockerfilePath, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockDockerfile.EXPECT().GetExposedPorts().Return([]dockerfile.Port{{Port: 80, Protocol: "", RawString: "80"}}, nil) }, @@ -742,7 +743,7 @@ type: Request-Driven Web Service`), nil) inSvcPort: wantedSvcPort, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) }, }, @@ -754,7 +755,7 @@ type: Request-Driven Web Service`), nil) inNoSubscribe: true, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) }, }, @@ -767,7 +768,7 @@ type: Request-Driven Web Service`), nil) inSubscribeTags: []string{"svc:name"}, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) }, }, @@ -779,9 +780,9 @@ type: Request-Driven Web Service`), nil) inDockerfilePath: "", setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) - m.mocktopicSel.EXPECT().Topics( + m.mocktopicSel.EXPECT().Topics(ctx, gomock.Eq(svcInitPublisherPrompt), gomock.Eq(svcInitPublisherHelpPrompt), gomock.Any(), @@ -792,7 +793,7 @@ type: Request-Driven Web Service`), nil) inSvcType: manifestinfo.StaticSiteType, inSvcName: wantedSvcName, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockSourceSel.EXPECT().StaticSources(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, mockError) }, @@ -806,7 +807,7 @@ type: Request-Driven Web Service`), nil) _ = afero.WriteFile(mockFS, filepath.Join(mockProjectRoot, mockFile), []byte("file guts"), 0644) }, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockMftReader.EXPECT().ReadWorkloadManifest(wantedSvcName).Return(nil, &workspace.ErrFileNotExists{FileName: wantedSvcName}) m.mockSourceSel.EXPECT().StaticSources(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]string{mockFile, mockDir}, nil) m.mockCachedWSRoot = mockProjectRoot @@ -831,7 +832,7 @@ type: Request-Driven Web Service`), nil) _ = afero.WriteFile(mockFS, mockFile, []byte("file guts"), 0644) }, setupMocks: func(m *initSvcMocks) { - m.mockStore.EXPECT().GetService(mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) + m.mockStore.EXPECT().GetService(ctx, mockAppName, wantedSvcName).Return(nil, &config.ErrNoSuchService{}) m.mockPrompt.EXPECT().Get(gomock.Eq("What is the path to the directory or file for frontend?"), gomock.Eq("Path to directory or file to use for building your static site."), gomock.Any(), gomock.Any()).Return(mockFile, nil) m.mockPrompt.EXPECT().Confirm(gomock.Eq("Would you like to enter another path?"), gomock.Eq("You may add multiple custom paths. Enter 'y' to type another."), gomock.Any()).Return(false, nil) }, @@ -901,7 +902,7 @@ type: Request-Driven Web Service`), nil) } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedErr != nil { @@ -961,7 +962,7 @@ network: inSvcPort: 80, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -980,7 +981,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", }, @@ -991,7 +992,7 @@ network: inSvcType: manifestinfo.BackendServiceType, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1009,7 +1010,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", }, @@ -1029,7 +1030,7 @@ network: m.EXPECT().GetPlatform().Times(0) }, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1040,7 +1041,7 @@ network: }).Return("manifest/path", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", }, @@ -1060,7 +1061,7 @@ network: m.EXPECT().GetPlatform().Times(0) }, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1071,7 +1072,7 @@ network: }).Return("manifest/path", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", @@ -1085,7 +1086,7 @@ network: inSvcPort: 80, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1106,7 +1107,7 @@ network: m.EXPECT().GetPlatform().Return("windows", "amd64", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", @@ -1120,7 +1121,7 @@ network: inSvcPort: 80, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1141,7 +1142,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "arm", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", @@ -1153,7 +1154,7 @@ network: inSvcType: manifestinfo.WorkerServiceType, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1171,7 +1172,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockTopicSel: func(m *mocks.MocktopicSelector) { - m.EXPECT().Topics( + m.EXPECT().Topics(ctx, gomock.Eq(svcInitPublisherPrompt), gomock.Eq(svcInitPublisherHelpPrompt), gomock.Any(), @@ -1183,7 +1184,7 @@ network: }, nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", @@ -1196,7 +1197,7 @@ network: inSvcType: manifestinfo.BackendServiceType, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "backend", @@ -1208,7 +1209,7 @@ network: }, mockDockerfile: func(m *mocks.MockdockerfileParser) {}, // Be sure that no dockerfile parsing happens. mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", @@ -1221,7 +1222,7 @@ network: inSvcType: manifestinfo.LoadBalancedWebServiceType, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1233,7 +1234,7 @@ network: }, mockDockerfile: func(m *mocks.MockdockerfileParser) {}, // Be sure that no dockerfile parsing happens. mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return(nil, nil) + m.EXPECT().ListEnvironments(ctx, "sample").Return(nil, nil) }, wantedManifestPath: "manifest/path", @@ -1268,7 +1269,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("").Return(nil, errors.New("some error")) + m.EXPECT().ListEnvironments(ctx, "").Return(nil, errors.New("some error")) }, wantedErr: errors.New("list environments for application : some error"), }, @@ -1281,7 +1282,7 @@ network: inSvcPort: 80, mockSvcInit: func(m *mocks.MocksvcInitializer) { - m.EXPECT().Service(&initialize.ServiceProps{ + m.EXPECT().Service(ctx, &initialize.ServiceProps{ WorkloadProps: initialize.WorkloadProps{ App: "sample", Name: "frontend", @@ -1303,7 +1304,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return([]*config.Environment{ + m.EXPECT().ListEnvironments(ctx, "sample").Return([]*config.Environment{ { App: "sample", Name: "test", @@ -1330,7 +1331,7 @@ network: m.EXPECT().GetPlatform().Return("linux", "amd64", nil) }, mockStore: func(m *mocks.Mockstore) { - m.EXPECT().ListEnvironments("sample").Return([]*config.Environment{ + m.EXPECT().ListEnvironments(ctx, "sample").Return([]*config.Environment{ { App: "sample", Name: "test", @@ -1393,13 +1394,13 @@ network: store: mockStore, topicSel: mockTopicSel, manifestExists: tc.inManifestExists, - initEnvDescriber: func(string, string) (envDescriber, error) { + initEnvDescriber: func(_ context.Context, appName, envName string) (envDescriber, error) { return mockEnvDescriber, nil }, } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedErr == nil { diff --git a/internal/pkg/cli/svc_list.go b/internal/pkg/cli/svc_list.go index 4904155174e..df72fde7816 100644 --- a/internal/pkg/cli/svc_list.go +++ b/internal/pkg/cli/svc_list.go @@ -67,14 +67,14 @@ func (o *listSvcOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *listSvcOpts) Ask() error { +func (o *listSvcOpts) Ask(ctx context.Context) error { if o.appName != "" { // NOTE: Skip validating app name here because `Execute` will fail pretty soon with a clear error message. // The validation (config.GetApplication) would only add additional operation time in this particular case. return nil } - name, err := o.sel.Application(svcAppNamePrompt, wkldAppNameHelpPrompt) + name, err := o.sel.Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application name: %w", err) } @@ -83,8 +83,8 @@ func (o *listSvcOpts) Ask() error { } // Execute lists the services through the prompt. -func (o *listSvcOpts) Execute() error { - if err := o.list.Write(o.appName); err != nil { +func (o *listSvcOpts) Execute(ctx context.Context) error { + if err := o.list.Write(ctx, o.appName); err != nil { return err } @@ -105,10 +105,10 @@ func buildSvcListCmd() *cobra.Command { if err != nil { return err } - if err := opts.Ask(); err != nil { + if err := opts.Ask(cmd.Context()); err != nil { return err } - return opts.Execute() + return opts.Execute(cmd.Context()) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/svc_list_test.go b/internal/pkg/cli/svc_list_test.go index 128dfed1378..b94d50a11f2 100644 --- a/internal/pkg/cli/svc_list_test.go +++ b/internal/pkg/cli/svc_list_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "testing" @@ -33,7 +34,7 @@ func TestListSvcOpts_Execute(t *testing.T) { }, mocking: func() { mockLister.EXPECT(). - Write("coolapp"). + Write(ctx, "coolapp"). Return(nil) }, }, @@ -46,7 +47,7 @@ func TestListSvcOpts_Execute(t *testing.T) { }, mocking: func() { mockLister.EXPECT(). - Write(gomock.Eq("coolapp")). + Write(ctx, gomock.Eq("coolapp")). Return(mockError) }, expectedErr: fmt.Errorf("error"), @@ -55,7 +56,7 @@ func TestListSvcOpts_Execute(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { tc.mocking() - err := tc.opts.Execute() + err := tc.opts.Execute(context.Background()) if tc.expectedErr != nil { require.EqualError(t, tc.expectedErr, err.Error()) @@ -76,13 +77,13 @@ func TestListSvcOpts_Ask(t *testing.T) { }{ "with no flags set": { mockSel: func(m *mocks.MockappSelector) { - m.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("myapp", nil) + m.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("myapp", nil) }, wantedApp: "myapp", }, "with app flag set": { mockSel: func(m *mocks.MockappSelector) { - m.EXPECT().Application(gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Application(ctx, gomock.Any(), gomock.Any()).Times(0) }, inApp: "myapp", wantedApp: "myapp", @@ -104,7 +105,7 @@ func TestListSvcOpts_Ask(t *testing.T) { sel: mockSel, } - err := listApps.Ask() + err := listApps.Ask(context.Background()) require.NoError(t, err) require.Equal(t, tc.wantedApp, listApps.appName, "expected application names to match") diff --git a/internal/pkg/cli/svc_logs.go b/internal/pkg/cli/svc_logs.go index d6285048255..f646579f930 100644 --- a/internal/pkg/cli/svc_logs.go +++ b/internal/pkg/cli/svc_logs.go @@ -83,7 +83,7 @@ type wkldLogOpts struct { sel deploySelector logsSvc logEventsWriter ecs serviceDescriber - initRuntimeClients func() error // Overridden in tests. + initRuntimeClients func(context.Context) error // Overridden in tests. } func newSvcLogOpts(vars svcLogsVars) (*svcLogsOpts, error) { @@ -107,8 +107,8 @@ func newSvcLogOpts(vars svcLogsVars) (*svcLogsOpts, error) { sel: selector.NewDeploySelect(prompt.New(), configStore, deployStore), }, } - opts.initRuntimeClients = func() error { - env, err := opts.getTargetEnv() + opts.initRuntimeClients = func(ctx context.Context) error { + env, err := opts.getTargetEnv(ctx) if err != nil { return fmt.Errorf("get environment: %w", err) } @@ -119,6 +119,7 @@ func newSvcLogOpts(vars svcLogsVars) (*svcLogsOpts, error) { opts.ecs = ecs.New(cfg) newWorkloadLoggerOpts := &logging.NewWorkloadLoggerOpts{ + Ctx: ctx, App: opts.appName, Env: opts.envName, Name: opts.name, @@ -187,16 +188,16 @@ func (o *svcLogsOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *svcLogsOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *svcLogsOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - return o.validateAndAskSvcEnvName() + return o.validateAndAskSvcEnvName(ctx) } // Execute outputs logs of the service. -func (o *svcLogsOpts) Execute() error { - if err := o.initRuntimeClients(); err != nil { +func (o *svcLogsOpts) Execute(ctx context.Context) error { + if err := o.initRuntimeClients(ctx); err != nil { return err } eventsWriter := logging.WriteHumanLogs @@ -253,12 +254,12 @@ func (o *svcLogsOpts) latestStoppedTaskID() (string, error) { return "", noPreviousTasksErr } -func (o *svcLogsOpts) validateOrAskApp() error { +func (o *svcLogsOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.configStore.GetApplication(o.appName) + _, err := o.configStore.GetApplication(ctx, o.appName) return err } - app, err := o.sel.Application(svcAppNamePrompt, wkldAppNameHelpPrompt) + app, err := o.sel.Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -266,21 +267,21 @@ func (o *svcLogsOpts) validateOrAskApp() error { return nil } -func (o *svcLogsOpts) validateAndAskSvcEnvName() error { +func (o *svcLogsOpts) validateAndAskSvcEnvName(ctx context.Context) error { if o.envName != "" { - if _, err := o.getTargetEnv(); err != nil { + if _, err := o.getTargetEnv(ctx); err != nil { return err } } if o.name != "" { - if _, err := o.configStore.GetService(o.appName, o.name); err != nil { + if _, err := o.configStore.GetService(ctx, o.appName, o.name); err != nil { return err } } // Note: we let prompter handle the case when there is only option for user to choose from. // This is naturally the case when `o.envName != "" && o.name != ""`. - deployedService, err := o.sel.DeployedService(svcLogNamePrompt, svcLogNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.name)) + deployedService, err := o.sel.DeployedService(ctx, svcLogNamePrompt, svcLogNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.name)) if err != nil { return fmt.Errorf("select deployed services for application %s: %w", o.appName, err) } @@ -303,11 +304,11 @@ func (o *svcLogsOpts) validatePrevious() error { return nil } -func (o *svcLogsOpts) getTargetEnv() (*config.Environment, error) { +func (o *svcLogsOpts) getTargetEnv(ctx context.Context) (*config.Environment, error) { if o.targetEnv != nil { return o.targetEnv, nil } - env, err := o.configStore.GetEnvironment(o.appName, o.envName) + env, err := o.configStore.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return nil, err } @@ -354,7 +355,7 @@ func buildSvcLogsCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", svcFlagDescription) diff --git a/internal/pkg/cli/svc_logs_test.go b/internal/pkg/cli/svc_logs_test.go index 5e0119263d9..2e62afb0f72 100644 --- a/internal/pkg/cli/svc_logs_test.go +++ b/internal/pkg/cli/svc_logs_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -185,10 +186,10 @@ func TestSvcLogs_Ask(t *testing.T) { inputEnvName: inputEnv, setupMocks: func(m wkldLogsMock) { gomock.InOrder( - m.configStore.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil), - m.configStore.EXPECT().GetEnvironment("my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), - m.configStore.EXPECT().GetService("my-app", "my-svc").Return(&config.Workload{}, nil), - m.sel.EXPECT().DeployedService(svcLogNamePrompt, svcLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil), + m.configStore.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), + m.configStore.EXPECT().GetService(ctx, "my-app", "my-svc").Return(&config.Workload{}, nil), + m.sel.EXPECT().DeployedService(ctx, svcLogNamePrompt, svcLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -205,13 +206,13 @@ func TestSvcLogs_Ask(t *testing.T) { inputEnvName: inputEnv, setupMocks: func(m wkldLogsMock) { gomock.InOrder( - m.configStore.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil), - m.configStore.EXPECT().GetEnvironment("my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), - m.configStore.EXPECT().GetService("my-app", "my-svc").Return( + m.configStore.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil), + m.configStore.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), + m.configStore.EXPECT().GetService(ctx, "my-app", "my-svc").Return( &config.Workload{ Type: manifestinfo.StaticSiteType, }, nil)) - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedService{ + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", SvcType: manifestinfo.StaticSiteType, @@ -223,11 +224,11 @@ func TestSvcLogs_Ask(t *testing.T) { inputSvc: inputSvc, inputEnvName: inputEnv, setupMocks: func(m wkldLogsMock) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) - m.configStore.EXPECT().GetApplication(gomock.Any()).Times(0) - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedService{ + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", SvcType: manifestinfo.BackendServiceType, @@ -240,7 +241,7 @@ func TestSvcLogs_Ask(t *testing.T) { "returns error if fail to select app": { setupMocks: func(m wkldLogsMock) { gomock.InOrder( - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")), + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")), ) }, wantedError: fmt.Errorf("select application: some error"), @@ -248,10 +249,10 @@ func TestSvcLogs_Ask(t *testing.T) { "prompt for svc and env": { inputApp: "my-app", setupMocks: func(m wkldLogsMock) { - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.configStore.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(svcLogNamePrompt, svcLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.configStore.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, svcLogNamePrompt, svcLogNameHelpPrompt, "my-app", gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -264,10 +265,10 @@ func TestSvcLogs_Ask(t *testing.T) { "return error if fail to select deployed services": { inputApp: inputApp, setupMocks: func(m wkldLogsMock) { - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.configStore.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(svcLogNamePrompt, svcLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.configStore.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, svcLogNamePrompt, svcLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("select deployed services for application my-app: some error"), @@ -276,10 +277,10 @@ func TestSvcLogs_Ask(t *testing.T) { inputApp: inputApp, inputTaskIDs: []string{"mockTask1, mockTask2"}, setupMocks: func(m wkldLogsMock) { - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.configStore.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(svcLogNamePrompt, svcLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.configStore.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, svcLogNamePrompt, svcLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ SvcType: manifestinfo.RequestDrivenWebServiceType, }, nil) @@ -289,10 +290,10 @@ func TestSvcLogs_Ask(t *testing.T) { "return error if selected svc is of Static Site type": { inputApp: inputApp, setupMocks: func(m wkldLogsMock) { - m.configStore.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.configStore.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.configStore.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(svcLogNamePrompt, svcLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). + m.configStore.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.configStore.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.configStore.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, svcLogNamePrompt, svcLogNameHelpPrompt, inputApp, gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ SvcType: manifestinfo.StaticSiteType, }, nil) @@ -332,7 +333,7 @@ func TestSvcLogs_Ask(t *testing.T) { } // WHEN - err := svcLogs.Ask() + err := svcLogs.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -553,7 +554,7 @@ func TestSvcLogs_Execute(t *testing.T) { wkldLogOpts: wkldLogOpts{ startTime: &tc.startTime, endTime: &tc.endTime, - initRuntimeClients: func() error { return nil }, + initRuntimeClients: func(_ context.Context) error { return nil }, logsSvc: mockLogsSvc, configStore: mockConfigStoreReader, sel: mockSelector, @@ -563,7 +564,7 @@ func TestSvcLogs_Execute(t *testing.T) { } // WHEN - err := svcLogs.Execute() + err := svcLogs.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/svc_override.go b/internal/pkg/cli/svc_override.go index 37bb4ef2014..3d6d45c73f5 100644 --- a/internal/pkg/cli/svc_override.go +++ b/internal/pkg/cli/svc_override.go @@ -30,7 +30,7 @@ type overrideWorkloadOpts struct { // Interfaces to interact with dependencies. ws wsWlDirReader wsPrompt wsSelector - validateOrAskName func() error + validateOrAskName func(ctx context.Context) error } func newOverrideWorkloadOpts(vars overrideWorkloadVars) (*overrideWorkloadOpts, error) { @@ -83,36 +83,36 @@ func (o *overrideWorkloadOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *overrideWorkloadOpts) Ask() error { - if err := o.validateOrAskName(); err != nil { +func (o *overrideWorkloadOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskName(ctx); err != nil { return err } - return o.overrideOpts.Ask() + return o.overrideOpts.Ask(ctx) } // Execute writes IaC override files to the local workspace. // This method assumes that the IaC tool chosen by the user is valid. -func (o *overrideWorkloadOpts) Execute() error { +func (o *overrideWorkloadOpts) Execute(ctx context.Context) error { o.overrideOpts.dir = func() string { return o.ws.WorkloadOverridesPath(o.name) } - return o.overrideOpts.Execute() + return o.overrideOpts.Execute(ctx) } func (o *overrideWorkloadOpts) validateEnvName() error { if o.envName == "" { return nil } - _, err := o.cfgStore.GetEnvironment(o.appName, o.envName) + _, err := o.cfgStore.GetEnvironment(context.Background(), o.appName, o.envName) if err != nil { return fmt.Errorf("get environment %q configuration: %v", o.envName, err) } return nil } -func (o *overrideWorkloadOpts) validateOrAskServiceName() error { +func (o *overrideWorkloadOpts) validateOrAskServiceName(ctx context.Context) error { if o.name == "" { - return o.askServiceName() + return o.askServiceName(ctx) } return o.validateServiceName() } @@ -128,8 +128,8 @@ func (o *overrideWorkloadOpts) validateServiceName() error { return nil } -func (o *overrideWorkloadOpts) askServiceName() error { - name, err := o.wsPrompt.Service("Which service's resources would you like to override?", "") +func (o *overrideWorkloadOpts) askServiceName(ctx context.Context) error { + name, err := o.wsPrompt.Service(ctx, "Which service's resources would you like to override?", "") if err != nil { return fmt.Errorf("select service name from workspace: %v", err) } @@ -160,7 +160,7 @@ func (o *overrideWorkloadOpts) targetEnvName() (string, error) { if o.envName != "" { return o.envName, nil } - envs, err := o.cfgStore.ListEnvironments(o.appName) + envs, err := o.cfgStore.ListEnvironments(context.Background(), o.appName) if err != nil { return "", fmt.Errorf("list environments in application %q: %v", o.appName, err) } @@ -187,7 +187,7 @@ or add new resources to the service's template.`, if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", svcFlagDescription) diff --git a/internal/pkg/cli/svc_override_test.go b/internal/pkg/cli/svc_override_test.go index 32f78e0776f..1803252cdc9 100644 --- a/internal/pkg/cli/svc_override_test.go +++ b/internal/pkg/cli/svc_override_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "path/filepath" @@ -32,7 +33,7 @@ func TestOverrideSvc_Validate(t *testing.T) { appName: "demo", initMocks: func(ctrl *gomock.Controller, cmd *overrideWorkloadOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).Return(nil, errors.New("some error")) + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, errors.New("some error")) cmd.cfgStore = mockSSM }, wanted: errors.New(`get application "demo" configuration: some error`), @@ -76,7 +77,7 @@ func TestOverrideSvc_Validate(t *testing.T) { "skip validating if environment name is empty": { initMocks: func(ctrl *gomock.Controller, cmd *overrideWorkloadOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() cmd.cfgStore = mockSSM }, }, @@ -84,8 +85,8 @@ func TestOverrideSvc_Validate(t *testing.T) { envName: "test", initMocks: func(ctrl *gomock.Controller, cmd *overrideWorkloadOpts) { mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).AnyTimes() - mockSSM.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Return(nil, &config.ErrNoSuchEnvironment{}) + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + mockSSM.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Return(nil, &config.ErrNoSuchEnvironment{}) cmd.cfgStore = mockSSM }, wanted: errors.New(`get environment "test" configuration`), @@ -139,7 +140,7 @@ func TestOverrideSvc_Validate(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockSSM := mocks.NewMockstore(ctrl) - mockSSM.EXPECT().GetApplication(gomock.Any()).Return(nil, nil) + mockSSM.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, nil) vars := overrideVars{appName: "demo", cdkLang: tc.lang} cmd := &overrideWorkloadOpts{ @@ -201,7 +202,7 @@ func TestOverrideSvc_Ask(t *testing.T) { name: "", initMocks: func(ctrl *gomock.Controller, cmd *overrideWorkloadOpts) { mockPrompt := mocks.NewMockwsSelector(ctrl) - mockPrompt.EXPECT().Service(gomock.Any(), gomock.Any()) + mockPrompt.EXPECT().Service(ctx, gomock.Any(), gomock.Any()) cmd.wsPrompt = mockPrompt }, }, @@ -222,7 +223,7 @@ func TestOverrideSvc_Ask(t *testing.T) { cfnPrompt: mockCfnPrompt, packageCmd: func(_ stringWriteCloser) (executor, error) { mockCmd := mocks.NewMockexecutor(ctrl) - mockCmd.EXPECT().Execute().AnyTimes() + mockCmd.EXPECT().Execute(gomock.Any()).AnyTimes() return mockCmd, nil }, spinner: &spinnerTestDouble{}, @@ -232,7 +233,7 @@ func TestOverrideSvc_Ask(t *testing.T) { tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { @@ -285,7 +286,7 @@ func TestOverrideSvc_Ask(t *testing.T) { cfnPrompt: mockCfnPrompt, packageCmd: func(_ stringWriteCloser) (executor, error) { mockCmd := mocks.NewMockexecutor(ctrl) - mockCmd.EXPECT().Execute().AnyTimes() + mockCmd.EXPECT().Execute(gomock.Any()).AnyTimes() return mockCmd, nil }, spinner: &spinnerTestDouble{}, @@ -298,7 +299,7 @@ func TestOverrideSvc_Ask(t *testing.T) { } // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { @@ -334,7 +335,7 @@ func TestOverrideSvc_Ask(t *testing.T) { "should return a wrapped error if package command fails to execute": { initMocks: func(ctrl *gomock.Controller, cmd *overrideWorkloadOpts) { mockPkgCmd := mocks.NewMockexecutor(ctrl) - mockPkgCmd.EXPECT().Execute().Return(errors.New("some error")) + mockPkgCmd.EXPECT().Execute(gomock.Any()).Return(errors.New("some error")) cmd.packageCmd = func(_ stringWriteCloser) (executor, error) { return mockPkgCmd, nil } @@ -344,7 +345,7 @@ func TestOverrideSvc_Ask(t *testing.T) { "should prompt for CloudFormation resources in a template": { initMocks: func(ctrl *gomock.Controller, cmd *overrideWorkloadOpts) { mockPkgCmd := mocks.NewMockexecutor(ctrl) - mockPkgCmd.EXPECT().Execute().Return(nil) + mockPkgCmd.EXPECT().Execute(gomock.Any()).Return(nil) mockPrompt := mocks.NewMockcfnSelector(ctrl) template := ` Resources: @@ -386,7 +387,7 @@ Resources: tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Ask() + err := cmd.Ask(context.Background()) // THEN if tc.wanted != nil { @@ -460,7 +461,7 @@ func TestOverrideSvc_Execute(t *testing.T) { tc.initMocks(ctrl, cmd) // WHEN - err := cmd.Execute() + err := cmd.Execute(context.Background()) // THEN if tc.wanted != nil { diff --git a/internal/pkg/cli/svc_package.go b/internal/pkg/cli/svc_package.go index 79b2c8818b6..52593cd3428 100644 --- a/internal/pkg/cli/svc_package.go +++ b/internal/pkg/cli/svc_package.go @@ -66,7 +66,7 @@ type packageSvcOpts struct { sel wsSelector unmarshal func([]byte) (manifest.DynamicWorkload, error) newInterpolator func(app, env string) interpolator - newStackGenerator func(*packageSvcOpts) (workloadStackGenerator, error) + newStackGenerator func(context.Context, *packageSvcOpts) (workloadStackGenerator, error) envFeaturesDescriber versionCompatibilityChecker gitShortCommit string @@ -117,12 +117,12 @@ func newPackageSvcOpts(vars packageSvcVars) (*packageSvcOpts, error) { return opts, nil } -func newWorkloadStackGenerator(o *packageSvcOpts) (workloadStackGenerator, error) { - targetApp, err := o.getTargetApp() +func newWorkloadStackGenerator(ctx context.Context, o *packageSvcOpts) (workloadStackGenerator, error) { + targetApp, err := o.getTargetApp(ctx) if err != nil { return nil, err } - targetEnv, err := o.getTargetEnv() + targetEnv, err := o.getTargetEnv(ctx) if err != nil { return nil, err } @@ -134,6 +134,7 @@ func newWorkloadStackGenerator(o *packageSvcOpts) (workloadStackGenerator, error content := o.appliedDynamicMft.Manifest() var deployer workloadStackGenerator in := clideploy.WorkloadDeployerInput{ + Ctx: ctx, SessionProvider: o.sessProvider, Name: o.name, App: targetApp, @@ -175,28 +176,28 @@ func (o *packageSvcOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *packageSvcOpts) Ask() error { +func (o *packageSvcOpts) Ask(ctx context.Context) error { if o.appName != "" { - if _, err := o.getTargetApp(); err != nil { + if _, err := o.getTargetApp(ctx); err != nil { return err } } else { // NOTE: This command is required to be executed under a workspace. We don't prompt for it. return errNoAppInWorkspace } - if err := o.validateOrAskSvcName(); err != nil { + if err := o.validateOrAskSvcName(ctx); err != nil { return err } - if err := o.validateOrAskEnvName(); err != nil { + if err := o.validateOrAskEnvName(ctx); err != nil { return err } return nil } // Execute prints the CloudFormation template of the application for the environment. -func (o *packageSvcOpts) Execute() error { +func (o *packageSvcOpts) Execute(ctx context.Context) error { if !o.clientConfigured { - if err := o.configureClients(); err != nil { + if err := o.configureClients(ctx); err != nil { return err } } @@ -210,15 +211,15 @@ func (o *packageSvcOpts) Execute() error { return err } } - targetEnv, err := o.getTargetEnv() + targetEnv, err := o.getTargetEnv(ctx) if err != nil { return nil } - gen, err := o.getStackGenerator(targetEnv) + gen, err := o.getStackGenerator(ctx, targetEnv) if err != nil { return err } - stack, err := o.getWorkloadStack(gen) + stack, err := o.getWorkloadStack(ctx, gen) if err != nil { return err } @@ -256,7 +257,7 @@ func (o *packageSvcOpts) Execute() error { return o.writeAndClose(o.addonsWriter, addonsTemplate) } -func (o *packageSvcOpts) validateOrAskSvcName() error { +func (o *packageSvcOpts) validateOrAskSvcName(ctx context.Context) error { if o.name != "" { names, err := o.ws.ListServices() if err != nil { @@ -268,7 +269,7 @@ func (o *packageSvcOpts) validateOrAskSvcName() error { return nil } - name, err := o.sel.Service(svcPackageSvcNamePrompt, "") + name, err := o.sel.Service(ctx, svcPackageSvcNamePrompt, "") if err != nil { return fmt.Errorf("select service: %w", err) } @@ -276,13 +277,13 @@ func (o *packageSvcOpts) validateOrAskSvcName() error { return nil } -func (o *packageSvcOpts) validateOrAskEnvName() error { +func (o *packageSvcOpts) validateOrAskEnvName(ctx context.Context) error { if o.envName != "" { - _, err := o.getTargetEnv() + _, err := o.getTargetEnv(ctx) return err } - name, err := o.sel.Environment(svcPackageEnvNamePrompt, "", o.appName) + name, err := o.sel.Environment(ctx, svcPackageEnvNamePrompt, "", o.appName) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -290,14 +291,14 @@ func (o *packageSvcOpts) validateOrAskEnvName() error { return nil } -func (o *packageSvcOpts) configureClients() error { +func (o *packageSvcOpts) configureClients(ctx context.Context) error { o.gitShortCommit = imageTagFromGit(o.runner) // Best effort assign git tag. // client to retrieve an application's resources created with CloudFormation. defaultConfig, err := o.sessProvider.DefaultConfig(context.Background()) if err != nil { return fmt.Errorf("create default config: %w", err) } - targetEnv, err := o.getTargetEnv() + targetEnv, err := o.getTargetEnv(ctx) if err != nil { return err } @@ -307,13 +308,13 @@ func (o *packageSvcOpts) configureClients() error { } o.envConfig = envConfig // client to retrieve caller identity. - caller, err := identity.New(defaultConfig).Get() + caller, err := identity.New(defaultConfig).Get(ctx) if err != nil { return fmt.Errorf("get identity: %w", err) } o.rootUserARN = caller.RootUserARN - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: o.appName, Env: o.envName, ConfigStore: o.store, @@ -323,7 +324,7 @@ func (o *packageSvcOpts) configureClients() error { } o.envFeaturesDescriber = envDescriber - wkldDescriber, err := describe.NewWorkloadStackDescriber(describe.NewWorkloadConfig{ + wkldDescriber, err := describe.NewWorkloadStackDescriber(ctx, describe.NewWorkloadConfig{ App: o.appName, Env: o.envName, Name: o.name, @@ -341,7 +342,7 @@ type cfnStackConfig struct { parameters string } -func (o *packageSvcOpts) getStackGenerator(env *config.Environment) (workloadStackGenerator, error) { +func (o *packageSvcOpts) getStackGenerator(ctx context.Context, env *config.Environment) (workloadStackGenerator, error) { mft, interpolated, err := workloadManifest(&workloadManifestInput{ name: o.name, appName: o.appName, @@ -359,12 +360,12 @@ func (o *packageSvcOpts) getStackGenerator(env *config.Environment) (workloadSta if err := validateWorkloadManifestCompatibilityWithEnv(o.ws, o.envFeaturesDescriber, o.appliedDynamicMft, o.envName); err != nil { return nil, err } - return o.newStackGenerator(o) + return o.newStackGenerator(ctx, o) } // getWorkloadStack returns the CloudFormation stack's template and its parameters for the service. -func (o *packageSvcOpts) getWorkloadStack(generator workloadStackGenerator) (*cfnStackConfig, error) { - targetApp, err := o.getTargetApp() +func (o *packageSvcOpts) getWorkloadStack(ctx context.Context, generator workloadStackGenerator) (*cfnStackConfig, error) { + targetApp, err := o.getTargetApp(ctx) if err != nil { return nil, err } @@ -433,11 +434,11 @@ func (o *packageSvcOpts) setAddonsFileWriter() error { return nil } -func (o *packageSvcOpts) getTargetApp() (*config.Application, error) { +func (o *packageSvcOpts) getTargetApp(ctx context.Context) (*config.Application, error) { if o.targetApp != nil { return o.targetApp, nil } - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { return nil, fmt.Errorf("get application %s configuration: %w", o.appName, err) } @@ -445,11 +446,11 @@ func (o *packageSvcOpts) getTargetApp() (*config.Application, error) { return o.targetApp, nil } -func (o *packageSvcOpts) getTargetEnv() (*config.Environment, error) { +func (o *packageSvcOpts) getTargetEnv(ctx context.Context) (*config.Environment, error) { if o.targetEnv != nil { return o.targetEnv, nil } - env, err := o.store.GetEnvironment(o.appName, o.envName) + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return nil, fmt.Errorf("get environment %s: %w", o.envName, err) } @@ -509,7 +510,7 @@ func buildSvcPackageCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.name, nameFlag, nameFlagShort, "", svcFlagDescription) diff --git a/internal/pkg/cli/svc_package_test.go b/internal/pkg/cli/svc_package_test.go index 52c21884fbc..cef22561017 100644 --- a/internal/pkg/cli/svc_package_test.go +++ b/internal/pkg/cli/svc_package_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "io" @@ -43,11 +44,11 @@ func TestPackageSvcOpts_Ask(t *testing.T) { inEnvName: "prod-iad", inSvcName: "frontend", setupMocks: func(m svcPackageAskMock) { - m.store.EXPECT().GetApplication("phonetool") - m.store.EXPECT().GetEnvironment("phonetool", "prod-iad").Return(&config.Environment{Name: "prod-iad"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool") + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "prod-iad").Return(&config.Environment{Name: "prod-iad"}, nil) m.ws.EXPECT().ListServices().Return([]string{"frontend"}, nil) - m.sel.EXPECT().Service(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().Service(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedAppName: "phonetool", wantedSvcName: "frontend", @@ -55,7 +56,7 @@ func TestPackageSvcOpts_Ask(t *testing.T) { }, "error instead of prompting for application name if not provided": { setupMocks: func(m svcPackageAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) }, wantedError: errNoAppInWorkspace, }, @@ -63,11 +64,11 @@ func TestPackageSvcOpts_Ask(t *testing.T) { inAppName: "phonetool", inEnvName: "test", setupMocks: func(m svcPackageAskMock) { - m.sel.EXPECT().Service("Which service would you like to generate a CloudFormation template for?", ""). + m.sel.EXPECT().Service(ctx, "Which service would you like to generate a CloudFormation template for?", ""). Return("frontend", nil) m.ws.EXPECT().ListServices().Times(0) - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() }, wantedAppName: "phonetool", wantedSvcName: "frontend", @@ -78,9 +79,9 @@ func TestPackageSvcOpts_Ask(t *testing.T) { inSvcName: "frontend", setupMocks: func(m svcPackageAskMock) { - m.sel.EXPECT().Environment(gomock.Any(), gomock.Any(), "phonetool").Return("prod-iad", nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetApplication("phonetool").AnyTimes() + m.sel.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), "phonetool").Return("prod-iad", nil) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetApplication(ctx, "phonetool").AnyTimes() m.ws.EXPECT().ListServices().Return([]string{"frontend"}, nil).AnyTimes() }, wantedAppName: "phonetool", @@ -114,7 +115,7 @@ func TestPackageSvcOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -364,7 +365,7 @@ count: 1` newInterpolator: func(_, _ string) interpolator { return m.interpolator }, - newStackGenerator: func(_ *packageSvcOpts) (workloadStackGenerator, error) { + newStackGenerator: func(_ context.Context, _ *packageSvcOpts) (workloadStackGenerator, error) { return m.generator, nil }, envFeaturesDescriber: m.envFeaturesDescriber, @@ -373,7 +374,7 @@ count: 1` } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedErr != nil { diff --git a/internal/pkg/cli/svc_pause.go b/internal/pkg/cli/svc_pause.go index 5d76ffbdc6e..fdb2d323790 100644 --- a/internal/pkg/cli/svc_pause.go +++ b/internal/pkg/cli/svc_pause.go @@ -47,7 +47,7 @@ type svcPauseOpts struct { prompt prompter sel deploySelector client servicePauser - initSvcPause func() error + initSvcPause func(ctx context.Context) error svcARN string prog progress @@ -75,12 +75,12 @@ func newSvcPauseOpts(vars svcPauseVars) (*svcPauseOpts, error) { sel: selector.NewDeploySelect(prompt.New(), configStore, deployStore), prog: termprogress.NewSpinner(log.DiagnosticWriter), } - opts.initSvcPause = func() error { - env, err := opts.getTargetEnv() + opts.initSvcPause = func(ctx context.Context) error { + env, err := opts.getTargetEnv(ctx) if err != nil { return err } - wl, err := configStore.GetWorkload(opts.appName, opts.svcName) + wl, err := configStore.GetWorkload(ctx, opts.appName, opts.svcName) if err != nil { return fmt.Errorf("get workload: %w", err) } @@ -92,7 +92,7 @@ func newSvcPauseOpts(vars svcPauseVars) (*svcPauseOpts, error) { return err } opts.client = apprunner.New(cfg) - d, err := describe.NewRDWebServiceDescriber(describe.NewServiceConfig{ + d, err := describe.NewRDWebServiceDescriber(ctx, describe.NewServiceConfig{ App: opts.appName, Svc: opts.svcName, ConfigStore: opts.store, @@ -115,11 +115,11 @@ func (o *svcPauseOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *svcPauseOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *svcPauseOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - if err := o.validateAndAskSvcEnvName(); err != nil { + if err := o.validateAndAskSvcEnvName(ctx); err != nil { return err } @@ -137,12 +137,12 @@ func (o *svcPauseOpts) Ask() error { return nil } -func (o *svcPauseOpts) validateOrAskApp() error { +func (o *svcPauseOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.store.GetApplication(o.appName) + _, err := o.store.GetApplication(ctx, o.appName) return err } - app, err := o.sel.Application(svcPauseAppNamePrompt, wkldAppNameHelpPrompt) + app, err := o.sel.Application(ctx, svcPauseAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -150,22 +150,22 @@ func (o *svcPauseOpts) validateOrAskApp() error { return nil } -func (o *svcPauseOpts) validateAndAskSvcEnvName() error { +func (o *svcPauseOpts) validateAndAskSvcEnvName(ctx context.Context) error { if o.envName != "" { - if _, err := o.getTargetEnv(); err != nil { + if _, err := o.getTargetEnv(ctx); err != nil { return err } } if o.svcName != "" { - if _, err := o.store.GetService(o.appName, o.svcName); err != nil { + if _, err := o.store.GetService(ctx, o.appName, o.svcName); err != nil { return err } } // Note: we let prompter handle the case when there is only option for user to choose from. // This is naturally the case when `o.envName != "" && o.svcName != ""`. - deployedService, err := o.sel.DeployedService( + deployedService, err := o.sel.DeployedService(ctx, fmt.Sprintf(svcPauseNamePrompt, color.HighlightUserInput(o.appName)), svcPauseSvcNameHelpPrompt, o.appName, @@ -182,8 +182,8 @@ func (o *svcPauseOpts) validateAndAskSvcEnvName() error { } // Execute pause the running App Runner service. -func (o *svcPauseOpts) Execute() error { - if err := o.initSvcPause(); err != nil { +func (o *svcPauseOpts) Execute(ctx context.Context) error { + if err := o.initSvcPause(ctx); err != nil { return err } @@ -199,11 +199,11 @@ func (o *svcPauseOpts) Execute() error { return nil } -func (o *svcPauseOpts) getTargetEnv() (*config.Environment, error) { +func (o *svcPauseOpts) getTargetEnv(ctx context.Context) (*config.Environment, error) { if o.targetEnv != nil { return o.targetEnv, nil } - env, err := o.store.GetEnvironment(o.appName, o.envName) + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return nil, fmt.Errorf("get environment: %w", err) } @@ -235,7 +235,7 @@ func buildSvcPauseCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.svcName, nameFlag, nameFlagShort, "", svcFlagDescription) diff --git a/internal/pkg/cli/svc_pause_test.go b/internal/pkg/cli/svc_pause_test.go index fb635c06e4c..dd660fecf4c 100644 --- a/internal/pkg/cli/svc_pause_test.go +++ b/internal/pkg/cli/svc_pause_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -56,11 +57,11 @@ func TestSvcPause_Ask(t *testing.T) { skipConfirmation: true, setupMocks: func(m svcPauseAskMock) { gomock.InOrder( - m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil), - m.store.EXPECT().GetEnvironment("my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), - m.store.EXPECT().GetService("my-app", "my-svc").Return(&config.Workload{}, nil), + m.store.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil), + m.store.EXPECT().GetEnvironment(ctx, "my-app", "my-env").Return(&config.Environment{Name: "my-env"}, nil), + m.store.EXPECT().GetService(ctx, "my-app", "my-svc").Return(&config.Workload{}, nil), ) - m.sel.EXPECT().DeployedService(fmt.Sprintf(svcPauseNamePrompt, inputApp), svcPauseSvcNameHelpPrompt, "my-app", gomock.Any(), gomock.Any(), gomock.Any()). + m.sel.EXPECT().DeployedService(ctx, fmt.Sprintf(svcPauseNamePrompt, inputApp), svcPauseSvcNameHelpPrompt, "my-app", gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -76,11 +77,11 @@ func TestSvcPause_Ask(t *testing.T) { inputEnvironment: inputEnv, skipConfirmation: true, setupMocks: func(m svcPauseAskMock) { - m.sel.EXPECT().Application(svcPauseAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) - m.store.EXPECT().GetApplication(gomock.Any()).Times(0) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + m.sel.EXPECT().Application(ctx, svcPauseAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -94,7 +95,7 @@ func TestSvcPause_Ask(t *testing.T) { "errors if failed to select application": { skipConfirmation: true, setupMocks: func(m svcPauseAskMock) { - m.sel.EXPECT().Application(svcPauseAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) + m.sel.EXPECT().Application(ctx, svcPauseAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) }, wantedError: fmt.Errorf("select application: some error"), }, @@ -102,10 +103,10 @@ func TestSvcPause_Ask(t *testing.T) { inputApp: "my-app", skipConfirmation: true, setupMocks: func(m svcPauseAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(fmt.Sprintf(svcPauseNamePrompt, inputApp), svcPauseSvcNameHelpPrompt, "my-app", gomock.Any(), gomock.Any(), gomock.Any()). + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, fmt.Sprintf(svcPauseNamePrompt, inputApp), svcPauseSvcNameHelpPrompt, "my-app", gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -119,10 +120,10 @@ func TestSvcPause_Ask(t *testing.T) { inputApp: inputApp, skipConfirmation: true, setupMocks: func(m svcPauseAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(fmt.Sprintf(svcPauseNamePrompt, inputApp), svcPauseSvcNameHelpPrompt, inputApp, gomock.Any(), gomock.Any(), gomock.Any()). + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, fmt.Sprintf(svcPauseNamePrompt, inputApp), svcPauseSvcNameHelpPrompt, inputApp, gomock.Any(), gomock.Any(), gomock.Any()). Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("select deployed services for application my-app: some error"), @@ -133,10 +134,10 @@ func TestSvcPause_Ask(t *testing.T) { inputEnvironment: "mockEnv", skipConfirmation: false, setupMocks: func(m svcPauseAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -152,10 +153,10 @@ func TestSvcPause_Ask(t *testing.T) { inputEnvironment: "mockEnv", skipConfirmation: false, setupMocks: func(m svcPauseAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -171,10 +172,10 @@ func TestSvcPause_Ask(t *testing.T) { inputEnvironment: inputEnv, skipConfirmation: false, setupMocks: func(m svcPauseAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "my-env", Name: "my-svc", @@ -213,7 +214,7 @@ func TestSvcPause_Ask(t *testing.T) { } // WHEN - err := svcPause.Ask() + err := svcPause.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -271,11 +272,11 @@ func TestSvcPause_Execute(t *testing.T) { store: mockStore, client: mockServicePauser, prog: mockProgress, - initSvcPause: func() error { return nil }, + initSvcPause: func(_ context.Context) error { return nil }, } // WHEN - err := svcPause.Execute() + err := svcPause.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/svc_resume.go b/internal/pkg/cli/svc_resume.go index 1af64552994..9fef6f7893d 100644 --- a/internal/pkg/cli/svc_resume.go +++ b/internal/pkg/cli/svc_resume.go @@ -36,7 +36,7 @@ type resumeSvcVars struct { envName string } -type resumeSvcInitClients func() error +type resumeSvcInitClients func(ctx context.Context) error type resumeSvcOpts struct { resumeSvcVars @@ -54,19 +54,19 @@ func (o *resumeSvcOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *resumeSvcOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *resumeSvcOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - return o.validateAndAskSvcEnvName() + return o.validateAndAskSvcEnvName(ctx) } // Execute resumes the service through the prompt. -func (o *resumeSvcOpts) Execute() error { +func (o *resumeSvcOpts) Execute(ctx context.Context) error { if o.svcName == "" { return nil } - if err := o.initClients(); err != nil { + if err := o.initClients(ctx); err != nil { return err } svcARN, err := o.apprunnerDescriber.ServiceARN(o.envName) @@ -83,12 +83,12 @@ func (o *resumeSvcOpts) Execute() error { return nil } -func (o *resumeSvcOpts) validateOrAskApp() error { +func (o *resumeSvcOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.store.GetApplication(o.appName) + _, err := o.store.GetApplication(ctx, o.appName) return err } - appName, err := o.sel.Application(svcAppNamePrompt, wkldAppNameHelpPrompt) + appName, err := o.sel.Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -97,21 +97,21 @@ func (o *resumeSvcOpts) validateOrAskApp() error { return nil } -func (o *resumeSvcOpts) validateAndAskSvcEnvName() error { +func (o *resumeSvcOpts) validateAndAskSvcEnvName(ctx context.Context) error { if o.envName != "" { - if _, err := o.store.GetEnvironment(o.appName, o.envName); err != nil { + if _, err := o.store.GetEnvironment(ctx, o.appName, o.envName); err != nil { return err } } if o.svcName != "" { - if _, err := o.store.GetService(o.appName, o.svcName); err != nil { + if _, err := o.store.GetService(ctx, o.appName, o.svcName); err != nil { return err } } // Note: we let prompter handle the case when there is only option for user to choose from. // This is naturally the case when `o.envName != "" && o.svcName != ""`. - deployedService, err := o.sel.DeployedService( + deployedService, err := o.sel.DeployedService(ctx, fmt.Sprintf(svcResumeSvcNamePrompt, color.HighlightUserInput(o.appName)), svcResumeSvcNameHelpPrompt, o.appName, @@ -146,14 +146,14 @@ func newResumeSvcOpts(vars resumeSvcVars) (*resumeSvcOpts, error) { sel: selector.NewDeploySelect(prompt.New(), configStore, deployStore), spinner: termprogress.NewSpinner(log.DiagnosticWriter), } - opts.initClients = func() error { + opts.initClients = func(ctx context.Context) error { var a *apprunner.AppRunner var d *describe.RDWebServiceDescriber - env, err := configStore.GetEnvironment(opts.appName, opts.envName) + env, err := configStore.GetEnvironment(ctx, opts.appName, opts.envName) if err != nil { return fmt.Errorf("get environment: %w", err) } - svc, err := opts.store.GetService(opts.appName, opts.svcName) + svc, err := opts.store.GetService(ctx, opts.appName, opts.svcName) if err != nil { return err } @@ -164,7 +164,7 @@ func newResumeSvcOpts(vars resumeSvcVars) (*resumeSvcOpts, error) { return err } a = apprunner.New(cfg) - d, err = describe.NewRDWebServiceDescriber(describe.NewServiceConfig{ + d, err = describe.NewRDWebServiceDescriber(ctx, describe.NewServiceConfig{ App: opts.appName, Svc: opts.svcName, ConfigStore: configStore, @@ -201,7 +201,7 @@ func buildSvcResumeCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/svc_resume_test.go b/internal/pkg/cli/svc_resume_test.go index ff31d211924..5e4142bc518 100644 --- a/internal/pkg/cli/svc_resume_test.go +++ b/internal/pkg/cli/svc_resume_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "testing" @@ -53,11 +54,11 @@ func TestResumeSvcOpts_Ask(t *testing.T) { inputEnv: testEnvName, setupMocks: func(m svcResumeAskMock) { gomock.InOrder( - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil), - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test"}, nil), - m.store.EXPECT().GetService("phonetool", "api").Return(&config.Workload{}, nil), + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil), + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test"}, nil), + m.store.EXPECT().GetService(ctx, "phonetool", "api").Return(&config.Workload{}, nil), ) - m.sel.EXPECT().DeployedService(fmt.Sprintf(svcResumeSvcNamePrompt, testAppName), svcResumeSvcNameHelpPrompt, "phonetool", gomock.Any(), gomock.Any(), gomock.Any()). + m.sel.EXPECT().DeployedService(ctx, fmt.Sprintf(svcResumeSvcNamePrompt, testAppName), svcResumeSvcNameHelpPrompt, "phonetool", gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "test", Name: "api", @@ -72,11 +73,11 @@ func TestResumeSvcOpts_Ask(t *testing.T) { inputSvc: testSvcName, skipConfirmation: true, setupMocks: func(m svcResumeAskMock) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("phonetool", nil) - m.store.EXPECT().GetApplication(gomock.Any()).Times(0) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("phonetool", nil) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: testEnvName, Name: testSvcName, @@ -89,7 +90,7 @@ func TestResumeSvcOpts_Ask(t *testing.T) { "errors if failed to select application": { skipConfirmation: true, setupMocks: func(m svcResumeAskMock) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) }, wantedError: fmt.Errorf("select application: some error"), }, @@ -99,10 +100,10 @@ func TestResumeSvcOpts_Ask(t *testing.T) { inputSvc: "", skipConfirmation: true, setupMocks: func(m svcResumeAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService("Which service of phonetool would you like to resume?", + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, "Which service of phonetool would you like to resume?", svcResumeSvcNameHelpPrompt, testAppName, gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: testEnvName, @@ -120,10 +121,10 @@ func TestResumeSvcOpts_Ask(t *testing.T) { skipConfirmation: true, setupMocks: func(m svcResumeAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService("Which service of phonetool would you like to resume?", + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, "Which service of phonetool would you like to resume?", svcResumeSvcNameHelpPrompt, testAppName, gomock.Any(), gomock.Any(), gomock.Any()). Return(nil, mockError) }, @@ -151,7 +152,7 @@ func TestResumeSvcOpts_Ask(t *testing.T) { store: m.store, } - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if test.wantedError != nil { @@ -260,13 +261,13 @@ func TestResumeSvcOpts_Execute(t *testing.T) { spinner: mockSpinner, serviceResumer: mockserviceResumer, apprunnerDescriber: mockapprunnerDescriber, - initClients: func() error { + initClients: func(_ context.Context) error { return nil }, } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if test.wantedError != nil { diff --git a/internal/pkg/cli/svc_show.go b/internal/pkg/cli/svc_show.go index 396f1927bb7..7eb8f3fd7c8 100644 --- a/internal/pkg/cli/svc_show.go +++ b/internal/pkg/cli/svc_show.go @@ -44,7 +44,7 @@ type showSvcOpts struct { store store describer workloadDescriber sel configSelector - initDescriber func() error // Overridden in tests. + initDescriber func(ctx context.Context) error // Overridden in tests. // Cached variables. targetSvc *config.Workload @@ -69,9 +69,9 @@ func newShowSvcOpts(vars showSvcVars) (*showSvcOpts, error) { w: log.OutputWriter, sel: selector.NewConfigSelector(prompt.New(), ssmStore), } - opts.initDescriber = func() error { + opts.initDescriber = func(ctx context.Context) error { var d workloadDescriber - svc, err := opts.getTargetSvc() + svc, err := opts.getTargetSvc(ctx) if err != nil { return err } @@ -84,15 +84,15 @@ func newShowSvcOpts(vars showSvcVars) (*showSvcOpts, error) { } switch svc.Type { case manifestinfo.LoadBalancedWebServiceType: - d, err = describe.NewLBWebServiceDescriber(config) + d, err = describe.NewLBWebServiceDescriber(ctx, config) case manifestinfo.RequestDrivenWebServiceType: - d, err = describe.NewRDWebServiceDescriber(config) + d, err = describe.NewRDWebServiceDescriber(ctx, config) case manifestinfo.BackendServiceType: - d, err = describe.NewBackendServiceDescriber(config) + d, err = describe.NewBackendServiceDescriber(ctx, config) case manifestinfo.WorkerServiceType: - d, err = describe.NewWorkerServiceDescriber(config) + d, err = describe.NewWorkerServiceDescriber(ctx, config) case manifestinfo.StaticSiteType: - d, err = describe.NewStaticSiteDescriber(config) + d, err = describe.NewStaticSiteDescriber(ctx, config) default: return fmt.Errorf(`service type %q is not supported for %s`, svc.Type, color.HighlightCode("svc show")) } @@ -112,19 +112,19 @@ func (o *showSvcOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *showSvcOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *showSvcOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - return o.validateOrAskSvcName() + return o.validateOrAskSvcName(ctx) } // Execute shows the services through the prompt. -func (o *showSvcOpts) Execute() error { +func (o *showSvcOpts) Execute(ctx context.Context) error { if o.svcName == "" { return nil } - if err := o.initDescriber(); err != nil { + if err := o.initDescriber(ctx); err != nil { return err } @@ -149,12 +149,12 @@ func (o *showSvcOpts) Execute() error { return nil } -func (o *showSvcOpts) validateOrAskApp() error { +func (o *showSvcOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.store.GetApplication(o.appName) + _, err := o.store.GetApplication(ctx, o.appName) return err } - appName, err := o.sel.Application(svcAppNamePrompt, wkldAppNameHelpPrompt) + appName, err := o.sel.Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application name: %w", err) } @@ -162,12 +162,12 @@ func (o *showSvcOpts) validateOrAskApp() error { return nil } -func (o *showSvcOpts) validateOrAskSvcName() error { +func (o *showSvcOpts) validateOrAskSvcName(ctx context.Context) error { if o.svcName != "" { - _, err := o.getTargetSvc() + _, err := o.getTargetSvc(ctx) return err } - svcName, err := o.sel.Service(fmt.Sprintf(svcShowSvcNamePrompt, color.HighlightUserInput(o.appName)), + svcName, err := o.sel.Service(ctx, fmt.Sprintf(svcShowSvcNamePrompt, color.HighlightUserInput(o.appName)), svcShowSvcNameHelpPrompt, o.appName) if err != nil { return fmt.Errorf("select service for application %s: %w", o.appName, err) @@ -177,11 +177,11 @@ func (o *showSvcOpts) validateOrAskSvcName() error { return nil } -func (o *showSvcOpts) getTargetSvc() (*config.Workload, error) { +func (o *showSvcOpts) getTargetSvc(ctx context.Context) (*config.Workload, error) { if o.targetSvc != nil { return o.targetSvc, nil } - svc, err := o.store.GetService(o.appName, o.svcName) + svc, err := o.store.GetService(ctx, o.appName, o.svcName) if err != nil { return nil, err } @@ -221,7 +221,7 @@ func buildSvcShowCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/svc_show_test.go b/internal/pkg/cli/svc_show_test.go index 4b506bb6e63..51fa96158e4 100644 --- a/internal/pkg/cli/svc_show_test.go +++ b/internal/pkg/cli/svc_show_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -55,8 +56,8 @@ func TestSvcShow_Ask(t *testing.T) { inputApp: "my-app", inputSvc: "my-svc", setupMocks: func(m showSvcMocks) { - m.storeSvc.EXPECT().GetApplication("my-app").Return(&config.Application{}, nil) - m.storeSvc.EXPECT().GetService("my-app", "my-svc").Return(&config.Workload{}, nil) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{}, nil) + m.storeSvc.EXPECT().GetService(ctx, "my-app", "my-svc").Return(&config.Workload{}, nil) }, wantedApp: "my-app", wantedSvc: "my-svc", @@ -64,9 +65,9 @@ func TestSvcShow_Ask(t *testing.T) { "prompt for app name": { inputSvc: "my-svc", setupMocks: func(m showSvcMocks) { - m.sel.EXPECT().Application(gomock.Any(), gomock.Any(), gomock.Any()).Return("my-app", nil) - m.storeSvc.EXPECT().GetApplication("my-app").Times(0) - m.storeSvc.EXPECT().GetService("my-app", "my-svc").AnyTimes() + m.sel.EXPECT().Application(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return("my-app", nil) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").Times(0) + m.storeSvc.EXPECT().GetService(ctx, "my-app", "my-svc").AnyTimes() }, wantedApp: "my-app", wantedSvc: "my-svc", @@ -74,17 +75,17 @@ func TestSvcShow_Ask(t *testing.T) { "error when fail to select apps": { inputSvc: "my-svc", setupMocks: func(m showSvcMocks) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) }, wantedError: fmt.Errorf("select application name: some error"), }, "prompt for service name": { inputApp: "my-app", setupMocks: func(m showSvcMocks) { - m.sel.EXPECT().Service(fmt.Sprintf(svcShowSvcNamePrompt, "my-app"), svcShowSvcNameHelpPrompt, "my-app").Return("my-svc", nil) - m.storeSvc.EXPECT().GetService("my-app", "my-svc").Times(0) - m.storeSvc.EXPECT().GetApplication("my-app").AnyTimes() - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).AnyTimes() + m.sel.EXPECT().Service(ctx, fmt.Sprintf(svcShowSvcNamePrompt, "my-app"), svcShowSvcNameHelpPrompt, "my-app").Return("my-svc", nil) + m.storeSvc.EXPECT().GetService(ctx, "my-app", "my-svc").Times(0) + m.storeSvc.EXPECT().GetApplication(ctx, "my-app").AnyTimes() + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).AnyTimes() }, wantedApp: "my-app", wantedSvc: "my-svc", @@ -92,8 +93,8 @@ func TestSvcShow_Ask(t *testing.T) { "error when fail to select services": { setupMocks: func(m showSvcMocks) { gomock.InOrder( - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil), - m.sel.EXPECT().Service(fmt.Sprintf(svcShowSvcNamePrompt, "my-app"), svcShowSvcNameHelpPrompt, "my-app").Return("", errors.New("some error")), + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("my-app", nil), + m.sel.EXPECT().Service(ctx, fmt.Sprintf(svcShowSvcNamePrompt, "my-app"), svcShowSvcNameHelpPrompt, "my-app").Return("", errors.New("some error")), ) }, wantedError: fmt.Errorf("select service for application my-app: some error"), @@ -127,7 +128,7 @@ func TestSvcShow_Ask(t *testing.T) { } // WHEN - err := showSvcs.Ask() + err := showSvcs.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -238,12 +239,12 @@ func TestSvcShow_Execute(t *testing.T) { outputManifestForEnv: tc.outputManifestForEnv, }, describer: mockSvcDescriber, - initDescriber: func() error { return nil }, + initDescriber: func(_ context.Context) error { return nil }, w: b, } // WHEN - err := showSvcs.Execute() + err := showSvcs.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/svc_status.go b/internal/pkg/cli/svc_status.go index b7868e62595..e8f4d656c7b 100644 --- a/internal/pkg/cli/svc_status.go +++ b/internal/pkg/cli/svc_status.go @@ -38,7 +38,7 @@ type svcStatusOpts struct { store store statusDescriber statusDescriber sel deploySelector - initStatusDescriber func(*svcStatusOpts) error + initStatusDescriber func(context.Context, *svcStatusOpts) error } func newSvcStatusOpts(vars svcStatusVars) (*svcStatusOpts, error) { @@ -58,14 +58,14 @@ func newSvcStatusOpts(vars svcStatusVars) (*svcStatusOpts, error) { store: configStore, w: log.OutputWriter, sel: selector.NewDeploySelect(prompt.New(), configStore, deployStore), - initStatusDescriber: func(o *svcStatusOpts) error { - wkld, err := configStore.GetWorkload(o.appName, o.svcName) + initStatusDescriber: func(ctx context.Context, o *svcStatusOpts) error { + wkld, err := configStore.GetWorkload(ctx, o.appName, o.svcName) if err != nil { return fmt.Errorf("retrieve %s from application %s: %w", o.appName, o.svcName, err) } switch wkld.Type { case manifestinfo.RequestDrivenWebServiceType: - d, err := describe.NewAppRunnerStatusDescriber(&describe.NewServiceStatusConfig{ + d, err := describe.NewAppRunnerStatusDescriber(ctx, &describe.NewServiceStatusConfig{ App: o.appName, Env: o.envName, Svc: o.svcName, @@ -76,7 +76,7 @@ func newSvcStatusOpts(vars svcStatusVars) (*svcStatusOpts, error) { } o.statusDescriber = d case manifestinfo.StaticSiteType: - d, err := describe.NewStaticSiteStatusDescriber(&describe.NewServiceStatusConfig{ + d, err := describe.NewStaticSiteStatusDescriber(ctx, &describe.NewServiceStatusConfig{ App: o.appName, Env: o.envName, Svc: o.svcName, @@ -87,7 +87,7 @@ func newSvcStatusOpts(vars svcStatusVars) (*svcStatusOpts, error) { } o.statusDescriber = d default: - d, err := describe.NewECSStatusDescriber(&describe.NewServiceStatusConfig{ + d, err := describe.NewECSStatusDescriber(ctx, &describe.NewServiceStatusConfig{ App: o.appName, Env: o.envName, Svc: o.svcName, @@ -109,16 +109,16 @@ func (o *svcStatusOpts) Validate() error { } // Ask prompts for and validates any required flags. -func (o *svcStatusOpts) Ask() error { - if err := o.validateOrAskApp(); err != nil { +func (o *svcStatusOpts) Ask(ctx context.Context) error { + if err := o.validateOrAskApp(ctx); err != nil { return err } - return o.validateAndAskSvcEnvName() + return o.validateAndAskSvcEnvName(ctx) } // Execute displays the status of the service. -func (o *svcStatusOpts) Execute() error { - err := o.initStatusDescriber(o) +func (o *svcStatusOpts) Execute(ctx context.Context) error { + err := o.initStatusDescriber(ctx, o) if err != nil { return err } @@ -139,12 +139,12 @@ func (o *svcStatusOpts) Execute() error { return nil } -func (o *svcStatusOpts) validateOrAskApp() error { +func (o *svcStatusOpts) validateOrAskApp(ctx context.Context) error { if o.appName != "" { - _, err := o.store.GetApplication(o.appName) + _, err := o.store.GetApplication(ctx, o.appName) return err } - app, err := o.sel.Application(svcAppNamePrompt, wkldAppNameHelpPrompt) + app, err := o.sel.Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -152,21 +152,21 @@ func (o *svcStatusOpts) validateOrAskApp() error { return nil } -func (o *svcStatusOpts) validateAndAskSvcEnvName() error { +func (o *svcStatusOpts) validateAndAskSvcEnvName(ctx context.Context) error { if o.envName != "" { - if _, err := o.store.GetEnvironment(o.appName, o.envName); err != nil { + if _, err := o.store.GetEnvironment(ctx, o.appName, o.envName); err != nil { return err } } if o.svcName != "" { - if _, err := o.store.GetService(o.appName, o.svcName); err != nil { + if _, err := o.store.GetService(ctx, o.appName, o.svcName); err != nil { return err } } // Note: we let prompter handle the case when there is only option for user to choose from. // This is naturally the case when `o.envName != "" && o.svcName != ""`. - deployedService, err := o.sel.DeployedService(svcStatusNamePrompt, svcStatusNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.svcName)) + deployedService, err := o.sel.DeployedService(ctx, svcStatusNamePrompt, svcStatusNameHelpPrompt, o.appName, selector.WithEnv(o.envName), selector.WithName(o.svcName)) if err != nil { return fmt.Errorf("select deployed services for application %s: %w", o.appName, err) } @@ -191,7 +191,7 @@ func buildSvcStatusCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.svcName, nameFlag, nameFlagShort, "", svcFlagDescription) diff --git a/internal/pkg/cli/svc_status_test.go b/internal/pkg/cli/svc_status_test.go index f16184522fd..a67183953e7 100644 --- a/internal/pkg/cli/svc_status_test.go +++ b/internal/pkg/cli/svc_status_test.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "testing" @@ -51,11 +52,11 @@ func TestSvcStatus_Ask(t *testing.T) { inputEnv: testEnvName, setupMocks: func(m svcStatusAskMock) { gomock.InOrder( - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil), - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test"}, nil), - m.store.EXPECT().GetService("phonetool", "api").Return(&config.Workload{}, nil), + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil), + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test"}, nil), + m.store.EXPECT().GetService(ctx, "phonetool", "api").Return(&config.Workload{}, nil), ) - m.sel.EXPECT().DeployedService(svcStatusNamePrompt, svcStatusNameHelpPrompt, "phonetool", gomock.Any(), gomock.Any()). + m.sel.EXPECT().DeployedService(ctx, svcStatusNamePrompt, svcStatusNameHelpPrompt, "phonetool", gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: "test", Name: "api", @@ -69,11 +70,11 @@ func TestSvcStatus_Ask(t *testing.T) { inputEnv: testEnvName, inputSvc: testSvcName, setupMocks: func(m svcStatusAskMock) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("phonetool", nil) - m.store.EXPECT().GetApplication(gomock.Any()).Times(0) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).AnyTimes() - m.sel.EXPECT().DeployedService(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("phonetool", nil) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).Times(0) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).AnyTimes() + m.sel.EXPECT().DeployedService(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: testEnvName, Name: testSvcName, @@ -85,17 +86,17 @@ func TestSvcStatus_Ask(t *testing.T) { }, "errors if failed to select application": { setupMocks: func(m svcStatusAskMock) { - m.sel.EXPECT().Application(svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) + m.sel.EXPECT().Application(ctx, svcAppNamePrompt, wkldAppNameHelpPrompt).Return("", errors.New("some error")) }, wantedError: fmt.Errorf("select application: some error"), }, "prompt for service and env": { inputApp: testAppName, setupMocks: func(m svcStatusAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(svcStatusNamePrompt, svcStatusNameHelpPrompt, testAppName, gomock.Any(), gomock.Any()). + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, svcStatusNamePrompt, svcStatusNameHelpPrompt, testAppName, gomock.Any(), gomock.Any()). Return(&selector.DeployedService{ Env: testEnvName, Name: testSvcName, @@ -108,10 +109,10 @@ func TestSvcStatus_Ask(t *testing.T) { "errors if failed to select deployed service": { inputApp: "mockApp", setupMocks: func(m svcStatusAskMock) { - m.store.EXPECT().GetApplication(gomock.Any()).AnyTimes() - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) - m.store.EXPECT().GetService(gomock.Any(), gomock.Any()).Times(0) - m.sel.EXPECT().DeployedService(svcStatusNamePrompt, svcStatusNameHelpPrompt, "mockApp", gomock.Any(), gomock.Any()).Return(nil, mockError) + m.store.EXPECT().GetApplication(ctx, gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetService(ctx, gomock.Any(), gomock.Any()).Times(0) + m.sel.EXPECT().DeployedService(ctx, svcStatusNamePrompt, svcStatusNameHelpPrompt, "mockApp", gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantedError: fmt.Errorf("select deployed services for application mockApp: some error"), @@ -139,7 +140,7 @@ func TestSvcStatus_Ask(t *testing.T) { } // WHEN - err := svcStatus.Ask() + err := svcStatus.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -185,12 +186,12 @@ func TestSvcStatus_Execute(t *testing.T) { appName: "mockApp", }, statusDescriber: mockStatusDescriber, - initStatusDescriber: func(*svcStatusOpts) error { return nil }, + initStatusDescriber: func(_ context.Context, _ *svcStatusOpts) error { return nil }, w: b, } // WHEN - err := svcStatus.Execute() + err := svcStatus.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/task_delete.go b/internal/pkg/cli/task_delete.go index 30ae0be4c8d..192f36fcb50 100644 --- a/internal/pkg/cli/task_delete.go +++ b/internal/pkg/cli/task_delete.go @@ -128,26 +128,26 @@ func (o *deleteTaskOpts) Validate() error { return err } - if err := o.validateFlagsWithEnv(); err != nil { + if err := o.validateFlagsWithEnv(context.Background()); err != nil { return err } return nil } -func (o *deleteTaskOpts) validateFlagsWithEnv() error { +func (o *deleteTaskOpts) validateFlagsWithEnv(ctx context.Context) error { if o.app != "" { - if _, err := o.store.GetApplication(o.app); err != nil { + if _, err := o.store.GetApplication(ctx, o.app); err != nil { return fmt.Errorf("get application: %w", err) } } if o.app != "" && o.env != "" { - if _, err := o.store.GetEnvironment(o.app, o.env); err != nil { + if _, err := o.store.GetEnvironment(ctx, o.app, o.env); err != nil { return fmt.Errorf("get environment: %w", err) } - if err := o.validateTaskName(); err != nil { + if err := o.validateTaskName(ctx); err != nil { return fmt.Errorf("get task: %w", err) } } @@ -155,12 +155,12 @@ func (o *deleteTaskOpts) validateFlagsWithEnv() error { return nil } -func (o *deleteTaskOpts) validateTaskName() error { +func (o *deleteTaskOpts) validateTaskName(ctx context.Context) error { if o.name != "" { // If fully specified, validate that the stack exists and is a task. // This check prevents the command from stopping arbitrary tasks or emptying arbitrary ECR // repositories. - _, err := o.getTaskInfo() + _, err := o.getTaskInfo(ctx) if err != nil { return err } @@ -188,14 +188,14 @@ func (o *deleteTaskOpts) validateFlagsWithDefaultCluster() error { return fmt.Errorf("cannot specify both `--env` and `--default`") } - if err := o.validateTaskName(); err != nil { + if err := o.validateTaskName(context.Background()); err != nil { return fmt.Errorf("get task: %w", err) } return nil } -func (o *deleteTaskOpts) askAppName() error { +func (o *deleteTaskOpts) askAppName(ctx context.Context) error { if o.defaultCluster { return nil } @@ -204,7 +204,7 @@ func (o *deleteTaskOpts) askAppName() error { return nil } - app, err := o.sel.Application(taskDeleteAppPrompt, "", appEnvOptionNone) + app, err := o.sel.Application(ctx, taskDeleteAppPrompt, "", appEnvOptionNone) if err != nil { return fmt.Errorf("select application name: %w", err) } @@ -217,7 +217,7 @@ func (o *deleteTaskOpts) askAppName() error { return nil } -func (o *deleteTaskOpts) askEnvName() error { +func (o *deleteTaskOpts) askEnvName(ctx context.Context) error { if o.defaultCluster { return nil } @@ -225,7 +225,7 @@ func (o *deleteTaskOpts) askEnvName() error { if o.env != "" { return nil } - env, err := o.sel.Environment(taskDeleteEnvPrompt, "", o.app, prompt.Option{Value: appEnvOptionNone}) + env, err := o.sel.Environment(ctx, taskDeleteEnvPrompt, "", o.app, prompt.Option{Value: appEnvOptionNone}) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -240,16 +240,16 @@ func (o *deleteTaskOpts) askEnvName() error { } // Ask prompts for missing information and fills in gaps. -func (o *deleteTaskOpts) Ask() error { - if err := o.askAppName(); err != nil { +func (o *deleteTaskOpts) Ask(ctx context.Context) error { + if err := o.askAppName(ctx); err != nil { return err } - if err := o.askEnvName(); err != nil { + if err := o.askEnvName(ctx); err != nil { return err } - if err := o.askTaskName(); err != nil { + if err := o.askTaskName(ctx); err != nil { return err } @@ -282,7 +282,7 @@ func (o *deleteTaskOpts) Ask() error { return nil } -func (o *deleteTaskOpts) getConfig() (aws.Config, error) { +func (o *deleteTaskOpts) getConfig(ctx context.Context) (aws.Config, error) { if o.hasConfig { return o.cfg, nil } @@ -296,7 +296,7 @@ func (o *deleteTaskOpts) getConfig() (aws.Config, error) { return cfg, nil } // Get environment manager role for deleting stack. - env, err := o.store.GetEnvironment(o.app, o.env) + env, err := o.store.GetEnvironment(ctx, o.app, o.env) if err != nil { return aws.Config{}, err } @@ -309,12 +309,12 @@ func (o *deleteTaskOpts) getConfig() (aws.Config, error) { return cfg, nil } -func (o *deleteTaskOpts) askTaskName() error { +func (o *deleteTaskOpts) askTaskName(ctx context.Context) error { if o.name != "" { return nil } - cfg, err := o.getConfig() + cfg, err := o.getConfig(ctx) if err != nil { return fmt.Errorf("get task select session: %w", err) } @@ -335,21 +335,21 @@ func (o *deleteTaskOpts) askTaskName() error { return nil } -func (o *deleteTaskOpts) Execute() error { - if err := o.stopTasks(); err != nil { +func (o *deleteTaskOpts) Execute(ctx context.Context) error { + if err := o.stopTasks(ctx); err != nil { return err } - if err := o.clearECRRepository(); err != nil { + if err := o.clearECRRepository(ctx); err != nil { return err } - if err := o.deleteStack(); err != nil { + if err := o.deleteStack(ctx); err != nil { return err } return nil } -func (o *deleteTaskOpts) stopTasks() error { - cfg, err := o.getConfig() +func (o *deleteTaskOpts) stopTasks(ctx context.Context) error { + cfg, err := o.getConfig(ctx) if err != nil { return fmt.Errorf("get session: %w", err) } @@ -372,10 +372,10 @@ func (o *deleteTaskOpts) stopTasks() error { return nil } -func (o *deleteTaskOpts) clearECRRepository() error { +func (o *deleteTaskOpts) clearECRRepository(ctx context.Context) error { // ECR Deletion happens from the default profile in app delete. We can do it here too by getting // a default session in whichever region we're deleting from. - defaultConfig, err := o.getConfig() + defaultConfig, err := o.getConfig(ctx) if err != nil { return err } @@ -399,9 +399,9 @@ func (o *deleteTaskOpts) clearECRRepository() error { return nil } -func (o *deleteTaskOpts) emptyS3Bucket(info *deploy.TaskStackInfo) error { +func (o *deleteTaskOpts) emptyS3Bucket(ctx context.Context, info *deploy.TaskStackInfo) error { o.spinner.Start(fmt.Sprintf("Emptying S3 bucket for task %s.", color.HighlightUserInput(o.name))) - cfg, err := o.getConfig() + cfg, err := o.getConfig(ctx) if err != nil { return err } @@ -417,11 +417,11 @@ func (o *deleteTaskOpts) emptyS3Bucket(info *deploy.TaskStackInfo) error { // getTaskInfo returns a struct of information about the task, including the app and env it's deployed to, if // applicable, and the ARN of any CF role it's associated with. -func (o *deleteTaskOpts) getTaskInfo() (*deploy.TaskStackInfo, error) { +func (o *deleteTaskOpts) getTaskInfo(ctx context.Context) (*deploy.TaskStackInfo, error) { if o.stackInfo != nil { return o.stackInfo, nil } - cfg, err := o.getConfig() + cfg, err := o.getConfig(ctx) if err != nil { return nil, err } @@ -434,12 +434,12 @@ func (o *deleteTaskOpts) getTaskInfo() (*deploy.TaskStackInfo, error) { return info, nil } -func (o *deleteTaskOpts) deleteStack() error { - cfg, err := o.getConfig() +func (o *deleteTaskOpts) deleteStack(ctx context.Context) error { + cfg, err := o.getConfig(ctx) if err != nil { return err } - info, err := o.getTaskInfo() + info, err := o.getTaskInfo(ctx) if err != nil { // If the stack doesn't exist, don't error. var errStackNotExist *awscfn.ErrStackNotFound @@ -453,7 +453,7 @@ func (o *deleteTaskOpts) deleteStack() error { return nil } if info.BucketName != "" { - if err := o.emptyS3Bucket(info); err != nil { + if err := o.emptyS3Bucket(ctx, info); err != nil { return err } } @@ -492,7 +492,7 @@ func BuildTaskDeleteCmd() *cobra.Command { if err != nil { return err } - return run(opts) + return run(cmd.Context(), opts) }), } diff --git a/internal/pkg/cli/task_delete_test.go b/internal/pkg/cli/task_delete_test.go index 74d01e4a893..428409f8f4e 100644 --- a/internal/pkg/cli/task_delete_test.go +++ b/internal/pkg/cli/task_delete_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "testing" @@ -38,7 +39,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { "with only app flag": { inAppName: "phonetool", setupMocks: func(m validateMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) }, want: nil, }, @@ -50,8 +51,8 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { inAppName: "phonetool", inEnvName: "test", setupMocks: func(m validateMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) }, want: nil, }, @@ -60,9 +61,9 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { inEnvName: "test", inName: "oneoff", setupMocks: func(m validateMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.cfn.EXPECT().GetTaskStack("oneoff") }, @@ -74,9 +75,9 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { inName: "oneoff", want: errors.New("get task: some error"), setupMocks: func(m validateMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) - m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(&config.Application{Name: "phonetool"}, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.store.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.cfn.EXPECT().GetTaskStack("oneoff").Return(nil, errors.New("some error")) }, @@ -101,7 +102,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { inAppName: "phonetool", inEnvName: "test", setupMocks: func(m validateMocks) { - m.store.EXPECT().GetApplication("phonetool").Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "phonetool").Return(nil, errors.New("some error")) }, want: errors.New("get application: some error"), }, @@ -185,7 +186,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { mockStore: func(m *mocks.Mockstore) { // This call is in GetSession when an environment is specified and we need to get the Manager Role's session. - m.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) }, mockSel: func(m *mocks.MockwsSelector) {}, mockTaskSelect: func(m *mocks.MockcfTaskSelector) { @@ -204,7 +205,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { mockStore: func(m *mocks.Mockstore) { // This call is in GetSession when an environment is specified and we need to get the Manager Role's session. - m.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) }, mockSel: func(m *mocks.MockwsSelector) {}, mockTaskSelect: func(m *mocks.MockcfTaskSelector) { @@ -237,11 +238,11 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { "no flags specified": { mockStore: func(m *mocks.Mockstore) { // This call is in GetSession when an environment is specified and we need to get the Manager Role's session. - m.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) + m.EXPECT().GetEnvironment(ctx, "phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) }, mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Application(taskDeleteAppPrompt, "", appEnvOptionNone).Return("phonetool", nil) - m.EXPECT().Environment(taskDeleteEnvPrompt, "", "phonetool", prompt.Option{Value: appEnvOptionNone}).Return("test", nil) + m.EXPECT().Application(ctx, taskDeleteAppPrompt, "", appEnvOptionNone).Return("phonetool", nil) + m.EXPECT().Environment(ctx, taskDeleteEnvPrompt, "", "phonetool", prompt.Option{Value: appEnvOptionNone}).Return("test", nil) }, mockTaskSelect: func(m *mocks.MockcfTaskSelector) { m.EXPECT().Task(taskDeleteNamePrompt, "", gomock.Any()).Return("abc", nil) @@ -256,7 +257,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { "no flags specified (default path)": { mockStore: func(m *mocks.Mockstore) {}, mockSel: func(m *mocks.MockwsSelector) { - m.EXPECT().Application(taskDeleteAppPrompt, "", appEnvOptionNone).Return(appEnvOptionNone, nil) + m.EXPECT().Application(ctx, taskDeleteAppPrompt, "", appEnvOptionNone).Return(appEnvOptionNone, nil) }, mockTaskSelect: func(m *mocks.MockcfTaskSelector) { m.EXPECT().Task(taskDeleteNamePrompt, "", gomock.Any()).Return("abc", nil) @@ -306,7 +307,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { } // WHEN - err := opts.Ask() + err := opts.Ask(context.Background()) // THEN if tc.wantErr != "" { @@ -378,7 +379,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopOneOffTasks(mockApp, mockEnvName, mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -447,7 +448,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { setupMocks: func(m deleteTaskMocks) { gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(nil, mockError), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(nil, mockError), ) }, }, @@ -462,7 +463,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopOneOffTasks(mockApp, mockEnvName, mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -489,7 +490,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopOneOffTasks(mockApp, mockEnvName, mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -511,7 +512,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopOneOffTasks(mockApp, mockEnvName, mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -532,7 +533,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopOneOffTasks(mockApp, mockEnvName, mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -556,7 +557,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { setupMocks: func(m deleteTaskMocks) { m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopOneOffTasks(mockApp, mockEnvName, mockTaskName).Return(mockError), m.spinner.EXPECT().Stop(gomock.Any()), @@ -574,7 +575,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( - m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), + m.store.EXPECT().GetEnvironment(ctx, mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopOneOffTasks(mockApp, mockEnvName, mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -660,7 +661,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { } // WHEN - err := opts.Execute() + err := opts.Execute(context.Background()) // THEN if tc.wantedErr != nil { diff --git a/internal/pkg/cli/task_exec.go b/internal/pkg/cli/task_exec.go index 4fa9cfe1876..1a6d86cbc31 100644 --- a/internal/pkg/cli/task_exec.go +++ b/internal/pkg/cli/task_exec.go @@ -80,15 +80,16 @@ func newTaskExecOpts(vars taskExecVars) (*taskExecOpts, error) { // Validate returns an error if the values provided by the user are invalid. func (o *taskExecOpts) Validate() error { + ctx := context.Background() if o.useDefault && (o.appName != tryReadingAppName() || o.envName != "") { return fmt.Errorf("cannot specify both default flag and app or env flags") } if o.appName != "" { - if _, err := o.store.GetApplication(o.appName); err != nil { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return err } if o.envName != "" { - if _, err := o.store.GetEnvironment(o.appName, o.envName); err != nil { + if _, err := o.store.GetEnvironment(ctx, o.appName, o.envName); err != nil { return err } } @@ -97,12 +98,12 @@ func (o *taskExecOpts) Validate() error { } // Ask asks for fields that are required but not passed in. -func (o *taskExecOpts) Ask() error { +func (o *taskExecOpts) Ask(ctx context.Context) error { if o.useDefault { return o.selectTaskInDefaultCluster() } if o.appName == "" { - appName, err := o.configSel.Application(taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption) + appName, err := o.configSel.Application(ctx, taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption) if err != nil { return fmt.Errorf("select application: %w", err) } @@ -113,7 +114,7 @@ func (o *taskExecOpts) Ask() error { o.appName = appName } if o.envName == "" { - envName, err := o.configSel.Environment(taskExecEnvNamePrompt, taskExecEnvNameHelpPrompt, o.appName, prompt.Option{Value: useDefaultClusterOption}) + envName, err := o.configSel.Environment(ctx, taskExecEnvNamePrompt, taskExecEnvNameHelpPrompt, o.appName, prompt.Option{Value: useDefaultClusterOption}) if err != nil { return fmt.Errorf("select environment: %w", err) } @@ -123,12 +124,12 @@ func (o *taskExecOpts) Ask() error { } o.envName = envName } - return o.selectTaskInAppEnvCluster() + return o.selectTaskInAppEnvCluster(ctx) } // Execute executes a command in a running container. -func (o *taskExecOpts) Execute() error { - cfg, err := o.config() +func (o *taskExecOpts) Execute(ctx context.Context) error { + cfg, err := o.config(ctx) if err != nil { return err } @@ -164,8 +165,8 @@ func (o *taskExecOpts) selectTaskInDefaultCluster() error { return nil } -func (o *taskExecOpts) selectTaskInAppEnvCluster() error { - env, err := o.store.GetEnvironment(o.appName, o.envName) +func (o *taskExecOpts) selectTaskInAppEnvCluster(ctx context.Context) error { + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return fmt.Errorf("get environment %s: %w", o.envName, err) } @@ -182,11 +183,11 @@ func (o *taskExecOpts) selectTaskInAppEnvCluster() error { return nil } -func (o *taskExecOpts) config() (aws.Config, error) { +func (o *taskExecOpts) config(ctx context.Context) (aws.Config, error) { if o.useDefault { return o.provider.DefaultConfig(context.Background()) } - env, err := o.store.GetEnvironment(o.appName, o.envName) + env, err := o.store.GetEnvironment(ctx, o.appName, o.envName) if err != nil { return aws.Config{}, fmt.Errorf("get environment %s: %w", o.envName, err) } @@ -218,7 +219,7 @@ func buildTaskExecCmd() *cobra.Command { opts.skipConfirmation = aws.Bool(true) } } - return run(opts) + return run(cmd.Context(), opts) }), } cmd.Flags().StringVarP(&vars.appName, appFlag, appFlagShort, tryReadingAppName(), appFlagDescription) diff --git a/internal/pkg/cli/task_exec_test.go b/internal/pkg/cli/task_exec_test.go index 243f43090e1..3a314ce5cbe 100644 --- a/internal/pkg/cli/task_exec_test.go +++ b/internal/pkg/cli/task_exec_test.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" @@ -59,7 +60,7 @@ func TestTaskExec_Validate(t *testing.T) { "should bubble error if failed to get app": { inApp: mockApp, setupMocks: func(m execTaskMocks) { - m.storeSvc.EXPECT().GetApplication(mockApp).Return(nil, mockErr) + m.storeSvc.EXPECT().GetApplication(ctx, mockApp).Return(nil, mockErr) }, wantedError: fmt.Errorf("some error"), @@ -68,8 +69,8 @@ func TestTaskExec_Validate(t *testing.T) { inApp: mockApp, inEnv: mockEnv, setupMocks: func(m execTaskMocks) { - m.storeSvc.EXPECT().GetApplication(mockApp).Return(&config.Application{}, nil) - m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(nil, mockErr) + m.storeSvc.EXPECT().GetApplication(ctx, mockApp).Return(&config.Application{}, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(nil, mockErr) }, wantedError: fmt.Errorf("some error"), @@ -84,8 +85,8 @@ func TestTaskExec_Validate(t *testing.T) { inApp: mockApp, inEnv: mockEnv, setupMocks: func(m execTaskMocks) { - m.storeSvc.EXPECT().GetApplication(mockApp).Return(&config.Application{}, nil) - m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(&config.Environment{}, nil) + m.storeSvc.EXPECT().GetApplication(ctx, mockApp).Return(&config.Application{}, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(&config.Environment{}, nil) m.ssmPluginManager.EXPECT().ValidateBinary().Return(nil) }, }, @@ -164,7 +165,7 @@ func TestTaskExec_Ask(t *testing.T) { }, "should bubble error if fail to select application": { setupMocks: func(m execTaskMocks) { - m.configSel.EXPECT().Application(taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption). + m.configSel.EXPECT().Application(ctx, taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption). Return("", mockErr) }, @@ -173,7 +174,7 @@ func TestTaskExec_Ask(t *testing.T) { "should bubble error if fail to select environment": { inApp: mockApp, setupMocks: func(m execTaskMocks) { - m.configSel.EXPECT().Environment(taskExecEnvNamePrompt, taskExecEnvNameHelpPrompt, mockApp, prompt.Option{Value: useDefaultClusterOption}). + m.configSel.EXPECT().Environment(ctx, taskExecEnvNamePrompt, taskExecEnvNameHelpPrompt, mockApp, prompt.Option{Value: useDefaultClusterOption}). Return("", mockErr) }, @@ -183,7 +184,7 @@ func TestTaskExec_Ask(t *testing.T) { inApp: mockApp, inEnv: mockEnv, setupMocks: func(m execTaskMocks) { - m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(nil, mockErr) + m.storeSvc.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(nil, mockErr) }, wantedError: fmt.Errorf("get environment my-env: some error"), @@ -192,7 +193,7 @@ func TestTaskExec_Ask(t *testing.T) { inApp: mockApp, inEnv: mockEnv, setupMocks: func(m execTaskMocks) { - m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(&config.Environment{}, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(&config.Environment{}, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, mockErr) @@ -214,7 +215,7 @@ func TestTaskExec_Ask(t *testing.T) { "success with default option chose": { setupMocks: func(m execTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.configSel.EXPECT().Application(taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption). + m.configSel.EXPECT().Application(ctx, taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption). Return(useDefaultClusterOption, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(mockTask, nil) @@ -225,11 +226,11 @@ func TestTaskExec_Ask(t *testing.T) { }, "success with env cluster": { setupMocks: func(m execTaskMocks) { - m.configSel.EXPECT().Application(taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption). + m.configSel.EXPECT().Application(ctx, taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption). Return(mockApp, nil) - m.configSel.EXPECT().Environment(taskExecEnvNamePrompt, taskExecEnvNameHelpPrompt, mockApp, prompt.Option{Value: useDefaultClusterOption}). + m.configSel.EXPECT().Environment(ctx, taskExecEnvNamePrompt, taskExecEnvNameHelpPrompt, mockApp, prompt.Option{Value: useDefaultClusterOption}). Return(mockEnv, nil) - m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(&config.Environment{}, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(&config.Environment{}, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(mockTask, nil) @@ -278,7 +279,7 @@ func TestTaskExec_Ask(t *testing.T) { } // WHEN - err := execTasks.Ask() + err := execTasks.Ask(context.Background()) // THEN if tc.wantedError != nil { @@ -322,7 +323,7 @@ func TestTaskExec_Execute(t *testing.T) { }{ "should bubble error if fail to get environment": { setupMocks: func(m execTaskMocks) { - m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(nil, mockErr) + m.storeSvc.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(nil, mockErr) }, wantedError: fmt.Errorf("get environment my-env: some error"), @@ -362,7 +363,7 @@ func TestTaskExec_Execute(t *testing.T) { "success": { inTask: mockTask, setupMocks: func(m execTaskMocks) { - m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(&config.Environment{}, nil) + m.storeSvc.EXPECT().GetEnvironment(ctx, mockApp, mockEnv).Return(&config.Environment{}, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.commandExec.EXPECT().ExecuteCommand(ecs.ExecuteCommandInput{ Cluster: mockClusterARN, @@ -408,7 +409,7 @@ func TestTaskExec_Execute(t *testing.T) { } // WHEN - err := execTasks.Execute() + err := execTasks.Execute(context.Background()) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/cli/task_run.go b/internal/pkg/cli/task_run.go index c492a0241d5..3dea54627ca 100644 --- a/internal/pkg/cli/task_run.go +++ b/internal/pkg/cli/task_run.go @@ -164,7 +164,7 @@ type runTaskOpts struct { targetEnvironment *config.Environment // Configurer functions. - configureRuntimeOpts func() error + configureRuntimeOpts func(ctx context.Context) error configureRepository func() error // NOTE: configureEventsWriter is only called when tailing logs (i.e. --follow is specified) configureEventsWriter func(tasks []*task.Task) @@ -183,7 +183,7 @@ type runTaskOpts struct { ssmParamSecrets map[string]string secretsManagerSecrets map[string]string envFileARN string - envCompatibilityChecker func(app, env string) (versionCompatibilityChecker, error) + envCompatibilityChecker func(ctx context.Context, app, env string) (versionCompatibilityChecker, error) } func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { @@ -208,8 +208,8 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { ssmParamSecrets: make(map[string]string), } - opts.configureRuntimeOpts = func() error { - opts.runner, err = opts.configureRunner() + opts.configureRuntimeOpts = func(ctx context.Context) error { + opts.runner, err = opts.configureRunner(ctx) if err != nil { return fmt.Errorf("configure task runner: %w", err) } @@ -241,8 +241,8 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { opts.configureUploader = func(cfg aws.Config) uploader { return s3.New(cfg) } - opts.envCompatibilityChecker = func(app, env string) (versionCompatibilityChecker, error) { - envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + opts.envCompatibilityChecker = func(ctx context.Context, app, env string) (versionCompatibilityChecker, error) { + envDescriber, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: app, Env: env, ConfigStore: opts.store, @@ -259,7 +259,7 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { return &opts, nil } -func (o *runTaskOpts) configureRunner() (taskRunner, error) { +func (o *runTaskOpts) configureRunner(ctx context.Context) (taskRunner, error) { vpcGetter := ec2.New(o.cfg) ecsService := awsecs.New(o.cfg) @@ -269,7 +269,7 @@ func (o *runTaskOpts) configureRunner() (taskRunner, error) { return nil, fmt.Errorf("connect to copilot deploy store: %w", err) } - d, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ + d, err := describe.NewEnvDescriber(ctx, describe.NewEnvDescriberConfig{ App: o.appName, Env: o.env, ConfigStore: o.store, @@ -316,13 +316,13 @@ func (o *runTaskOpts) configureRunner() (taskRunner, error) { } -func (o *runTaskOpts) configureSessAndEnv() error { +func (o *runTaskOpts) configureSessAndEnv(ctx context.Context) error { var cfg aws.Config var env *config.Environment if o.env != "" { var err error - env, err = o.targetEnv(o.appName, o.env) + env, err = o.targetEnv(ctx, o.appName, o.env) if err != nil { return err } @@ -418,13 +418,13 @@ func (o *runTaskOpts) Validate() error { } if o.appName != "" { - if err := o.validateAppName(); err != nil { + if err := o.validateAppName(context.Background()); err != nil { return err } } if o.env != "" { - if err := o.validateEnvName(); err != nil { + if err := o.validateEnvName(context.Background()); err != nil { return err } } @@ -516,8 +516,8 @@ func (o *runTaskOpts) confirmSecretsAccess() error { return nil } -func (o *runTaskOpts) validateEnvCompatibilityForGenerateJobCmd(app, env string) error { - envStack, err := o.envCompatibilityChecker(app, env) +func (o *runTaskOpts) validateEnvCompatibilityForGenerateJobCmd(ctx context.Context, app, env string) error { + envStack, err := o.envCompatibilityChecker(ctx, app, env) if err != nil { return err } @@ -630,15 +630,15 @@ func isWindowsOS(os string) bool { } // Ask prompts the user for any required or important fields that are not provided. -func (o *runTaskOpts) Ask() error { +func (o *runTaskOpts) Ask(ctx context.Context) error { if o.generateCommandTarget != "" { return nil } if o.shouldPromptForAppEnv() { - if err := o.askAppName(); err != nil { + if err := o.askAppName(ctx); err != nil { return err } - if err := o.askEnvName(); err != nil { + if err := o.askEnvName(ctx); err != nil { return err } } @@ -662,9 +662,9 @@ func (o *runTaskOpts) shouldPromptForAppEnv() bool { } // Execute deploys and runs the task. -func (o *runTaskOpts) Execute() error { +func (o *runTaskOpts) Execute(ctx context.Context) error { if o.generateCommandTarget != "" { - return o.generateCommand() + return o.generateCommand(ctx) } if o.groupName == "" { @@ -677,11 +677,11 @@ func (o *runTaskOpts) Execute() error { } // NOTE: all runtime options must be configured only after session is configured - if err := o.configureSessAndEnv(); err != nil { + if err := o.configureSessAndEnv(ctx); err != nil { return err } - if err := o.configureRuntimeOpts(); err != nil { + if err := o.configureRuntimeOpts(ctx); err != nil { return err } @@ -700,7 +700,7 @@ func (o *runTaskOpts) Execute() error { } } - if err := o.deployTaskResources(); err != nil { + if err := o.deployTaskResources(ctx); err != nil { return err } @@ -712,7 +712,7 @@ func (o *runTaskOpts) Execute() error { var shouldUpdate bool if o.envFile != "" { - envFileARN, err := o.deployEnvFile() + envFileARN, err := o.deployEnvFile(ctx) if err != nil { return fmt.Errorf("deploy env file %s: %w", o.envFile, err) } @@ -742,7 +742,7 @@ func (o *runTaskOpts) Execute() error { } if shouldUpdate { - if err := o.updateTaskResources(); err != nil { + if err := o.updateTaskResources(ctx); err != nil { return err } } @@ -771,8 +771,8 @@ Did you tag your secrets with the "copilot-application" and "copilot-environment return nil } -func (o *runTaskOpts) generateCommand() error { - command, err := o.runTaskCommand() +func (o *runTaskOpts) generateCommand(ctx context.Context) error { + command, err := o.runTaskCommand(ctx) if err != nil { return err } @@ -784,7 +784,7 @@ func (o *runTaskOpts) generateCommand() error { return nil } -func (o *runTaskOpts) runTaskCommand() (cliStringer, error) { +func (o *runTaskOpts) runTaskCommand(ctx context.Context) (cliStringer, error) { var cmd cliStringer if arn.IsARN(o.generateCommandTarget) { clusterName, serviceName, err := o.parseARN() @@ -811,7 +811,7 @@ func (o *runTaskOpts) runTaskCommand() (cliStringer, error) { } case 3: appName, envName, workloadName := parts[0], parts[1], parts[2] - env, err := o.targetEnv(appName, envName) + env, err := o.targetEnv(ctx, appName, envName) if err != nil { return nil, err } @@ -819,7 +819,7 @@ func (o *runTaskOpts) runTaskCommand() (cliStringer, error) { if err != nil { return nil, fmt.Errorf("get environment config: %s", err) } - cmd, err = o.runTaskCommandFromWorkload(cfg, appName, envName, workloadName) + cmd, err = o.runTaskCommandFromWorkload(ctx, cfg, appName, envName, workloadName) if err != nil { return nil, err } @@ -850,8 +850,8 @@ func (o *runTaskOpts) runTaskCommandFromECSService(cfg aws.Config, clusterName, return cmd, nil } -func (o *runTaskOpts) runTaskCommandFromWorkload(cfg aws.Config, appName, envName, workloadName string) (cliStringer, error) { - workloadType, err := o.workloadType(appName, workloadName) +func (o *runTaskOpts) runTaskCommandFromWorkload(ctx context.Context, cfg aws.Config, appName, envName, workloadName string) (cliStringer, error) { + workloadType, err := o.workloadType(ctx, appName, workloadName) if err != nil { return nil, err } @@ -859,7 +859,7 @@ func (o *runTaskOpts) runTaskCommandFromWorkload(cfg aws.Config, appName, envNam var cmd cliStringer switch workloadType { case workloadTypeJob: - if err := o.validateEnvCompatibilityForGenerateJobCmd(appName, envName); err != nil { + if err := o.validateEnvCompatibilityForGenerateJobCmd(ctx, appName, envName); err != nil { return nil, err } cmd, err = o.runTaskRequestFromJob(o.configureJobDescriber(cfg), appName, envName, workloadName) @@ -875,8 +875,8 @@ func (o *runTaskOpts) runTaskCommandFromWorkload(cfg aws.Config, appName, envNam return cmd, nil } -func (o *runTaskOpts) workloadType(appName, workloadName string) (string, error) { - _, err := o.store.GetJob(appName, workloadName) +func (o *runTaskOpts) workloadType(ctx context.Context, appName, workloadName string) (string, error) { + _, err := o.store.GetJob(ctx, appName, workloadName) if err == nil { return workloadTypeJob, nil } @@ -886,7 +886,7 @@ func (o *runTaskOpts) workloadType(appName, workloadName string) (string, error) return "", fmt.Errorf("determine whether workload %s is a job: %w", workloadName, err) } - _, err = o.store.GetService(appName, workloadName) + _, err = o.store.GetService(ctx, appName, workloadName) if err == nil { return workloadTypeSvc, nil } @@ -978,21 +978,21 @@ func (o *runTaskOpts) buildAndPushImage(uri string) error { return nil } -func (o *runTaskOpts) deployTaskResources() error { - if err := o.deploy(); err != nil { +func (o *runTaskOpts) deployTaskResources(ctx context.Context) error { + if err := o.deploy(ctx); err != nil { return fmt.Errorf("provision resources for task %s: %w", o.groupName, err) } return nil } -func (o *runTaskOpts) updateTaskResources() error { - if err := o.deploy(); err != nil { +func (o *runTaskOpts) updateTaskResources(ctx context.Context) error { + if err := o.deploy(ctx); err != nil { return fmt.Errorf("update resources for task %s: %w", o.groupName, err) } return nil } -func (o *runTaskOpts) deploy() error { +func (o *runTaskOpts) deploy(ctx context.Context) error { var deployOpts []awscloudformation.StackOption if o.env != "" { deployOpts = []awscloudformation.StackOption{awscloudformation.WithRoleARN(o.targetEnvironment.ExecutionRoleARN)} @@ -1000,7 +1000,7 @@ func (o *runTaskOpts) deploy() error { var boundaryPolicy string if o.appName != "" { - app, err := o.store.GetApplication(o.appName) + app, err := o.store.GetApplication(ctx, o.appName) if err != nil { return fmt.Errorf("get application: %w", err) } @@ -1043,7 +1043,7 @@ func (o *runTaskOpts) deploy() error { } // deployEnvFileIfNeeded uploads the env file if needed, ensures that an S3 bucket is available, and returns the ARN of uploaded file. -func (o *runTaskOpts) deployEnvFile() (string, error) { +func (o *runTaskOpts) deployEnvFile(ctx context.Context) (string, error) { if o.envFile == "" { return "", nil } @@ -1090,16 +1090,16 @@ func (o *runTaskOpts) pushEnvFileToS3(bucket string) (string, error) { return s3.FormatARN(partition.ID(), fmt.Sprintf("%s/%s", bucket, key)), nil } -func (o *runTaskOpts) validateAppName() error { - if _, err := o.store.GetApplication(o.appName); err != nil { +func (o *runTaskOpts) validateAppName(ctx context.Context) error { + if _, err := o.store.GetApplication(ctx, o.appName); err != nil { return fmt.Errorf("get application: %w", err) } return nil } -func (o *runTaskOpts) validateEnvName() error { +func (o *runTaskOpts) validateEnvName(ctx context.Context) error { if o.appName != "" { - if _, err := o.targetEnv(o.appName, o.env); err != nil { + if _, err := o.targetEnv(ctx, o.appName, o.env); err != nil { return err } } else { @@ -1109,13 +1109,13 @@ func (o *runTaskOpts) validateEnvName() error { return nil } -func (o *runTaskOpts) askAppName() error { +func (o *runTaskOpts) askAppName(ctx context.Context) error { if o.appName != "" { return nil } // If the application is empty then the user wants to run in the default VPC. Do not prompt for an environment name. - app, err := o.sel.Application(taskRunAppPrompt, taskRunAppPromptHelp, appEnvOptionNone) + app, err := o.sel.Application(ctx, taskRunAppPrompt, taskRunAppPromptHelp, appEnvOptionNone) if err != nil { return fmt.Errorf("ask for application: %w", err) } @@ -1128,7 +1128,7 @@ func (o *runTaskOpts) askAppName() error { return nil } -func (o *runTaskOpts) askEnvName() error { +func (o *runTaskOpts) askEnvName(ctx context.Context) error { if o.env != "" { return nil } @@ -1138,7 +1138,7 @@ func (o *runTaskOpts) askEnvName() error { return nil } - env, err := o.sel.Environment(taskRunEnvPrompt, taskRunEnvPromptHelp, o.appName, prompt.Option{Value: appEnvOptionNone}) + env, err := o.sel.Environment(ctx, taskRunEnvPrompt, taskRunEnvPromptHelp, o.appName, prompt.Option{Value: appEnvOptionNone}) if err != nil { return fmt.Errorf("ask for environment: %w", err) } @@ -1151,8 +1151,8 @@ func (o *runTaskOpts) askEnvName() error { return nil } -func (o *runTaskOpts) targetEnv(appName, envName string) (*config.Environment, error) { - env, err := o.store.GetEnvironment(appName, envName) +func (o *runTaskOpts) targetEnv(ctx context.Context, appName, envName string) (*config.Environment, error) { + env, err := o.store.GetEnvironment(ctx, appName, envName) if err != nil { return nil, fmt.Errorf("get environment %s config: %w", o.env, err) } @@ -1190,7 +1190,7 @@ func BuildTaskRunCmd() *cobra.Command { if cmd.Flags().Changed(dockerFileFlag) { opts.isDockerfileSet = true } - return run(opts) + return run(cmd.Context(), opts) }), } diff --git a/internal/pkg/cli/task_run_test.go b/internal/pkg/cli/task_run_test.go index 59e6eae6e80..a70b28a132a 100644 --- a/internal/pkg/cli/task_run_test.go +++ b/internal/pkg/cli/task_run_test.go @@ -122,11 +122,11 @@ func TestTaskRunOpts_Validate(t *testing.T) { appName: "my-app", mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", }, nil) - m.EXPECT().GetEnvironment("my-app", "dev").Return(&config.Environment{ + m.EXPECT().GetEnvironment(ctx, "my-app", "dev").Return(&config.Environment{ App: "my-app", Name: "dev", }, nil) @@ -273,7 +273,7 @@ func TestTaskRunOpts_Validate(t *testing.T) { appName: "my-app", mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", }, nil) }, @@ -285,7 +285,7 @@ func TestTaskRunOpts_Validate(t *testing.T) { appName: "my-app", mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetApplication("my-app").Return(nil, &config.ErrNoSuchApplication{ + m.EXPECT().GetApplication(ctx, "my-app").Return(nil, &config.ErrNoSuchApplication{ ApplicationName: "my-app", AccountID: "115", Region: "us-east-1", @@ -300,12 +300,12 @@ func TestTaskRunOpts_Validate(t *testing.T) { inEnv: "dev", mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("my-app", "dev").Return(&config.Environment{ + m.EXPECT().GetEnvironment(ctx, "my-app", "dev").Return(&config.Environment{ App: "my-app", Name: "dev", }, nil) - m.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", }, nil) }, @@ -318,12 +318,12 @@ func TestTaskRunOpts_Validate(t *testing.T) { inEnv: "dev", mockStore: func(m *mocks.Mockstore) { - m.EXPECT().GetEnvironment("my-app", "dev").Return(nil, &config.ErrNoSuchEnvironment{ + m.EXPECT().GetEnvironment(ctx, "my-app", "dev").Return(nil, &config.ErrNoSuchEnvironment{ ApplicationName: "my-app", EnvironmentName: "dev", }) - m.EXPECT().GetApplication("my-app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{ Name: "my-app", }, nil) }, @@ -493,8 +493,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), appEnvOptionNone).Return("app", nil) - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Times(1) + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), appEnvOptionNone).Return("app", nil) + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Times(1) }, wantedApp: "app", }, @@ -503,7 +503,7 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), appEnvOptionNone).Return(appEnvOptionNone, nil) + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), appEnvOptionNone).Return(appEnvOptionNone, nil) }, wantedApp: "", }, @@ -514,8 +514,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() }, wantedApp: "my-app", }, @@ -527,7 +527,7 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedEnv: "test", @@ -538,8 +538,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(gomock.Any(), gomock.Any(), appEnvOptionNone).Return(appEnvOptionNone, nil) - m.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Application(ctx, gomock.Any(), gomock.Any(), appEnvOptionNone).Return(appEnvOptionNone, nil) + m.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedEnv: "", @@ -550,8 +550,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() }, wantedApp: "", }, @@ -561,8 +561,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() - m.EXPECT().Environment(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Application(ctx, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() + m.EXPECT().Environment(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantedEnv: "", @@ -573,8 +573,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() }, }, "don't prompt for app if cluster is specified": { @@ -583,8 +583,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) }, }, "don't prompt for env if subnets are specified": { @@ -593,8 +593,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) }, }, "don't prompt for env if cluster is specified": { @@ -603,8 +603,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) }, }, "don't prompt for app if security groups are specified": { @@ -613,8 +613,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).AnyTimes() }, }, "don't prompt for env if security groups are specified": { @@ -623,8 +623,8 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Application(taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) + m.EXPECT().Application(ctx, taskRunAppPrompt, gomock.Any(), gomock.Any()).AnyTimes() + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), appEnvOptionNone).Times(0) }, }, "selected an existing environment": { @@ -634,7 +634,7 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), "my-app", prompt.Option{Value: appEnvOptionNone}).Return("test", nil) }, @@ -648,7 +648,7 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), "my-app", prompt.Option{Value: appEnvOptionNone}).Return(appEnvOptionNone, nil) }, @@ -662,7 +662,7 @@ func TestTaskRunOpts_Ask(t *testing.T) { m.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() }, mockSel: func(m *mocks.MockappEnvSelector) { - m.EXPECT().Environment(taskRunEnvPrompt, gomock.Any(), gomock.Any(), prompt.Option{Value: appEnvOptionNone}). + m.EXPECT().Environment(ctx, taskRunEnvPrompt, gomock.Any(), gomock.Any(), prompt.Option{Value: appEnvOptionNone}). Return("", fmt.Errorf("error selecting environment")) }, @@ -740,7 +740,7 @@ func TestTaskRunOpts_Ask(t *testing.T) { ssmParamSecrets: tc.inSsmParamSecrets, } - err := opts.Ask() + err := opts.Ask(context.Background()) if tc.wantedError == nil { require.NoError(t, err) @@ -811,7 +811,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "check if default cluster exists if deploying to default cluster": { setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) m.deployer.EXPECT().DeployTask(gomock.Any()).Return(nil).AnyTimes() mockRepositoryAnytime(m) @@ -823,7 +823,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { setupMocks: func(m runTaskMocks) { m.defaultClusterGetter.EXPECT().HasDefaultCluster().Times(0) m.store.EXPECT(). - GetEnvironment(gomock.Any(), "test"). + GetEnvironment(ctx, gomock.Any(), "test"). Return(&config.Environment{ ExecutionRoleARN: "env execution role", }, nil) @@ -836,7 +836,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "error deploying resources": { setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, Image: "", @@ -850,7 +850,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "error performing docker login": { setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, Image: "", @@ -865,7 +865,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "error updating resources": { setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, Image: "", @@ -887,7 +887,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "error running tasks": { setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(gomock.Any()).Return(nil).Times(2) mockRepositoryAnytime(m) m.runner.EXPECT().Run().Return(nil, errors.New("error running")) @@ -898,7 +898,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "deploy with execution role option if env is not empty": { inEnv: "test", setupMocks: func(m runTaskMocks) { - m.store.EXPECT().GetEnvironment(gomock.Any(), "test"). + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), "test"). Return(&config.Environment{ ExecutionRoleARN: "env execution role", }, nil) @@ -912,7 +912,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "deploy without execution role option if env is empty": { setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).Times(0) m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Len(0)).AnyTimes() // NOTE: matching length because gomock is unable to match function arguments. mockRepositoryAnytime(m) m.runner.EXPECT().Run().AnyTimes() @@ -923,7 +923,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { inTag: tag, setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(gomock.Any()).AnyTimes() m.repository.EXPECT().Login().Return(mockRepoURI, nil) m.repository.EXPECT().BuildAndPush(ctx, gomock.Eq( @@ -941,7 +941,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { inDockerCtx: "../../other", setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(gomock.Any()).AnyTimes() m.repository.EXPECT().Login().Return(mockRepoURI, nil) m.repository.EXPECT().BuildAndPush(ctx, gomock.Eq( @@ -960,7 +960,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { inEntryPoint: `exec "some command"`, setupMocks: func(m runTaskMocks) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, Image: "", @@ -1039,12 +1039,12 @@ func TestTaskRunOpts_Execute(t *testing.T) { inApp: "my-app", inEnv: "test", setupMocks: func(m runTaskMocks) { - m.store.EXPECT().GetEnvironment(gomock.Any(), "test"). + m.store.EXPECT().GetEnvironment(ctx, gomock.Any(), "test"). Return(&config.Environment{ ExecutionRoleARN: "env execution role", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) - m.store.EXPECT().GetApplication("my-app").Return(nil, errors.New("some error")) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(nil, errors.New("some error")) m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Len(1)).AnyTimes() // NOTE: matching length because gomock is unable to match function arguments. mockRepositoryAnytime(m) m.runner.EXPECT().Run().AnyTimes() @@ -1066,7 +1066,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) info := deploy.TaskStackInfo{BucketName: "arn:aws:s3:::bigbucket"} - m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil).Times(2) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil).Times(2) m.deployer.EXPECT().GetTaskStack(inGroupName).Return(&info, nil) key := "manual/env-files/magic.env/4963d64294508aa3fa103ccac5ad1537944c577d469608ddccad09b6f79b6406.env" url := "https://bigbucket.s3-us-west-2.amazonaws.com/" + key @@ -1086,7 +1086,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) info := deploy.TaskStackInfo{BucketName: "arn:aws:s3:::bigbucket"} - m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil) m.deployer.EXPECT().GetTaskStack(inGroupName).Return(&info, nil) m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Any()).Return(nil) }, @@ -1105,7 +1105,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Any()).Return(nil) m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) - m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil) m.deployer.EXPECT().GetTaskStack(inGroupName).Return(nil, errors.New("hull breach in sector 3")) }, wantedError: errors.New("deploy env file testdir/../magic.env: deploy env file: hull breach in sector 3"), @@ -1124,7 +1124,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) info := deploy.TaskStackInfo{BucketName: "arn:aws:s3:::bigbucket"} - m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil) + m.store.EXPECT().GetApplication(ctx, "my-app").Return(&config.Application{Name: "my-app"}, nil) m.deployer.EXPECT().GetTaskStack(inGroupName).Return(&info, nil) key := "manual/env-files/magic.env/4963d64294508aa3fa103ccac5ad1537944c577d469608ddccad09b6f79b6406.env" @@ -1181,7 +1181,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { provider: mocks.provider, fs: fs.Fs, } - opts.configureRuntimeOpts = func() error { + opts.configureRuntimeOpts = func(_ context.Context) error { opts.runner = mocks.runner opts.deployer = mocks.deployer opts.defaultClusterGetter = mocks.defaultClusterGetter @@ -1199,7 +1199,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { return mocks.uploader } - err := opts.Execute() + err := opts.Execute(context.Background()) if tc.wantedError != nil { require.EqualError(t, err, tc.wantedError.Error()) } else { @@ -1284,13 +1284,13 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "should generate a command given an app/env/svc target": { inGenerateCommandTarget: "good-app/good-env/good-service", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "good-service").Return(nil, &config.ErrNoSuchJob{}) - m.store.EXPECT().GetService("good-app", "good-service").Return(&config.Workload{}, nil) + m.store.EXPECT().GetJob(ctx, "good-app", "good-service").Return(nil, &config.ErrNoSuchJob{}) + m.store.EXPECT().GetService(ctx, "good-app", "good-service").Return(&config.Workload{}, nil) }, mockRunTaskRequester: mockRunTaskRequester{ mockRunTaskRequestFromService: func(client ecs.ServiceDescriber, app, env, svc string) (*ecs.RunTaskRequest, error) { @@ -1302,13 +1302,13 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "fail to generate a command given an app/env/svc target": { inGenerateCommandTarget: "good-app/good-env/good-service", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "good-service").Return(nil, &config.ErrNoSuchJob{}) - m.store.EXPECT().GetService("good-app", "good-service").Return(&config.Workload{}, nil) + m.store.EXPECT().GetJob(ctx, "good-app", "good-service").Return(nil, &config.ErrNoSuchJob{}) + m.store.EXPECT().GetService(ctx, "good-app", "good-service").Return(&config.Workload{}, nil) }, mockRunTaskRequester: mockRunTaskRequester{ mockRunTaskRequestFromService: func(client ecs.ServiceDescriber, app, env, svc string) (*ecs.RunTaskRequest, error) { @@ -1320,12 +1320,12 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "should generate a command given an app/env/job target": { inGenerateCommandTarget: "good-app/good-env/good-job", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) + m.store.EXPECT().GetJob(ctx, "good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("v1.12.2", nil) }, mockRunTaskRequester: mockRunTaskRequester{ @@ -1338,12 +1338,12 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "fail to generate a command given an app/env/job target": { inGenerateCommandTarget: "good-app/good-env/good-job", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) + m.store.EXPECT().GetJob(ctx, "good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("v1.12.2", nil) }, mockRunTaskRequester: mockRunTaskRequester{ @@ -1356,12 +1356,12 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "error out if fail to get env version when target is job": { inGenerateCommandTarget: "good-app/good-env/good-job", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) + m.store.EXPECT().GetJob(ctx, "good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("", errors.New("some error")) }, @@ -1370,12 +1370,12 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "error out if env version doesn't support `--generate-cmd` for jobs": { inGenerateCommandTarget: "good-app/good-env/good-job", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) + m.store.EXPECT().GetJob(ctx, "good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("v1.9.0", nil) }, @@ -1384,38 +1384,38 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "fail to determine if the workload is a job given an app/env/workload target": { inGenerateCommandTarget: "good-app/good-env/bad-workload", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "bad-workload").Return(nil, errors.New("some error")) + m.store.EXPECT().GetJob(ctx, "good-app", "bad-workload").Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("determine whether workload bad-workload is a job: some error"), }, "fail to determine if the workload is a service given an app/env/workload target": { inGenerateCommandTarget: "good-app/good-env/bad-workload", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "bad-workload").Return(nil, &config.ErrNoSuchJob{}) - m.store.EXPECT().GetService("good-app", "bad-workload").Return(nil, errors.New("some error")) + m.store.EXPECT().GetJob(ctx, "good-app", "bad-workload").Return(nil, &config.ErrNoSuchJob{}) + m.store.EXPECT().GetService(ctx, "good-app", "bad-workload").Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("determine whether workload bad-workload is a service: some error"), }, "workload is neither a job nor a service": { inGenerateCommandTarget: "good-app/good-env/bad-workload", setUpMocks: func(m *taskRunMocks) { - m.store.EXPECT().GetEnvironment("good-app", "good-env").Return(&config.Environment{ + m.store.EXPECT().GetEnvironment(ctx, "good-app", "good-env").Return(&config.Environment{ ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) - m.store.EXPECT().GetJob("good-app", "bad-workload").Return(nil, &config.ErrNoSuchJob{}) - m.store.EXPECT().GetService("good-app", "bad-workload").Return(nil, &config.ErrNoSuchService{}) + m.store.EXPECT().GetJob(ctx, "good-app", "bad-workload").Return(nil, &config.ErrNoSuchJob{}) + m.store.EXPECT().GetService(ctx, "good-app", "bad-workload").Return(nil, &config.ErrNoSuchService{}) }, wantedError: fmt.Errorf("workload bad-workload is neither a service nor a job"), }, @@ -1457,12 +1457,12 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { runTaskRequestFromECSService: tc.mockRunTaskRequester.mockRunTaskRequestFromECSService, runTaskRequestFromService: tc.mockRunTaskRequester.mockRunTaskRequestFromService, runTaskRequestFromJob: tc.mockRunTaskRequester.mockRunTaskRequestFromJob, - envCompatibilityChecker: func(app, env string) (versionCompatibilityChecker, error) { + envCompatibilityChecker: func(_ context.Context, app, env string) (versionCompatibilityChecker, error) { return m.envCompatibilityChecker, nil }, } - got, err := opts.runTaskCommand() + got, err := opts.runTaskCommand(ctx) if tc.wantedError != nil { require.EqualError(t, err, tc.wantedError.Error()) } else { diff --git a/internal/pkg/config/app.go b/internal/pkg/config/app.go index 96665f01ed2..b6a1a2b7b3c 100644 --- a/internal/pkg/config/app.go +++ b/internal/pkg/config/app.go @@ -4,6 +4,7 @@ package config import ( + "context" "encoding/json" "errors" "fmt" @@ -25,7 +26,7 @@ type Application struct { } // CreateApplication instantiates a new application, validates its uniqueness and stores it in SSM. -func (s *Store) CreateApplication(application *Application) error { +func (s *Store) CreateApplication(ctx context.Context, application *Application) error { applicationPath := fmt.Sprintf(fmtApplicationPath, application.Name) application.Version = schemaVersion @@ -34,7 +35,7 @@ func (s *Store) CreateApplication(application *Application) error { return fmt.Errorf("serializing application %s: %w", application.Name, err) } - _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ + _, err = s.ssm.PutParameter(ctx, &ssm.PutParameterInput{ Name: aws.String(applicationPath), Description: aws.String("Copilot Application"), Type: types.ParameterTypeString, @@ -58,7 +59,7 @@ func (s *Store) CreateApplication(application *Application) error { } // UpdateApplication updates the data in SSM about an application. -func (s *Store) UpdateApplication(application *Application) error { +func (s *Store) UpdateApplication(ctx context.Context, application *Application) error { applicationPath := fmt.Sprintf(fmtApplicationPath, application.Name) application.Version = schemaVersion @@ -67,7 +68,7 @@ func (s *Store) UpdateApplication(application *Application) error { return fmt.Errorf("serializing application %s: %w", application.Name, err) } - if _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ + if _, err = s.ssm.PutParameter(ctx, &ssm.PutParameterInput{ Name: aws.String(applicationPath), Description: aws.String("Copilot Application"), Type: types.ParameterTypeString, @@ -80,16 +81,16 @@ func (s *Store) UpdateApplication(application *Application) error { } // GetApplication fetches an application by name. If it can't be found, return a ErrNoSuchApplication -func (s *Store) GetApplication(applicationName string) (*Application, error) { +func (s *Store) GetApplication(ctx context.Context, applicationName string) (*Application, error) { applicationPath := fmt.Sprintf(fmtApplicationPath, applicationName) - applicationParam, err := s.ssm.GetParameter(&ssm.GetParameterInput{ + applicationParam, err := s.ssm.GetParameter(ctx, &ssm.GetParameterInput{ Name: aws.String(applicationPath), }) if err != nil { var notFoundErr *types.ParameterNotFound if errors.As(err, ¬FoundErr) { - account, region := s.getCallerAccountAndRegion() + account, region := s.getCallerAccountAndRegion(ctx) return nil, &ErrNoSuchApplication{ ApplicationName: applicationName, AccountID: account, @@ -107,9 +108,9 @@ func (s *Store) GetApplication(applicationName string) (*Application, error) { } // ListApplications returns the list of existing applications in the customer's account and region. -func (s *Store) ListApplications() ([]*Application, error) { +func (s *Store) ListApplications(ctx context.Context) ([]*Application, error) { var applications []*Application - serializedApplications, err := s.listParams(rootApplicationPath) + serializedApplications, err := s.listParams(ctx, rootApplicationPath) if err != nil { return nil, fmt.Errorf("list applications: %w", err) } @@ -125,10 +126,10 @@ func (s *Store) ListApplications() ([]*Application, error) { } // DeleteApplication deletes the SSM parameter related to the application. -func (s *Store) DeleteApplication(name string) error { +func (s *Store) DeleteApplication(ctx context.Context, name string) error { paramName := fmt.Sprintf(fmtApplicationPath, name) - _, err := s.ssm.DeleteParameter(&ssm.DeleteParameterInput{ + _, err := s.ssm.DeleteParameter(ctx, &ssm.DeleteParameterInput{ Name: aws.String(paramName), }) diff --git a/internal/pkg/config/app_test.go b/internal/pkg/config/app_test.go index 4418c5e50a2..b4e13252497 100644 --- a/internal/pkg/config/app_test.go +++ b/internal/pkg/config/app_test.go @@ -4,6 +4,7 @@ package config import ( + "context" "errors" "fmt" "testing" @@ -16,6 +17,7 @@ import ( ) func TestStore_ListApplications(t *testing.T) { + ctx := context.WithValue(context.Background(), "operation", "list-applications") testApplication := Application{Name: "chicken", Version: "1.0"} testApplicationString, err := marshal(testApplication) require.NoError(t, err, "Marshal application should not fail") @@ -27,13 +29,14 @@ func TestStore_ListApplications(t *testing.T) { lastPageInPaginatedResp := false testCases := map[string]struct { - mockGetParametersByPath func(t *testing.T, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) + mockGetParametersByPath func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) wantedApplicationNames []string wantedErr error }{ "with multiple existing applications": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, gotCtx context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + require.Equal(t, ctx, gotCtx) require.Equal(t, rootApplicationPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -53,7 +56,7 @@ func TestStore_ListApplications(t *testing.T) { wantedErr: nil, }, "with malformed json": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, rootApplicationPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -67,7 +70,7 @@ func TestStore_ListApplications(t *testing.T) { wantedErr: fmt.Errorf("read application configuration: invalid character 'o' looking for beginning of value"), }, "with SSM error": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, rootApplicationPath, *param.Path) return nil, fmt.Errorf("broken") }, @@ -76,7 +79,7 @@ func TestStore_ListApplications(t *testing.T) { wantedErr: fmt.Errorf("list applications: broken"), }, "with paginated response": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, rootApplicationPath, *param.Path) // this closure references the `lastPageInPaginatedResp` variable @@ -120,7 +123,7 @@ func TestStore_ListApplications(t *testing.T) { } // WHEN - apps, err := store.ListApplications() + apps, err := store.ListApplications(ctx) // THEN if tc.wantedErr != nil { @@ -138,19 +141,21 @@ func TestStore_ListApplications(t *testing.T) { } func TestStore_GetApplication(t *testing.T) { + ctx := context.WithValue(context.Background(), "operation", "get-application") testApplication := Application{Name: "chicken", AccountID: "1234", Version: "1.0"} testApplicationString, err := marshal(testApplication) testApplicationPath := fmt.Sprintf(fmtApplicationPath, testApplication.Name) require.NoError(t, err, "Marshal application should not fail") testCases := map[string]struct { - mockGetParameter func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) - mockIdentityServiceGet func() (identity.Caller, error) + mockGetParameter func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + mockIdentityServiceGet func(context.Context) (identity.Caller, error) wantedApplication Application wantedErr error }{ "with existing application": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, gotCtx context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + require.Equal(t, ctx, gotCtx) require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -164,11 +169,12 @@ func TestStore_GetApplication(t *testing.T) { wantedErr: nil, }, "with no existing application": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return nil, &types.ParameterNotFound{} }, - mockIdentityServiceGet: func() (identity.Caller, error) { + mockIdentityServiceGet: func(gotCtx context.Context) (identity.Caller, error) { + require.Equal(t, ctx, gotCtx) return identity.Caller{ Account: "12345", }, nil @@ -180,11 +186,11 @@ func TestStore_GetApplication(t *testing.T) { }, }, "with no existing application and failed STS call": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return nil, &types.ParameterNotFound{} }, - mockIdentityServiceGet: func() (identity.Caller, error) { + mockIdentityServiceGet: func(_ context.Context) (identity.Caller, error) { return identity.Caller{}, fmt.Errorf("Error") }, wantedErr: &ErrNoSuchApplication{ @@ -194,7 +200,7 @@ func TestStore_GetApplication(t *testing.T) { }, }, "with malformed json": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -207,7 +213,7 @@ func TestStore_GetApplication(t *testing.T) { wantedErr: fmt.Errorf("read configuration for application chicken: invalid character 'o' looking for beginning of value"), }, "with SSM error": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return nil, fmt.Errorf("broken") }, @@ -230,7 +236,7 @@ func TestStore_GetApplication(t *testing.T) { } // WHEN - app, err := store.GetApplication("chicken") + app, err := store.GetApplication(ctx, "chicken") // THEN if tc.wantedErr != nil { @@ -243,6 +249,7 @@ func TestStore_GetApplication(t *testing.T) { } func TestStore_CreateApplication(t *testing.T) { + ctx := context.WithValue(context.Background(), "operation", "create-application") tagForApplicationParam := []types.Tag{ { Key: aws.String("copilot-application"), @@ -252,12 +259,13 @@ func TestStore_CreateApplication(t *testing.T) { testCases := map[string]struct { inApplication *Application - mockPutParameter func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) + mockPutParameter func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) wantedErr error }{ "with no existing application": { inApplication: &Application{Name: "phonetool", AccountID: "1234", Domain: "phonetool.com", DomainHostedZoneID: "mockHostedZoneID", Tags: map[string]string{"owner": "boss"}}, - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, gotCtx context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + require.Equal(t, ctx, gotCtx) require.Equal(t, fmt.Sprintf(fmtApplicationPath, "phonetool"), *param.Name) require.Equal(t, fmt.Sprintf(`{"name":"phonetool","account":"1234","domain":"phonetool.com","domainHostedZoneID":"mockHostedZoneID","version":"%s","tags":{"owner":"boss"}}`, schemaVersion), *param.Value) require.Equal(t, tagForApplicationParam, param.Tags) @@ -269,7 +277,7 @@ func TestStore_CreateApplication(t *testing.T) { }, "with existing application": { inApplication: &Application{Name: "phonetool", AccountID: "1234"}, - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, tagForApplicationParam, param.Tags) return nil, &types.ParameterAlreadyExists{} }, @@ -277,7 +285,7 @@ func TestStore_CreateApplication(t *testing.T) { }, "with SSM error": { inApplication: &Application{Name: "phonetool", AccountID: "1234"}, - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, tagForApplicationParam, param.Tags) return nil, fmt.Errorf("broken") }, @@ -295,7 +303,7 @@ func TestStore_CreateApplication(t *testing.T) { } // WHEN - err := store.CreateApplication(tc.inApplication) + err := store.CreateApplication(ctx, tc.inApplication) // THEN if tc.wantedErr != nil { @@ -310,12 +318,12 @@ func TestStore_UpdateApplication(t *testing.T) { testCases := map[string]struct { inApplication *Application - mockPutParameter func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) + mockPutParameter func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) wantedErr error }{ "success": { inApplication: &Application{Name: "phonetool", AccountID: "1234", Domain: "phonetool.com", DomainHostedZoneID: "mockHostedZoneID", Tags: map[string]string{"owner": "boss"}}, - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, fmt.Sprintf(fmtApplicationPath, "phonetool"), *param.Name) require.Equal(t, fmt.Sprintf(`{"name":"phonetool","account":"1234","domain":"phonetool.com","domainHostedZoneID":"mockHostedZoneID","version":"%s","tags":{"owner":"boss"}}`, schemaVersion), *param.Value) @@ -327,7 +335,7 @@ func TestStore_UpdateApplication(t *testing.T) { }, "with SSM error": { inApplication: &Application{Name: "phonetool", AccountID: "1234"}, - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { return nil, fmt.Errorf("broken") }, wantedErr: fmt.Errorf("update application phonetool: broken"), @@ -344,7 +352,7 @@ func TestStore_UpdateApplication(t *testing.T) { } // WHEN - err := store.UpdateApplication(tc.inApplication) + err := store.UpdateApplication(context.Background(), tc.inApplication) // THEN if tc.wantedErr != nil { @@ -357,16 +365,18 @@ func TestStore_UpdateApplication(t *testing.T) { } func TestDeleteApplication(t *testing.T) { + ctx := context.WithValue(context.Background(), "operation", "delete-application") mockApplicationName := "mockApplicationName" mockError := errors.New("mockError") tests := map[string]struct { - mockDeleteParameter func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) + mockDeleteParameter func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) want error }{ "should return nil given success": { - mockDeleteParameter: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParameter: func(t *testing.T, gotCtx context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + require.Equal(t, ctx, gotCtx) require.Equal(t, fmt.Sprintf(fmtApplicationPath, mockApplicationName), *in.Name) return &ssm.DeleteParameterOutput{}, nil @@ -374,7 +384,7 @@ func TestDeleteApplication(t *testing.T) { want: nil, }, "should return nil given paramter not found error code": { - mockDeleteParameter: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParameter: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { require.Equal(t, fmt.Sprintf(fmtApplicationPath, mockApplicationName), *in.Name) return nil, &types.ParameterNotFound{} @@ -382,7 +392,7 @@ func TestDeleteApplication(t *testing.T) { want: nil, }, "should return unhandled non-awserr": { - mockDeleteParameter: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParameter: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { require.Equal(t, fmt.Sprintf(fmtApplicationPath, mockApplicationName), *in.Name) return nil, mockError @@ -400,7 +410,7 @@ func TestDeleteApplication(t *testing.T) { }, } - got := store.DeleteApplication(mockApplicationName) + got := store.DeleteApplication(ctx, mockApplicationName) require.Equal(t, test.want, got) }) diff --git a/internal/pkg/config/env.go b/internal/pkg/config/env.go index 6ac062010a6..bf74dd467eb 100644 --- a/internal/pkg/config/env.go +++ b/internal/pkg/config/env.go @@ -4,6 +4,7 @@ package config import ( + "context" "encoding/json" "errors" "fmt" @@ -68,8 +69,8 @@ type Telemetry struct { // CreateEnvironment instantiates a new environment within an existing App. Skip if // the environment already exists in the App. -func (s *Store) CreateEnvironment(environment *Environment) error { - if _, err := s.GetApplication(environment.App); err != nil { +func (s *Store) CreateEnvironment(ctx context.Context, environment *Environment) error { + if _, err := s.GetApplication(ctx, environment.App); err != nil { return err } @@ -79,7 +80,7 @@ func (s *Store) CreateEnvironment(environment *Environment) error { return fmt.Errorf("serializing environment %s: %w", environment.Name, err) } - _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ + _, err = s.ssm.PutParameter(ctx, &ssm.PutParameterInput{ Name: aws.String(environmentPath), Description: aws.String(fmt.Sprintf("The %s deployment stage", environment.Name)), Type: types.ParameterTypeString, @@ -107,9 +108,9 @@ func (s *Store) CreateEnvironment(environment *Environment) error { // GetEnvironment gets an environment belonging to a particular application by name. If no environment is found // it returns ErrNoSuchEnvironment. -func (s *Store) GetEnvironment(appName string, environmentName string) (*Environment, error) { +func (s *Store) GetEnvironment(ctx context.Context, appName string, environmentName string) (*Environment, error) { environmentPath := fmt.Sprintf(fmtEnvParamPath, appName, environmentName) - environmentParam, err := s.ssm.GetParameter(&ssm.GetParameterInput{ + environmentParam, err := s.ssm.GetParameter(ctx, &ssm.GetParameterInput{ Name: aws.String(environmentPath), }) @@ -133,11 +134,11 @@ func (s *Store) GetEnvironment(appName string, environmentName string) (*Environ } // ListEnvironments returns all environments belonging to a particular application. -func (s *Store) ListEnvironments(appName string) ([]*Environment, error) { +func (s *Store) ListEnvironments(ctx context.Context, appName string) ([]*Environment, error) { var environments []*Environment environmentsPath := fmt.Sprintf(rootEnvParamPath, appName) - serializedEnvs, err := s.listParams(environmentsPath) + serializedEnvs, err := s.listParams(ctx, environmentsPath) if err != nil { return nil, fmt.Errorf("list environments for application %s: %w", appName, err) } @@ -155,9 +156,9 @@ func (s *Store) ListEnvironments(appName string) ([]*Environment, error) { // DeleteEnvironment removes an environment from SSM. // If the environment does not exist in the store or is successfully deleted then returns nil. Otherwise, returns an error. -func (s *Store) DeleteEnvironment(appName, environmentName string) error { +func (s *Store) DeleteEnvironment(ctx context.Context, appName, environmentName string) error { paramName := fmt.Sprintf(fmtEnvParamPath, appName, environmentName) - _, err := s.ssm.DeleteParameter(&ssm.DeleteParameterInput{ + _, err := s.ssm.DeleteParameter(ctx, &ssm.DeleteParameterInput{ Name: aws.String(paramName), }) diff --git a/internal/pkg/config/env_test.go b/internal/pkg/config/env_test.go index 63df36de9a6..ef39210ccb6 100644 --- a/internal/pkg/config/env_test.go +++ b/internal/pkg/config/env_test.go @@ -4,6 +4,7 @@ package config import ( + "context" "errors" "fmt" "testing" @@ -35,13 +36,13 @@ func TestStore_ListEnvironments(t *testing.T) { lastPageInPaginatedResp := false testCases := map[string]struct { - mockGetParametersByPath func(t *testing.T, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) + mockGetParametersByPath func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) wantedEnvironments []Environment wantedErr error }{ "with multiple existing environments": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, environmentPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -61,7 +62,7 @@ func TestStore_ListEnvironments(t *testing.T) { wantedErr: nil, }, "with malformed json": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, environmentPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -75,14 +76,14 @@ func TestStore_ListEnvironments(t *testing.T) { wantedErr: fmt.Errorf("read environment configuration for application chicken: invalid character 'o' looking for beginning of value"), }, "with SSM error": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, environmentPath, *param.Path) return nil, fmt.Errorf("broken") }, wantedErr: fmt.Errorf("list environments for application chicken: broken"), }, "with paginated response": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, environmentPath, *param.Path) if !lastPageInPaginatedResp { @@ -129,7 +130,7 @@ func TestStore_ListEnvironments(t *testing.T) { } // WHEN - envPointers, err := store.ListEnvironments("chicken") + envPointers, err := store.ListEnvironments(context.Background(), "chicken") // THEN if tc.wantedErr != nil { require.EqualError(t, err, tc.wantedErr.Error()) @@ -151,12 +152,12 @@ func TestStore_GetEnvironment(t *testing.T) { require.NoError(t, err, "Marshal environment should not fail") testCases := map[string]struct { - mockGetParameter func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + mockGetParameter func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) wantedEnvironment Environment wantedErr error }{ "with existing environment": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -169,7 +170,7 @@ func TestStore_GetEnvironment(t *testing.T) { wantedErr: nil, }, "with no existing environment": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) return nil, &types.ParameterNotFound{} }, @@ -179,7 +180,7 @@ func TestStore_GetEnvironment(t *testing.T) { }, }, "with malformed json": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -191,7 +192,7 @@ func TestStore_GetEnvironment(t *testing.T) { wantedErr: fmt.Errorf("read configuration for environment test in application chicken: invalid character 'o' looking for beginning of value"), }, "with SSM error": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { return nil, fmt.Errorf("broken") }, wantedErr: fmt.Errorf("get environment test in application chicken: broken"), @@ -209,7 +210,7 @@ func TestStore_GetEnvironment(t *testing.T) { } // WHEN - env, err := store.GetEnvironment("chicken", "test") + env, err := store.GetEnvironment(context.Background(), "chicken", "test") // THEN if tc.wantedErr != nil { @@ -256,12 +257,12 @@ func TestStore_CreateEnvironment(t *testing.T) { } testCases := map[string]struct { - mockGetParameter func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) - mockPutParameter func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) + mockGetParameter func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + mockPutParameter func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) wantedErr error }{ "with no existing environment": { - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) require.Equal(t, testEnvironmentString, *param.Value) require.Equal(t, tagsForEnvParam, param.Tags) @@ -269,7 +270,7 @@ func TestStore_CreateEnvironment(t *testing.T) { Version: 1, }, nil }, - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -282,12 +283,12 @@ func TestStore_CreateEnvironment(t *testing.T) { wantedErr: nil, }, "with existing environment": { - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) require.Equal(t, tagsForEnvParam, param.Tags) return nil, &types.ParameterAlreadyExists{} }, - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -299,11 +300,11 @@ func TestStore_CreateEnvironment(t *testing.T) { wantedErr: nil, }, "with SSM error": { - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, tagsForEnvParam, param.Tags) return nil, fmt.Errorf("broken") }, - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -328,7 +329,7 @@ func TestStore_CreateEnvironment(t *testing.T) { } // WHEN - err := store.CreateEnvironment(&Environment{ + err := store.CreateEnvironment(context.Background(), &Environment{ Name: testEnvironment.Name, App: testEnvironment.App, AccountID: testEnvironment.AccountID, @@ -348,21 +349,21 @@ func TestStore_DeleteEnvironment(t *testing.T) { testCases := map[string]struct { inApplicationName string inEnvName string - mockDeleteParam func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) + mockDeleteParam func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) wantedError error }{ "parameter is already deleted": { inApplicationName: "phonetool", inEnvName: "test", - mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParam: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { return nil, &types.ParameterNotFound{} }, }, "unexpected error": { inApplicationName: "phonetool", inEnvName: "test", - mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParam: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { return nil, errors.New("some error") }, wantedError: errors.New("delete environment test from application phonetool: some error"), @@ -370,7 +371,7 @@ func TestStore_DeleteEnvironment(t *testing.T) { "successfully deleted param": { inApplicationName: "phonetool", inEnvName: "test", - mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParam: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { wantedPath := fmt.Sprintf(fmtEnvParamPath, "phonetool", "test") require.Equal(t, wantedPath, *in.Name) return nil, nil @@ -389,7 +390,7 @@ func TestStore_DeleteEnvironment(t *testing.T) { } // WHEN - err := store.DeleteEnvironment(tc.inApplicationName, tc.inEnvName) + err := store.DeleteEnvironment(context.Background(), tc.inApplicationName, tc.inEnvName) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/config/store.go b/internal/pkg/config/store.go index 9766937541f..06a671dd058 100644 --- a/internal/pkg/config/store.go +++ b/internal/pkg/config/store.go @@ -40,40 +40,15 @@ const ( // IAMIdentityGetter is the interface to get information about the IAM user or role whose credentials are used to make AWS requests. type IAMIdentityGetter interface { - Get() (identity.Caller, error) + Get(ctx context.Context) (identity.Caller, error) } // SSM is the interface for the AWS SSM client. type SSM interface { - PutParameter(in *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) - GetParametersByPath(in *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) - GetParameter(in *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) - DeleteParameter(in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) -} - -type ssmClient struct { - client *ssm.Client -} - -// NewSSMClient adapts the SDK v2 SSM client to Store's narrow SSM interface. -func NewSSMClient(cfg aws.Config) SSM { - return &ssmClient{client: ssm.NewFromConfig(cfg)} -} - -func (c *ssmClient) PutParameter(in *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { - return c.client.PutParameter(context.Background(), in) -} - -func (c *ssmClient) GetParametersByPath(in *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) { - return c.client.GetParametersByPath(context.Background(), in) -} - -func (c *ssmClient) GetParameter(in *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { - return c.client.GetParameter(context.Background(), in) -} - -func (c *ssmClient) DeleteParameter(in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { - return c.client.DeleteParameter(context.Background(), in) + PutParameter(context.Context, *ssm.PutParameterInput, ...func(*ssm.Options)) (*ssm.PutParameterOutput, error) + GetParametersByPath(context.Context, *ssm.GetParametersByPathInput, ...func(*ssm.Options)) (*ssm.GetParametersByPathOutput, error) + GetParameter(context.Context, *ssm.GetParameterInput, ...func(*ssm.Options)) (*ssm.GetParameterOutput, error) + DeleteParameter(context.Context, *ssm.DeleteParameterInput, ...func(*ssm.Options)) (*ssm.DeleteParameterOutput, error) } // Store is in charge of fetching and creating applications, environment, services and other workloads, and pipeline configuration in SSM. @@ -92,12 +67,12 @@ func NewSSMStore(sts IAMIdentityGetter, ssm SSM, appRegion string) *Store { } } -func (s *Store) listParams(path string) ([]*string, error) { +func (s *Store) listParams(ctx context.Context, path string) ([]*string, error) { var serializedParams []*string var nextToken *string for { - params, err := s.ssm.GetParametersByPath(&ssm.GetParametersByPathInput{ + params, err := s.ssm.GetParametersByPath(ctx, &ssm.GetParametersByPathInput{ Path: aws.String(path), Recursive: aws.Bool(false), NextToken: nextToken, @@ -121,8 +96,8 @@ func (s *Store) listParams(path string) ([]*string, error) { // Retrieves the caller's Account ID with a best effort. If it fails to fetch the Account ID, // this returns "unknown". -func (s *Store) getCallerAccountAndRegion() (string, string) { - identity, err := s.sts.Get() +func (s *Store) getCallerAccountAndRegion(ctx context.Context) (string, string) { + identity, err := s.sts.Get(ctx) region := s.appRegion if err != nil { log.Printf("Failed to get caller's Account ID %v", err) diff --git a/internal/pkg/config/store_integration_test.go b/internal/pkg/config/store_integration_test.go index 2984149bd6c..1aa3b3511b9 100644 --- a/internal/pkg/config/store_integration_test.go +++ b/internal/pkg/config/store_integration_test.go @@ -29,24 +29,24 @@ func Test_SSM_Application_Integration(t *testing.T) { store := config.NewSSMStore(identity.New(defaultConfig), ssm.NewFromConfig(defaultConfig), defaultConfig.Region) applicationToCreate := config.Application{Name: randStringBytes(10), Version: "1.0"} - defer store.DeleteApplication(applicationToCreate.Name) + defer store.DeleteApplication(context.Background(), applicationToCreate.Name) t.Run("Create, Get and List Applications", func(t *testing.T) { // Create our first application - err := store.CreateApplication(&applicationToCreate) + err := store.CreateApplication(context.Background(), &applicationToCreate) require.NoError(t, err) // Can't overwrite an existing application - err = store.CreateApplication(&applicationToCreate) + err = store.CreateApplication(context.Background(), &applicationToCreate) require.NoError(t, err) // Fetch the application back from SSM - application, err := store.GetApplication(applicationToCreate.Name) + application, err := store.GetApplication(context.Background(), applicationToCreate.Name) require.NoError(t, err) require.Equal(t, applicationToCreate, *application) // List returns a non-empty list of applications - applications, err := store.ListApplications() + applications, err := store.ListApplications(context.Background()) require.NoError(t, err) require.NotEmpty(t, applications) }) @@ -62,36 +62,36 @@ func Test_SSM_Environment_Integration(t *testing.T) { prodEnvironment := config.Environment{Name: "prod", App: applicationToCreate.Name, Region: "us-west-2", AccountID: " 1234"} defer func() { - store.DeleteEnvironment(applicationToCreate.Name, testEnvironment.Name) - store.DeleteEnvironment(applicationToCreate.Name, prodEnvironment.Name) - store.DeleteApplication(applicationToCreate.Name) + store.DeleteEnvironment(context.Background(), applicationToCreate.Name, testEnvironment.Name) + store.DeleteEnvironment(context.Background(), applicationToCreate.Name, prodEnvironment.Name) + store.DeleteApplication(context.Background(), applicationToCreate.Name) }() t.Run("Create, Get and List Environments", func(t *testing.T) { // Create our first application - err := store.CreateApplication(&applicationToCreate) + err := store.CreateApplication(context.Background(), &applicationToCreate) require.NoError(t, err) // Make sure there are no envs with our new application - envs, err := store.ListEnvironments(applicationToCreate.Name) + envs, err := store.ListEnvironments(context.Background(), applicationToCreate.Name) require.NoError(t, err) require.Empty(t, envs) // Add our environments - err = store.CreateEnvironment(&testEnvironment) + err = store.CreateEnvironment(context.Background(), &testEnvironment) require.NoError(t, err) - err = store.CreateEnvironment(&prodEnvironment) + err = store.CreateEnvironment(context.Background(), &prodEnvironment) require.NoError(t, err) // Skip and do not return error if environment already exists - err = store.CreateEnvironment(&prodEnvironment) + err = store.CreateEnvironment(context.Background(), &prodEnvironment) require.NoError(t, err) // Wait for consistency to kick in (ssm path commands are eventually consistent) time.Sleep(5 * time.Second) // Make sure all the environments are under our application - envs, err = store.ListEnvironments(applicationToCreate.Name) + envs, err = store.ListEnvironments(context.Background(), applicationToCreate.Name) require.NoError(t, err) var environments []config.Environment for _, e := range envs { @@ -100,11 +100,11 @@ func Test_SSM_Environment_Integration(t *testing.T) { require.ElementsMatch(t, environments, []config.Environment{testEnvironment, prodEnvironment}) // Fetch our saved environments, one by one - env, err := store.GetEnvironment(applicationToCreate.Name, testEnvironment.Name) + env, err := store.GetEnvironment(context.Background(), applicationToCreate.Name, testEnvironment.Name) require.NoError(t, err) require.Equal(t, testEnvironment, *env) - env, err = store.GetEnvironment(applicationToCreate.Name, prodEnvironment.Name) + env, err = store.GetEnvironment(context.Background(), applicationToCreate.Name, prodEnvironment.Name) require.NoError(t, err) require.Equal(t, prodEnvironment, *env) }) @@ -120,37 +120,37 @@ func Test_SSM_Service_Integration(t *testing.T) { feService := config.Workload{Name: "front-end", App: applicationToCreate.Name, Type: "Load Balanced Web Service"} defer func() { - store.DeleteService(applicationToCreate.Name, apiService.Name) - store.DeleteService(applicationToCreate.Name, feService.Name) - store.DeleteApplication(applicationToCreate.Name) + store.DeleteService(context.Background(), applicationToCreate.Name, apiService.Name) + store.DeleteService(context.Background(), applicationToCreate.Name, feService.Name) + store.DeleteApplication(context.Background(), applicationToCreate.Name) }() t.Run("Create, Get and List Applications", func(t *testing.T) { // Create our first application - err := store.CreateApplication(&applicationToCreate) + err := store.CreateApplication(context.Background(), &applicationToCreate) require.NoError(t, err) // Make sure there are no svcs with our new application - svcs, err := store.ListServices(applicationToCreate.Name) + svcs, err := store.ListServices(context.Background(), applicationToCreate.Name) require.NoError(t, err) require.Empty(t, svcs) // Add our services - err = store.CreateService(&apiService) + err = store.CreateService(context.Background(), &apiService) require.NoError(t, err) - err = store.CreateService(&feService) + err = store.CreateService(context.Background(), &feService) require.NoError(t, err) // Skip and do not return error if services already exists - err = store.CreateService(&feService) + err = store.CreateService(context.Background(), &feService) require.NoError(t, err) // Wait for consistency to kick in (ssm path commands are eventually consistent) time.Sleep(5 * time.Second) // Make sure all the svcs are under our application - svcs, err = store.ListServices(applicationToCreate.Name) + svcs, err = store.ListServices(context.Background(), applicationToCreate.Name) require.NoError(t, err) var services []config.Workload for _, s := range svcs { @@ -159,11 +159,11 @@ func Test_SSM_Service_Integration(t *testing.T) { require.ElementsMatch(t, services, []config.Workload{apiService, feService}) // Fetch our saved svcs, one by one - svc, err := store.GetService(applicationToCreate.Name, apiService.Name) + svc, err := store.GetService(context.Background(), applicationToCreate.Name, apiService.Name) require.NoError(t, err) require.Equal(t, apiService, *svc) - svc, err = store.GetService(applicationToCreate.Name, feService.Name) + svc, err = store.GetService(context.Background(), applicationToCreate.Name, feService.Name) require.NoError(t, err) require.Equal(t, feService, *svc) }) diff --git a/internal/pkg/config/store_test.go b/internal/pkg/config/store_test.go index e87fc24f41d..2a5393c338e 100644 --- a/internal/pkg/config/store_test.go +++ b/internal/pkg/config/store_test.go @@ -4,6 +4,7 @@ package config import ( + "context" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" @@ -12,32 +13,32 @@ import ( type mockSSM struct { t *testing.T - mockPutParameter func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) - mockGetParametersByPath func(t *testing.T, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) - mockGetParameter func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) - mockDeleteParameter func(t *testing.T, param *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) + mockPutParameter func(t *testing.T, ctx context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) + mockGetParametersByPath func(t *testing.T, ctx context.Context, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) + mockGetParameter func(t *testing.T, ctx context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + mockDeleteParameter func(t *testing.T, ctx context.Context, param *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) } -func (m *mockSSM) PutParameter(in *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { - return m.mockPutParameter(m.t, in) +func (m *mockSSM) PutParameter(ctx context.Context, in *ssm.PutParameterInput, opts ...func(*ssm.Options)) (*ssm.PutParameterOutput, error) { + return m.mockPutParameter(m.t, ctx, in) } -func (m *mockSSM) GetParametersByPath(in *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) { - return m.mockGetParametersByPath(m.t, in) +func (m *mockSSM) GetParametersByPath(ctx context.Context, in *ssm.GetParametersByPathInput, opts ...func(*ssm.Options)) (*ssm.GetParametersByPathOutput, error) { + return m.mockGetParametersByPath(m.t, ctx, in) } -func (m *mockSSM) GetParameter(in *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { - return m.mockGetParameter(m.t, in) +func (m *mockSSM) GetParameter(ctx context.Context, in *ssm.GetParameterInput, opts ...func(*ssm.Options)) (*ssm.GetParameterOutput, error) { + return m.mockGetParameter(m.t, ctx, in) } -func (m *mockSSM) DeleteParameter(in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { - return m.mockDeleteParameter(m.t, in) +func (m *mockSSM) DeleteParameter(ctx context.Context, in *ssm.DeleteParameterInput, opts ...func(*ssm.Options)) (*ssm.DeleteParameterOutput, error) { + return m.mockDeleteParameter(m.t, ctx, in) } type mockIdentityService struct { - mockIdentityServiceGet func() (identity.Caller, error) + mockIdentityServiceGet func(context.Context) (identity.Caller, error) } -func (m mockIdentityService) Get() (identity.Caller, error) { - return m.mockIdentityServiceGet() +func (m mockIdentityService) Get(ctx context.Context) (identity.Caller, error) { + return m.mockIdentityServiceGet(ctx) } diff --git a/internal/pkg/config/workload.go b/internal/pkg/config/workload.go index c13a4e4f6b7..adae129acf0 100644 --- a/internal/pkg/config/workload.go +++ b/internal/pkg/config/workload.go @@ -4,6 +4,7 @@ package config import ( + "context" "encoding/json" "errors" "fmt" @@ -23,8 +24,8 @@ type Workload struct { // CreateService instantiates a new service within an existing application. Skip if // the service already exists in the application. -func (s *Store) CreateService(svc *Workload) error { - if err := s.createWorkload(svc); err != nil { +func (s *Store) CreateService(ctx context.Context, svc *Workload) error { + if err := s.createWorkload(ctx, svc); err != nil { return fmt.Errorf("create service %s in application %s: %w", svc.Name, svc.App, err) } return nil @@ -32,15 +33,15 @@ func (s *Store) CreateService(svc *Workload) error { // CreateJob instantiates a new job within an existing application. Skip if the job already // exists in the application. -func (s *Store) CreateJob(job *Workload) error { - if err := s.createWorkload(job); err != nil { +func (s *Store) CreateJob(ctx context.Context, job *Workload) error { + if err := s.createWorkload(ctx, job); err != nil { return fmt.Errorf("create job %s in application %s: %w", job.Name, job.App, err) } return nil } -func (s *Store) createWorkload(wkld *Workload) error { - if _, err := s.GetApplication(wkld.App); err != nil { +func (s *Store) createWorkload(ctx context.Context, wkld *Workload) error { + if _, err := s.GetApplication(ctx, wkld.App); err != nil { return err } @@ -50,7 +51,7 @@ func (s *Store) createWorkload(wkld *Workload) error { return fmt.Errorf("serialize data: %w", err) } - _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ + _, err = s.ssm.PutParameter(ctx, &ssm.PutParameterInput{ Name: aws.String(wkldPath), Description: aws.String(fmt.Sprintf("Copilot %s %s", wkld.Type, wkld.Name)), Type: types.ParameterTypeString, @@ -78,8 +79,8 @@ func (s *Store) createWorkload(wkld *Workload) error { // GetService gets a service belonging to a particular application by name. If no job or svc is found // it returns ErrNoSuchService. -func (s *Store) GetService(appName, svcName string) (*Workload, error) { - param, err := s.getWorkloadParam(appName, svcName) +func (s *Store) GetService(ctx context.Context, appName, svcName string) (*Workload, error) { + param, err := s.getWorkloadParam(ctx, appName, svcName) if err != nil { var errNoSuchWkld *errNoSuchWorkload if errors.As(err, &errNoSuchWkld) { @@ -107,8 +108,8 @@ func (s *Store) GetService(appName, svcName string) (*Workload, error) { // GetJob gets a job belonging to a particular application by name. If no job by that name is found, // it returns ErrNoSuchJob. -func (s *Store) GetJob(appName, jobName string) (*Workload, error) { - param, err := s.getWorkloadParam(appName, jobName) +func (s *Store) GetJob(ctx context.Context, appName, jobName string) (*Workload, error) { + param, err := s.getWorkloadParam(ctx, appName, jobName) if err != nil { var errNoSuchWkld *errNoSuchWorkload if errors.As(err, &errNoSuchWkld) { @@ -135,8 +136,8 @@ func (s *Store) GetJob(appName, jobName string) (*Workload, error) { } // GetWorkload gets a workload belonging to an application by name. -func (s *Store) GetWorkload(appName, name string) (*Workload, error) { - param, err := s.getWorkloadParam(appName, name) +func (s *Store) GetWorkload(ctx context.Context, appName, name string) (*Workload, error) { + param, err := s.getWorkloadParam(ctx, appName, name) if err != nil { return nil, err } @@ -148,9 +149,9 @@ func (s *Store) GetWorkload(appName, name string) (*Workload, error) { return &wl, nil } -func (s *Store) getWorkloadParam(appName, name string) ([]byte, error) { +func (s *Store) getWorkloadParam(ctx context.Context, appName, name string) ([]byte, error) { wlPath := fmt.Sprintf(fmtWkldParamPath, appName, name) - wlParam, err := s.ssm.GetParameter(&ssm.GetParameterInput{ + wlParam, err := s.ssm.GetParameter(ctx, &ssm.GetParameterInput{ Name: aws.String(wlPath), }) if err != nil { @@ -167,8 +168,8 @@ func (s *Store) getWorkloadParam(appName, name string) ([]byte, error) { } // ListServices returns all services belonging to a particular application. -func (s *Store) ListServices(appName string) ([]*Workload, error) { - wklds, err := s.listWorkloads(appName) +func (s *Store) ListServices(ctx context.Context, appName string) ([]*Workload, error) { + wklds, err := s.listWorkloads(ctx, appName) if err != nil { return nil, fmt.Errorf("read service configuration for application %s: %w", appName, err) } @@ -184,8 +185,8 @@ func (s *Store) ListServices(appName string) ([]*Workload, error) { } // ListJobs returns all jobs belonging to a particular application. -func (s *Store) ListJobs(appName string) ([]*Workload, error) { - wklds, err := s.listWorkloads(appName) +func (s *Store) ListJobs(ctx context.Context, appName string) ([]*Workload, error) { + wklds, err := s.listWorkloads(ctx, appName) if err != nil { return nil, fmt.Errorf("read job configuration for application %s: %w", appName, err) } @@ -201,8 +202,8 @@ func (s *Store) ListJobs(appName string) ([]*Workload, error) { } // ListWorkloads returns all workloads belonging to a particular application. -func (s *Store) ListWorkloads(appName string) ([]*Workload, error) { - wklds, err := s.listWorkloads(appName) +func (s *Store) ListWorkloads(ctx context.Context, appName string) ([]*Workload, error) { + wklds, err := s.listWorkloads(ctx, appName) if err != nil { return nil, fmt.Errorf("read workload configuration for application %s: %w", appName, err) } @@ -210,11 +211,11 @@ func (s *Store) ListWorkloads(appName string) ([]*Workload, error) { return wklds, nil } -func (s *Store) listWorkloads(appName string) ([]*Workload, error) { +func (s *Store) listWorkloads(ctx context.Context, appName string) ([]*Workload, error) { var workloads []*Workload workloadsPath := fmt.Sprintf(rootWkldParamPath, appName) - serializedWklds, err := s.listParams(workloadsPath) + serializedWklds, err := s.listParams(ctx, workloadsPath) if err != nil { return nil, err } @@ -231,8 +232,8 @@ func (s *Store) listWorkloads(appName string) ([]*Workload, error) { // DeleteService removes a service from SSM. // If the service does not exist in the store or is successfully deleted then returns nil. Otherwise, returns an error. -func (s *Store) DeleteService(appName, svcName string) error { - if err := s.deleteWorkload(appName, svcName); err != nil { +func (s *Store) DeleteService(ctx context.Context, appName, svcName string) error { + if err := s.deleteWorkload(ctx, appName, svcName); err != nil { return fmt.Errorf("delete service %s from application %s: %w", svcName, appName, err) } return nil @@ -240,16 +241,16 @@ func (s *Store) DeleteService(appName, svcName string) error { // DeleteJob removes a job from SSM. // If the job does not exist in the store or is successfully deleted then returns nil. Otherwise, returns an error. -func (s *Store) DeleteJob(appName, jobName string) error { - if err := s.deleteWorkload(appName, jobName); err != nil { +func (s *Store) DeleteJob(ctx context.Context, appName, jobName string) error { + if err := s.deleteWorkload(ctx, appName, jobName); err != nil { return fmt.Errorf("delete job %s from application %s: %w", jobName, appName, err) } return nil } -func (s *Store) deleteWorkload(appName, wkldName string) error { +func (s *Store) deleteWorkload(ctx context.Context, appName, wkldName string) error { paramName := fmt.Sprintf(fmtWkldParamPath, appName, wkldName) - _, err := s.ssm.DeleteParameter(&ssm.DeleteParameterInput{ + _, err := s.ssm.DeleteParameter(ctx, &ssm.DeleteParameterInput{ Name: aws.String(paramName), }) diff --git a/internal/pkg/config/workload_test.go b/internal/pkg/config/workload_test.go index ce2f8652862..90a9f263a15 100644 --- a/internal/pkg/config/workload_test.go +++ b/internal/pkg/config/workload_test.go @@ -4,6 +4,7 @@ package config import ( + "context" "errors" "fmt" "testing" @@ -30,13 +31,13 @@ func TestStore_ListServices(t *testing.T) { lastPageInPaginatedResp := false testCases := map[string]struct { - mockGetParametersByPath func(t *testing.T, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) + mockGetParametersByPath func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) wantedSvcs []Workload wantedErr error }{ "with multiple existing svcs": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, servicePath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -56,7 +57,7 @@ func TestStore_ListServices(t *testing.T) { wantedErr: nil, }, "with malformed json": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, servicePath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -70,14 +71,14 @@ func TestStore_ListServices(t *testing.T) { wantedErr: fmt.Errorf("read service configuration for application chicken: invalid character 'o' looking for beginning of value"), }, "with SSM error": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, servicePath, *param.Path) return nil, fmt.Errorf("broken") }, wantedErr: fmt.Errorf("read service configuration for application chicken: broken"), }, "with paginated response": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, servicePath, *param.Path) if !lastPageInPaginatedResp { @@ -120,7 +121,7 @@ func TestStore_ListServices(t *testing.T) { } // WHEN - svcPointers, err := store.ListServices("chicken") + svcPointers, err := store.ListServices(context.Background(), "chicken") // THEN if tc.wantedErr != nil { require.EqualError(t, err, tc.wantedErr.Error()) @@ -149,13 +150,13 @@ func TestStore_ListWorkloads(t *testing.T) { workloadPath := fmt.Sprintf(rootWkldParamPath, mailerJob.App) testCases := map[string]struct { - mockGetParametersByPath func(t *testing.T, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) + mockGetParametersByPath func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) wantedWls []Workload wantedErr error }{ "with existing workloads": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -174,7 +175,7 @@ func TestStore_ListWorkloads(t *testing.T) { wantedErr: nil, }, "with job": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -200,7 +201,7 @@ func TestStore_ListWorkloads(t *testing.T) { } // WHEN - wlPointers, err := store.ListWorkloads("chicken") + wlPointers, err := store.ListWorkloads(context.Background(), "chicken") // THEN if tc.wantedErr != nil { require.EqualError(t, err, tc.wantedErr.Error()) @@ -234,13 +235,13 @@ func TestStore_ListJobs(t *testing.T) { workloadPath := fmt.Sprintf(rootWkldParamPath, mailerJob.App) testCases := map[string]struct { - mockGetParametersByPath func(t *testing.T, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) + mockGetParametersByPath func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) wantedJobs []Workload wantedErr error }{ "with existing jobs": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -259,7 +260,7 @@ func TestStore_ListJobs(t *testing.T) { wantedErr: nil, }, "with service and job": { - mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { + mockGetParametersByPath: func(t *testing.T, _ context.Context, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ @@ -289,7 +290,7 @@ func TestStore_ListJobs(t *testing.T) { } // WHEN - jobPointers, err := store.ListJobs("chicken") + jobPointers, err := store.ListJobs(context.Background(), "chicken") // THEN if tc.wantedErr != nil { require.EqualError(t, err, tc.wantedErr.Error()) @@ -311,12 +312,12 @@ func TestStore_GetService(t *testing.T) { require.NoError(t, err, "Marshal svc should not fail") testCases := map[string]struct { - mockGetParameter func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + mockGetParameter func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) wantedSvc Workload wantedErr error }{ "with existing service": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -329,14 +330,14 @@ func TestStore_GetService(t *testing.T) { wantedErr: nil, }, "with no existing svc": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) return nil, &types.ParameterNotFound{} }, wantedErr: errors.New("couldn't find service api in the application chicken"), }, "with malformed json": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -348,7 +349,7 @@ func TestStore_GetService(t *testing.T) { wantedErr: fmt.Errorf("read configuration for service api in application chicken: invalid character 'o' looking for beginning of value"), }, "with SSM error": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { return nil, fmt.Errorf("broken") }, wantedErr: fmt.Errorf("broken"), @@ -366,7 +367,7 @@ func TestStore_GetService(t *testing.T) { } // WHEN - svc, err := store.GetService("chicken", "api") + svc, err := store.GetService(context.Background(), "chicken", "api") // THEN if tc.wantedErr != nil { @@ -390,12 +391,12 @@ func TestStore_GetJob(t *testing.T) { require.NoError(t, err, "Marshal svc should not fail") testCases := map[string]struct { - mockGetParameter func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + mockGetParameter func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) wantedJob Workload wantedErr error }{ "with existing job": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, mailerJobPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -408,14 +409,14 @@ func TestStore_GetJob(t *testing.T) { wantedErr: nil, }, "with no existing job": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, mailerJobPath, *param.Name) return nil, &types.ParameterNotFound{} }, wantedErr: errors.New("couldn't find job mailer in the application chicken"), }, "with existing service": { - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, mailerJobPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -441,7 +442,7 @@ func TestStore_GetJob(t *testing.T) { } // WHEN - job, err := store.GetJob("chicken", "mailer") + job, err := store.GetJob(context.Background(), "chicken", "mailer") // THEN if tc.wantedErr != nil { @@ -474,12 +475,12 @@ func TestStore_CreateService(t *testing.T) { }, } testCases := map[string]struct { - mockGetParameter func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) - mockPutParameter func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) + mockGetParameter func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) + mockPutParameter func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) wantedErr error }{ "with no existing svc": { - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) require.Equal(t, testServiceString, *param.Value) require.Equal(t, tagsForServiceParam, param.Tags) @@ -487,7 +488,7 @@ func TestStore_CreateService(t *testing.T) { Version: 1, }, nil }, - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -498,12 +499,12 @@ func TestStore_CreateService(t *testing.T) { }, }, "with existing svc": { - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) require.Equal(t, tagsForServiceParam, param.Tags) return nil, &types.ParameterAlreadyExists{} }, - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -515,11 +516,11 @@ func TestStore_CreateService(t *testing.T) { wantedErr: nil, }, "with SSM error": { - mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + mockPutParameter: func(t *testing.T, _ context.Context, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, tagsForServiceParam, param.Tags) return nil, fmt.Errorf("broken") }, - mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + mockGetParameter: func(t *testing.T, _ context.Context, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ Parameter: &types.Parameter{ @@ -544,7 +545,7 @@ func TestStore_CreateService(t *testing.T) { } // WHEN - err := store.CreateService(&Workload{ + err := store.CreateService(context.Background(), &Workload{ Name: testService.Name, App: testService.App, Type: testService.Type}) @@ -563,23 +564,23 @@ func TestDeleteService(t *testing.T) { mockError := errors.New("mockError") tests := map[string]struct { - mockDeleteParam func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) + mockDeleteParam func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) want error }{ "parameter is already deleted": { - mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParam: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { return nil, &types.ParameterNotFound{} }, }, "unexpected error": { - mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParam: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { return nil, mockError }, want: fmt.Errorf("delete service %s from application %s: %w", mockSvcName, mockApplicationName, mockError), }, "successfully deleted param": { - mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + mockDeleteParam: func(t *testing.T, _ context.Context, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { wantedPath := fmt.Sprintf(fmtWkldParamPath, mockApplicationName, mockSvcName) require.Equal(t, wantedPath, *in.Name) @@ -599,7 +600,7 @@ func TestDeleteService(t *testing.T) { }, } - got := s.DeleteService(mockApplicationName, mockSvcName) + got := s.DeleteService(context.Background(), mockApplicationName, mockSvcName) require.Equal(t, test.want, got) }) diff --git a/internal/pkg/deploy/cloudformation/cloudformation.go b/internal/pkg/deploy/cloudformation/cloudformation.go index aa57f0337aa..9c0ad1dd0c4 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation.go +++ b/internal/pkg/deploy/cloudformation/cloudformation.go @@ -112,6 +112,7 @@ type cfnClient interface { DeleteAndWait(stackName string) error DeleteAndWaitWithRoleARN(stackName, roleARN string) error Describe(stackName string) (*cloudformation.StackDescription, error) + DescribeWithContext(ctx context.Context, stackName string) (*cloudformation.StackDescription, error) DescribeChangeSet(changeSetID, stackName string) (*cloudformation.ChangeSetDescription, error) TemplateBody(stackName string) (string, error) TemplateBodyFromChangeSet(changeSetID, stackName string) (string, error) diff --git a/internal/pkg/deploy/cloudformation/env.go b/internal/pkg/deploy/cloudformation/env.go index 87aa05d1f3c..5fd3c5e8561 100644 --- a/internal/pkg/deploy/cloudformation/env.go +++ b/internal/pkg/deploy/cloudformation/env.go @@ -90,14 +90,14 @@ func (cf CloudFormation) DeleteEnvironment(appName, envName, cfnExecRoleARN stri } // GetEnvironment returns the Environment metadata from the CloudFormation stack. -func (cf CloudFormation) GetEnvironment(appName, envName string) (*config.Environment, error) { +func (cf CloudFormation) GetEnvironment(ctx context.Context, appName, envName string) (*config.Environment, error) { conf := stack.NewBootstrapEnvStackConfig(&stack.EnvConfig{ App: deploy.AppInformation{ Name: appName, }, Name: envName, }) - descr, err := cf.cfnClient.Describe(conf.StackName()) + descr, err := cf.cfnClient.DescribeWithContext(ctx, conf.StackName()) if err != nil { return nil, err } diff --git a/internal/pkg/deploy/cloudformation/env_test.go b/internal/pkg/deploy/cloudformation/env_test.go index 3452d8c4517..2c864cbdb2c 100644 --- a/internal/pkg/deploy/cloudformation/env_test.go +++ b/internal/pkg/deploy/cloudformation/env_test.go @@ -4,10 +4,12 @@ package cloudformation import ( + "context" "errors" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" + "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/mocks" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aws/aws-sdk-go-v2/aws" @@ -16,6 +18,44 @@ import ( "github.com/stretchr/testify/require" ) +func TestCloudFormation_GetEnvironment(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + parent := context.WithValue(context.Background(), "key", "value") + mockClient := mocks.NewMockcfnClient(ctrl) + mockClient.EXPECT().DescribeWithContext(parent, "phonetool-test"). + Return(&cloudformation.StackDescription{ + StackId: aws.String("arn:aws:cloudformation:us-west-2:123456789012:stack/phonetool-test/abc123"), + Outputs: []awscfn.Output{ + { + OutputKey: aws.String("EnvironmentManagerRoleARN"), + OutputValue: aws.String("arn:aws:iam::123456789012:role/manager"), + }, + { + OutputKey: aws.String("CFNExecutionRoleARN"), + OutputValue: aws.String("arn:aws:iam::123456789012:role/execution"), + }, + }, + }, nil) + + cf := &CloudFormation{ + cfnClient: mockClient, + } + + got, err := cf.GetEnvironment(parent, "phonetool", "test") + + require.NoError(t, err) + require.Equal(t, &config.Environment{ + App: "phonetool", + Name: "test", + AccountID: "123456789012", + Region: "us-west-2", + ManagerRoleARN: "arn:aws:iam::123456789012:role/manager", + ExecutionRoleARN: "arn:aws:iam::123456789012:role/execution", + }, got) +} + func TestCloudFormation_DeployedEnvironmentParameters(t *testing.T) { testCases := map[string]struct { inAppName string diff --git a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go index 3802592ce0e..2aad8f735be 100644 --- a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go +++ b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go @@ -400,6 +400,21 @@ func (mr *MockcfnClientMockRecorder) DescribeStackEvents(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackEvents", reflect.TypeOf((*MockcfnClient)(nil).DescribeStackEvents), arg0) } +// DescribeWithContext mocks base method. +func (m *MockcfnClient) DescribeWithContext(ctx context.Context, stackName string) (*cloudformation.StackDescription, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DescribeWithContext", ctx, stackName) + ret0, _ := ret[0].(*cloudformation.StackDescription) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeWithContext indicates an expected call of DescribeWithContext. +func (mr *MockcfnClientMockRecorder) DescribeWithContext(ctx, stackName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeWithContext", reflect.TypeOf((*MockcfnClient)(nil).DescribeWithContext), ctx, stackName) +} + // ErrorEvents mocks base method. func (m *MockcfnClient) ErrorEvents(stackName string) ([]cloudformation.StackEvent, error) { m.ctrl.T.Helper() diff --git a/internal/pkg/deploy/deploy.go b/internal/pkg/deploy/deploy.go index ae258fb9c33..17275f2b0d4 100644 --- a/internal/pkg/deploy/deploy.go +++ b/internal/pkg/deploy/deploy.go @@ -49,11 +49,11 @@ type ResourceGetter interface { // ConfigStoreClient wraps config store methods utilized by deploy store. type ConfigStoreClient interface { - GetEnvironment(appName string, environmentName string) (*config.Environment, error) - ListEnvironments(appName string) ([]*config.Environment, error) - ListWorkloads(appName string) ([]*config.Workload, error) - GetService(appName, svcName string) (*config.Workload, error) - GetJob(appName, jobname string) (*config.Workload, error) + GetEnvironment(ctx context.Context, appName string, environmentName string) (*config.Environment, error) + ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) + ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) + GetService(ctx context.Context, appName, svcName string) (*config.Workload, error) + GetJob(ctx context.Context, appName, jobname string) (*config.Workload, error) } // SessionProvider is the interface to provide configuration for the AWS SDK's service clients. @@ -64,8 +64,8 @@ type SessionProvider interface { // Store fetches information on deployed services. type Store struct { configStore ConfigStoreClient - newRgClientFromIDs func(string, string) (ResourceGetter, error) - newRgClientFromRole func(string, string) (ResourceGetter, error) + newRgClientFromIDs func(context.Context, string, string) (ResourceGetter, error) + newRgClientFromRole func(context.Context, string, string) (ResourceGetter, error) } // NewStore returns a new store. @@ -73,19 +73,19 @@ func NewStore(sessProvider SessionProvider, store ConfigStoreClient) (*Store, er s := &Store{ configStore: store, } - s.newRgClientFromIDs = func(appName, envName string) (ResourceGetter, error) { - env, err := s.configStore.GetEnvironment(appName, envName) + s.newRgClientFromIDs = func(ctx context.Context, appName, envName string) (ResourceGetter, error) { + env, err := s.configStore.GetEnvironment(ctx, appName, envName) if err != nil { return nil, fmt.Errorf("get environment config %s: %w", envName, err) } - cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) + cfg, err := sessProvider.ConfigFromRole(ctx, env.ManagerRoleARN, env.Region) if err != nil { return nil, fmt.Errorf("create new config from env role: %w", err) } return rg.New(cfg), nil } - s.newRgClientFromRole = func(roleARN, region string) (ResourceGetter, error) { - cfg, err := sessProvider.ConfigFromRole(context.Background(), roleARN, region) + s.newRgClientFromRole = func(ctx context.Context, roleARN, region string) (ResourceGetter, error) { + cfg, err := sessProvider.ConfigFromRole(ctx, roleARN, region) if err != nil { return nil, fmt.Errorf("create new config from env role: %w", err) } @@ -149,22 +149,22 @@ func (p *PipelineStore) ListDeployedPipelines(appName string) ([]Pipeline, error } // ListDeployedServices returns the names of deployed services in an environment. -func (s *Store) ListDeployedServices(appName string, envName string) ([]string, error) { - return s.listDeployedWorkloads(appName, envName, manifestinfo.ServiceTypes()) +func (s *Store) ListDeployedServices(ctx context.Context, appName string, envName string) ([]string, error) { + return s.listDeployedWorkloads(ctx, appName, envName, manifestinfo.ServiceTypes()) } // ListDeployedJobs returns the names of deployed jobs in an environment. -func (s *Store) ListDeployedJobs(appName string, envName string) ([]string, error) { - return s.listDeployedWorkloads(appName, envName, manifestinfo.JobTypes()) +func (s *Store) ListDeployedJobs(ctx context.Context, appName string, envName string) ([]string, error) { + return s.listDeployedWorkloads(ctx, appName, envName, manifestinfo.JobTypes()) } // ListDeployedWorkloads returns the names of deployed workloads in an environment. -func (s *Store) ListDeployedWorkloads(appName string, envName string) ([]string, error) { - return s.listDeployedWorkloads(appName, envName, manifestinfo.WorkloadTypes()) +func (s *Store) ListDeployedWorkloads(ctx context.Context, appName string, envName string) ([]string, error) { + return s.listDeployedWorkloads(ctx, appName, envName, manifestinfo.WorkloadTypes()) } -func (s *Store) listDeployedWorkloads(appName string, envName string, workloadType []string) ([]string, error) { - allWorkloads, err := s.configStore.ListWorkloads(appName) +func (s *Store) listDeployedWorkloads(ctx context.Context, appName string, envName string, workloadType []string) ([]string, error) { + allWorkloads, err := s.configStore.ListWorkloads(ctx, appName) if err != nil { return nil, fmt.Errorf("list all workloads in application %s: %w", appName, err) } @@ -178,7 +178,7 @@ func (s *Store) listDeployedWorkloads(appName string, envName string, workloadTy } } - rgClient, err := s.newRgClientFromIDs(appName, envName) + rgClient, err := s.newRgClientFromIDs(ctx, appName, envName) if err != nil { return nil, err } @@ -206,8 +206,8 @@ func (s *Store) listDeployedWorkloads(appName string, envName string, workloadTy // ListSNSTopics returns a list of SNS topics deployed to the current environment and tagged with // Copilot identifiers. -func (s *Store) ListSNSTopics(appName string, envName string) ([]Topic, error) { - rgClient, err := s.newRgClientFromIDs(appName, envName) +func (s *Store) ListSNSTopics(ctx context.Context, appName string, envName string) ([]Topic, error) { + rgClient, err := s.newRgClientFromIDs(ctx, appName, envName) if err != nil { return nil, err } @@ -270,8 +270,8 @@ func (s *Store) deployedServices(rgClient ResourceGetter, app, env, svc string) } // ListEnvironmentsDeployedTo returns all the environment that a service is deployed in. -func (s *Store) ListEnvironmentsDeployedTo(appName string, svcName string) ([]string, error) { - envs, err := s.configStore.ListEnvironments(appName) +func (s *Store) ListEnvironmentsDeployedTo(ctx context.Context, appName string, svcName string) ([]string, error) { + envs, err := s.configStore.ListEnvironments(ctx, appName) if err != nil { return nil, fmt.Errorf("list environment for app %s: %w", appName, err) } @@ -279,7 +279,7 @@ func (s *Store) ListEnvironmentsDeployedTo(appName string, svcName string) ([]st defer close(deployedEnv) for _, env := range envs { go func(env *config.Environment) { - rgClient, err := s.newRgClientFromRole(env.ManagerRoleARN, env.Region) + rgClient, err := s.newRgClientFromRole(ctx, env.ManagerRoleARN, env.Region) if err != nil { deployedEnv <- result{err: err} return @@ -301,18 +301,18 @@ func (s *Store) ListEnvironmentsDeployedTo(appName string, svcName string) ([]st } // IsServiceDeployed returns whether a service is deployed in an environment or not. -func (s *Store) IsServiceDeployed(appName string, envName string, svcName string) (bool, error) { - return s.IsWorkloadDeployed(appName, envName, svcName) +func (s *Store) IsServiceDeployed(ctx context.Context, appName string, envName string, svcName string) (bool, error) { + return s.IsWorkloadDeployed(ctx, appName, envName, svcName) } // IsJobDeployed returns whether a job is deployed in an environment or not by checking for a state machine. -func (s *Store) IsJobDeployed(appName, envName, jobName string) (bool, error) { - return s.IsWorkloadDeployed(appName, envName, jobName) +func (s *Store) IsJobDeployed(ctx context.Context, appName, envName, jobName string) (bool, error) { + return s.IsWorkloadDeployed(ctx, appName, envName, jobName) } // IsWorkloadDeployed returns whether a workload is deployed in an environment or not. -func (s *Store) IsWorkloadDeployed(appName, envName, name string) (bool, error) { - rgClient, err := s.newRgClientFromIDs(appName, envName) +func (s *Store) IsWorkloadDeployed(ctx context.Context, appName, envName, name string) (bool, error) { + rgClient, err := s.newRgClientFromIDs(ctx, appName, envName) if err != nil { return false, err } diff --git a/internal/pkg/deploy/deploy_test.go b/internal/pkg/deploy/deploy_test.go index 2120e6b97bb..e92d07cc70f 100644 --- a/internal/pkg/deploy/deploy_test.go +++ b/internal/pkg/deploy/deploy_test.go @@ -4,6 +4,7 @@ package deploy import ( + "context" "errors" "fmt" "testing" @@ -18,6 +19,8 @@ import ( "github.com/stretchr/testify/require" ) +var ctx = context.Background() + type storeMock struct { rgGetter *mocks.MockResourceGetter configStore *mocks.MockConfigStoreClient @@ -38,7 +41,7 @@ func TestStore_ListDeployedServices(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListWorkloads("mockApp").Return([]*config.Workload{}, nil), + m.configStore.EXPECT().ListWorkloads(context.Background(), "mockApp").Return([]*config.Workload{}, nil), m.rgGetter.EXPECT().GetResourcesByTags(stackResourceType, map[string]string{ AppTagKey: "mockApp", EnvTagKey: "mockEnv", @@ -54,7 +57,7 @@ func TestStore_ListDeployedServices(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListWorkloads("mockApp").Return([]*config.Workload{}, nil), + m.configStore.EXPECT().ListWorkloads(context.Background(), "mockApp").Return([]*config.Workload{}, nil), m.rgGetter.EXPECT().GetResourcesByTags(stackResourceType, map[string]string{ AppTagKey: "mockApp", EnvTagKey: "mockEnv", @@ -70,7 +73,7 @@ func TestStore_ListDeployedServices(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListWorkloads("mockApp").Return(nil, errors.New("some error")), + m.configStore.EXPECT().ListWorkloads(context.Background(), "mockApp").Return(nil, errors.New("some error")), m.rgGetter.EXPECT().GetResourcesByTags(stackResourceType, map[string]string{ AppTagKey: "mockApp", EnvTagKey: "mockEnv", @@ -86,7 +89,7 @@ func TestStore_ListDeployedServices(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListWorkloads("mockApp").Return([]*config.Workload{ + m.configStore.EXPECT().ListWorkloads(context.Background(), "mockApp").Return([]*config.Workload{ { App: "mockApp", Name: "mockSvc1", @@ -132,11 +135,11 @@ func TestStore_ListDeployedServices(t *testing.T) { store := &Store{ configStore: mockConfigStore, - newRgClientFromIDs: func(string, string) (ResourceGetter, error) { return mockRgGetter, nil }, + newRgClientFromIDs: func(context.Context, string, string) (ResourceGetter, error) { return mockRgGetter, nil }, } // WHEN - svcs, err := store.ListDeployedServices(tc.inputApp, tc.inputEnv) + svcs, err := store.ListDeployedServices(ctx, tc.inputApp, tc.inputEnv) // THEN if tc.wantedError != nil { @@ -164,7 +167,7 @@ func TestStore_ListDeployedJobs(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListWorkloads("mockApp").Return([]*config.Workload{ + m.configStore.EXPECT().ListWorkloads(context.Background(), "mockApp").Return([]*config.Workload{ { App: "mockApp", Name: "mockSvc1", @@ -202,7 +205,7 @@ func TestStore_ListDeployedJobs(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListWorkloads("mockApp").Return([]*config.Workload{}, nil), + m.configStore.EXPECT().ListWorkloads(context.Background(), "mockApp").Return([]*config.Workload{}, nil), m.rgGetter.EXPECT().GetResourcesByTags(stackResourceType, map[string]string{ AppTagKey: "mockApp", EnvTagKey: "mockEnv", @@ -228,10 +231,10 @@ func TestStore_ListDeployedJobs(t *testing.T) { store := &Store{ configStore: mockConfigStore, - newRgClientFromIDs: func(string, string) (ResourceGetter, error) { return mockRgGetter, nil }, + newRgClientFromIDs: func(context.Context, string, string) (ResourceGetter, error) { return mockRgGetter, nil }, } // WHEN - jobs, err := store.ListDeployedJobs(tc.inputApp, tc.inputEnv) + jobs, err := store.ListDeployedJobs(ctx, tc.inputApp, tc.inputEnv) // THEN if tc.wantedError != nil { @@ -259,7 +262,7 @@ func TestStore_ListEnvironmentsDeployedTo(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListEnvironments("mockApp").Return(nil, errors.New("some error")), + m.configStore.EXPECT().ListEnvironments(context.Background(), "mockApp").Return(nil, errors.New("some error")), ) }, @@ -271,7 +274,7 @@ func TestStore_ListEnvironmentsDeployedTo(t *testing.T) { setupMocks: func(m storeMock) { gomock.InOrder( - m.configStore.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configStore.EXPECT().ListEnvironments(context.Background(), "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv", @@ -292,7 +295,7 @@ func TestStore_ListEnvironmentsDeployedTo(t *testing.T) { inputSvc: "mockSvc", setupMocks: func(m storeMock) { - m.configStore.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configStore.EXPECT().ListEnvironments(context.Background(), "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv1", @@ -335,11 +338,11 @@ func TestStore_ListEnvironmentsDeployedTo(t *testing.T) { store := &Store{ configStore: mockConfigStore, - newRgClientFromRole: func(string, string) (ResourceGetter, error) { return mockRgGetter, nil }, + newRgClientFromRole: func(context.Context, string, string) (ResourceGetter, error) { return mockRgGetter, nil }, } // WHEN - envs, err := store.ListEnvironmentsDeployedTo(tc.inputApp, tc.inputSvc) + envs, err := store.ListEnvironmentsDeployedTo(ctx, tc.inputApp, tc.inputSvc) // THEN if tc.wantedError != nil { @@ -432,11 +435,11 @@ func TestStore_IsServiceDeployed(t *testing.T) { store := &Store{ configStore: mockConfigStore, - newRgClientFromIDs: func(string, string) (ResourceGetter, error) { return mockRgGetter, nil }, + newRgClientFromIDs: func(context.Context, string, string) (ResourceGetter, error) { return mockRgGetter, nil }, } // WHEN - deployed, err := store.IsServiceDeployed(tc.inputApp, tc.inputEnv, tc.inputSvc) + deployed, err := store.IsServiceDeployed(ctx, tc.inputApp, tc.inputEnv, tc.inputSvc) // THEN if tc.wantedError != nil { @@ -527,11 +530,11 @@ func Test_IsJobDeployed(t *testing.T) { store := &Store{ configStore: mockConfigStore, - newRgClientFromIDs: func(string, string) (ResourceGetter, error) { return mockRgGetter, nil }, + newRgClientFromIDs: func(context.Context, string, string) (ResourceGetter, error) { return mockRgGetter, nil }, } // WHEN - deployed, err := store.IsJobDeployed(tc.inputApp, tc.inputEnv, tc.inputJob) + deployed, err := store.IsJobDeployed(ctx, tc.inputApp, tc.inputEnv, tc.inputJob) // THEN if tc.wantedError != nil { @@ -672,11 +675,11 @@ func TestStore_ListSNSTopics(t *testing.T) { store := &Store{ configStore: mockConfigStore, - newRgClientFromIDs: func(string, string) (ResourceGetter, error) { return mockRgGetter, nil }, + newRgClientFromIDs: func(context.Context, string, string) (ResourceGetter, error) { return mockRgGetter, nil }, } // WHEN - topics, err := store.ListSNSTopics(tc.inputApp, tc.inputEnv) + topics, err := store.ListSNSTopics(ctx, tc.inputApp, tc.inputEnv) // THEN if tc.wantedError != nil { diff --git a/internal/pkg/deploy/mocks/mock_deploy.go b/internal/pkg/deploy/mocks/mock_deploy.go index a7b9ae6aa8f..ea3d408b63a 100644 --- a/internal/pkg/deploy/mocks/mock_deploy.go +++ b/internal/pkg/deploy/mocks/mock_deploy.go @@ -76,78 +76,78 @@ func (m *MockConfigStoreClient) EXPECT() *MockConfigStoreClientMockRecorder { } // GetEnvironment mocks base method. -func (m *MockConfigStoreClient) GetEnvironment(appName, environmentName string) (*config.Environment, error) { +func (m *MockConfigStoreClient) GetEnvironment(ctx context.Context, appName, environmentName string) (*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "GetEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // GetEnvironment indicates an expected call of GetEnvironment. -func (mr *MockConfigStoreClientMockRecorder) GetEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockConfigStoreClientMockRecorder) GetEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockConfigStoreClient)(nil).GetEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockConfigStoreClient)(nil).GetEnvironment), ctx, appName, environmentName) } // GetJob mocks base method. -func (m *MockConfigStoreClient) GetJob(appName, jobname string) (*config.Workload, error) { +func (m *MockConfigStoreClient) GetJob(ctx context.Context, appName, jobname string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetJob", appName, jobname) + ret := m.ctrl.Call(m, "GetJob", ctx, appName, jobname) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetJob indicates an expected call of GetJob. -func (mr *MockConfigStoreClientMockRecorder) GetJob(appName, jobname interface{}) *gomock.Call { +func (mr *MockConfigStoreClientMockRecorder) GetJob(ctx, appName, jobname interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJob", reflect.TypeOf((*MockConfigStoreClient)(nil).GetJob), appName, jobname) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJob", reflect.TypeOf((*MockConfigStoreClient)(nil).GetJob), ctx, appName, jobname) } // GetService mocks base method. -func (m *MockConfigStoreClient) GetService(appName, svcName string) (*config.Workload, error) { +func (m *MockConfigStoreClient) GetService(ctx context.Context, appName, svcName string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetService", appName, svcName) + ret := m.ctrl.Call(m, "GetService", ctx, appName, svcName) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetService indicates an expected call of GetService. -func (mr *MockConfigStoreClientMockRecorder) GetService(appName, svcName interface{}) *gomock.Call { +func (mr *MockConfigStoreClientMockRecorder) GetService(ctx, appName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockConfigStoreClient)(nil).GetService), appName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockConfigStoreClient)(nil).GetService), ctx, appName, svcName) } // ListEnvironments mocks base method. -func (m *MockConfigStoreClient) ListEnvironments(appName string) ([]*config.Environment, error) { +func (m *MockConfigStoreClient) ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironments", appName) + ret := m.ctrl.Call(m, "ListEnvironments", ctx, appName) ret0, _ := ret[0].([]*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironments indicates an expected call of ListEnvironments. -func (mr *MockConfigStoreClientMockRecorder) ListEnvironments(appName interface{}) *gomock.Call { +func (mr *MockConfigStoreClientMockRecorder) ListEnvironments(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockConfigStoreClient)(nil).ListEnvironments), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockConfigStoreClient)(nil).ListEnvironments), ctx, appName) } // ListWorkloads mocks base method. -func (m *MockConfigStoreClient) ListWorkloads(appName string) ([]*config.Workload, error) { +func (m *MockConfigStoreClient) ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListWorkloads", appName) + ret := m.ctrl.Call(m, "ListWorkloads", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListWorkloads indicates an expected call of ListWorkloads. -func (mr *MockConfigStoreClientMockRecorder) ListWorkloads(appName interface{}) *gomock.Call { +func (mr *MockConfigStoreClientMockRecorder) ListWorkloads(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockConfigStoreClient)(nil).ListWorkloads), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockConfigStoreClient)(nil).ListWorkloads), ctx, appName) } // MockSessionProvider is a mock of SessionProvider interface. diff --git a/internal/pkg/describe/backend_service.go b/internal/pkg/describe/backend_service.go index 65fad477f94..47b1cb77d13 100644 --- a/internal/pkg/describe/backend_service.go +++ b/internal/pkg/describe/backend_service.go @@ -32,6 +32,7 @@ const ( // BackendServiceDescriber retrieves information about a backend service. type BackendServiceDescriber struct { + ctx context.Context app string svc string enableResources bool @@ -47,8 +48,9 @@ type BackendServiceDescriber struct { } // NewBackendServiceDescriber instantiates a backend service describer. -func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, error) { +func NewBackendServiceDescriber(ctx context.Context, opt NewServiceConfig) (*BackendServiceDescriber, error) { describer := &BackendServiceDescriber{ + ctx: ctx, app: opt.App, svc: opt.Svc, enableResources: opt.EnableResources, @@ -57,7 +59,7 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, envStackDescriber: make(map[string]envDescriber), } describer.initLBDescriber = func(envName string) (lbDescriber, error) { - env, err := opt.ConfigStore.GetEnvironment(opt.App, envName) + env, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, envName) if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } @@ -71,7 +73,7 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if describer, ok := describer.ecsServiceDescribers[env]; ok { return describer, nil } - svcDescr, err := newECSServiceDescriber(NewServiceConfig{ + svcDescr, err := newECSServiceDescriber(ctx, NewServiceConfig{ App: opt.App, Env: env, Svc: opt.Svc, @@ -87,7 +89,7 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if describer, ok := describer.cwAlarmDescribers[envName]; ok { return describer, nil } - env, err := opt.ConfigStore.GetEnvironment(opt.App, envName) + env, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, envName) if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } @@ -101,7 +103,7 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if describer, ok := describer.envStackDescriber[env]; ok { return describer, nil } - envDescr, err := NewEnvDescriber(NewEnvDescriberConfig{ + envDescr, err := NewEnvDescriber(ctx, NewEnvDescriberConfig{ App: opt.App, Env: env, ConfigStore: opt.ConfigStore, @@ -117,7 +119,11 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, // Describe returns info of a backend service. func (d *BackendServiceDescriber) Describe() (HumanJSONStringer, error) { - environments, err := d.store.ListEnvironmentsDeployedTo(d.app, d.svc) + ctx := d.ctx + if ctx == nil { + ctx = context.Background() + } + environments, err := d.store.ListEnvironmentsDeployedTo(ctx, d.app, d.svc) if err != nil { return nil, fmt.Errorf("list deployed environments for application %s: %w", d.app, err) } diff --git a/internal/pkg/describe/backend_service_test.go b/internal/pkg/describe/backend_service_test.go index 777e384a332..4c2d0430e09 100644 --- a/internal/pkg/describe/backend_service_test.go +++ b/internal/pkg/describe/backend_service_test.go @@ -51,7 +51,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { "return error if fail to list environment": { setupMocks: func(m backendSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return(nil, mockErr), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return(nil, mockErr), ) }, wantedError: fmt.Errorf("list deployed environments for application phonetool: some error"), @@ -59,7 +59,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve service deployment configuration": { setupMocks: func(m backendSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(nil, mockErr), ) @@ -69,7 +69,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve svc discovery endpoint": { setupMocks: func(m backendSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTargetPortParamKey: "80", @@ -92,7 +92,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "512", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(params, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -113,7 +113,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "512", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(params, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -135,7 +135,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "512", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(params, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -161,7 +161,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "512", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(params, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -188,7 +188,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "512", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(params, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -215,7 +215,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "512", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(params, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -249,7 +249,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "512", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(testParams, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -313,7 +313,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { cfnstack.WorkloadTaskMemoryParamKey: "1024", } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv, prodEnv, mockEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv, prodEnv, mockEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(nil, nil), m.ecsDescriber.EXPECT().Params().Return(testParams, nil), m.ecsDescriber.EXPECT().ServiceConnectDNSNames().Return(nil, nil), @@ -556,7 +556,7 @@ func TestBackendServiceDescriber_Describe(t *testing.T) { }, } gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return(resources, nil), m.ecsDescriber.EXPECT().Params().Return(params, nil), m.ecsDescriber.EXPECT().StackResources().Return(resources, nil), diff --git a/internal/pkg/describe/context_test.go b/internal/pkg/describe/context_test.go new file mode 100644 index 00000000000..18cd1fce5f0 --- /dev/null +++ b/internal/pkg/describe/context_test.go @@ -0,0 +1,8 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package describe + +import "context" + +var ctx = context.Background() diff --git a/internal/pkg/describe/env.go b/internal/pkg/describe/env.go index 31c0071978f..a4f243fcd09 100644 --- a/internal/pkg/describe/env.go +++ b/internal/pkg/describe/env.go @@ -50,6 +50,7 @@ type EnvDescriber struct { app string env *config.Environment enableResources bool + ctx context.Context configStore ConfigStoreSvc deployStore DeployedEnvServicesLister @@ -69,8 +70,8 @@ type NewEnvDescriberConfig struct { } // NewEnvDescriber instantiates an environment describer. -func NewEnvDescriber(opt NewEnvDescriberConfig) (*EnvDescriber, error) { - env, err := opt.ConfigStore.GetEnvironment(opt.App, opt.Env) +func NewEnvDescriber(ctx context.Context, opt NewEnvDescriberConfig) (*EnvDescriber, error) { + env, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, opt.Env) if err != nil { return nil, fmt.Errorf("get environment: %w", err) } @@ -82,6 +83,7 @@ func NewEnvDescriber(opt NewEnvDescriberConfig) (*EnvDescriber, error) { app: opt.App, env: env, enableResources: opt.EnableResources, + ctx: ctx, configStore: opt.ConfigStore, deployStore: opt.DeployStore, @@ -239,7 +241,7 @@ func (d *EnvDescriber) loadStackInfo() (map[string]string, EnvironmentVPC, error } func (d *EnvDescriber) filterDeployedSvcs() ([]*config.Workload, error) { - allSvcs, err := d.configStore.ListServices(d.app) + allSvcs, err := d.configStore.ListServices(d.ctx, d.app) if err != nil { return nil, fmt.Errorf("list services for app %s: %w", d.app, err) } @@ -247,7 +249,7 @@ func (d *EnvDescriber) filterDeployedSvcs() ([]*config.Workload, error) { for _, svc := range allSvcs { svcs[svc.Name] = svc } - deployedSvcNames, err := d.deployStore.ListDeployedServices(d.app, d.env.Name) + deployedSvcNames, err := d.deployStore.ListDeployedServices(d.ctx, d.app, d.env.Name) if err != nil { return nil, fmt.Errorf("list deployed services in env %s: %w", d.env.Name, err) } @@ -260,7 +262,7 @@ func (d *EnvDescriber) filterDeployedSvcs() ([]*config.Workload, error) { // filterDeployedJobs lists the jobs that are deployed on the given app and environment func (d *EnvDescriber) filterDeployedJobs() ([]*config.Workload, error) { - allJobs, err := d.configStore.ListJobs(d.app) + allJobs, err := d.configStore.ListJobs(d.ctx, d.app) if err != nil { return nil, fmt.Errorf("list jobs for app %s: %w", d.app, err) } @@ -268,7 +270,7 @@ func (d *EnvDescriber) filterDeployedJobs() ([]*config.Workload, error) { for _, job := range allJobs { jobs[job.Name] = job } - deployedJobNames, err := d.deployStore.ListDeployedJobs(d.app, d.env.Name) + deployedJobNames, err := d.deployStore.ListDeployedJobs(d.ctx, d.app, d.env.Name) if err != nil { return nil, fmt.Errorf("list deployed jobs in env %s: %w", d.env.Name, err) } diff --git a/internal/pkg/describe/env_test.go b/internal/pkg/describe/env_test.go index 0fa2a7bf9de..d515cb0a50b 100644 --- a/internal/pkg/describe/env_test.go +++ b/internal/pkg/describe/env_test.go @@ -4,6 +4,7 @@ package describe import ( + "context" "errors" "fmt" "testing" @@ -103,7 +104,7 @@ func TestEnvDescriber_Describe(t *testing.T) { "error if fail to list all services": { setupMocks: func(m envDescriberMocks) { gomock.InOrder( - m.configStoreSvc.EXPECT().ListServices(testApp).Return(nil, mockError), + m.configStoreSvc.EXPECT().ListServices(context.Background(), testApp).Return(nil, mockError), ) }, wantedError: fmt.Errorf("list services for app testApp: some error"), @@ -111,10 +112,10 @@ func TestEnvDescriber_Describe(t *testing.T) { "error if fail to list deployed services": { setupMocks: func(m envDescriberMocks) { gomock.InOrder( - m.configStoreSvc.EXPECT().ListServices(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListServices(context.Background(), testApp).Return([]*config.Workload{ testSvc1, testSvc2, testSvc3, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedServices(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedServices(ctx, testApp, testEnv.Name). Return(nil, mockError), ) }, @@ -123,15 +124,15 @@ func TestEnvDescriber_Describe(t *testing.T) { "error if fail to get env tags": { setupMocks: func(m envDescriberMocks) { gomock.InOrder( - m.configStoreSvc.EXPECT().ListServices(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListServices(context.Background(), testApp).Return([]*config.Workload{ testSvc1, testSvc2, testSvc3, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedServices(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedServices(ctx, testApp, testEnv.Name). Return([]string{"testSvc1", "testSvc2"}, nil), - m.configStoreSvc.EXPECT().ListJobs(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListJobs(context.Background(), testApp).Return([]*config.Workload{ testJob1, testJob2, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedJobs(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedJobs(ctx, testApp, testEnv.Name). Return([]string{"testJob1", "testJob2"}, nil), m.stackDescriber.EXPECT().Describe().Return(stack.StackDescription{}, mockError), ) @@ -142,15 +143,15 @@ func TestEnvDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m envDescriberMocks) { gomock.InOrder( - m.configStoreSvc.EXPECT().ListServices(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListServices(context.Background(), testApp).Return([]*config.Workload{ testSvc1, testSvc2, testSvc3, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedServices(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedServices(ctx, testApp, testEnv.Name). Return([]string{"testSvc1", "testSvc2"}, nil), - m.configStoreSvc.EXPECT().ListJobs(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListJobs(context.Background(), testApp).Return([]*config.Workload{ testJob1, testJob2, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedJobs(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedJobs(ctx, testApp, testEnv.Name). Return([]string{"testJob1", "testJob2"}, nil), m.stackDescriber.EXPECT().Describe().Return(stack.StackDescription{ Tags: stackTags, @@ -165,15 +166,15 @@ func TestEnvDescriber_Describe(t *testing.T) { shouldOutputResources: false, setupMocks: func(m envDescriberMocks) { gomock.InOrder( - m.configStoreSvc.EXPECT().ListServices(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListServices(context.Background(), testApp).Return([]*config.Workload{ testSvc1, testSvc2, testSvc3, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedServices(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedServices(ctx, testApp, testEnv.Name). Return([]string{"testSvc1", "testSvc2"}, nil), - m.configStoreSvc.EXPECT().ListJobs(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListJobs(context.Background(), testApp).Return([]*config.Workload{ testJob1, testJob2, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedJobs(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedJobs(ctx, testApp, testEnv.Name). Return([]string{"testJob1", "testJob2"}, nil), m.stackDescriber.EXPECT().Describe().Return(stack.StackDescription{ Tags: stackTags, @@ -197,15 +198,15 @@ func TestEnvDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m envDescriberMocks) { gomock.InOrder( - m.configStoreSvc.EXPECT().ListServices(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListServices(context.Background(), testApp).Return([]*config.Workload{ testSvc1, testSvc2, testSvc3, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedServices(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedServices(ctx, testApp, testEnv.Name). Return([]string{"testSvc1", "testSvc2"}, nil), - m.configStoreSvc.EXPECT().ListJobs(testApp).Return([]*config.Workload{ + m.configStoreSvc.EXPECT().ListJobs(context.Background(), testApp).Return([]*config.Workload{ testJob1, testJob2, }, nil), - m.deployStoreSvc.EXPECT().ListDeployedJobs(testApp, testEnv.Name). + m.deployStoreSvc.EXPECT().ListDeployedJobs(ctx, testApp, testEnv.Name). Return([]string{"testJob1", "testJob2"}, nil), m.stackDescriber.EXPECT().Describe().Return(stack.StackDescription{ Tags: stackTags, @@ -249,6 +250,7 @@ func TestEnvDescriber_Describe(t *testing.T) { tc.setupMocks(mocks) d := &EnvDescriber{ + ctx: context.Background(), env: testEnv, app: testApp, enableResources: tc.shouldOutputResources, @@ -284,6 +286,7 @@ func TestEnvDescriber_Manifest(t *testing.T) { m := mocks.NewMockstackDescriber(ctrl) m.EXPECT().StackMetadata().Return("", errors.New("some error")) return &EnvDescriber{ + ctx: context.Background(), cfn: m, } }, @@ -297,6 +300,7 @@ Metadata: Version: 1.9.0 `, nil) return &EnvDescriber{ + ctx: context.Background(), env: &config.Environment{ Name: "test", }, @@ -311,6 +315,7 @@ type: Environment`), m := mocks.NewMockstackDescriber(ctrl) m.EXPECT().StackMetadata().Return(`{"Version":"1.9.0","Manifest":"\nname: prod\ntype: Environment"}`, nil) return &EnvDescriber{ + ctx: context.Background(), env: &config.Environment{ Name: "test", }, @@ -355,6 +360,7 @@ func TestEnvDescriber_Version(t *testing.T) { m := mocks.NewMockstackDescriber(ctrl) m.EXPECT().StackMetadata().Return("", nil) return &EnvDescriber{ + ctx: context.Background(), app: "phonetool", env: &config.Environment{Name: "test"}, cfn: m, @@ -367,6 +373,7 @@ func TestEnvDescriber_Version(t *testing.T) { m := mocks.NewMockstackDescriber(ctrl) m.EXPECT().StackMetadata().Return(`{"Version":"1.0.0"}`, nil) return &EnvDescriber{ + ctx: context.Background(), app: "phonetool", env: &config.Environment{Name: "test"}, cfn: m, @@ -410,6 +417,7 @@ func TestEnvDescriber_ServiceDiscoveryEndpoint(t *testing.T) { m := mocks.NewMockstackDescriber(ctrl) m.EXPECT().Describe().Return(stack.StackDescription{Parameters: map[string]string{}}, nil) return &EnvDescriber{ + ctx: context.Background(), app: "phonetool", env: &config.Environment{Name: "test"}, cfn: m, @@ -425,6 +433,7 @@ func TestEnvDescriber_ServiceDiscoveryEndpoint(t *testing.T) { cfnstack.EnvParamServiceDiscoveryEndpoint: "test.phonetool.local", }}, nil) return &EnvDescriber{ + ctx: context.Background(), app: "phonetool", env: &config.Environment{Name: "test"}, cfn: m, @@ -440,6 +449,7 @@ func TestEnvDescriber_ServiceDiscoveryEndpoint(t *testing.T) { cfnstack.EnvParamServiceDiscoveryEndpoint: "", }}, nil) return &EnvDescriber{ + ctx: context.Background(), app: "phonetool", env: &config.Environment{Name: "test"}, cfn: m, @@ -529,6 +539,7 @@ func TestEnvDescriber_Features(t *testing.T) { } tc.setupMock(m) d := &EnvDescriber{ + ctx: context.Background(), cfn: m.stackDescriber, } @@ -672,6 +683,7 @@ func TestEnvDescriber_ValidateCFServiceDomainAliases(t *testing.T) { } tc.setupMock(m) d := &EnvDescriber{ + ctx: context.Background(), app: mockAppName, env: &mockEnvConfig, cfn: m.stackDescriber, diff --git a/internal/pkg/describe/lb_web_service.go b/internal/pkg/describe/lb_web_service.go index 64047d95ed3..a62b8918b8a 100644 --- a/internal/pkg/describe/lb_web_service.go +++ b/internal/pkg/describe/lb_web_service.go @@ -56,6 +56,7 @@ type lbDescriber interface { // LBWebServiceDescriber retrieves information about a load balanced web service. type LBWebServiceDescriber struct { + ctx context.Context app string svc string enableResources bool @@ -71,8 +72,9 @@ type LBWebServiceDescriber struct { } // NewLBWebServiceDescriber instantiates a load balanced service describer. -func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, error) { +func NewLBWebServiceDescriber(ctx context.Context, opt NewServiceConfig) (*LBWebServiceDescriber, error) { describer := &LBWebServiceDescriber{ + ctx: ctx, app: opt.App, svc: opt.Svc, enableResources: opt.EnableResources, @@ -81,7 +83,7 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err envDescriber: make(map[string]envDescriber), } describer.initLBDescriber = func(envName string) (lbDescriber, error) { - env, err := opt.ConfigStore.GetEnvironment(opt.App, envName) + env, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, envName) if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } @@ -95,7 +97,7 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if describer, ok := describer.ecsServiceDescribers[env]; ok { return describer, nil } - svcDescr, err := newECSServiceDescriber(NewServiceConfig{ + svcDescr, err := newECSServiceDescriber(ctx, NewServiceConfig{ App: opt.App, Env: env, Svc: opt.Svc, @@ -111,7 +113,7 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if describer, ok := describer.envDescriber[env]; ok { return describer, nil } - envDescr, err := NewEnvDescriber(NewEnvDescriberConfig{ + envDescr, err := NewEnvDescriber(ctx, NewEnvDescriberConfig{ App: opt.App, Env: env, ConfigStore: opt.ConfigStore, @@ -126,7 +128,7 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if describer, ok := describer.cwAlarmDescribers[envName]; ok { return describer, nil } - env, err := opt.ConfigStore.GetEnvironment(opt.App, envName) + env, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, envName) if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } @@ -141,7 +143,11 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err // Describe returns info of a web service. func (d *LBWebServiceDescriber) Describe() (HumanJSONStringer, error) { - environments, err := d.store.ListEnvironmentsDeployedTo(d.app, d.svc) + ctx := d.ctx + if ctx == nil { + ctx = context.Background() + } + environments, err := d.store.ListEnvironmentsDeployedTo(ctx, d.app, d.svc) if err != nil { return nil, fmt.Errorf("list deployed environments for application %s: %w", d.app, err) } diff --git a/internal/pkg/describe/lb_web_service_test.go b/internal/pkg/describe/lb_web_service_test.go index 4cb11bfd52a..49ae82e92e2 100644 --- a/internal/pkg/describe/lb_web_service_test.go +++ b/internal/pkg/describe/lb_web_service_test.go @@ -67,7 +67,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to list environment": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return(nil, mockErr), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return(nil, mockErr), ) }, wantedError: fmt.Errorf("list deployed environments for application phonetool: some error"), @@ -75,7 +75,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve URI for ALB service": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -89,7 +89,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve service params": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -118,7 +118,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve service discovery endpoint": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -149,7 +149,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve platform": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -167,7 +167,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve environment variables": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -189,7 +189,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve rollback alarm names": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -219,7 +219,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve alarm descriptions": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -250,7 +250,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve service connect DNS names": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -282,7 +282,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve secrets": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -316,7 +316,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -361,7 +361,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { "should not try to fetch descriptions if no ROLLBACK alarms present": { setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, @@ -421,7 +421,7 @@ func TestLBWebServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m lbWebSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv, prodEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv, prodEnv}, nil), m.ecsDescriber.EXPECT().StackResources().Return([]*stack.Resource{ { LogicalID: svcStackResourceALBTargetGroupLogicalID, diff --git a/internal/pkg/describe/mocks/mock_service.go b/internal/pkg/describe/mocks/mock_service.go index 086998aef9f..39d7f276248 100644 --- a/internal/pkg/describe/mocks/mock_service.go +++ b/internal/pkg/describe/mocks/mock_service.go @@ -5,6 +5,7 @@ package mocks import ( + context "context" reflect "reflect" apprunner "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" @@ -39,78 +40,78 @@ func (m *MockConfigStoreSvc) EXPECT() *MockConfigStoreSvcMockRecorder { } // GetEnvironment mocks base method. -func (m *MockConfigStoreSvc) GetEnvironment(appName, environmentName string) (*config.Environment, error) { +func (m *MockConfigStoreSvc) GetEnvironment(ctx context.Context, appName, environmentName string) (*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnvironment", appName, environmentName) + ret := m.ctrl.Call(m, "GetEnvironment", ctx, appName, environmentName) ret0, _ := ret[0].(*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // GetEnvironment indicates an expected call of GetEnvironment. -func (mr *MockConfigStoreSvcMockRecorder) GetEnvironment(appName, environmentName interface{}) *gomock.Call { +func (mr *MockConfigStoreSvcMockRecorder) GetEnvironment(ctx, appName, environmentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockConfigStoreSvc)(nil).GetEnvironment), appName, environmentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnvironment", reflect.TypeOf((*MockConfigStoreSvc)(nil).GetEnvironment), ctx, appName, environmentName) } // GetWorkload mocks base method. -func (m *MockConfigStoreSvc) GetWorkload(appName, name string) (*config.Workload, error) { +func (m *MockConfigStoreSvc) GetWorkload(ctx context.Context, appName, name string) (*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetWorkload", appName, name) + ret := m.ctrl.Call(m, "GetWorkload", ctx, appName, name) ret0, _ := ret[0].(*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // GetWorkload indicates an expected call of GetWorkload. -func (mr *MockConfigStoreSvcMockRecorder) GetWorkload(appName, name interface{}) *gomock.Call { +func (mr *MockConfigStoreSvcMockRecorder) GetWorkload(ctx, appName, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkload", reflect.TypeOf((*MockConfigStoreSvc)(nil).GetWorkload), appName, name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkload", reflect.TypeOf((*MockConfigStoreSvc)(nil).GetWorkload), ctx, appName, name) } // ListEnvironments mocks base method. -func (m *MockConfigStoreSvc) ListEnvironments(appName string) ([]*config.Environment, error) { +func (m *MockConfigStoreSvc) ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironments", appName) + ret := m.ctrl.Call(m, "ListEnvironments", ctx, appName) ret0, _ := ret[0].([]*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironments indicates an expected call of ListEnvironments. -func (mr *MockConfigStoreSvcMockRecorder) ListEnvironments(appName interface{}) *gomock.Call { +func (mr *MockConfigStoreSvcMockRecorder) ListEnvironments(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockConfigStoreSvc)(nil).ListEnvironments), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockConfigStoreSvc)(nil).ListEnvironments), ctx, appName) } // ListJobs mocks base method. -func (m *MockConfigStoreSvc) ListJobs(appName string) ([]*config.Workload, error) { +func (m *MockConfigStoreSvc) ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListJobs", appName) + ret := m.ctrl.Call(m, "ListJobs", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListJobs indicates an expected call of ListJobs. -func (mr *MockConfigStoreSvcMockRecorder) ListJobs(appName interface{}) *gomock.Call { +func (mr *MockConfigStoreSvcMockRecorder) ListJobs(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockConfigStoreSvc)(nil).ListJobs), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockConfigStoreSvc)(nil).ListJobs), ctx, appName) } // ListServices mocks base method. -func (m *MockConfigStoreSvc) ListServices(appName string) ([]*config.Workload, error) { +func (m *MockConfigStoreSvc) ListServices(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", appName) + ret := m.ctrl.Call(m, "ListServices", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockConfigStoreSvcMockRecorder) ListServices(appName interface{}) *gomock.Call { +func (mr *MockConfigStoreSvcMockRecorder) ListServices(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockConfigStoreSvc)(nil).ListServices), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockConfigStoreSvc)(nil).ListServices), ctx, appName) } // MockDeployedEnvServicesLister is a mock of DeployedEnvServicesLister interface. @@ -137,48 +138,48 @@ func (m *MockDeployedEnvServicesLister) EXPECT() *MockDeployedEnvServicesListerM } // ListDeployedJobs mocks base method. -func (m *MockDeployedEnvServicesLister) ListDeployedJobs(appName, envName string) ([]string, error) { +func (m *MockDeployedEnvServicesLister) ListDeployedJobs(ctx context.Context, appName, envName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployedJobs", appName, envName) + ret := m.ctrl.Call(m, "ListDeployedJobs", ctx, appName, envName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListDeployedJobs indicates an expected call of ListDeployedJobs. -func (mr *MockDeployedEnvServicesListerMockRecorder) ListDeployedJobs(appName, envName interface{}) *gomock.Call { +func (mr *MockDeployedEnvServicesListerMockRecorder) ListDeployedJobs(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedJobs", reflect.TypeOf((*MockDeployedEnvServicesLister)(nil).ListDeployedJobs), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedJobs", reflect.TypeOf((*MockDeployedEnvServicesLister)(nil).ListDeployedJobs), ctx, appName, envName) } // ListDeployedServices mocks base method. -func (m *MockDeployedEnvServicesLister) ListDeployedServices(appName, envName string) ([]string, error) { +func (m *MockDeployedEnvServicesLister) ListDeployedServices(ctx context.Context, appName, envName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployedServices", appName, envName) + ret := m.ctrl.Call(m, "ListDeployedServices", ctx, appName, envName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListDeployedServices indicates an expected call of ListDeployedServices. -func (mr *MockDeployedEnvServicesListerMockRecorder) ListDeployedServices(appName, envName interface{}) *gomock.Call { +func (mr *MockDeployedEnvServicesListerMockRecorder) ListDeployedServices(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedServices", reflect.TypeOf((*MockDeployedEnvServicesLister)(nil).ListDeployedServices), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedServices", reflect.TypeOf((*MockDeployedEnvServicesLister)(nil).ListDeployedServices), ctx, appName, envName) } // ListEnvironmentsDeployedTo mocks base method. -func (m *MockDeployedEnvServicesLister) ListEnvironmentsDeployedTo(appName, svcName string) ([]string, error) { +func (m *MockDeployedEnvServicesLister) ListEnvironmentsDeployedTo(ctx context.Context, appName, svcName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironmentsDeployedTo", appName, svcName) + ret := m.ctrl.Call(m, "ListEnvironmentsDeployedTo", ctx, appName, svcName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironmentsDeployedTo indicates an expected call of ListEnvironmentsDeployedTo. -func (mr *MockDeployedEnvServicesListerMockRecorder) ListEnvironmentsDeployedTo(appName, svcName interface{}) *gomock.Call { +func (mr *MockDeployedEnvServicesListerMockRecorder) ListEnvironmentsDeployedTo(ctx, appName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironmentsDeployedTo", reflect.TypeOf((*MockDeployedEnvServicesLister)(nil).ListEnvironmentsDeployedTo), appName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironmentsDeployedTo", reflect.TypeOf((*MockDeployedEnvServicesLister)(nil).ListEnvironmentsDeployedTo), ctx, appName, svcName) } // MockecsClient is a mock of ecsClient interface. diff --git a/internal/pkg/describe/rd_web_service.go b/internal/pkg/describe/rd_web_service.go index fc8792c67b4..98750213bb5 100644 --- a/internal/pkg/describe/rd_web_service.go +++ b/internal/pkg/describe/rd_web_service.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -19,6 +20,7 @@ import ( // RDWebServiceDescriber retrieves information about a request-driven web service. type RDWebServiceDescriber struct { + ctx context.Context app string svc string enableResources bool @@ -29,8 +31,9 @@ type RDWebServiceDescriber struct { } // NewRDWebServiceDescriber instantiates a request-driven service describer. -func NewRDWebServiceDescriber(opt NewServiceConfig) (*RDWebServiceDescriber, error) { +func NewRDWebServiceDescriber(ctx context.Context, opt NewServiceConfig) (*RDWebServiceDescriber, error) { describer := &RDWebServiceDescriber{ + ctx: ctx, app: opt.App, svc: opt.Svc, enableResources: opt.EnableResources, @@ -42,7 +45,7 @@ func NewRDWebServiceDescriber(opt NewServiceConfig) (*RDWebServiceDescriber, err if describer, ok := describer.envSvcDescribers[env]; ok { return describer, nil } - d, err := newAppRunnerServiceDescriber(NewServiceConfig{ + d, err := newAppRunnerServiceDescriber(ctx, NewServiceConfig{ App: opt.App, Env: env, Svc: opt.Svc, @@ -68,7 +71,11 @@ func (d *RDWebServiceDescriber) ServiceARN(env string) (string, error) { // Describe returns info for a request-driven web service. func (d *RDWebServiceDescriber) Describe() (HumanJSONStringer, error) { - environments, err := d.store.ListEnvironmentsDeployedTo(d.app, d.svc) + ctx := d.ctx + if ctx == nil { + ctx = context.Background() + } + environments, err := d.store.ListEnvironmentsDeployedTo(ctx, d.app, d.svc) if err != nil { return nil, fmt.Errorf("list deployed environments for application %s: %w", d.app, err) } diff --git a/internal/pkg/describe/rd_web_service_test.go b/internal/pkg/describe/rd_web_service_test.go index d66e3df800b..f1e090b7914 100644 --- a/internal/pkg/describe/rd_web_service_test.go +++ b/internal/pkg/describe/rd_web_service_test.go @@ -83,7 +83,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { "return error if fail to list environment": { setupMocks: func(m apprunnerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return(nil, mockErr), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return(nil, mockErr), ) }, wantedError: fmt.Errorf("list deployed environments for application testapp: some error"), @@ -91,7 +91,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve service configuration": { setupMocks: func(m apprunnerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsSvcDescriber.EXPECT().Service().Return(nil, mockErr), ) }, @@ -101,7 +101,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m apprunnerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsSvcDescriber.EXPECT().Service().Return(&apprunner.Service{}, nil), m.ecsSvcDescriber.EXPECT().ServiceURL().Return("", mockErr), ) @@ -112,7 +112,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m apprunnerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsSvcDescriber.EXPECT().Service().Return(&apprunner.Service{}, nil), m.ecsSvcDescriber.EXPECT().ServiceURL().Return("", nil), m.ecsSvcDescriber.EXPECT().IsPrivate().Return(false, mockErr), @@ -124,7 +124,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m apprunnerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsSvcDescriber.EXPECT().Service().Return(&apprunner.Service{}, nil), m.ecsSvcDescriber.EXPECT().ServiceURL().Return("", nil), m.ecsSvcDescriber.EXPECT().IsPrivate().Return(false, nil), @@ -137,7 +137,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m apprunnerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv, prodEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv, prodEnv}, nil), m.ecsSvcDescriber.EXPECT().Service().Return(&apprunner.Service{ ServiceARN: "arn:aws:apprunner:us-east-1:111111111111:service/testapp-test-testsvc", ServiceURL: "6znxd4ra33.public.us-east-1.apprunner.amazonaws.com", @@ -269,7 +269,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m apprunnerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv, prodEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv, prodEnv}, nil), m.ecsSvcDescriber.EXPECT().Service().Return(&apprunner.Service{ ServiceARN: "arn:aws:apprunner:us-east-1:111111111111:service/testapp-test-testsvc", ServiceURL: "6znxd4ra33.public.us-east-1.apprunner.amazonaws.com", diff --git a/internal/pkg/describe/service.go b/internal/pkg/describe/service.go index f255b4a9116..f96538a303e 100644 --- a/internal/pkg/describe/service.go +++ b/internal/pkg/describe/service.go @@ -4,6 +4,7 @@ package describe import ( + "context" "encoding/json" "errors" "fmt" @@ -37,18 +38,18 @@ const maxAlarmShowColumnWidth = 40 // ConfigStoreSvc wraps methods of config store. type ConfigStoreSvc interface { - GetEnvironment(appName string, environmentName string) (*config.Environment, error) - ListEnvironments(appName string) ([]*config.Environment, error) - ListServices(appName string) ([]*config.Workload, error) - GetWorkload(appName string, name string) (*config.Workload, error) - ListJobs(appName string) ([]*config.Workload, error) + GetEnvironment(ctx context.Context, appName string, environmentName string) (*config.Environment, error) + ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) + ListServices(ctx context.Context, appName string) ([]*config.Workload, error) + GetWorkload(ctx context.Context, appName string, name string) (*config.Workload, error) + ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) } // DeployedEnvServicesLister wraps methods of deploy store. type DeployedEnvServicesLister interface { - ListEnvironmentsDeployedTo(appName string, svcName string) ([]string, error) - ListDeployedServices(appName string, envName string) ([]string, error) - ListDeployedJobs(appName string, envName string) ([]string, error) + ListEnvironmentsDeployedTo(ctx context.Context, appName string, svcName string) ([]string, error) + ListDeployedServices(ctx context.Context, appName string, envName string) ([]string, error) + ListDeployedJobs(ctx context.Context, appName string, envName string) ([]string, error) } type ecsClient interface { @@ -139,8 +140,8 @@ type NewServiceConfig struct { DeployStore DeployedEnvServicesLister } -func newECSServiceDescriber(opt NewServiceConfig) (*ecsServiceDescriber, error) { - stackDescriber, err := NewWorkloadStackDescriber(NewWorkloadConfig{ +func newECSServiceDescriber(ctx context.Context, opt NewServiceConfig) (*ecsServiceDescriber, error) { + stackDescriber, err := NewWorkloadStackDescriber(ctx, NewWorkloadConfig{ App: opt.App, Env: opt.Env, Name: opt.Svc, @@ -155,8 +156,8 @@ func newECSServiceDescriber(opt NewServiceConfig) (*ecsServiceDescriber, error) }, nil } -func newAppRunnerServiceDescriber(opt NewServiceConfig) (*appRunnerServiceDescriber, error) { - stackDescriber, err := NewWorkloadStackDescriber(NewWorkloadConfig{ +func newAppRunnerServiceDescriber(ctx context.Context, opt NewServiceConfig) (*appRunnerServiceDescriber, error) { + stackDescriber, err := NewWorkloadStackDescriber(ctx, NewWorkloadConfig{ App: opt.App, Env: opt.Env, Name: opt.Svc, diff --git a/internal/pkg/describe/static_site.go b/internal/pkg/describe/static_site.go index da34118fd70..17110e3bb8e 100644 --- a/internal/pkg/describe/static_site.go +++ b/internal/pkg/describe/static_site.go @@ -28,6 +28,7 @@ const ( // StaticSiteDescriber retrieves information about a static site service. type StaticSiteDescriber struct { + ctx context.Context app string svc string @@ -39,8 +40,9 @@ type StaticSiteDescriber struct { } // NewStaticSiteDescriber instantiates a static site service describer. -func NewStaticSiteDescriber(opt NewServiceConfig) (*StaticSiteDescriber, error) { +func NewStaticSiteDescriber(ctx context.Context, opt NewServiceConfig) (*StaticSiteDescriber, error) { describer := &StaticSiteDescriber{ + ctx: ctx, app: opt.App, svc: opt.Svc, enableResources: opt.EnableResources, @@ -51,7 +53,7 @@ func NewStaticSiteDescriber(opt NewServiceConfig) (*StaticSiteDescriber, error) if describer, ok := describer.wkldDescribers[env]; ok { return describer, nil } - svcDescr, err := NewWorkloadStackDescriber(NewWorkloadConfig{ + svcDescr, err := NewWorkloadStackDescriber(ctx, NewWorkloadConfig{ App: opt.App, Env: env, Name: opt.Svc, @@ -64,7 +66,7 @@ func NewStaticSiteDescriber(opt NewServiceConfig) (*StaticSiteDescriber, error) return svcDescr, nil } describer.initS3Client = func(env string) (bucketDescriber, bucketNameGetter, error) { - environment, err := opt.ConfigStore.GetEnvironment(opt.App, env) + environment, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, env) if err != nil { return nil, nil, fmt.Errorf("get environment %s: %w", env, err) } @@ -102,7 +104,11 @@ func (d *StaticSiteDescriber) URI(envName string) (URI, error) { // Describe returns info of a static site. func (d *StaticSiteDescriber) Describe() (HumanJSONStringer, error) { - environments, err := d.store.ListEnvironmentsDeployedTo(d.app, d.svc) + ctx := d.ctx + if ctx == nil { + ctx = context.Background() + } + environments, err := d.store.ListEnvironmentsDeployedTo(ctx, d.app, d.svc) if err != nil { return nil, fmt.Errorf("list deployed environments for service %q: %w", d.svc, err) } diff --git a/internal/pkg/describe/static_site_test.go b/internal/pkg/describe/static_site_test.go index cea3fb66262..b4f2173469f 100644 --- a/internal/pkg/describe/static_site_test.go +++ b/internal/pkg/describe/static_site_test.go @@ -122,7 +122,7 @@ func TestStaticSiteDescriber_Describe(t *testing.T) { "return error if fail to list environments": { setupMocks: func(m staticSiteDescriberMocks) { gomock.InOrder( - m.store.EXPECT().ListEnvironmentsDeployedTo(mockApp, mockSvc).Return(nil, mockErr), + m.store.EXPECT().ListEnvironmentsDeployedTo(ctx, mockApp, mockSvc).Return(nil, mockErr), ) }, wantedError: fmt.Errorf(`list deployed environments for service "static": some error`), @@ -130,7 +130,7 @@ func TestStaticSiteDescriber_Describe(t *testing.T) { "success without resources flag or objects in bucket": { setupMocks: func(m staticSiteDescriberMocks) { gomock.InOrder( - m.store.EXPECT().ListEnvironmentsDeployedTo(mockApp, mockSvc).Return([]string{"test"}, nil), + m.store.EXPECT().ListEnvironmentsDeployedTo(ctx, mockApp, mockSvc).Return([]string{"test"}, nil), m.wkldDescriber.EXPECT().Outputs().Return(map[string]string{ "CloudFrontDistributionDomainName": "dut843shvcmvn.cloudfront.net", }, nil), @@ -156,7 +156,7 @@ Routes shouldOutputResources: true, setupMocks: func(m staticSiteDescriberMocks) { gomock.InOrder( - m.store.EXPECT().ListEnvironmentsDeployedTo(mockApp, mockSvc).Return([]string{"test"}, nil), + m.store.EXPECT().ListEnvironmentsDeployedTo(ctx, mockApp, mockSvc).Return([]string{"test"}, nil), m.wkldDescriber.EXPECT().Outputs().Return(map[string]string{ "CloudFrontDistributionDomainName": "dut843shvcmvn.cloudfront.net", }, nil), @@ -171,7 +171,7 @@ Routes shouldOutputResources: true, setupMocks: func(m staticSiteDescriberMocks) { gomock.InOrder( - m.store.EXPECT().ListEnvironmentsDeployedTo(mockApp, mockSvc).Return([]string{"test"}, nil), + m.store.EXPECT().ListEnvironmentsDeployedTo(ctx, mockApp, mockSvc).Return([]string{"test"}, nil), m.wkldDescriber.EXPECT().Outputs().Return(map[string]string{ "CloudFrontDistributionDomainName": "dut843shvcmvn.cloudfront.net", }, nil), diff --git a/internal/pkg/describe/status_describe.go b/internal/pkg/describe/status_describe.go index a152b4faa43..b7821c614c9 100644 --- a/internal/pkg/describe/status_describe.go +++ b/internal/pkg/describe/status_describe.go @@ -92,8 +92,8 @@ type NewServiceStatusConfig struct { } // NewECSStatusDescriber instantiates a new ecsStatusDescriber struct. -func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, error) { - env, err := opt.ConfigStore.GetEnvironment(opt.App, opt.Env) +func NewECSStatusDescriber(ctx context.Context, opt *NewServiceStatusConfig) (*ecsStatusDescriber, error) { + env, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, opt.Env) if err != nil { return nil, fmt.Errorf("get environment %s: %w", opt.Env, err) } @@ -114,8 +114,8 @@ func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, er } // NewAppRunnerStatusDescriber instantiates a new appRunnerStatusDescriber struct. -func NewAppRunnerStatusDescriber(opt *NewServiceStatusConfig) (*appRunnerStatusDescriber, error) { - appRunnerSvcDescriber, err := newAppRunnerServiceDescriber(NewServiceConfig{ +func NewAppRunnerStatusDescriber(ctx context.Context, opt *NewServiceStatusConfig) (*appRunnerStatusDescriber, error) { + appRunnerSvcDescriber, err := newAppRunnerServiceDescriber(ctx, NewServiceConfig{ App: opt.App, Env: opt.Env, Svc: opt.Svc, @@ -135,14 +135,14 @@ func NewAppRunnerStatusDescriber(opt *NewServiceStatusConfig) (*appRunnerStatusD } // NewStaticSiteStatusDescriber instantiates a new staticSiteStatusDescriber struct. -func NewStaticSiteStatusDescriber(opt *NewServiceStatusConfig) (*staticSiteStatusDescriber, error) { +func NewStaticSiteStatusDescriber(ctx context.Context, opt *NewServiceStatusConfig) (*staticSiteStatusDescriber, error) { describer := &staticSiteStatusDescriber{ app: opt.App, env: opt.Env, svc: opt.Svc, } describer.initS3Client = func(env string) (bucketDataGetter, bucketNameGetter, error) { - environment, err := opt.ConfigStore.GetEnvironment(opt.App, env) + environment, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, env) if err != nil { return nil, nil, fmt.Errorf("get environment %s: %w", env, err) } diff --git a/internal/pkg/describe/uri.go b/internal/pkg/describe/uri.go index c9a08e59ec5..558708e0676 100644 --- a/internal/pkg/describe/uri.go +++ b/internal/pkg/describe/uri.go @@ -4,6 +4,7 @@ package describe import ( + "context" "fmt" "regexp" "strings" @@ -46,8 +47,8 @@ type ReachableService interface { } // NewReachableService returns a ReachableService based on the type of the service. -func NewReachableService(app, svc string, store ConfigStoreSvc) (ReachableService, error) { - cfg, err := store.GetWorkload(app, svc) +func NewReachableService(ctx context.Context, app, svc string, store ConfigStoreSvc) (ReachableService, error) { + cfg, err := store.GetWorkload(ctx, app, svc) if err != nil { return nil, err } @@ -58,13 +59,13 @@ func NewReachableService(app, svc string, store ConfigStoreSvc) (ReachableServic } switch cfg.Type { case manifestinfo.LoadBalancedWebServiceType: - return NewLBWebServiceDescriber(in) + return NewLBWebServiceDescriber(ctx, in) case manifestinfo.RequestDrivenWebServiceType: - return NewRDWebServiceDescriber(in) + return NewRDWebServiceDescriber(ctx, in) case manifestinfo.BackendServiceType: - return NewBackendServiceDescriber(in) + return NewBackendServiceDescriber(ctx, in) case manifestinfo.StaticSiteType: - return NewStaticSiteDescriber(in) + return NewStaticSiteDescriber(ctx, in) default: return nil, &ErrNonAccessibleServiceType{ name: svc, diff --git a/internal/pkg/describe/worker_service.go b/internal/pkg/describe/worker_service.go index 4c545f8063e..76498c05c6e 100644 --- a/internal/pkg/describe/worker_service.go +++ b/internal/pkg/describe/worker_service.go @@ -22,6 +22,7 @@ import ( // WorkerServiceDescriber retrieves information about a worker service. type WorkerServiceDescriber struct { + ctx context.Context app string svc string enableResources bool @@ -34,8 +35,9 @@ type WorkerServiceDescriber struct { } // NewWorkerServiceDescriber instantiates a worker service describer. -func NewWorkerServiceDescriber(opt NewServiceConfig) (*WorkerServiceDescriber, error) { +func NewWorkerServiceDescriber(ctx context.Context, opt NewServiceConfig) (*WorkerServiceDescriber, error) { describer := &WorkerServiceDescriber{ + ctx: ctx, app: opt.App, svc: opt.Svc, enableResources: opt.EnableResources, @@ -47,7 +49,7 @@ func NewWorkerServiceDescriber(opt NewServiceConfig) (*WorkerServiceDescriber, e if describer, ok := describer.svcStackDescriber[env]; ok { return describer, nil } - d, err := newECSServiceDescriber(NewServiceConfig{ + d, err := newECSServiceDescriber(ctx, NewServiceConfig{ App: opt.App, Env: env, Svc: opt.Svc, @@ -63,7 +65,7 @@ func NewWorkerServiceDescriber(opt NewServiceConfig) (*WorkerServiceDescriber, e if describer, ok := describer.cwAlarmDescribers[envName]; ok { return describer, nil } - env, err := opt.ConfigStore.GetEnvironment(opt.App, envName) + env, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, envName) if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } @@ -78,7 +80,11 @@ func NewWorkerServiceDescriber(opt NewServiceConfig) (*WorkerServiceDescriber, e // Describe returns info of a worker service. func (d *WorkerServiceDescriber) Describe() (HumanJSONStringer, error) { - environments, err := d.store.ListEnvironmentsDeployedTo(d.app, d.svc) + ctx := d.ctx + if ctx == nil { + ctx = context.Background() + } + environments, err := d.store.ListEnvironmentsDeployedTo(ctx, d.app, d.svc) if err != nil { return nil, fmt.Errorf("list deployed environments for application %s: %w", d.app, err) } diff --git a/internal/pkg/describe/worker_service_test.go b/internal/pkg/describe/worker_service_test.go index f25eea60327..8264e845417 100644 --- a/internal/pkg/describe/worker_service_test.go +++ b/internal/pkg/describe/worker_service_test.go @@ -48,7 +48,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "return error if fail to list environment": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return(nil, mockErr), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return(nil, mockErr), ) }, wantedError: fmt.Errorf("list deployed environments for application phonetool: some error"), @@ -56,7 +56,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve service deployment configuration": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(nil, mockErr), ) }, @@ -65,7 +65,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve platform": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTaskCountParamKey: "1", cfnstack.WorkloadTaskCPUParamKey: "256", @@ -79,7 +79,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve rollback alarm names": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTaskCountParamKey: "1", cfnstack.WorkloadTaskCPUParamKey: "256", @@ -97,7 +97,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve alarm descriptions": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTaskCountParamKey: "1", cfnstack.WorkloadTaskCPUParamKey: "256", @@ -116,7 +116,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve environment variables": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTaskCountParamKey: "1", cfnstack.WorkloadTaskMemoryParamKey: "512", @@ -135,7 +135,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "return error if fail to retrieve secrets": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTaskCountParamKey: "1", @@ -162,7 +162,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { "should not fetch descriptions if no ROLLBACK alarms present": { setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTaskCountParamKey: "1", @@ -202,7 +202,7 @@ func TestWorkerServiceDescriber_Describe(t *testing.T) { shouldOutputResources: true, setupMocks: func(m workerSvcDescriberMocks) { gomock.InOrder( - m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(testApp, testSvc).Return([]string{testEnv, prodEnv, mockEnv}, nil), + m.storeSvc.EXPECT().ListEnvironmentsDeployedTo(ctx, testApp, testSvc).Return([]string{testEnv, prodEnv, mockEnv}, nil), m.ecsDescriber.EXPECT().Params().Return(map[string]string{ cfnstack.WorkloadTaskCountParamKey: "1", diff --git a/internal/pkg/describe/workload.go b/internal/pkg/describe/workload.go index b209cd881f7..7201618f305 100644 --- a/internal/pkg/describe/workload.go +++ b/internal/pkg/describe/workload.go @@ -40,8 +40,8 @@ type NewWorkloadConfig struct { } // NewWorkloadStackDescriber instantiates the core elements of a new workload. -func NewWorkloadStackDescriber(opt NewWorkloadConfig) (*WorkloadStackDescriber, error) { - environment, err := opt.ConfigStore.GetEnvironment(opt.App, opt.Env) +func NewWorkloadStackDescriber(ctx context.Context, opt NewWorkloadConfig) (*WorkloadStackDescriber, error) { + environment, err := opt.ConfigStore.GetEnvironment(ctx, opt.App, opt.Env) if err != nil { return nil, fmt.Errorf("get environment %s: %w", opt.Env, err) } diff --git a/internal/pkg/initialize/mocks/mock_workload.go b/internal/pkg/initialize/mocks/mock_workload.go index f6bbdbe9488..1937544f543 100644 --- a/internal/pkg/initialize/mocks/mock_workload.go +++ b/internal/pkg/initialize/mocks/mock_workload.go @@ -5,6 +5,7 @@ package mocks import ( + context "context" encoding "encoding" reflect "reflect" @@ -37,76 +38,76 @@ func (m *MockStore) EXPECT() *MockStoreMockRecorder { } // CreateJob mocks base method. -func (m *MockStore) CreateJob(job *config.Workload) error { +func (m *MockStore) CreateJob(ctx context.Context, job *config.Workload) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateJob", job) + ret := m.ctrl.Call(m, "CreateJob", ctx, job) ret0, _ := ret[0].(error) return ret0 } // CreateJob indicates an expected call of CreateJob. -func (mr *MockStoreMockRecorder) CreateJob(job interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) CreateJob(ctx, job interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateJob", reflect.TypeOf((*MockStore)(nil).CreateJob), job) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateJob", reflect.TypeOf((*MockStore)(nil).CreateJob), ctx, job) } // CreateService mocks base method. -func (m *MockStore) CreateService(service *config.Workload) error { +func (m *MockStore) CreateService(ctx context.Context, service *config.Workload) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateService", service) + ret := m.ctrl.Call(m, "CreateService", ctx, service) ret0, _ := ret[0].(error) return ret0 } // CreateService indicates an expected call of CreateService. -func (mr *MockStoreMockRecorder) CreateService(service interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) CreateService(ctx, service interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateService", reflect.TypeOf((*MockStore)(nil).CreateService), service) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateService", reflect.TypeOf((*MockStore)(nil).CreateService), ctx, service) } // GetApplication mocks base method. -func (m *MockStore) GetApplication(appName string) (*config.Application, error) { +func (m *MockStore) GetApplication(ctx context.Context, appName string) (*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetApplication", appName) + ret := m.ctrl.Call(m, "GetApplication", ctx, appName) ret0, _ := ret[0].(*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // GetApplication indicates an expected call of GetApplication. -func (mr *MockStoreMockRecorder) GetApplication(appName interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) GetApplication(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockStore)(nil).GetApplication), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockStore)(nil).GetApplication), ctx, appName) } // ListJobs mocks base method. -func (m *MockStore) ListJobs(appName string) ([]*config.Workload, error) { +func (m *MockStore) ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListJobs", appName) + ret := m.ctrl.Call(m, "ListJobs", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListJobs indicates an expected call of ListJobs. -func (mr *MockStoreMockRecorder) ListJobs(appName interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) ListJobs(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockStore)(nil).ListJobs), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockStore)(nil).ListJobs), ctx, appName) } // ListServices mocks base method. -func (m *MockStore) ListServices(appName string) ([]*config.Workload, error) { +func (m *MockStore) ListServices(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", appName) + ret := m.ctrl.Call(m, "ListServices", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockStoreMockRecorder) ListServices(appName interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) ListServices(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockStore)(nil).ListServices), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockStore)(nil).ListServices), ctx, appName) } // MockWorkloadAdder is a mock of WorkloadAdder interface. diff --git a/internal/pkg/initialize/workload.go b/internal/pkg/initialize/workload.go index bd1162f42e0..6ea3c1e5b2d 100644 --- a/internal/pkg/initialize/workload.go +++ b/internal/pkg/initialize/workload.go @@ -5,6 +5,7 @@ package initialize import ( + "context" "encoding" "fmt" "os" @@ -14,6 +15,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" + "github.com/aproint/copilot-cli/internal/pkg/metadata" "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/workspace" @@ -29,11 +31,11 @@ var fmtErrUnrecognizedWlType = "unrecognized workload type %s" // Store represents the methods needed to add workloads to the SSM parameter store. type Store interface { - GetApplication(appName string) (*config.Application, error) - CreateService(service *config.Workload) error - CreateJob(job *config.Workload) error - ListServices(appName string) ([]*config.Workload, error) - ListJobs(appName string) ([]*config.Workload, error) + GetApplication(ctx context.Context, appName string) (*config.Application, error) + CreateService(ctx context.Context, service *config.Workload) error + CreateJob(ctx context.Context, job *config.Workload) error + ListServices(ctx context.Context, appName string) ([]*config.Workload, error) + ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) } // WorkloadAdder contains the methods needed to add jobs and services to an existing application. @@ -98,18 +100,18 @@ type WorkloadInitializer struct { // AddWorkloadToApp contains the logic to create the SSM parameter and perform the stackset template update required // to add any workload to the app. It does not write the manifest. -func (w *WorkloadInitializer) AddWorkloadToApp(appName, name, workloadType string) error { +func (w *WorkloadInitializer) AddWorkloadToApp(ctx context.Context, appName, name, workloadType string) error { svcOrJob := svcWlType if manifestinfo.IsTypeAJob(workloadType) { svcOrJob = jobWlType } - app, err := w.Store.GetApplication(appName) + app, err := w.Store.GetApplication(ctx, appName) if err != nil { return fmt.Errorf("get application %s: %w", appName, err) } // addWlToAppandSSM only uses the App, Name, and Type - return w.addWlToAppAndSSM(app, WorkloadProps{ + return w.addWlToAppAndSSM(ctx, app, WorkloadProps{ App: appName, Type: workloadType, Name: name, @@ -117,13 +119,13 @@ func (w *WorkloadInitializer) AddWorkloadToApp(appName, name, workloadType strin } // Service writes the service manifest, creates an ECR repository, and adds the service to SSM. -func (w *WorkloadInitializer) Service(i *ServiceProps) (string, error) { - return w.initService(i) +func (w *WorkloadInitializer) Service(ctx context.Context, i *ServiceProps) (string, error) { + return w.initService(ctx, i) } // Job writes the job manifest, creates an ECR repository, and adds the job to SSM. -func (w *WorkloadInitializer) Job(i *JobProps) (string, error) { - return w.initJob(i) +func (w *WorkloadInitializer) Job(ctx context.Context, i *JobProps) (string, error) { + return w.initJob(ctx, i) } func (w *WorkloadInitializer) addWlToApp(app *config.Application, props WorkloadProps, wlType string) error { @@ -140,18 +142,18 @@ func (w *WorkloadInitializer) addWlToApp(app *config.Application, props Workload } } -func (w *WorkloadInitializer) addWlToStore(wl *config.Workload, wlType string) error { +func (w *WorkloadInitializer) addWlToStore(ctx context.Context, wl *config.Workload, wlType string) error { switch wlType { case svcWlType: - return w.Store.CreateService(wl) + return w.Store.CreateService(ctx, wl) case jobWlType: - return w.Store.CreateJob(wl) + return w.Store.CreateJob(ctx, wl) default: return fmt.Errorf(fmtErrUnrecognizedWlType, wlType) } } -func (w *WorkloadInitializer) initJob(props *JobProps) (string, error) { +func (w *WorkloadInitializer) initJob(ctx context.Context, props *JobProps) (string, error) { if props.DockerfilePath != "" { path, err := w.Ws.Rel(props.DockerfilePath) if err != nil { @@ -189,12 +191,12 @@ func (w *WorkloadInitializer) initJob(props *JobProps) (string, error) { log.Infoln(color.Help(helpText)) log.Infoln() - app, err := w.Store.GetApplication(props.App) + app, err := w.Store.GetApplication(ctx, props.App) if err != nil { return "", fmt.Errorf("get application %s: %w", props.App, err) } - err = w.addJobToAppAndSSM(app, props.WorkloadProps) + err = w.addJobToAppAndSSM(ctx, app, props.WorkloadProps) if err != nil { return "", err } @@ -206,7 +208,7 @@ func (w *WorkloadInitializer) initJob(props *JobProps) (string, error) { return path, nil } -func (w *WorkloadInitializer) initService(props *ServiceProps) (string, error) { +func (w *WorkloadInitializer) initService(ctx context.Context, props *ServiceProps) (string, error) { if props.DockerfilePath != "" { path, err := w.Ws.Rel(props.DockerfilePath) if err != nil { @@ -214,7 +216,7 @@ func (w *WorkloadInitializer) initService(props *ServiceProps) (string, error) { } props.DockerfilePath = path } - app, err := w.Store.GetApplication(props.App) + app, err := w.Store.GetApplication(ctx, props.App) if err != nil { return "", fmt.Errorf("get application %s: %w", props.App, err) } @@ -223,7 +225,7 @@ func (w *WorkloadInitializer) initService(props *ServiceProps) (string, error) { } var manifestExists bool - mf, err := w.newServiceManifest(props) + mf, err := w.newServiceManifest(ctx, props) if err != nil { return "", err } @@ -249,7 +251,7 @@ func (w *WorkloadInitializer) initService(props *ServiceProps) (string, error) { log.Infoln(color.Help(helpText)) log.Infoln() - err = w.addSvcToAppAndSSM(app, props.WorkloadProps) + err = w.addSvcToAppAndSSM(ctx, app, props.WorkloadProps) if err != nil { return "", err } @@ -261,26 +263,34 @@ func (w *WorkloadInitializer) initService(props *ServiceProps) (string, error) { return path, nil } -func (w *WorkloadInitializer) addSvcToAppAndSSM(app *config.Application, props WorkloadProps) error { - return w.addWlToAppAndSSM(app, props, svcWlType) +func (w *WorkloadInitializer) addSvcToAppAndSSM(ctx context.Context, app *config.Application, props WorkloadProps) error { + return w.addWlToAppAndSSM(ctx, app, props, svcWlType) } -func (w *WorkloadInitializer) addJobToAppAndSSM(app *config.Application, props WorkloadProps) error { - return w.addWlToAppAndSSM(app, props, jobWlType) +func (w *WorkloadInitializer) addJobToAppAndSSM(ctx context.Context, app *config.Application, props WorkloadProps) error { + return w.addWlToAppAndSSM(ctx, app, props, jobWlType) } // addWlToAppAndSSM is a type-agnostic method to add a workload to the app and config store. -func (w *WorkloadInitializer) addWlToAppAndSSM(app *config.Application, props WorkloadProps, wlType string) error { +func (w *WorkloadInitializer) addWlToAppAndSSM(ctx context.Context, app *config.Application, props WorkloadProps, wlType string) error { + if err := ctx.Err(); err != nil { + return err + } if err := w.addWlToApp(app, props, wlType); err != nil { return fmt.Errorf("add %s %s to application %s: %w", wlType, props.Name, props.App, err) } - if err := w.addWlToStore(&config.Workload{ + if ctx.Err() != nil { + log.Warningln(metadata.CommitAfterCancellationWarning) + } + commitCtx, cancel := metadata.CommitContext(ctx) + defer cancel() + if err := w.addWlToStore(commitCtx, &config.Workload{ App: props.App, Name: props.Name, Type: props.Type, }, wlType); err != nil { - return fmt.Errorf("saving %s %s: %w", wlType, props.Name, err) + return metadata.NewCommitError("workload registration in application stack", fmt.Errorf("saving %s %s: %w", wlType, props.Name, err)) } return nil @@ -308,10 +318,10 @@ func newJobManifest(i *JobProps) (encoding.BinaryMarshaler, error) { } } -func (w *WorkloadInitializer) newServiceManifest(i *ServiceProps) (encoding.BinaryMarshaler, error) { +func (w *WorkloadInitializer) newServiceManifest(ctx context.Context, i *ServiceProps) (encoding.BinaryMarshaler, error) { switch i.Type { case manifestinfo.LoadBalancedWebServiceType: - return w.newLoadBalancedWebServiceManifest(i) + return w.newLoadBalancedWebServiceManifest(ctx, i) case manifestinfo.RequestDrivenWebServiceType: return newRequestDrivenWebServiceManifest(i), nil case manifestinfo.BackendServiceType: @@ -325,7 +335,7 @@ func (w *WorkloadInitializer) newServiceManifest(i *ServiceProps) (encoding.Bina } } -func (w *WorkloadInitializer) newLoadBalancedWebServiceManifest(inProps *ServiceProps) (*manifest.LoadBalancedWebService, error) { +func (w *WorkloadInitializer) newLoadBalancedWebServiceManifest(ctx context.Context, inProps *ServiceProps) (*manifest.LoadBalancedWebService, error) { outProps := &manifest.LoadBalancedWebServiceProps{ WorkloadProps: &manifest.WorkloadProps{ Name: inProps.Name, @@ -338,7 +348,7 @@ func (w *WorkloadInitializer) newLoadBalancedWebServiceManifest(inProps *Service HealthCheck: inProps.HealthCheck, Platform: inProps.Platform, } - existingSvcs, err := w.Store.ListServices(inProps.App) + existingSvcs, err := w.Store.ListServices(ctx, inProps.App) if err != nil { return nil, err } diff --git a/internal/pkg/initialize/workload_test.go b/internal/pkg/initialize/workload_test.go index bfe779eacfc..8486014a3d2 100644 --- a/internal/pkg/initialize/workload_test.go +++ b/internal/pkg/initialize/workload_test.go @@ -3,20 +3,25 @@ package initialize import ( + "context" "errors" "fmt" "testing" "time" "github.com/aproint/copilot-cli/internal/pkg/config" + cloudformation "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/initialize/mocks" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" + "github.com/aproint/copilot-cli/internal/pkg/metadata" "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) +var ctx = context.Background() + func TestWorkloadInitializer_Job(t *testing.T) { testCases := map[string]struct { inJobType string @@ -52,8 +57,8 @@ func TestWorkloadInitializer_Job(t *testing.T) { m.EXPECT().WriteJobManifest(gomock.Any(), "resizer").Return("/resizer/copilot/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateJob(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateJob(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "resizer", App: "app", @@ -61,7 +66,7 @@ func TestWorkloadInitializer_Job(t *testing.T) { }, app) }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -89,8 +94,8 @@ func TestWorkloadInitializer_Job(t *testing.T) { }).Return("/resizer/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateJob(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateJob(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "resizer", App: "app", @@ -98,7 +103,7 @@ func TestWorkloadInitializer_Job(t *testing.T) { }, app) }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -138,7 +143,7 @@ func TestWorkloadInitializer_Job(t *testing.T) { m.EXPECT().WriteJobManifest(gomock.Any(), "resizer").Return("/copilot/resizer/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().GetApplication(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().GetApplication(ctx, gomock.Any()).Return(nil, errors.New("some error")) }, wantedErr: errors.New("get application app: some error"), }, @@ -155,7 +160,7 @@ func TestWorkloadInitializer_Job(t *testing.T) { m.EXPECT().WriteJobManifest(gomock.Any(), "resizer").Return("/resizer/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{ + m.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -178,14 +183,14 @@ func TestWorkloadInitializer_Job(t *testing.T) { m.EXPECT().WriteJobManifest(gomock.Any(), "resizer").Return("/resizer/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateJob(gomock.Any()). + m.EXPECT().CreateJob(gomock.Any(), gomock.Any()). Return(fmt.Errorf("oops")) - m.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{}, nil) + m.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{}, nil) }, mockappDeployer: func(m *mocks.MockWorkloadAdder) { m.EXPECT().AddJobToApp(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) }, - wantedErr: fmt.Errorf("saving job resizer: oops"), + wantedErr: fmt.Errorf("workload registration in application stack succeeded, but Copilot metadata commit failed: saving job resizer: oops"), }, } for name, tc := range testCases { @@ -228,7 +233,7 @@ func TestWorkloadInitializer_Job(t *testing.T) { } // WHEN - _, err := initializer.Job(initJobProps) + _, err := initializer.Job(ctx, initJobProps) // THEN if tc.wantedErr != nil { @@ -259,7 +264,7 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) { inDockerfilePath: "/Dockerfile", mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{}, nil) + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{}, nil) }, wantedPath: "/", @@ -271,7 +276,7 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) { inDockerfilePath: "/Dockerfile", mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{ + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{ { Name: "frontend", Type: manifestinfo.LoadBalancedWebServiceType, @@ -288,7 +293,7 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) { inDockerfilePath: "/Dockerfile", mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{ + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{ { Name: "another-app", Type: "backend", @@ -305,7 +310,7 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) { inDockerfilePath: "/Dockerfile", mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{ + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{ { Name: "admin", Type: manifestinfo.LoadBalancedWebServiceType, @@ -323,7 +328,7 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) { inAppDomain: "example.com", mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{ + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{ { Name: "admin", Type: manifestinfo.LoadBalancedWebServiceType, @@ -361,7 +366,7 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) { } // WHEN - manifest, err := initter.newLoadBalancedWebServiceManifest(&props) + manifest, err := initter.newLoadBalancedWebServiceManifest(ctx, &props) // THEN if tc.wantedErr == nil { @@ -469,9 +474,9 @@ func TestWorkloadInitializer_Service(t *testing.T) { m.EXPECT().WriteServiceManifest(gomock.Any(), "frontend").Return("/frontend/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{}, nil) - m.EXPECT().CreateService(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{}, nil) + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "frontend", App: "app", @@ -479,7 +484,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { }, app) }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -503,8 +508,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { m.EXPECT().WriteServiceManifest(gomock.Any(), "static").Return("/static/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateService(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "static", App: "app", @@ -512,7 +517,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { }, app) }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -536,7 +541,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { m.EXPECT().Rel("frontend/Dockerfile").Return("Dockerfile", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().GetApplication("app").Return(nil, errors.New("some error")) + m.EXPECT().GetApplication(ctx, "app").Return(nil, errors.New("some error")) }, wantedErr: errors.New("get application app: some error"), }, @@ -553,8 +558,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { m.EXPECT().WriteServiceManifest(gomock.Any(), "frontend").Return("/frontend/manifest.yml", errors.New("some error")) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app") - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().ListServices(ctx, "app") + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -574,8 +579,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { m.EXPECT().WriteServiceManifest(gomock.Any(), "frontend").Return("/frontend/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{}, nil) - m.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{ + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{}, nil) + m.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -597,15 +602,15 @@ func TestWorkloadInitializer_Service(t *testing.T) { m.EXPECT().WriteServiceManifest(gomock.Any(), "frontend").Return("/frontend/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().ListServices("app").Return([]*config.Workload{}, nil) - m.EXPECT().CreateService(gomock.Any()). + m.EXPECT().ListServices(ctx, "app").Return([]*config.Workload{}, nil) + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). Return(fmt.Errorf("oops")) - m.EXPECT().GetApplication(gomock.Any()).Return(&config.Application{}, nil) + m.EXPECT().GetApplication(ctx, gomock.Any()).Return(&config.Application{}, nil) }, mockappDeployer: func(m *mocks.MockWorkloadAdder) { m.EXPECT().AddServiceToApp(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) }, - wantedErr: fmt.Errorf("saving service frontend: oops"), + wantedErr: fmt.Errorf("workload registration in application stack succeeded, but Copilot metadata commit failed: saving service frontend: oops"), }, "using existing image": { inSvcType: manifestinfo.BackendServiceType, @@ -625,8 +630,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { }).Return("/backend/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateService(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "backend", App: "app", @@ -635,7 +640,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -666,8 +671,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { }).Return("/backend/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateService(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "backend", App: "app", @@ -676,7 +681,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -719,8 +724,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { }).Return("/backend/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateService(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "backend", App: "app", @@ -728,7 +733,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { }, app) }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -765,8 +770,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { }).Return("/worker/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateService(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "worker", App: "app", @@ -775,7 +780,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -813,8 +818,8 @@ func TestWorkloadInitializer_Service(t *testing.T) { }).Return("/worker/manifest.yml", nil) }, mockstore: func(m *mocks.MockStore) { - m.EXPECT().CreateService(gomock.Any()). - Do(func(app *config.Workload) { + m.EXPECT().CreateService(gomock.Any(), gomock.Any()). + Do(func(_ context.Context, app *config.Workload) { require.Equal(t, &config.Workload{ Name: "worker", App: "app", @@ -823,7 +828,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { }). Return(nil) - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", AccountID: "1234", }, nil) @@ -866,7 +871,7 @@ func TestWorkloadInitializer_Service(t *testing.T) { } // WHEN - _, err := initializer.Service(&ServiceProps{ + _, err := initializer.Service(ctx, &ServiceProps{ WorkloadProps: WorkloadProps{ App: tc.inAppName, Name: tc.inSvcName, @@ -906,10 +911,10 @@ func TestWorkloadInitializer_AddWorkloadToApp(t *testing.T) { inWlName: "job", mockstore: func(m *mocks.MockStore) { - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", }, nil) - m.EXPECT().CreateJob(&config.Workload{ + m.EXPECT().CreateJob(gomock.Any(), &config.Workload{ App: "app", Name: "job", Type: manifestinfo.ScheduledJobType, @@ -927,10 +932,10 @@ func TestWorkloadInitializer_AddWorkloadToApp(t *testing.T) { inWlName: "svc", mockstore: func(m *mocks.MockStore) { - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", }, nil) - m.EXPECT().CreateService(&config.Workload{ + m.EXPECT().CreateService(gomock.Any(), &config.Workload{ App: "app", Name: "svc", Type: manifestinfo.LoadBalancedWebServiceType, @@ -948,10 +953,10 @@ func TestWorkloadInitializer_AddWorkloadToApp(t *testing.T) { inWlName: "svc", mockstore: func(m *mocks.MockStore) { - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", }, nil) - m.EXPECT().CreateService(&config.Workload{ + m.EXPECT().CreateService(gomock.Any(), &config.Workload{ App: "app", Name: "svc", Type: manifestinfo.StaticSiteType, @@ -970,10 +975,10 @@ func TestWorkloadInitializer_AddWorkloadToApp(t *testing.T) { wantedErr: errors.New("get application app: some error"), mockstore: func(m *mocks.MockStore) { - m.EXPECT().GetApplication("app").Return(&config.Application{ + m.EXPECT().GetApplication(ctx, "app").Return(&config.Application{ Name: "app", }, errors.New("some error")) - m.EXPECT().CreateService(gomock.Any()).Times(0) + m.EXPECT().CreateService(gomock.Any(), gomock.Any()).Times(0) }, }, } @@ -999,7 +1004,7 @@ func TestWorkloadInitializer_AddWorkloadToApp(t *testing.T) { } // WHEN - err := initializer.AddWorkloadToApp(tc.inAppName, tc.inWlName, tc.inWlType) + err := initializer.AddWorkloadToApp(ctx, tc.inAppName, tc.inWlName, tc.inWlType) // THEN if tc.wantedErr != nil { @@ -1010,3 +1015,90 @@ func TestWorkloadInitializer_AddWorkloadToApp(t *testing.T) { }) } } + +func TestWorkloadInitializer_AddWorkloadToApp_PreMutationCanceledContextPreventsRegistration(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + parent, cancel := context.WithCancel(context.Background()) + cancel() + mockstore := mocks.NewMockStore(ctrl) + mockappDeployer := mocks.NewMockWorkloadAdder(ctrl) + + mockstore.EXPECT().GetApplication(parent, "app").Return(&config.Application{Name: "app"}, nil) + mockappDeployer.EXPECT().AddServiceToApp(gomock.Any(), gomock.Any()).Times(0) + mockstore.EXPECT().CreateService(gomock.Any(), gomock.Any()).Times(0) + + initializer := &WorkloadInitializer{ + Store: mockstore, + Deployer: mockappDeployer, + } + + err := initializer.AddWorkloadToApp(parent, "app", "svc", manifestinfo.LoadBalancedWebServiceType) + + require.ErrorIs(t, err, context.Canceled) +} + +func TestWorkloadInitializer_AddWorkloadToApp_CanceledParentStillCommitsMetadata(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + parent, cancel := context.WithCancel(context.Background()) + mockstore := mocks.NewMockStore(ctrl) + mockappDeployer := mocks.NewMockWorkloadAdder(ctrl) + + mockstore.EXPECT().GetApplication(parent, "app").Return(&config.Application{Name: "app"}, nil) + mockappDeployer.EXPECT().AddServiceToApp(&config.Application{Name: "app"}, "svc").DoAndReturn(func(*config.Application, string, ...cloudformation.AddWorkloadToAppOpt) error { + cancel() + return nil + }) + mockstore.EXPECT().CreateService(gomock.Any(), &config.Workload{ + App: "app", + Name: "svc", + Type: manifestinfo.LoadBalancedWebServiceType, + }).DoAndReturn(func(gotCtx context.Context, _ *config.Workload) error { + require.NoError(t, gotCtx.Err()) + deadline, ok := gotCtx.Deadline() + require.True(t, ok) + require.WithinDuration(t, time.Now().Add(metadata.CommitTimeout), deadline, time.Second) + return nil + }) + + initializer := &WorkloadInitializer{ + Store: mockstore, + Deployer: mockappDeployer, + } + + err := initializer.AddWorkloadToApp(parent, "app", "svc", manifestinfo.LoadBalancedWebServiceType) + + require.NoError(t, err) +} + +func TestWorkloadInitializer_AddWorkloadToApp_MetadataCommitErrorIsPartialSuccess(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockErr := errors.New("some create error") + mockstore := mocks.NewMockStore(ctrl) + mockappDeployer := mocks.NewMockWorkloadAdder(ctrl) + + mockstore.EXPECT().GetApplication(ctx, "app").Return(&config.Application{Name: "app"}, nil) + mockappDeployer.EXPECT().AddJobToApp(&config.Application{Name: "app"}, "job").Return(nil) + mockstore.EXPECT().CreateJob(gomock.Any(), &config.Workload{ + App: "app", + Name: "job", + Type: manifestinfo.ScheduledJobType, + }).Return(mockErr) + + initializer := &WorkloadInitializer{ + Store: mockstore, + Deployer: mockappDeployer, + } + + err := initializer.AddWorkloadToApp(ctx, "app", "job", manifestinfo.ScheduledJobType) + + var commitErr *metadata.CommitError + require.ErrorAs(t, err, &commitErr) + require.ErrorIs(t, err, mockErr) + require.EqualError(t, err, "workload registration in application stack succeeded, but Copilot metadata commit failed: saving job job: some create error") +} diff --git a/internal/pkg/logging/workload.go b/internal/pkg/logging/workload.go index 3bfe0fa2039..70707d604ff 100644 --- a/internal/pkg/logging/workload.go +++ b/internal/pkg/logging/workload.go @@ -5,6 +5,7 @@ package logging import ( + "context" "fmt" "io" "strings" @@ -35,6 +36,7 @@ type serviceARNGetter interface { // NewWorkloadLoggerOpts contains fields that initiate workloadLogger struct. type NewWorkloadLoggerOpts struct { + Ctx context.Context App string Env string Name string @@ -145,7 +147,11 @@ type NewAppRunnerServiceLoggerOpts struct { // NewAppRunnerServiceLogger returns an AppRunnerServiceLogger for the service under env and app. func NewAppRunnerServiceLogger(opts *NewAppRunnerServiceLoggerOpts) (*AppRunnerServiceLogger, error) { - serviceDescriber, err := describe.NewRDWebServiceDescriber(describe.NewServiceConfig{ + ctx := opts.Ctx + if ctx == nil { + ctx = context.Background() + } + serviceDescriber, err := describe.NewRDWebServiceDescriber(ctx, describe.NewServiceConfig{ App: opts.App, Svc: opts.Name, ConfigStore: opts.ConfigStore, diff --git a/internal/pkg/metadata/commit.go b/internal/pkg/metadata/commit.go new file mode 100644 index 00000000000..dba455cc33f --- /dev/null +++ b/internal/pkg/metadata/commit.go @@ -0,0 +1,57 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package metadata contains helpers for Copilot metadata commit operations. +package metadata + +import ( + "context" + "fmt" + "time" +) + +const ( + // CommitTimeout bounds short metadata writes that must complete after a durable + // infrastructure mutation has already succeeded. + CommitTimeout = 30 * time.Second + + // CommitAfterCancellationWarning is shown when a required metadata commit is + // started after the caller context has already been canceled. + CommitAfterCancellationWarning = "Command was canceled; finishing required Copilot metadata write with a 30s timeout." +) + +// CommitContext returns a short, detached context for required metadata writes +// after a durable infrastructure mutation has already succeeded. +// +// Use this only for short metadata commits that preserve Copilot consistency +// after infrastructure has been durably changed. Pre-mutation reads, validation, +// and normal command-scoped work should continue to use the caller context. +func CommitContext(parent context.Context) (context.Context, context.CancelFunc) { + return context.WithTimeout(context.WithoutCancel(parent), CommitTimeout) +} + +// CommitError reports that a durable mutation succeeded but the required Copilot +// metadata commit failed. +type CommitError struct { + Mutation string + Err error +} + +func (e *CommitError) Error() string { + return fmt.Sprintf("%s succeeded, but Copilot metadata commit failed: %v", e.Mutation, e.Err) +} + +func (e *CommitError) Unwrap() error { + return e.Err +} + +// NewCommitError wraps a metadata commit failure after mutation has succeeded. +func NewCommitError(mutation string, err error) error { + if err == nil { + return nil + } + return &CommitError{ + Mutation: mutation, + Err: err, + } +} diff --git a/internal/pkg/metadata/commit_test.go b/internal/pkg/metadata/commit_test.go new file mode 100644 index 00000000000..418ffc009bc --- /dev/null +++ b/internal/pkg/metadata/commit_test.go @@ -0,0 +1,40 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package metadata_test + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/aproint/copilot-cli/internal/pkg/metadata" + "github.com/stretchr/testify/require" +) + +func TestCommitContext(t *testing.T) { + type contextKey string + parent, cancelParent := context.WithCancel(context.WithValue(context.Background(), contextKey("key"), "value")) + cancelParent() + + ctx, cancelCommit := metadata.CommitContext(parent) + defer cancelCommit() + + require.NoError(t, ctx.Err()) + require.Equal(t, "value", ctx.Value(contextKey("key"))) + deadline, ok := ctx.Deadline() + require.True(t, ok) + require.WithinDuration(t, time.Now().Add(metadata.CommitTimeout), deadline, time.Second) +} + +func TestNewCommitError(t *testing.T) { + root := errors.New("boom") + + err := metadata.NewCommitError("application infrastructure deployment", root) + + require.EqualError(t, err, "application infrastructure deployment succeeded, but Copilot metadata commit failed: boom") + require.ErrorIs(t, err, root) + var commitErr *metadata.CommitError + require.ErrorAs(t, err, &commitErr) +} diff --git a/internal/pkg/term/selector/mocks/mock_selector.go b/internal/pkg/term/selector/mocks/mock_selector.go index 725a4e10c8a..d91e252ab19 100644 --- a/internal/pkg/term/selector/mocks/mock_selector.go +++ b/internal/pkg/term/selector/mocks/mock_selector.go @@ -5,6 +5,7 @@ package mocks import ( + context "context" reflect "reflect" ecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" @@ -183,33 +184,33 @@ func (m *MockappEnvLister) EXPECT() *MockappEnvListerMockRecorder { } // ListApplications mocks base method. -func (m *MockappEnvLister) ListApplications() ([]*config.Application, error) { +func (m *MockappEnvLister) ListApplications(ctx context.Context) ([]*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListApplications") + ret := m.ctrl.Call(m, "ListApplications", ctx) ret0, _ := ret[0].([]*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // ListApplications indicates an expected call of ListApplications. -func (mr *MockappEnvListerMockRecorder) ListApplications() *gomock.Call { +func (mr *MockappEnvListerMockRecorder) ListApplications(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockappEnvLister)(nil).ListApplications)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockappEnvLister)(nil).ListApplications), ctx) } // ListEnvironments mocks base method. -func (m *MockappEnvLister) ListEnvironments(appName string) ([]*config.Environment, error) { +func (m *MockappEnvLister) ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironments", appName) + ret := m.ctrl.Call(m, "ListEnvironments", ctx, appName) ret0, _ := ret[0].([]*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironments indicates an expected call of ListEnvironments. -func (mr *MockappEnvListerMockRecorder) ListEnvironments(appName interface{}) *gomock.Call { +func (mr *MockappEnvListerMockRecorder) ListEnvironments(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockappEnvLister)(nil).ListEnvironments), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockappEnvLister)(nil).ListEnvironments), ctx, appName) } // MockconfigWorkloadLister is a mock of configWorkloadLister interface. @@ -236,48 +237,48 @@ func (m *MockconfigWorkloadLister) EXPECT() *MockconfigWorkloadListerMockRecorde } // ListJobs mocks base method. -func (m *MockconfigWorkloadLister) ListJobs(appName string) ([]*config.Workload, error) { +func (m *MockconfigWorkloadLister) ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListJobs", appName) + ret := m.ctrl.Call(m, "ListJobs", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListJobs indicates an expected call of ListJobs. -func (mr *MockconfigWorkloadListerMockRecorder) ListJobs(appName interface{}) *gomock.Call { +func (mr *MockconfigWorkloadListerMockRecorder) ListJobs(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockconfigWorkloadLister)(nil).ListJobs), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockconfigWorkloadLister)(nil).ListJobs), ctx, appName) } // ListServices mocks base method. -func (m *MockconfigWorkloadLister) ListServices(appName string) ([]*config.Workload, error) { +func (m *MockconfigWorkloadLister) ListServices(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", appName) + ret := m.ctrl.Call(m, "ListServices", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockconfigWorkloadListerMockRecorder) ListServices(appName interface{}) *gomock.Call { +func (mr *MockconfigWorkloadListerMockRecorder) ListServices(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockconfigWorkloadLister)(nil).ListServices), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockconfigWorkloadLister)(nil).ListServices), ctx, appName) } // ListWorkloads mocks base method. -func (m *MockconfigWorkloadLister) ListWorkloads(appName string) ([]*config.Workload, error) { +func (m *MockconfigWorkloadLister) ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListWorkloads", appName) + ret := m.ctrl.Call(m, "ListWorkloads", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListWorkloads indicates an expected call of ListWorkloads. -func (mr *MockconfigWorkloadListerMockRecorder) ListWorkloads(appName interface{}) *gomock.Call { +func (mr *MockconfigWorkloadListerMockRecorder) ListWorkloads(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockconfigWorkloadLister)(nil).ListWorkloads), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockconfigWorkloadLister)(nil).ListWorkloads), ctx, appName) } // MockconfigLister is a mock of configLister interface. @@ -304,78 +305,78 @@ func (m *MockconfigLister) EXPECT() *MockconfigListerMockRecorder { } // ListApplications mocks base method. -func (m *MockconfigLister) ListApplications() ([]*config.Application, error) { +func (m *MockconfigLister) ListApplications(ctx context.Context) ([]*config.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListApplications") + ret := m.ctrl.Call(m, "ListApplications", ctx) ret0, _ := ret[0].([]*config.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // ListApplications indicates an expected call of ListApplications. -func (mr *MockconfigListerMockRecorder) ListApplications() *gomock.Call { +func (mr *MockconfigListerMockRecorder) ListApplications(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockconfigLister)(nil).ListApplications)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplications", reflect.TypeOf((*MockconfigLister)(nil).ListApplications), ctx) } // ListEnvironments mocks base method. -func (m *MockconfigLister) ListEnvironments(appName string) ([]*config.Environment, error) { +func (m *MockconfigLister) ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListEnvironments", appName) + ret := m.ctrl.Call(m, "ListEnvironments", ctx, appName) ret0, _ := ret[0].([]*config.Environment) ret1, _ := ret[1].(error) return ret0, ret1 } // ListEnvironments indicates an expected call of ListEnvironments. -func (mr *MockconfigListerMockRecorder) ListEnvironments(appName interface{}) *gomock.Call { +func (mr *MockconfigListerMockRecorder) ListEnvironments(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockconfigLister)(nil).ListEnvironments), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEnvironments", reflect.TypeOf((*MockconfigLister)(nil).ListEnvironments), ctx, appName) } // ListJobs mocks base method. -func (m *MockconfigLister) ListJobs(appName string) ([]*config.Workload, error) { +func (m *MockconfigLister) ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListJobs", appName) + ret := m.ctrl.Call(m, "ListJobs", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListJobs indicates an expected call of ListJobs. -func (mr *MockconfigListerMockRecorder) ListJobs(appName interface{}) *gomock.Call { +func (mr *MockconfigListerMockRecorder) ListJobs(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockconfigLister)(nil).ListJobs), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobs", reflect.TypeOf((*MockconfigLister)(nil).ListJobs), ctx, appName) } // ListServices mocks base method. -func (m *MockconfigLister) ListServices(appName string) ([]*config.Workload, error) { +func (m *MockconfigLister) ListServices(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", appName) + ret := m.ctrl.Call(m, "ListServices", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockconfigListerMockRecorder) ListServices(appName interface{}) *gomock.Call { +func (mr *MockconfigListerMockRecorder) ListServices(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockconfigLister)(nil).ListServices), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockconfigLister)(nil).ListServices), ctx, appName) } // ListWorkloads mocks base method. -func (m *MockconfigLister) ListWorkloads(appName string) ([]*config.Workload, error) { +func (m *MockconfigLister) ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListWorkloads", appName) + ret := m.ctrl.Call(m, "ListWorkloads", ctx, appName) ret0, _ := ret[0].([]*config.Workload) ret1, _ := ret[1].(error) return ret0, ret1 } // ListWorkloads indicates an expected call of ListWorkloads. -func (mr *MockconfigListerMockRecorder) ListWorkloads(appName interface{}) *gomock.Call { +func (mr *MockconfigListerMockRecorder) ListWorkloads(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockconfigLister)(nil).ListWorkloads), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListWorkloads", reflect.TypeOf((*MockconfigLister)(nil).ListWorkloads), ctx, appName) } // MockwsWorkloadLister is a mock of wsWorkloadLister interface. @@ -682,108 +683,108 @@ func (m *MockdeployedWorkloadsRetriever) EXPECT() *MockdeployedWorkloadsRetrieve } // IsJobDeployed mocks base method. -func (m *MockdeployedWorkloadsRetriever) IsJobDeployed(appName, envName, jobName string) (bool, error) { +func (m *MockdeployedWorkloadsRetriever) IsJobDeployed(ctx context.Context, appName, envName, jobName string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsJobDeployed", appName, envName, jobName) + ret := m.ctrl.Call(m, "IsJobDeployed", ctx, appName, envName, jobName) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // IsJobDeployed indicates an expected call of IsJobDeployed. -func (mr *MockdeployedWorkloadsRetrieverMockRecorder) IsJobDeployed(appName, envName, jobName interface{}) *gomock.Call { +func (mr *MockdeployedWorkloadsRetrieverMockRecorder) IsJobDeployed(ctx, appName, envName, jobName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsJobDeployed", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).IsJobDeployed), appName, envName, jobName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsJobDeployed", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).IsJobDeployed), ctx, appName, envName, jobName) } // IsServiceDeployed mocks base method. -func (m *MockdeployedWorkloadsRetriever) IsServiceDeployed(appName, envName, svcName string) (bool, error) { +func (m *MockdeployedWorkloadsRetriever) IsServiceDeployed(ctx context.Context, appName, envName, svcName string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsServiceDeployed", appName, envName, svcName) + ret := m.ctrl.Call(m, "IsServiceDeployed", ctx, appName, envName, svcName) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // IsServiceDeployed indicates an expected call of IsServiceDeployed. -func (mr *MockdeployedWorkloadsRetrieverMockRecorder) IsServiceDeployed(appName, envName, svcName interface{}) *gomock.Call { +func (mr *MockdeployedWorkloadsRetrieverMockRecorder) IsServiceDeployed(ctx, appName, envName, svcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsServiceDeployed", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).IsServiceDeployed), appName, envName, svcName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsServiceDeployed", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).IsServiceDeployed), ctx, appName, envName, svcName) } // IsWorkloadDeployed mocks base method. -func (m *MockdeployedWorkloadsRetriever) IsWorkloadDeployed(appName, envName, wkldName string) (bool, error) { +func (m *MockdeployedWorkloadsRetriever) IsWorkloadDeployed(ctx context.Context, appName, envName, wkldName string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsWorkloadDeployed", appName, envName, wkldName) + ret := m.ctrl.Call(m, "IsWorkloadDeployed", ctx, appName, envName, wkldName) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // IsWorkloadDeployed indicates an expected call of IsWorkloadDeployed. -func (mr *MockdeployedWorkloadsRetrieverMockRecorder) IsWorkloadDeployed(appName, envName, wkldName interface{}) *gomock.Call { +func (mr *MockdeployedWorkloadsRetrieverMockRecorder) IsWorkloadDeployed(ctx, appName, envName, wkldName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsWorkloadDeployed", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).IsWorkloadDeployed), appName, envName, wkldName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsWorkloadDeployed", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).IsWorkloadDeployed), ctx, appName, envName, wkldName) } // ListDeployedJobs mocks base method. -func (m *MockdeployedWorkloadsRetriever) ListDeployedJobs(appName, envName string) ([]string, error) { +func (m *MockdeployedWorkloadsRetriever) ListDeployedJobs(ctx context.Context, appName, envName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployedJobs", appName, envName) + ret := m.ctrl.Call(m, "ListDeployedJobs", ctx, appName, envName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListDeployedJobs indicates an expected call of ListDeployedJobs. -func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListDeployedJobs(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListDeployedJobs(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedJobs", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListDeployedJobs), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedJobs", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListDeployedJobs), ctx, appName, envName) } // ListDeployedServices mocks base method. -func (m *MockdeployedWorkloadsRetriever) ListDeployedServices(appName, envName string) ([]string, error) { +func (m *MockdeployedWorkloadsRetriever) ListDeployedServices(ctx context.Context, appName, envName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployedServices", appName, envName) + ret := m.ctrl.Call(m, "ListDeployedServices", ctx, appName, envName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListDeployedServices indicates an expected call of ListDeployedServices. -func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListDeployedServices(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListDeployedServices(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedServices", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListDeployedServices), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedServices", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListDeployedServices), ctx, appName, envName) } // ListDeployedWorkloads mocks base method. -func (m *MockdeployedWorkloadsRetriever) ListDeployedWorkloads(appName, envName string) ([]string, error) { +func (m *MockdeployedWorkloadsRetriever) ListDeployedWorkloads(ctx context.Context, appName, envName string) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployedWorkloads", appName, envName) + ret := m.ctrl.Call(m, "ListDeployedWorkloads", ctx, appName, envName) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // ListDeployedWorkloads indicates an expected call of ListDeployedWorkloads. -func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListDeployedWorkloads(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListDeployedWorkloads(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedWorkloads", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListDeployedWorkloads), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployedWorkloads", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListDeployedWorkloads), ctx, appName, envName) } // ListSNSTopics mocks base method. -func (m *MockdeployedWorkloadsRetriever) ListSNSTopics(appName, envName string) ([]deploy.Topic, error) { +func (m *MockdeployedWorkloadsRetriever) ListSNSTopics(ctx context.Context, appName, envName string) ([]deploy.Topic, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListSNSTopics", appName, envName) + ret := m.ctrl.Call(m, "ListSNSTopics", ctx, appName, envName) ret0, _ := ret[0].([]deploy.Topic) ret1, _ := ret[1].(error) return ret0, ret1 } // ListSNSTopics indicates an expected call of ListSNSTopics. -func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListSNSTopics(appName, envName interface{}) *gomock.Call { +func (mr *MockdeployedWorkloadsRetrieverMockRecorder) ListSNSTopics(ctx, appName, envName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSNSTopics", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListSNSTopics), appName, envName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSNSTopics", reflect.TypeOf((*MockdeployedWorkloadsRetriever)(nil).ListSNSTopics), ctx, appName, envName) } // MocktaskStackDescriber is a mock of taskStackDescriber interface. diff --git a/internal/pkg/term/selector/selector.go b/internal/pkg/term/selector/selector.go index ae7ca866fc5..720f9e775b6 100644 --- a/internal/pkg/term/selector/selector.go +++ b/internal/pkg/term/selector/selector.go @@ -5,6 +5,7 @@ package selector import ( + "context" "errors" "fmt" "sort" @@ -111,14 +112,14 @@ type Prompter interface { } type appEnvLister interface { - ListEnvironments(appName string) ([]*config.Environment, error) - ListApplications() ([]*config.Application, error) + ListEnvironments(ctx context.Context, appName string) ([]*config.Environment, error) + ListApplications(ctx context.Context) ([]*config.Application, error) } type configWorkloadLister interface { - ListServices(appName string) ([]*config.Workload, error) - ListJobs(appName string) ([]*config.Workload, error) - ListWorkloads(appName string) ([]*config.Workload, error) + ListServices(ctx context.Context, appName string) ([]*config.Workload, error) + ListJobs(ctx context.Context, appName string) ([]*config.Workload, error) + ListWorkloads(ctx context.Context, appName string) ([]*config.Workload, error) } type configLister interface { @@ -154,13 +155,13 @@ type workspaceRetriever interface { // deployedWorkloadsRetriever retrieves information about deployed services or jobs. type deployedWorkloadsRetriever interface { - ListDeployedServices(appName string, envName string) ([]string, error) - ListDeployedJobs(appName, envName string) ([]string, error) - ListDeployedWorkloads(appName, envName string) ([]string, error) - IsServiceDeployed(appName string, envName string, svcName string) (bool, error) - IsJobDeployed(appName, envName, jobName string) (bool, error) - IsWorkloadDeployed(appName, envName, wkldName string) (bool, error) - ListSNSTopics(appName string, envName string) ([]deploy.Topic, error) + ListDeployedServices(ctx context.Context, appName string, envName string) ([]string, error) + ListDeployedJobs(ctx context.Context, appName, envName string) ([]string, error) + ListDeployedWorkloads(ctx context.Context, appName, envName string) ([]string, error) + IsServiceDeployed(ctx context.Context, appName string, envName string, svcName string) (bool, error) + IsJobDeployed(ctx context.Context, appName, envName, jobName string) (bool, error) + IsWorkloadDeployed(ctx context.Context, appName, envName, wkldName string) (bool, error) + ListSNSTopics(ctx context.Context, appName string, envName string) ([]deploy.Topic, error) } // taskStackDescriber wraps cloudformation client methods to describe task stacks @@ -579,8 +580,8 @@ func (s *CFTaskSelector) Task(msg, help string, opts ...GetDeployedTaskOpts) (st // DeployedJob has the user select a deployed job. Callers can provide either a particular environment, // a particular job to filter on, or both. -func (s *DeploySelector) DeployedJob(msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedJob, error) { - j, err := s.deployedWorkload(jobWorkloadType, msg, help, app, opts...) +func (s *DeploySelector) DeployedJob(ctx context.Context, msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedJob, error) { + j, err := s.deployedWorkload(ctx, jobWorkloadType, msg, help, app, opts...) if err != nil { return nil, err } @@ -592,8 +593,8 @@ func (s *DeploySelector) DeployedJob(msg, help string, app string, opts ...GetDe // DeployedService has the user select a deployed service. Callers can provide either a particular environment, // a particular service to filter on, or both. -func (s *DeploySelector) DeployedService(msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedService, error) { - svc, err := s.deployedWorkload(svcWorkloadType, msg, help, app, opts...) +func (s *DeploySelector) DeployedService(ctx context.Context, msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedService, error) { + svc, err := s.deployedWorkload(ctx, svcWorkloadType, msg, help, app, opts...) if err != nil { return nil, err } @@ -606,8 +607,8 @@ func (s *DeploySelector) DeployedService(msg, help string, app string, opts ...G // DeployedWorkload has the user select a deployed workload. Callers can provide either a particular environment, // a particular workload to filter on, or both. -func (s *DeploySelector) DeployedWorkload(msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedWorkload, error) { - wkld, err := s.deployedWorkload(anyWorkloadType, msg, help, app, opts...) +func (s *DeploySelector) DeployedWorkload(ctx context.Context, msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedWorkload, error) { + wkld, err := s.deployedWorkload(ctx, anyWorkloadType, msg, help, app, opts...) if err != nil { return nil, err } @@ -618,13 +619,13 @@ func (s *DeploySelector) DeployedWorkload(msg, help string, app string, opts ... }, nil } -func (s *DeploySelector) deployedWorkload(workloadType string, msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedWorkload, error) { +func (s *DeploySelector) deployedWorkload(ctx context.Context, workloadType string, msg, help string, app string, opts ...GetDeployedWorkloadOpts) (*DeployedWorkload, error) { for _, opt := range opts { opt(s) } - var isWorkloadDeployed func(string, string, string) (bool, error) - var listDeployedWorkloads func(string, string) ([]string, error) + var isWorkloadDeployed func(context.Context, string, string, string) (bool, error) + var listDeployedWorkloads func(context.Context, string, string) ([]string, error) var finalMessage string switch workloadType { case svcWorkloadType: @@ -647,7 +648,7 @@ func (s *DeploySelector) deployedWorkload(workloadType string, msg, help string, var err error var envNames []string wkldTypes := map[string]string{} - workloads, err := s.workloadLister.ListWorkloads(app) + workloads, err := s.workloadLister.ListWorkloads(ctx, app) if err != nil { return nil, fmt.Errorf("list %ss: %w", workloadType, err) } @@ -658,7 +659,7 @@ func (s *DeploySelector) deployedWorkload(workloadType string, msg, help string, if s.env != "" { envNames = append(envNames, s.env) } else { - envNames, err = s.retrieveEnvironments(app) + envNames, err = s.retrieveEnvironments(ctx, app) if err != nil { return nil, fmt.Errorf("list environments: %w", err) } @@ -667,7 +668,7 @@ func (s *DeploySelector) deployedWorkload(workloadType string, msg, help string, for _, envName := range envNames { var wkldNames []string if s.name != "" { - deployed, err := isWorkloadDeployed(app, envName, s.name) + deployed, err := isWorkloadDeployed(ctx, app, envName, s.name) if err != nil { return nil, fmt.Errorf("check if %s %s is deployed in environment %s: %w", workloadType, s.name, envName, err) } @@ -676,7 +677,7 @@ func (s *DeploySelector) deployedWorkload(workloadType string, msg, help string, } wkldNames = append(wkldNames, s.name) } else { - wkldNames, err = listDeployedWorkloads(app, envName) + wkldNames, err = listDeployedWorkloads(ctx, app, envName) if err != nil { return nil, fmt.Errorf("list deployed %ss for environment %s: %w", workloadType, envName, err) } @@ -694,7 +695,7 @@ func (s *DeploySelector) deployedWorkload(workloadType string, msg, help string, return nil, fmt.Errorf("no deployed %ss found in application %s", workloadType, color.HighlightUserInput(app)) } - if wkldEnvs, err = s.filterWorkloads(wkldEnvs); err != nil { + if wkldEnvs, err = s.filterWorkloads(ctx, wkldEnvs); err != nil { return nil, err } @@ -737,7 +738,7 @@ func (s *DeploySelector) deployedWorkload(workloadType string, msg, help string, return deployedWkld, nil } -func (s *DeploySelector) filterWorkloads(inWorkloads []*DeployedWorkload) ([]*DeployedWorkload, error) { +func (s *DeploySelector) filterWorkloads(ctx context.Context, inWorkloads []*DeployedWorkload) ([]*DeployedWorkload, error) { outWorkloads := inWorkloads for _, filter := range s.filters { if result, err := filterDeployedServices(filter, outWorkloads); err != nil { @@ -750,8 +751,8 @@ func (s *DeploySelector) filterWorkloads(inWorkloads []*DeployedWorkload) ([]*De } // Service fetches all services in the workspace and then prompts the user to select one. -func (s *LocalWorkloadSelector) Service(msg, help string) (string, error) { - options, err := s.getWorkloadSelectOptions(svcWorkloadType) +func (s *LocalWorkloadSelector) Service(ctx context.Context, msg, help string) (string, error) { + options, err := s.getWorkloadSelectOptions(ctx, svcWorkloadType) if err != nil { return "", err } @@ -768,8 +769,8 @@ func (s *LocalWorkloadSelector) Service(msg, help string) (string, error) { } // Job fetches all jobs in the workspace and then prompts the user to select one. -func (s *LocalWorkloadSelector) Job(msg, help string) (string, error) { - options, err := s.getWorkloadSelectOptions(jobWorkloadType) +func (s *LocalWorkloadSelector) Job(ctx context.Context, msg, help string) (string, error) { + options, err := s.getWorkloadSelectOptions(ctx, jobWorkloadType) if err != nil { return "", err } @@ -786,7 +787,7 @@ func (s *LocalWorkloadSelector) Job(msg, help string) (string, error) { } -func (s *LocalWorkloadSelector) getWorkloadSelectOptions(workloadType string) ([]prompt.Option, error) { +func (s *LocalWorkloadSelector) getWorkloadSelectOptions(ctx context.Context, workloadType string) ([]prompt.Option, error) { pluralNounString := english.PluralWord(2, workloadType, "") summary, err := s.ws.Summary() @@ -798,7 +799,7 @@ func (s *LocalWorkloadSelector) getWorkloadSelectOptions(workloadType string) ([ return nil, fmt.Errorf("retrieve %s from workspace: %w", pluralNounString, err) } - storeWls, err := s.retrieveStoreWorkloads(summary.Application, workloadType) + storeWls, err := s.retrieveStoreWorkloads(ctx, summary.Application, workloadType) if err != nil { return nil, fmt.Errorf("retrieve %s from store: %w", pluralNounString, err) } @@ -847,8 +848,8 @@ var OnlyInitializedWorkloads WorkloadSelectOption = func(s *LocalWorkloadSelecto // It can optionally select only initialized workloads which exist in the app (by passing the // OnlyInitializedWorkloads option to NewLocalWorkloadSelector) or list all workloads for which // there are manifests in the workspace (default). -func (s *LocalWorkloadSelector) Workloads(msg, help string) ([]string, error) { - options, err := s.getWorkloadSelectOptions(anyWorkloadType) +func (s *LocalWorkloadSelector) Workloads(ctx context.Context, msg, help string) ([]string, error) { + options, err := s.getWorkloadSelectOptions(ctx, anyWorkloadType) if err != nil { return nil, err } @@ -868,8 +869,8 @@ func (s *LocalWorkloadSelector) Workloads(msg, help string) ([]string, error) { // It can optionally select only initialized workloads which exist in the app (by passing the // OnlyInitializedWorkloads option to NewLocalWorkloadSelector) or list all workloads for which // there are manifests in the workspace (default). -func (s *LocalWorkloadSelector) Workload(msg, help string) (wl string, err error) { - options, err := s.getWorkloadSelectOptions(anyWorkloadType) +func (s *LocalWorkloadSelector) Workload(ctx context.Context, msg, help string) (wl string, err error) { + options, err := s.getWorkloadSelectOptions(ctx, anyWorkloadType) if err != nil { return "", err } @@ -908,7 +909,7 @@ func filterOutItems[T any](allItems []string, unwantedItems []T, stringFunc func } // LocalEnvironment fetches all environments belong to the app in the workspace and prompts the user to select one. -func (s *LocalEnvironmentSelector) LocalEnvironment(msg, help string) (string, error) { +func (s *LocalEnvironmentSelector) LocalEnvironment(ctx context.Context, msg, help string) (string, error) { summary, err := s.ws.Summary() if err != nil { return "", fmt.Errorf("read workspace summary: %w", err) @@ -917,7 +918,7 @@ func (s *LocalEnvironmentSelector) LocalEnvironment(msg, help string) (string, e if err != nil { return "", fmt.Errorf("retrieve environments from workspace: %w", err) } - envs, err := s.appEnvLister.ListEnvironments(summary.Application) + envs, err := s.appEnvLister.ListEnvironments(ctx, summary.Application) if err != nil { return "", fmt.Errorf("retrieve environments from store: %w", err) } @@ -1027,8 +1028,8 @@ func (s *CodePipelineSelector) DeployedPipeline(msg, help, app string) (deploy.P } // Service fetches all services in an app and prompts the user to select one. -func (s *ConfigSelector) Service(msg, help, app string) (string, error) { - services, err := s.retrieveServices(app) +func (s *ConfigSelector) Service(ctx context.Context, msg, help, app string) (string, error) { + services, err := s.retrieveServices(ctx, app) if err != nil { return "", err } @@ -1047,8 +1048,8 @@ func (s *ConfigSelector) Service(msg, help, app string) (string, error) { } // Job fetches all jobs in an app and prompts the user to select one. -func (s *ConfigSelector) Job(msg, help, app string) (string, error) { - jobs, err := s.retrieveJobs(app) +func (s *ConfigSelector) Job(ctx context.Context, msg, help, app string) (string, error) { + jobs, err := s.retrieveJobs(ctx, app) if err != nil { return "", err } @@ -1067,12 +1068,12 @@ func (s *ConfigSelector) Job(msg, help, app string) (string, error) { } // Workload fetches all workloads in an app and prompts the user to select one. -func (s *ConfigSelector) Workload(msg, help, app string) (string, error) { - services, err := s.retrieveServices(app) +func (s *ConfigSelector) Workload(ctx context.Context, msg, help, app string) (string, error) { + services, err := s.retrieveServices(ctx, app) if err != nil { return "", err } - jobs, err := s.retrieveJobs(app) + jobs, err := s.retrieveJobs(ctx, app) if err != nil { return "", err } @@ -1093,8 +1094,8 @@ func (s *ConfigSelector) Workload(msg, help, app string) (string, error) { } // Environment fetches all the environments in an app and prompts the user to select one. -func (s *AppEnvSelector) Environment(msg, help, app string, additionalOpts ...prompt.Option) (string, error) { - envs, err := s.retrieveEnvironments(app) +func (s *AppEnvSelector) Environment(ctx context.Context, msg, help, app string, additionalOpts ...prompt.Option) (string, error) { + envs, err := s.retrieveEnvironments(ctx, app) if err != nil { return "", fmt.Errorf("get environments for app %s from metadata store: %w", app, err) } @@ -1124,8 +1125,8 @@ func (s *AppEnvSelector) Environment(msg, help, app string, additionalOpts ...pr // Environments fetches all the environments in an app and prompts the user to select one OR MORE. // The List of options decreases as envs are chosen. Chosen envs displayed above with the finalMsg. -func (s *AppEnvSelector) Environments(prompt, help, app string, finalMsgFunc func(int) prompt.PromptConfig) ([]string, error) { - envs, err := s.retrieveEnvironments(app) +func (s *AppEnvSelector) Environments(ctx context.Context, prompt, help, app string, finalMsgFunc func(int) prompt.PromptConfig) ([]string, error) { + envs, err := s.retrieveEnvironments(ctx, app) if err != nil { return nil, fmt.Errorf("get environments for app %s from metadata store: %w", app, err) } @@ -1164,8 +1165,8 @@ func (s *AppEnvSelector) Environments(prompt, help, app string, finalMsgFunc fun } // Application fetches all the apps in an account/region and prompts the user to select one. -func (s *AppEnvSelector) Application(msg, help string, additionalOpts ...string) (string, error) { - appNames, err := s.retrieveApps() +func (s *AppEnvSelector) Application(ctx context.Context, msg, help string, additionalOpts ...string) (string, error) { + appNames, err := s.retrieveApps(ctx) if err != nil { return "", err } @@ -1191,8 +1192,8 @@ func (s *AppEnvSelector) Application(msg, help string, additionalOpts ...string) // Topics asks the user to select from all Copilot-managed SNS topics *which are deployed // across all environments* and returns the topic structs. -func (s *DeploySelector) Topics(promptMsg, help, app string) ([]deploy.Topic, error) { - envs, err := s.appEnvLister.ListEnvironments(app) +func (s *DeploySelector) Topics(ctx context.Context, promptMsg, help, app string) ([]deploy.Topic, error) { + envs, err := s.appEnvLister.ListEnvironments(ctx, app) if err != nil { return nil, fmt.Errorf("list environments: %w", err) } @@ -1203,7 +1204,7 @@ func (s *DeploySelector) Topics(promptMsg, help, app string) ([]deploy.Topic, er envTopics := make(map[string][]deploy.Topic, len(envs)) for _, env := range envs { - topics, err := s.deployStoreSvc.ListSNSTopics(app, env.Name) + topics, err := s.deployStoreSvc.ListSNSTopics(ctx, app, env.Name) if err != nil { return nil, fmt.Errorf("list SNS topics: %w", err) } @@ -1258,8 +1259,8 @@ func (s *DeploySelector) Topics(promptMsg, help, app string) ([]deploy.Topic, er return topics, nil } -func (s *AppEnvSelector) retrieveApps() ([]string, error) { - apps, err := s.appEnvLister.ListApplications() +func (s *AppEnvSelector) retrieveApps(ctx context.Context) ([]string, error) { + apps, err := s.appEnvLister.ListApplications(ctx) if err != nil { return nil, fmt.Errorf("list applications: %w", err) } @@ -1270,8 +1271,8 @@ func (s *AppEnvSelector) retrieveApps() ([]string, error) { return appNames, nil } -func (s *AppEnvSelector) retrieveEnvironments(app string) ([]string, error) { - envs, err := s.appEnvLister.ListEnvironments(app) +func (s *AppEnvSelector) retrieveEnvironments(ctx context.Context, app string) ([]string, error) { + envs, err := s.appEnvLister.ListEnvironments(ctx, app) if err != nil { return nil, fmt.Errorf("list environments: %w", err) } @@ -1282,8 +1283,8 @@ func (s *AppEnvSelector) retrieveEnvironments(app string) ([]string, error) { return envsNames, nil } -func (s *ConfigSelector) retrieveServices(app string) ([]string, error) { - services, err := s.workloadLister.ListServices(app) +func (s *ConfigSelector) retrieveServices(ctx context.Context, app string) ([]string, error) { + services, err := s.workloadLister.ListServices(ctx, app) if err != nil { return nil, fmt.Errorf("list services: %w", err) } @@ -1294,8 +1295,8 @@ func (s *ConfigSelector) retrieveServices(app string) ([]string, error) { return serviceNames, nil } -func (s *ConfigSelector) retrieveJobs(app string) ([]string, error) { - jobs, err := s.workloadLister.ListJobs(app) +func (s *ConfigSelector) retrieveJobs(ctx context.Context, app string) ([]string, error) { + jobs, err := s.workloadLister.ListJobs(ctx, app) if err != nil { return nil, fmt.Errorf("list jobs: %w", err) } @@ -1322,14 +1323,14 @@ func (s *LocalWorkloadSelector) retrieveWorkspaceJobs() ([]string, error) { return localJobNames, nil } -func (s *LocalWorkloadSelector) retrieveStoreWorkloads(appName, wlType string) ([]*config.Workload, error) { +func (s *LocalWorkloadSelector) retrieveStoreWorkloads(ctx context.Context, appName, wlType string) ([]*config.Workload, error) { switch wlType { case svcWorkloadType: - return s.ConfigSelector.workloadLister.ListServices(appName) + return s.ConfigSelector.workloadLister.ListServices(ctx, appName) case jobWorkloadType: - return s.ConfigSelector.workloadLister.ListJobs(appName) + return s.ConfigSelector.workloadLister.ListJobs(ctx, appName) case anyWorkloadType: - return s.ConfigSelector.workloadLister.ListWorkloads(appName) + return s.ConfigSelector.workloadLister.ListWorkloads(ctx, appName) } return nil, fmt.Errorf("unrecognized workload type %s", wlType) } diff --git a/internal/pkg/term/selector/selector_test.go b/internal/pkg/term/selector/selector_test.go index 25ff6f1b5ee..7bf7131a702 100644 --- a/internal/pkg/term/selector/selector_test.go +++ b/internal/pkg/term/selector/selector_test.go @@ -4,6 +4,7 @@ package selector import ( + "context" "errors" "fmt" "testing" @@ -22,6 +23,8 @@ import ( "github.com/stretchr/testify/require" ) +var ctx = context.Background() + type deploySelectMocks struct { deploySvc *mocks.MockdeployedWorkloadsRetriever configSvc *mocks.MockconfigLister @@ -44,24 +47,24 @@ func TestDeploySelect_Topics(t *testing.T) { }{ "return error if fail to retrieve topics from deploy": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListEnvironments(testApp).Return( + m.configSvc.EXPECT().ListEnvironments(ctx, testApp).Return( []*config.Environment{{Name: testEnv}}, nil, ) m.deploySvc. EXPECT(). - ListSNSTopics(testApp, testEnv). + ListSNSTopics(ctx, testApp, testEnv). Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("list SNS topics: some error"), }, "return error if fail to select topics": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListEnvironments(testApp).Return( + m.configSvc.EXPECT().ListEnvironments(ctx, testApp).Return( []*config.Environment{{Name: testEnv}}, nil, ) m.deploySvc. EXPECT(). - ListSNSTopics(testApp, testEnv). + ListSNSTopics(ctx, testApp, testEnv). Return([]deploy.Topic{*mockTopic}, nil) m.prompt. EXPECT(). @@ -72,16 +75,16 @@ func TestDeploySelect_Topics(t *testing.T) { }, "success": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListEnvironments(testApp).Return( + m.configSvc.EXPECT().ListEnvironments(ctx, testApp).Return( []*config.Environment{{Name: testEnv}, {Name: prodEnv}}, nil, ) m.deploySvc. EXPECT(). - ListSNSTopics(testApp, testEnv). + ListSNSTopics(ctx, testApp, testEnv). Return([]deploy.Topic{*mockTopic, *mockTopic2}, nil) m.deploySvc. EXPECT(). - ListSNSTopics(testApp, prodEnv). + ListSNSTopics(ctx, testApp, prodEnv). Return([]deploy.Topic{*mockTopic}, nil) m.prompt. EXPECT(). @@ -117,7 +120,7 @@ func TestDeploySelect_Topics(t *testing.T) { }, deployStoreSvc: mockdeploySvc, } - topics, err := sel.Topics("Select a deployed topic", "Help text", testApp) + topics, err := sel.Topics(ctx, "Select a deployed topic", "Help text", testApp) if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -214,10 +217,10 @@ func TestDeploySelect_Service(t *testing.T) { }{ "return error if fail to retrieve environment": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return(nil, errors.New("some error")) }, @@ -225,10 +228,10 @@ func TestDeploySelect_Service(t *testing.T) { }, "return error if fail to list deployed services": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -237,17 +240,17 @@ func TestDeploySelect_Service(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test"). + ListDeployedServices(ctx, testApp, "test"). Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("list deployed services for environment test: some error"), }, "return error if no deployed services found": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -256,17 +259,17 @@ func TestDeploySelect_Service(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test"). + ListDeployedServices(ctx, testApp, "test"). Return([]string{}, nil) }, wantErr: fmt.Errorf("no deployed services found in application %s", testApp), }, "return error if fail to select": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -275,7 +278,7 @@ func TestDeploySelect_Service(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test"). + ListDeployedServices(ctx, testApp, "test"). Return([]string{"mockSvc1", "mockSvc2"}, nil) m.prompt. @@ -287,7 +290,7 @@ func TestDeploySelect_Service(t *testing.T) { }, "success": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{ + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{ { App: testApp, Name: "mockSvc1", @@ -301,7 +304,7 @@ func TestDeploySelect_Service(t *testing.T) { }, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -310,7 +313,7 @@ func TestDeploySelect_Service(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test"). + ListDeployedServices(ctx, testApp, "test"). Return([]string{"mockSvc1", "mockSvc2"}, nil) m.prompt. @@ -324,7 +327,7 @@ func TestDeploySelect_Service(t *testing.T) { }, "skip with only one deployed service": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{ + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{ { App: testApp, Name: "mockSvc", @@ -333,7 +336,7 @@ func TestDeploySelect_Service(t *testing.T) { }, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -342,7 +345,7 @@ func TestDeploySelect_Service(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test"). + ListDeployedServices(ctx, testApp, "test"). Return([]string{"mockSvc"}, nil) }, wantEnv: "test", @@ -353,10 +356,10 @@ func TestDeploySelect_Service(t *testing.T) { env: "test", svc: "mockSvc", setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.deploySvc. EXPECT(). - IsServiceDeployed(testApp, "test", "mockSvc"). + IsServiceDeployed(ctx, testApp, "test", "mockSvc"). Return(false, errors.New("some error")) }, wantErr: fmt.Errorf("check if service mockSvc is deployed in environment test: some error"), @@ -365,10 +368,10 @@ func TestDeploySelect_Service(t *testing.T) { env: "test", svc: "mockSvc", setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.deploySvc. EXPECT(). - IsServiceDeployed(testApp, "test", "mockSvc"). + IsServiceDeployed(ctx, testApp, "test", "mockSvc"). Return(true, nil) }, wantEnv: "test", @@ -384,7 +387,7 @@ func TestDeploySelect_Service(t *testing.T) { setupMocks: func(m deploySelectMocks) { m.configSvc. EXPECT(). - ListWorkloads(testApp). + ListWorkloads(ctx, testApp). Return([]*config.Workload{ { App: testApp, @@ -410,7 +413,7 @@ func TestDeploySelect_Service(t *testing.T) { m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ {Name: "test1"}, {Name: "test2"}, @@ -418,12 +421,12 @@ func TestDeploySelect_Service(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test1"). + ListDeployedServices(ctx, testApp, "test1"). Return([]string{"mockSvc1", "mockSvc2", "mockSvc3"}, nil) m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test2"). + ListDeployedServices(ctx, testApp, "test2"). Return([]string{"mockSvc1", "mockSvc2", "mockSvc3"}, nil) m.prompt. @@ -444,7 +447,7 @@ func TestDeploySelect_Service(t *testing.T) { setupMocks: func(m deploySelectMocks) { m.configSvc. EXPECT(). - ListWorkloads(testApp). + ListWorkloads(ctx, testApp). Return([]*config.Workload{ { App: testApp, @@ -465,7 +468,7 @@ func TestDeploySelect_Service(t *testing.T) { m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ {Name: "test1"}, {Name: "test2"}, @@ -473,12 +476,12 @@ func TestDeploySelect_Service(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test1"). + ListDeployedServices(ctx, testApp, "test1"). Return([]string{"mockSvc1", "mockSvc2", "mockSvc3"}, nil) m.deploySvc. EXPECT(). - ListDeployedServices(testApp, "test2"). + ListDeployedServices(ctx, testApp, "test2"). Return([]string{"mockSvc1", "mockSvc2", "mockSvc3"}, nil) }, wantErr: fmt.Errorf("filter error"), @@ -512,7 +515,7 @@ func TestDeploySelect_Service(t *testing.T) { } opts := append([]GetDeployedWorkloadOpts{WithEnv(tc.env), WithName(tc.svc)}, tc.opts...) - gotDeployed, err := sel.DeployedService("Select a deployed service", "Help text", testApp, opts...) + gotDeployed, err := sel.DeployedService(ctx, "Select a deployed service", "Help text", testApp, opts...) if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -538,10 +541,10 @@ func TestDeploySelect_Job(t *testing.T) { }{ "return error if fail to retrieve environment": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return(nil, errors.New("some error")) }, @@ -549,10 +552,10 @@ func TestDeploySelect_Job(t *testing.T) { }, "return error if fail to list deployed job": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -561,17 +564,17 @@ func TestDeploySelect_Job(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test"). + ListDeployedJobs(ctx, testApp, "test"). Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("list deployed jobs for environment test: some error"), }, "return error if no deployed jobs found": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -580,17 +583,17 @@ func TestDeploySelect_Job(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test"). + ListDeployedJobs(ctx, testApp, "test"). Return([]string{}, nil) }, wantErr: fmt.Errorf("no deployed jobs found in application %s", testApp), }, "return error if fail to select": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -599,7 +602,7 @@ func TestDeploySelect_Job(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test"). + ListDeployedJobs(ctx, testApp, "test"). Return([]string{"mockJob1", "mockJob2"}, nil) m.prompt. @@ -611,10 +614,10 @@ func TestDeploySelect_Job(t *testing.T) { }, "success": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -623,7 +626,7 @@ func TestDeploySelect_Job(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test"). + ListDeployedJobs(ctx, testApp, "test"). Return([]string{"mockJob1", "mockJob2"}, nil) m.prompt. @@ -636,10 +639,10 @@ func TestDeploySelect_Job(t *testing.T) { }, "skip with only one deployed job": { setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ { Name: "test", @@ -648,7 +651,7 @@ func TestDeploySelect_Job(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test"). + ListDeployedJobs(ctx, testApp, "test"). Return([]string{"mockJob"}, nil) }, wantEnv: "test", @@ -658,10 +661,10 @@ func TestDeploySelect_Job(t *testing.T) { env: "test", job: "mockJob", setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.deploySvc. EXPECT(). - IsJobDeployed(testApp, "test", "mockJob"). + IsJobDeployed(ctx, testApp, "test", "mockJob"). Return(false, errors.New("some error")) }, wantErr: fmt.Errorf("check if job mockJob is deployed in environment test: some error"), @@ -670,10 +673,10 @@ func TestDeploySelect_Job(t *testing.T) { env: "test", job: "mockJob", setupMocks: func(m deploySelectMocks) { - m.configSvc.EXPECT().ListWorkloads(testApp).Return([]*config.Workload{}, nil) + m.configSvc.EXPECT().ListWorkloads(ctx, testApp).Return([]*config.Workload{}, nil) m.deploySvc. EXPECT(). - IsJobDeployed(testApp, "test", "mockJob"). + IsJobDeployed(ctx, testApp, "test", "mockJob"). Return(true, nil) }, wantEnv: "test", @@ -689,7 +692,7 @@ func TestDeploySelect_Job(t *testing.T) { setupMocks: func(m deploySelectMocks) { m.configSvc. EXPECT(). - ListWorkloads(testApp). + ListWorkloads(ctx, testApp). Return([]*config.Workload{ { App: testApp, @@ -715,7 +718,7 @@ func TestDeploySelect_Job(t *testing.T) { m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ {Name: "test1"}, {Name: "test2"}, @@ -723,12 +726,12 @@ func TestDeploySelect_Job(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test1"). + ListDeployedJobs(ctx, testApp, "test1"). Return([]string{"mockJob1"}, nil) m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test2"). + ListDeployedJobs(ctx, testApp, "test2"). Return([]string{"mockJob1", "mockJob2"}, nil) m.prompt. @@ -748,7 +751,7 @@ func TestDeploySelect_Job(t *testing.T) { setupMocks: func(m deploySelectMocks) { m.configSvc. EXPECT(). - ListWorkloads(testApp). + ListWorkloads(ctx, testApp). Return([]*config.Workload{ { App: testApp, @@ -769,7 +772,7 @@ func TestDeploySelect_Job(t *testing.T) { m.configSvc. EXPECT(). - ListEnvironments(testApp). + ListEnvironments(ctx, testApp). Return([]*config.Environment{ {Name: "test1"}, {Name: "test2"}, @@ -777,12 +780,12 @@ func TestDeploySelect_Job(t *testing.T) { m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test1"). + ListDeployedJobs(ctx, testApp, "test1"). Return([]string{"mockJob1", "mockJob2"}, nil) m.deploySvc. EXPECT(). - ListDeployedJobs(testApp, "test2"). + ListDeployedJobs(ctx, testApp, "test2"). Return([]string{"mockJob1", "mockJob2"}, nil) }, wantErr: fmt.Errorf("filter error"), @@ -816,7 +819,7 @@ func TestDeploySelect_Job(t *testing.T) { } opts := append([]GetDeployedWorkloadOpts{WithEnv(tc.env), WithName(tc.job)}, tc.opts...) - gotDeployed, err := sel.DeployedJob("Select a deployed job", "Help text", testApp, opts...) + gotDeployed, err := sel.DeployedJob(ctx, "Select a deployed job", "Help text", testApp, opts...) if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -848,7 +851,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{}, nil).Times(1) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Times(0) @@ -866,7 +869,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{}, nil).Times(1) }, wantErr: fmt.Errorf("no services found"), @@ -880,7 +883,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -901,7 +904,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -927,7 +930,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -951,7 +954,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -988,7 +991,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -1041,7 +1044,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( nil, errors.New("some error")) }, wantErr: errors.New("retrieve services from store: some error"), @@ -1059,7 +1062,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListServices("app-name").Return( + m.configLister.EXPECT().ListServices(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -1108,7 +1111,7 @@ func TestWorkspaceSelect_Service(t *testing.T) { ws: mockwsRetriever, onlyInitializedWorkloads: true, } - got, err := sel.Service("Select a service", "Help text") + got, err := sel.Service(ctx, "Select a service", "Help text") if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -1133,7 +1136,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( []*config.Workload{}, nil).Times(1) m.prompt. EXPECT(). @@ -1153,7 +1156,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( []*config.Workload{}, nil).Times(1) m.prompt. EXPECT(). @@ -1171,7 +1174,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -1198,7 +1201,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -1225,7 +1228,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -1249,7 +1252,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -1287,7 +1290,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { }, nil) m.configLister. EXPECT(). - ListJobs("app-name"). + ListJobs(ctx, "app-name"). Return( []*config.Workload{ { @@ -1342,7 +1345,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( nil, errors.New("some error")) }, wantErr: errors.New("retrieve jobs from store: some error"), @@ -1358,7 +1361,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { &workspace.Summary{ Application: "app-name", }, nil) - m.configLister.EXPECT().ListJobs("app-name").Return( + m.configLister.EXPECT().ListJobs(ctx, "app-name").Return( []*config.Workload{ { App: "app-name", @@ -1409,7 +1412,7 @@ func TestWorkspaceSelect_Job(t *testing.T) { ws: mockwsRetriever, onlyInitializedWorkloads: true, } - got, err := sel.Job("Select a job", "Help text") + got, err := sel.Job(ctx, "Select a job", "Help text") if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -1431,7 +1434,7 @@ func TestWorkspaceSelect_Workloads(t *testing.T) { Application: "app", }, nil) m.ws.EXPECT().ListWorkloads().Return([]string{"fe", "be", "worker"}, nil) - m.configLister.EXPECT().ListWorkloads("app").Return([]*config.Workload{ + m.configLister.EXPECT().ListWorkloads(ctx, "app").Return([]*config.Workload{ { App: "app", Name: "fe", @@ -1481,7 +1484,7 @@ func TestWorkspaceSelect_Workloads(t *testing.T) { ws: mockwsRetriever, onlyInitializedWorkloads: false, } - got, err := sel.Workloads("Select a workload", "Help text") + got, err := sel.Workloads(ctx, "Select a workload", "Help text") if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -1520,7 +1523,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv1", "mockEnv2"}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return(nil, errors.New("some error")) + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return(nil, errors.New("some error")) }, wantErr: errors.New("retrieve environments from store: some error"), }, @@ -1531,7 +1534,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv1", "mockEnv2"}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv1", @@ -1554,7 +1557,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{}, nil) + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{}, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantErr: fmt.Errorf("no environments found"), @@ -1566,7 +1569,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv"}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{}, nil) + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{}, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantErr: fmt.Errorf("no environments found"), @@ -1578,7 +1581,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv", @@ -1595,7 +1598,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv"}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv", @@ -1612,7 +1615,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv1", "mockEnv2"}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv1", @@ -1629,7 +1632,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv1"}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv1", @@ -1650,7 +1653,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { Application: "mockApp", }, nil) m.ws.EXPECT().ListEnvironments().Return([]string{"mockEnv1", "mockEnv2", "mockEnv3"}, nil).Times(1) - m.configLister.EXPECT().ListEnvironments("mockApp").Return([]*config.Environment{ + m.configLister.EXPECT().ListEnvironments(ctx, "mockApp").Return([]*config.Environment{ { App: "mockApp", Name: "mockEnv1", @@ -1691,7 +1694,7 @@ func TestWorkspaceSelect_EnvironmentsInWorkspace(t *testing.T) { }, ws: m.ws, } - got, err := sel.LocalEnvironment("Select an environment", "Help text") + got, err := sel.LocalEnvironment(ctx, "Select an environment", "Help text") if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -1719,7 +1722,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { }, nil).Times(1) m.ws.EXPECT().ListWorkloads().Return( []string{}, nil).Times(1) - m.configLister.EXPECT().ListWorkloads("app-name").Return( + m.configLister.EXPECT().ListWorkloads(ctx, "app-name").Return( []*config.Workload{}, nil).Times(1) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Times(0) @@ -1738,7 +1741,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { "service1", }, nil). Times(1) - m.configLister.EXPECT().ListWorkloads("app-name").Return( + m.configLister.EXPECT().ListWorkloads(ctx, "app-name").Return( []*config.Workload{}, nil).Times(1) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, @@ -1755,7 +1758,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { "service1", }, nil). Times(1) - m.configLister.EXPECT().ListWorkloads("app-name").Return( + m.configLister.EXPECT().ListWorkloads(ctx, "app-name").Return( []*config.Workload{ { Name: "service1", @@ -1779,7 +1782,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { "worker", }, nil). Times(1) - m.configLister.EXPECT().ListWorkloads("app-name").Return( + m.configLister.EXPECT().ListWorkloads(ctx, "app-name").Return( []*config.Workload{ { Name: "service1", @@ -1804,7 +1807,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { m.ws.EXPECT().Summary().Return( nil, errors.New("some error")).Times(1) m.ws.EXPECT().ListWorkloads().Times(0) - m.configLister.EXPECT().ListWorkloads(gomock.Any()).Times(0) + m.configLister.EXPECT().ListWorkloads(ctx, gomock.Any()).Times(0) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Times(0) }, @@ -1815,7 +1818,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { m.ws.EXPECT().Summary().Return( &workspace.Summary{Application: "my-app"}, nil).Times(1) m.ws.EXPECT().ListWorkloads().Return(nil, errors.New("some error")).Times(1) - m.configLister.EXPECT().ListWorkloads(gomock.Any()).Times(0) + m.configLister.EXPECT().ListWorkloads(ctx, gomock.Any()).Times(0) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Times(0) }, @@ -1826,7 +1829,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { m.ws.EXPECT().Summary().Return( &workspace.Summary{Application: "my-app"}, nil).Times(1) m.ws.EXPECT().ListWorkloads().Return([]string{"wkld"}, nil).Times(1) - m.configLister.EXPECT().ListWorkloads(gomock.Any()).Return(nil, errors.New("some error")). + m.configLister.EXPECT().ListWorkloads(ctx, gomock.Any()).Return(nil, errors.New("some error")). Times(1) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). Times(0) @@ -1847,7 +1850,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { "worker", }, nil). Times(1) - m.configLister.EXPECT().ListWorkloads("app-name").Return( + m.configLister.EXPECT().ListWorkloads(ctx, "app-name").Return( []*config.Workload{ { Name: "service1", @@ -1894,7 +1897,7 @@ func TestWorkspaceSelect_Workload(t *testing.T) { ws: mockwsRetriever, onlyInitializedWorkloads: tc.inOnlyInitializedWorkloads, } - got, err := sel.Workload("Select a workload", "Help text") + got, err := sel.Workload(ctx, "Select a workload", "Help text") if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -1942,7 +1945,7 @@ func TestConfigSelect_Service(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListServices(gomock.Eq(appName)). + ListServices(ctx, gomock.Eq(appName)). Return([]*config.Workload{}, nil). Times(1) m.prompt. @@ -1957,7 +1960,7 @@ func TestConfigSelect_Service(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListServices(gomock.Eq(appName)). + ListServices(ctx, gomock.Eq(appName)). Return([]*config.Workload{ { App: appName, @@ -1978,7 +1981,7 @@ func TestConfigSelect_Service(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListServices(gomock.Eq(appName)). + ListServices(ctx, gomock.Eq(appName)). Return([]*config.Workload{ { App: appName, @@ -2008,7 +2011,7 @@ func TestConfigSelect_Service(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListServices(gomock.Eq(appName)). + ListServices(ctx, gomock.Eq(appName)). Return([]*config.Workload{ { App: appName, @@ -2052,7 +2055,7 @@ func TestConfigSelect_Service(t *testing.T) { workloadLister: mockconfigLister, } - got, err := sel.Service("Select a service", "Help text", appName) + got, err := sel.Service(ctx, "Select a service", "Help text", appName) if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -2073,7 +2076,7 @@ func TestConfigSelect_Job(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListJobs(gomock.Eq(appName)). + ListJobs(ctx, gomock.Eq(appName)). Return([]*config.Workload{}, nil). Times(1) m.prompt. @@ -2088,7 +2091,7 @@ func TestConfigSelect_Job(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListJobs(gomock.Eq(appName)). + ListJobs(ctx, gomock.Eq(appName)). Return([]*config.Workload{ { App: appName, @@ -2109,7 +2112,7 @@ func TestConfigSelect_Job(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListJobs(gomock.Eq(appName)). + ListJobs(ctx, gomock.Eq(appName)). Return([]*config.Workload{ { App: appName, @@ -2139,7 +2142,7 @@ func TestConfigSelect_Job(t *testing.T) { setupMocks: func(m configSelectMocks) { m.workloadLister. EXPECT(). - ListJobs(gomock.Eq(appName)). + ListJobs(ctx, gomock.Eq(appName)). Return([]*config.Workload{ { App: appName, @@ -2183,7 +2186,7 @@ func TestConfigSelect_Job(t *testing.T) { workloadLister: mockconfigLister, } - got, err := sel.Job("Select a job", "Help text", appName) + got, err := sel.Job(ctx, "Select a job", "Help text", appName) if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -2202,29 +2205,29 @@ func TestConfigSelect_Workload(t *testing.T) { }{ "with no workloads": { setupMocks: func(m configSelectMocks) { - m.workloadLister.EXPECT().ListServices(gomock.Eq(appName)).Return([]*config.Workload{}, nil) - m.workloadLister.EXPECT().ListJobs(gomock.Eq(appName)).Return([]*config.Workload{}, nil) + m.workloadLister.EXPECT().ListServices(ctx, gomock.Eq(appName)).Return([]*config.Workload{}, nil) + m.workloadLister.EXPECT().ListJobs(ctx, gomock.Eq(appName)).Return([]*config.Workload{}, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, wantErr: fmt.Errorf("no workloads found in app myapp"), }, "with only one service (skips prompting)": { setupMocks: func(m configSelectMocks) { - m.workloadLister.EXPECT().ListServices(gomock.Eq(appName)).Return([]*config.Workload{ + m.workloadLister.EXPECT().ListServices(ctx, gomock.Eq(appName)).Return([]*config.Workload{ { App: appName, Name: "service1", Type: "load balanced web service", }, }, nil) - m.workloadLister.EXPECT().ListJobs(gomock.Eq(appName)).Return([]*config.Workload{}, nil) + m.workloadLister.EXPECT().ListJobs(ctx, gomock.Eq(appName)).Return([]*config.Workload{}, nil) m.prompt.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, want: "service1", }, "with multiple workloads": { setupMocks: func(m configSelectMocks) { - m.workloadLister.EXPECT().ListServices(gomock.Eq(appName)).Return([]*config.Workload{ + m.workloadLister.EXPECT().ListServices(ctx, gomock.Eq(appName)).Return([]*config.Workload{ { App: appName, Name: "service1", @@ -2236,7 +2239,7 @@ func TestConfigSelect_Workload(t *testing.T) { Type: "backend service", }, }, nil) - m.workloadLister.EXPECT().ListJobs(gomock.Eq(appName)).Return([]*config.Workload{ + m.workloadLister.EXPECT().ListJobs(ctx, gomock.Eq(appName)).Return([]*config.Workload{ { App: appName, Name: "job1", @@ -2249,7 +2252,7 @@ func TestConfigSelect_Workload(t *testing.T) { }, "with error selecting services": { setupMocks: func(m configSelectMocks) { - m.workloadLister.EXPECT().ListServices(gomock.Eq(appName)).Return([]*config.Workload{ + m.workloadLister.EXPECT().ListServices(ctx, gomock.Eq(appName)).Return([]*config.Workload{ { App: appName, Name: "service1", @@ -2261,7 +2264,7 @@ func TestConfigSelect_Workload(t *testing.T) { Type: "backend service", }, }, nil) - m.workloadLister.EXPECT().ListJobs(gomock.Eq(appName)).Return([]*config.Workload{ + m.workloadLister.EXPECT().ListJobs(ctx, gomock.Eq(appName)).Return([]*config.Workload{ { App: appName, Name: "job1", @@ -2294,7 +2297,7 @@ func TestConfigSelect_Workload(t *testing.T) { workloadLister: mockconfigLister, } - got, err := sel.Workload("Select a service", "Help text", appName) + got, err := sel.Workload(ctx, "Select a service", "Help text", appName) if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -2324,7 +2327,7 @@ func TestSelect_Environment(t *testing.T) { setupMocks: func(m environmentMocks) { m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{}, nil). Times(1) m.prompt. @@ -2339,7 +2342,7 @@ func TestSelect_Environment(t *testing.T) { setupMocks: func(m environmentMocks) { m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{ { App: appName, @@ -2359,7 +2362,7 @@ func TestSelect_Environment(t *testing.T) { setupMocks: func(m environmentMocks) { m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{ { App: appName, @@ -2387,7 +2390,7 @@ func TestSelect_Environment(t *testing.T) { setupMocks: func(m environmentMocks) { m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{ { App: appName, @@ -2412,7 +2415,7 @@ func TestSelect_Environment(t *testing.T) { setupMocks: func(m environmentMocks) { m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{}, nil). Times(1) m.prompt. @@ -2428,7 +2431,7 @@ func TestSelect_Environment(t *testing.T) { setupMocks: func(m environmentMocks) { m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{}, nil). Times(1) m.prompt. @@ -2460,7 +2463,7 @@ func TestSelect_Environment(t *testing.T) { appEnvLister: mockenvLister, } - got, err := sel.Environment("Select an environment", "Help text", appName, tc.inAdditionalOpts...) + got, err := sel.Environment(ctx, "Select an environment", "Help text", appName, tc.inAdditionalOpts...) if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { @@ -2484,7 +2487,7 @@ func TestSelect_Environments(t *testing.T) { gomock.InOrder( m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{}, nil). Times(1), m.prompt. @@ -2500,7 +2503,7 @@ func TestSelect_Environments(t *testing.T) { gomock.InOrder( m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{ { App: appName, @@ -2522,7 +2525,7 @@ func TestSelect_Environments(t *testing.T) { gomock.InOrder( m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{ { App: appName, @@ -2574,7 +2577,7 @@ func TestSelect_Environments(t *testing.T) { gomock.InOrder( m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{ { App: appName, @@ -2626,7 +2629,7 @@ func TestSelect_Environments(t *testing.T) { gomock.InOrder( m.envLister. EXPECT(). - ListEnvironments(gomock.Eq(appName)). + ListEnvironments(ctx, gomock.Eq(appName)). Return([]*config.Environment{ { App: appName, @@ -2667,7 +2670,7 @@ func TestSelect_Environments(t *testing.T) { appEnvLister: mockenvLister, } - got, err := sel.Environments("Select an environment", "Help text", appName, func(order int) prompt.PromptConfig { + got, err := sel.Environments(ctx, "Select an environment", "Help text", appName, func(order int) prompt.PromptConfig { return prompt.WithFinalMessage(fmt.Sprintf("%s stage:", humanize.Ordinal(order))) }) if tc.wantErr != nil { @@ -2694,7 +2697,7 @@ func TestSelect_Application(t *testing.T) { setupMocks: func(m applicationMocks) { m.appLister. EXPECT(). - ListApplications(). + ListApplications(ctx). Return([]*config.Application{}, nil). Times(1) m.prompt. @@ -2709,7 +2712,7 @@ func TestSelect_Application(t *testing.T) { setupMocks: func(m applicationMocks) { m.appLister. EXPECT(). - ListApplications(). + ListApplications(ctx). Return([]*config.Application{ { Name: "app1", @@ -2728,7 +2731,7 @@ func TestSelect_Application(t *testing.T) { setupMocks: func(m applicationMocks) { m.appLister. EXPECT(). - ListApplications(). + ListApplications(ctx). Return([]*config.Application{ { Name: "app1", @@ -2754,7 +2757,7 @@ func TestSelect_Application(t *testing.T) { setupMocks: func(m applicationMocks) { m.appLister. EXPECT(). - ListApplications(). + ListApplications(ctx). Return([]*config.Application{ { Name: "app1", @@ -2792,7 +2795,7 @@ func TestSelect_Application(t *testing.T) { appEnvLister: mockappLister, } - got, err := sel.Application("Select an app", "Help text") + got, err := sel.Application(ctx, "Select an app", "Help text") if tc.wantErr != nil { require.EqualError(t, err, tc.wantErr.Error()) } else { diff --git a/scripts/license.sh b/scripts/license.sh index a3107b6905f..f3398a00440 100755 --- a/scripts/license.sh +++ b/scripts/license.sh @@ -36,6 +36,9 @@ while IFS= read -r -d '' file; do $rootdir/*/node_modules/*) # Skip node modules for js files. ;; + $rootdir/*/coverage/*) + # Skip generated coverage reports. + ;; $rootdir/site/*) # Skip website content ;;