From 5389c211747de0b8cd7e74a92717093801930cfd Mon Sep 17 00:00:00 2001 From: KirtiRamchandani Date: Sun, 31 May 2026 23:00:42 +0530 Subject: [PATCH] feat(env deploy): support resource tags --- internal/pkg/cli/deploy/env.go | 4 +- internal/pkg/cli/deploy/env_test.go | 41 ++++++++++++++++++--- internal/pkg/cli/env_deploy.go | 7 +++- internal/pkg/cli/env_deploy_test.go | 10 +++++ site/content/docs/commands/env-deploy.en.md | 33 ++++++++++------- site/content/docs/commands/env-deploy.ja.md | 33 ++++++++++------- 6 files changed, 95 insertions(+), 33 deletions(-) diff --git a/internal/pkg/cli/deploy/env.go b/internal/pkg/cli/deploy/env.go index d9239d81f68..4e30456b71d 100644 --- a/internal/pkg/cli/deploy/env.go +++ b/internal/pkg/cli/deploy/env.go @@ -22,6 +22,7 @@ import ( "github.com/aws/copilot-cli/internal/pkg/aws/partitions" awss3 "github.com/aws/copilot-cli/internal/pkg/aws/s3" "github.com/aws/copilot-cli/internal/pkg/aws/sessions" + "github.com/aws/copilot-cli/internal/pkg/aws/tags" "github.com/aws/copilot-cli/internal/pkg/cli/deploy/patch" "github.com/aws/copilot-cli/internal/pkg/config" "github.com/aws/copilot-cli/internal/pkg/deploy" @@ -262,6 +263,7 @@ type DeployEnvironmentInput struct { DisableRollback bool Version string Detach bool + Tags map[string]string } // GenerateCloudFormationTemplate returns the environment stack's template and parameter configuration. @@ -405,7 +407,7 @@ func (d *envDeployer) buildStackInput(in *DeployEnvironmentInput) (*cfnstack.Env Domain: d.app.Domain, AccountPrincipalARN: in.RootUserARN, }, - AdditionalTags: d.app.Tags, + AdditionalTags: tags.Merge(d.app.Tags, in.Tags), Addons: addons, CustomResourcesURLs: in.CustomResourcesURLs, ArtifactBucketARN: awss3.FormatARN(partition.ID(), resources.S3Bucket), diff --git a/internal/pkg/cli/deploy/env_test.go b/internal/pkg/cli/deploy/env_test.go index ea656a6d416..da8fbae94e6 100644 --- a/internal/pkg/cli/deploy/env_test.go +++ b/internal/pkg/cli/deploy/env_test.go @@ -573,12 +573,18 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) { ) mockApp := &config.Application{ Name: mockAppName, + Tags: map[string]string{ + "team": "copilot", + "environment": "default", + }, } testCases := map[string]struct { - setUpMocks func(m *envDeployerMocks) - inManifest *manifest.Environment - inDisableRollback bool - wantedError error + setUpMocks func(m *envDeployerMocks) + inManifest *manifest.Environment + inDisableRollback bool + inTags map[string]string + wantedAdditionalTags map[string]string + wantedError error }{ "fail to get app resources by region": { setUpMocks: func(m *envDeployerMocks) { @@ -670,6 +676,27 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) { m.envDeployer.EXPECT().UpdateAndRenderEnvironment(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) }, }, + "successful environment deployment with additional tags": { + inTags: map[string]string{ + "environment": "test", + "owner": "platform", + }, + wantedAdditionalTags: map[string]string{ + "team": "copilot", + "environment": "test", + "owner": "platform", + }, + setUpMocks: func(m *envDeployerMocks) { + m.appCFN.EXPECT().GetAppResourcesByRegion(mockApp, mockEnvRegion).Return(&cfnstack.AppRegionalResources{ + S3Bucket: "mockS3Bucket", + }, nil) + m.prefixListGetter.EXPECT().CloudFrontManagedPrefixListID().Return("mockPrefixListID", nil).Times(0) + m.parseAddons = func() (stackBuilder, error) { return nil, &addon.ErrAddonsNotFound{} } + m.envDeployer.EXPECT().DeployedEnvironmentParameters(gomock.Any(), gomock.Any()).Return(nil, nil) + m.envDeployer.EXPECT().ForceUpdateOutputID(gomock.Any(), gomock.Any()).Return("", nil) + m.envDeployer.EXPECT().UpdateAndRenderEnvironment(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + }, + }, "successful environment deployment, no rollback": { inDisableRollback: true, setUpMocks: func(m *envDeployerMocks) { @@ -707,7 +734,10 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) { envDeployer: m.envDeployer, prefixListGetter: m.prefixListGetter, parseAddons: m.parseAddons, - newStack: func(_ *cfnstack.EnvConfig, _ string, _ []*awscfn.Parameter) (cloudformation.StackConfiguration, error) { + newStack: func(in *cfnstack.EnvConfig, _ string, _ []*awscfn.Parameter) (cloudformation.StackConfiguration, error) { + if tc.wantedAdditionalTags != nil { + require.Equal(t, tc.wantedAdditionalTags, in.AdditionalTags) + } return m.stackSerializer, nil }, } @@ -718,6 +748,7 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) { }, Manifest: tc.inManifest, DisableRollback: tc.inDisableRollback, + Tags: tc.inTags, } gotErr := d.DeployEnvironment(mockIn) if tc.wantedError != nil { diff --git a/internal/pkg/cli/env_deploy.go b/internal/pkg/cli/env_deploy.go index ddd7cd2c46a..11bd5825df2 100644 --- a/internal/pkg/cli/env_deploy.go +++ b/internal/pkg/cli/env_deploy.go @@ -42,6 +42,7 @@ type deployEnvVars struct { skipDiffPrompt bool allowEnvDowngrade bool detach bool + resourceTags map[string]string } type deployEnvOpts struct { @@ -211,6 +212,7 @@ func (o *deployEnvOpts) Execute() error { DisableRollback: o.disableRollback, Version: o.templateVersion, Detach: o.detach, + Tags: o.resourceTags, } if o.showDiff { contd, err := o.showDiffAndConfirmDeployment(deployer, deployInput) @@ -385,7 +387,9 @@ func buildEnvDeployCmd() *cobra.Command { Long: "Deploys an environment to an application.", Example: ` Deploy an environment named "test". -/code $copilot env deploy --name test`, +/code $ copilot env deploy --name test +Deploy an environment with additional resource tags. +/code $ copilot env deploy --resource-tags source/revision=bb133e7,deployment/initiator=manual`, RunE: runCmdE(func(cmd *cobra.Command, args []string) error { opts, err := newEnvDeployOpts(vars) if err != nil { @@ -402,5 +406,6 @@ Deploy an environment named "test". cmd.Flags().BoolVar(&vars.skipDiffPrompt, diffAutoApproveFlag, false, diffAutoApproveFlagDescription) cmd.Flags().BoolVar(&vars.allowEnvDowngrade, allowDowngradeFlag, false, allowDowngradeFlagDescription) cmd.Flags().BoolVar(&vars.detach, detachFlag, false, detachFlagDescription) + cmd.Flags().StringToStringVar(&vars.resourceTags, resourceTagsFlag, nil, resourceTagsFlagDescription) return cmd } diff --git a/internal/pkg/cli/env_deploy_test.go b/internal/pkg/cli/env_deploy_test.go index 17596da9970..83c54d34501 100644 --- a/internal/pkg/cli/env_deploy_test.go +++ b/internal/pkg/cli/env_deploy_test.go @@ -159,6 +159,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { inShowDiff bool inSkipDiffPrompt bool inAllowDowngrade bool + inResourceTags map[string]string unmarshalManifest func(in []byte) (*manifest.Environment, error) setUpMocks func(m *deployEnvExecuteMocks) wantedDiff string @@ -385,6 +386,10 @@ func TestDeployEnvOpts_Execute(t *testing.T) { wantedErr: errors.New("deploy environment mockEnv: some error"), }, "success": { + inResourceTags: map[string]string{ + "environment": "test", + "owner": "platform", + }, setUpMocks: func(m *deployEnvExecuteMocks) { m.envVersionGetter.EXPECT().Version().Return(version.EnvTemplateBootstrap, nil) m.ws.EXPECT().ReadEnvironmentManifest("mockEnv").Return([]byte("name: mockEnv\ntype: Environment\n"), nil) @@ -405,6 +410,10 @@ func TestDeployEnvOpts_Execute(t *testing.T) { require.Equal(t, in.CustomResourcesURLs, map[string]string{ "mockResource": "mockURL", }) + require.Equal(t, map[string]string{ + "environment": "test", + "owner": "platform", + }, in.Tags) require.Equal(t, in.Manifest, &manifest.Environment{ Workload: manifest.Workload{ Name: aws.String("mockEnv"), @@ -435,6 +444,7 @@ func TestDeployEnvOpts_Execute(t *testing.T) { showDiff: tc.inShowDiff, skipDiffPrompt: tc.inSkipDiffPrompt, allowEnvDowngrade: tc.inAllowDowngrade, + resourceTags: tc.inResourceTags, }, ws: m.ws, identity: m.identity, diff --git a/site/content/docs/commands/env-deploy.en.md b/site/content/docs/commands/env-deploy.en.md index 3f235bf642f..c68f285ba60 100644 --- a/site/content/docs/commands/env-deploy.en.md +++ b/site/content/docs/commands/env-deploy.en.md @@ -10,22 +10,29 @@ $ copilot env deploy ## What are the flags? ``` - --allow-downgrade Optional. Allow using an older version of Copilot to update Copilot components - updated by a newer version of Copilot. - -a, --app string Name of the application. - --detach Optional. Skip displaying CloudFormation deployment progress. - --diff Compares the generated CloudFormation template to the deployed stack. - --diff-yes Skip interactive approval of diff before deploying. - --force Optional. Force update the environment stack template. - -h, --help help for deploy - -n, --name string Name of the environment. - --no-rollback Optional. Disable automatic stack - rollback in case of deployment failure. - We do not recommend using this flag for a - production environment. + --allow-downgrade Optional. Allow using an older version of Copilot to update Copilot components + updated by a newer version of Copilot. + -a, --app string Name of the application. + --detach Optional. Skip displaying CloudFormation deployment progress. + --diff Compares the generated CloudFormation template to the deployed stack. + --diff-yes Skip interactive approval of diff before deploying. + --force Optional. Force update the environment stack template. + -h, --help help for deploy + -n, --name string Name of the environment. + --no-rollback Optional. Disable automatic stack + rollback in case of deployment failure. + We do not recommend using this flag for a + production environment. + --resource-tags stringToString Optional. Labels with a key and value separated by commas. + Allows you to categorize resources. (default []) ``` ## Examples +Deploy an environment with additional resource tags. +```console +$ copilot env deploy --resource-tags source/revision=bb133e7,deployment/initiator=manual +``` + Use `--diff` to see what will be changed before making a deployment. ```console diff --git a/site/content/docs/commands/env-deploy.ja.md b/site/content/docs/commands/env-deploy.ja.md index e3c27646d7b..fde01b1cebc 100644 --- a/site/content/docs/commands/env-deploy.ja.md +++ b/site/content/docs/commands/env-deploy.ja.md @@ -10,22 +10,29 @@ $ copilot env deploy ## フラグ ``` - --allow-downgrade Optional. Allow using an older version of Copilot to update Copilot components - updated by a newer version of Copilot. - -a, --app string Name of the application. - --detach Optional. Skip displaying CloudFormation deployment progress. - --diff Compares the generated CloudFormation template to the deployed stack. - --diff-yes Skip interactive approval of diff before deploying. - --force Optional. Force update the environment stack template. - -h, --help help for deploy - -n, --name string Name of the environment. - --no-rollback Optional. Disable automatic stack - rollback in case of deployment failure. - We do not recommend using this flag for a - production environment. + --allow-downgrade Optional. Allow using an older version of Copilot to update Copilot components + updated by a newer version of Copilot. + -a, --app string Name of the application. + --detach Optional. Skip displaying CloudFormation deployment progress. + --diff Compares the generated CloudFormation template to the deployed stack. + --diff-yes Skip interactive approval of diff before deploying. + --force Optional. Force update the environment stack template. + -h, --help help for deploy + -n, --name string Name of the environment. + --no-rollback Optional. Disable automatic stack + rollback in case of deployment failure. + We do not recommend using this flag for a + production environment. + --resource-tags stringToString Optional. Labels with a key and value separated by commas. + Allows you to categorize resources. (default []) ``` ## 実行例 +追加のリソースタグを付けて Environment をデプロイします。 +```console +$ copilot env deploy --resource-tags source/revision=bb133e7,deployment/initiator=manual +``` + デプロイを実行する前に、変更される内容を確認するために、`--diff` を使用します。 ```console