diff --git a/.changelog/32207.txt b/.changelog/32207.txt new file mode 100644 index 00000000000..e0573a13f09 --- /dev/null +++ b/.changelog/32207.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_codecommit_repository: Doesn't force replacement when renaming +``` \ No newline at end of file diff --git a/internal/service/codecommit/repository.go b/internal/service/codecommit/repository.go index fce802bca87..e417f6d172a 100644 --- a/internal/service/codecommit/repository.go +++ b/internal/service/codecommit/repository.go @@ -38,7 +38,6 @@ func ResourceRepository() *schema.Resource { "repository_name": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(0, 100), }, @@ -137,7 +136,11 @@ func resourceRepositoryRead(ctx context.Context, d *schema.ResourceData, meta in d.Set("repository_name", out.RepositoryMetadata.RepositoryName) if _, ok := d.GetOk("default_branch"); ok { - d.Set("default_branch", out.RepositoryMetadata.DefaultBranch) + // The default branch can only be set when there is code in the repository + // Preserve the configured value + if out.RepositoryMetadata.DefaultBranch != nil { // nosemgrep:ci.helper-schema-ResourceData-Set-extraneous-nil-check + d.Set("default_branch", out.RepositoryMetadata.DefaultBranch) + } } return diags @@ -147,6 +150,12 @@ func resourceRepositoryUpdate(ctx context.Context, d *schema.ResourceData, meta var diags diag.Diagnostics conn := meta.(*conns.AWSClient).CodeCommitConn(ctx) + if d.HasChange("repository_name") { + if err := resourceUpdateRepositoryName(ctx, conn, d); err != nil { + return sdkdiag.AppendErrorf(diags, "updating CodeCommit Repository (%s) name: %s", d.Id(), err) + } + } + if d.HasChange("default_branch") { if err := resourceUpdateDefaultBranch(ctx, conn, d); err != nil { return sdkdiag.AppendErrorf(diags, "updating CodeCommit Repository (%s) default branch: %s", d.Id(), err) @@ -177,6 +186,25 @@ func resourceRepositoryDelete(ctx context.Context, d *schema.ResourceData, meta return diags } +func resourceUpdateRepositoryName(ctx context.Context, conn *codecommit.CodeCommit, d *schema.ResourceData) error { + newName := d.Get("repository_name").(string) + + branchInput := &codecommit.UpdateRepositoryNameInput{ + OldName: aws.String(d.Id()), + NewName: aws.String(newName), + } + + _, err := conn.UpdateRepositoryNameWithContext(ctx, branchInput) + if err != nil { + return fmt.Errorf("Updating Repository Name for CodeCommit Repository: %s", err.Error()) + } + + // The Id is the name + d.SetId(newName) + + return nil +} + func resourceUpdateDescription(ctx context.Context, conn *codecommit.CodeCommit, d *schema.ResourceData) error { branchInput := &codecommit.UpdateRepositoryDescriptionInput{ RepositoryName: aws.String(d.Id()), @@ -211,8 +239,7 @@ func resourceUpdateDefaultBranch(ctx context.Context, conn *codecommit.CodeCommi DefaultBranchName: aws.String(d.Get("default_branch").(string)), } - _, err = conn.UpdateDefaultBranchWithContext(ctx, branchInput) - if err != nil { + if _, err := conn.UpdateDefaultBranchWithContext(ctx, branchInput); err != nil { return fmt.Errorf("Updating Default Branch for CodeCommit Repository: %s", err.Error()) } diff --git a/internal/service/codecommit/repository_test.go b/internal/service/codecommit/repository_test.go index 1195f852909..1623b01855a 100644 --- a/internal/service/codecommit/repository_test.go +++ b/internal/service/codecommit/repository_test.go @@ -20,8 +20,9 @@ import ( func TestAccCodeCommitRepository_basic(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_codecommit_repository.test" + var v codecommit.RepositoryMetadata resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -30,9 +31,17 @@ func TestAccCodeCommitRepository_basic(t *testing.T) { CheckDestroy: testAccCheckRepositoryDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRepositoryConfig_basic(rInt), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, "aws_codecommit_repository.test"), + Config: testAccRepositoryConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "repository_name", rName), + resource.TestCheckNoResourceAttr(resourceName, "default_branch"), + resource.TestCheckResourceAttr(resourceName, "description", "This is a test description"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "codecommit", rName), + resource.TestCheckResourceAttrSet(resourceName, "repository_id"), + resource.TestCheckResourceAttrSet(resourceName, "clone_url_http"), + resource.TestCheckResourceAttrSet(resourceName, "clone_url_ssh"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -46,8 +55,10 @@ func TestAccCodeCommitRepository_basic(t *testing.T) { func TestAccCodeCommitRepository_withChanges(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_codecommit_repository.test" + var v1, v2 codecommit.RepositoryMetadata resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -56,11 +67,19 @@ func TestAccCodeCommitRepository_withChanges(t *testing.T) { CheckDestroy: testAccCheckRepositoryDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRepositoryConfig_basic(rInt), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, "aws_codecommit_repository.test"), - resource.TestCheckResourceAttr( - "aws_codecommit_repository.test", "description", "This is a test description"), + Config: testAccRepositoryConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "description", "This is a test description"), + ), + }, + { + Config: testAccRepositoryConfig_changes(rNameUpdated), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v2), + testAccCheckRepositoryNotRecreated(&v1, &v2), + resource.TestCheckResourceAttr(resourceName, "description", "This is a test description - with changes"), + resource.TestCheckResourceAttr(resourceName, "repository_name", rNameUpdated), ), }, { @@ -68,22 +87,15 @@ func TestAccCodeCommitRepository_withChanges(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - { - Config: testAccRepositoryConfig_changes(rInt), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, "aws_codecommit_repository.test"), - resource.TestCheckResourceAttr( - "aws_codecommit_repository.test", "description", "This is a test description - with changes"), - ), - }, }, }) } func TestAccCodeCommitRepository_CreateDefault_branch(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_codecommit_repository.test" + var v codecommit.RepositoryMetadata resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -92,11 +104,10 @@ func TestAccCodeCommitRepository_CreateDefault_branch(t *testing.T) { CheckDestroy: testAccCheckRepositoryDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRepositoryConfig_defaultBranch(rInt), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, "aws_codecommit_repository.test"), - resource.TestCheckResourceAttr( - "aws_codecommit_repository.test", "default_branch", "master"), + Config: testAccRepositoryConfig_defaultBranch(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "default_branch", "main"), ), }, { @@ -111,8 +122,9 @@ func TestAccCodeCommitRepository_CreateDefault_branch(t *testing.T) { func TestAccCodeCommitRepository_CreateAndUpdateDefault_branch(t *testing.T) { ctx := acctest.Context(t) - rInt := sdkacctest.RandInt() + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_codecommit_repository.test" + var v1, v2 codecommit.RepositoryMetadata resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -121,25 +133,24 @@ func TestAccCodeCommitRepository_CreateAndUpdateDefault_branch(t *testing.T) { CheckDestroy: testAccCheckRepositoryDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRepositoryConfig_basic(rInt), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, "aws_codecommit_repository.test"), - resource.TestCheckNoResourceAttr( - "aws_codecommit_repository.test", "default_branch"), + Config: testAccRepositoryConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v1), + resource.TestCheckNoResourceAttr(resourceName, "default_branch"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + Config: testAccRepositoryConfig_defaultBranch(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, "default_branch", "main"), + ), }, { - Config: testAccRepositoryConfig_defaultBranch(rInt), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, "aws_codecommit_repository.test"), - resource.TestCheckResourceAttr( - "aws_codecommit_repository.test", "default_branch", "master"), - ), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"default_branch"}, }, }, }) @@ -149,6 +160,7 @@ func TestAccCodeCommitRepository_tags(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandString(10) resourceName := "aws_codecommit_repository.test" + var v1, v2, v3 codecommit.RepositoryMetadata resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -158,8 +170,8 @@ func TestAccCodeCommitRepository_tags(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRepositoryConfig_tags1(rName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, resourceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v1), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), @@ -171,26 +183,82 @@ func TestAccCodeCommitRepository_tags(t *testing.T) { }, { Config: testAccRepositoryConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, resourceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v2), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccRepositoryConfig_tags1(rName, "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckRepositoryExists(ctx, resourceName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v3), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } -func testAccCheckRepositoryExists(ctx context.Context, name string) resource.TestCheckFunc { +func TestAccCodeCommitRepository_UpdateNameAndTags(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_codecommit_repository.test" + var v1, v2 codecommit.RepositoryMetadata + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, codecommit.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRepositoryDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRepositoryConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "repository_name", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRepositoryConfig_tags2(rNameUpdated, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRepositoryExists(ctx, resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, "repository_name", rNameUpdated), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckRepositoryExists(ctx context.Context, name string, v *codecommit.RepositoryMetadata) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] if !ok { @@ -219,6 +287,8 @@ func testAccCheckRepositoryExists(ctx context.Context, name string) resource.Tes *out.RepositoryMetadata.RepositoryName, rs.Primary.ID) } + *v = *out.RepositoryMetadata + return nil } } @@ -250,55 +320,64 @@ func testAccCheckRepositoryDestroy(ctx context.Context) resource.TestCheckFunc { } } -func testAccRepositoryConfig_basic(rInt int) string { +func testAccCheckRepositoryNotRecreated(v1, v2 *codecommit.RepositoryMetadata) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.StringValue(v1.RepositoryId) != aws.StringValue(v2.RepositoryId) { + return fmt.Errorf("CodeCommit Repository recreated") + } + return nil + } +} + +func testAccRepositoryConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_codecommit_repository" "test" { - repository_name = "test_repository_%d" + repository_name = %[1]q description = "This is a test description" } -`, rInt) +`, rName) } -func testAccRepositoryConfig_changes(rInt int) string { +func testAccRepositoryConfig_changes(rName string) string { return fmt.Sprintf(` resource "aws_codecommit_repository" "test" { - repository_name = "test_repository_%d" + repository_name = %[1]q description = "This is a test description - with changes" } -`, rInt) +`, rName) } -func testAccRepositoryConfig_defaultBranch(rInt int) string { +func testAccRepositoryConfig_defaultBranch(rName string) string { return fmt.Sprintf(` resource "aws_codecommit_repository" "test" { - repository_name = "test_repository_%d" + repository_name = %[1]q description = "This is a test description" - default_branch = "master" + default_branch = "main" } -`, rInt) +`, rName) } -func testAccRepositoryConfig_tags1(r, tag1Key, tag1Value string) string { +func testAccRepositoryConfig_tags1(rName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_codecommit_repository" "test" { - repository_name = "terraform-test-%s" + repository_name = %[1]q tags = { - %q = %q + %[2]q = %[3]q } } -`, r, tag1Key, tag1Value) +`, rName, tag1Key, tag1Value) } -func testAccRepositoryConfig_tags2(r, tag1Key, tag1Value, tag2Key, tag2Value string) string { +func testAccRepositoryConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_codecommit_repository" "test" { - repository_name = "terraform-test-%s" + repository_name = %[1]q tags = { - %q = %q - %q = %q + %[2]q = %[3]q + %[4]q = %[5]q } } -`, r, tag1Key, tag1Value, tag2Key, tag2Value) +`, rName, tag1Key, tag1Value, tag2Key, tag2Value) }