diff --git a/cloudsmith/resource_repository_retention_rule.go b/cloudsmith/resource_repository_retention_rule.go index f9fc099..4471aa5 100644 --- a/cloudsmith/resource_repository_retention_rule.go +++ b/cloudsmith/resource_repository_retention_rule.go @@ -27,27 +27,28 @@ func resourceRepoRetentionRuleUpdate(d *schema.ResourceData, meta interface{}) e repo := requiredString(d, "repository") req := pc.APIClient.ReposApi.RepoRetentionPartialUpdate(pc.Auth, namespace, repo) + + // For integer fields with defaults, we need to always send the value to handle + // the case where users explicitly set them to 0 (which would otherwise be + // indistinguishable from "not set" using GetOk) + retentionCountLimit := int64(d.Get("retention_count_limit").(int)) + retentionDaysLimit := int64(d.Get("retention_days_limit").(int)) + updateData := cloudsmith.RepositoryRetentionRulesRequestPatch{ RetentionEnabled: optionalBool(d, "retention_enabled"), RetentionGroupByName: optionalBool(d, "retention_group_by_name"), RetentionGroupByFormat: optionalBool(d, "retention_group_by_format"), RetentionGroupByPackageType: optionalBool(d, "retention_group_by_package_type"), RetentionPackageQueryString: nullableString(d, "retention_package_query_string"), + RetentionCountLimit: &retentionCountLimit, + RetentionDaysLimit: &retentionDaysLimit, } - // Explicitly set these values, even if they're zero - if d.HasChange("retention_count_limit") { - value := int64(d.Get("retention_count_limit").(int)) - updateData.RetentionCountLimit = &value - } - if d.HasChange("retention_days_limit") { - value := int64(d.Get("retention_days_limit").(int)) - updateData.RetentionDaysLimit = &value - } - if d.HasChange("retention_size_limit") { - value := int64(d.Get("retention_size_limit").(int)) - updateData.RetentionSizeLimit = &value - } + // For retention_size_limit, we need to always send the value to handle + // the case where users explicitly set it to 0 (which would otherwise be + // indistinguishable from "not set" using GetOk) + retentionSizeLimit := int64(d.Get("retention_size_limit").(int)) + updateData.RetentionSizeLimit = &retentionSizeLimit req = req.Data(updateData) diff --git a/cloudsmith/resource_repository_retention_rule_test.go b/cloudsmith/resource_repository_retention_rule_test.go index ee4721e..9a3bad4 100644 --- a/cloudsmith/resource_repository_retention_rule_test.go +++ b/cloudsmith/resource_repository_retention_rule_test.go @@ -7,8 +7,27 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) +// testCheckResourceAttrWithMessage enhances output for attribute checks +func testCheckResourceAttrWithMessage(resourceName, attrName, expected string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + actual, ok := rs.Primary.Attributes[attrName] + if !ok { + return fmt.Errorf("Attribute '%s' not found in resource '%s'. State: %#v", attrName, resourceName, rs.Primary.Attributes) + } + if actual != expected { + return fmt.Errorf("Attribute '%s' in resource '%s' expected '%s', got '%s'. Full state: %#v", attrName, resourceName, expected, actual, rs.Primary.Attributes) + } + return nil + } +} + func TestAccRepositoryRetentionRule_basic(t *testing.T) { t.Parallel() @@ -26,14 +45,23 @@ func TestAccRepositoryRetentionRule_basic(t *testing.T) { Config: testAccRepositoryRetentionRuleConfigBasic, Check: resource.ComposeTestCheckFunc( testAccRepositoryCheckExists("cloudsmith_repository.test-retention"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_count_limit", "100"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_days_limit", "28"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_enabled", "false"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_group_by_name", "false"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_group_by_format", "false"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_group_by_package_type", "false"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_size_limit", "0"), - resource.TestCheckResourceAttr("cloudsmith_repository_retention_rule.test", "retention_package_query_string", "name:test"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_count_limit", "100"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_days_limit", "28"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_enabled", "false"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_group_by_name", "false"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_group_by_format", "false"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_group_by_package_type", "false"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_size_limit", "0"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_package_query_string", "name:test"), + ), + }, + { + Config: testAccRepositoryRetentionRuleConfigZero, + Check: resource.ComposeTestCheckFunc( + testAccRepositoryCheckExists("cloudsmith_repository.test-retention"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_count_limit", "0"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_days_limit", "0"), + testCheckResourceAttrWithMessage("cloudsmith_repository_retention_rule.test", "retention_size_limit", "0"), ), }, }, @@ -43,27 +71,47 @@ func TestAccRepositoryRetentionRule_basic(t *testing.T) { var testAccRepositoryConfig = fmt.Sprintf(` resource "cloudsmith_repository" "test-retention" { - name = "terraform-acc-repo-retention-rule" - namespace = "%s" + name = "terraform-acc-repo-retention-rule" + namespace = "%s" } `, os.Getenv("CLOUDSMITH_NAMESPACE")) var testAccRepositoryRetentionRuleConfigBasic = fmt.Sprintf(` resource "cloudsmith_repository" "test-retention" { - name = "terraform-acc-repo-retention-rule" - namespace = "%s" + name = "terraform-acc-repo-retention-rule" + namespace = "%s" +} + +resource "cloudsmith_repository_retention_rule" "test" { + namespace = "%s" + repository = cloudsmith_repository.test-retention.name + retention_enabled = false + retention_count_limit = 100 + retention_days_limit = 28 + retention_group_by_name = false + retention_group_by_format = false + retention_group_by_package_type = false + retention_size_limit = 0 + retention_package_query_string = "name:test" +} +`, os.Getenv("CLOUDSMITH_NAMESPACE"), os.Getenv("CLOUDSMITH_NAMESPACE")) + +var testAccRepositoryRetentionRuleConfigZero = fmt.Sprintf(` +resource "cloudsmith_repository" "test-retention" { + name = "terraform-acc-repo-retention-rule" + namespace = "%s" } resource "cloudsmith_repository_retention_rule" "test" { - namespace = "%s" - repository = cloudsmith_repository.test-retention.name - retention_enabled = false - retention_count_limit = 100 - retention_days_limit = 28 - retention_group_by_name = false - retention_group_by_format = false - retention_group_by_package_type = false - retention_size_limit = 0 - retention_package_query_string = "name:test" + namespace = "%s" + repository = cloudsmith_repository.test-retention.name + retention_enabled = false + retention_count_limit = 0 + retention_days_limit = 0 + retention_group_by_name = false + retention_group_by_format = false + retention_group_by_package_type = false + retention_size_limit = 0 + retention_package_query_string = "name:test" } `, os.Getenv("CLOUDSMITH_NAMESPACE"), os.Getenv("CLOUDSMITH_NAMESPACE")) diff --git a/docs/resources/repository_retention.md b/docs/resources/repository_retention.md index 45efcb5..766dcdb 100644 --- a/docs/resources/repository_retention.md +++ b/docs/resources/repository_retention.md @@ -44,12 +44,12 @@ The following arguments are supported: * `namespace` - (Required) The namespace of the repository. * `repository` - (Required) If true, the retention rules will be activated for the repository and settings will be updated. * `retention_enabled` - (Required) If true, the retention rules will be activated for the repository and settings will be updated. -* `retention_count_limit` - (Optional) The maximum number of packages to retain. Must be between 0 and 10000. +* `retention_count_limit` - (Optional) The maximum number of packages to retain. Must be between `0` and `10000`. Default set to 100 packages as part of repository creation. * `retention_days_limit` - (Optional) The number of days of packages to retain. Must be between `0` and `180`. Default set to 28 days as part of repository creation. * `retention_group_by_name` - (Optional) If true, retention will apply to groups of packages by name rather than all packages. * `retention_group_by_format` - (Optional) If true, retention will apply to packages by package formats rather than across all package formats. * `retention_group_by_package_type` - (Optional) If true, retention will apply to packages by package type rather than across all package types for one or more formats. -* `retention_size_limit` - (Optional) The maximum total size (in bytes) of packages to retain. Must be between `0` and `21474836480` (21.47 GB / 21474.83 MB). +* `retention_size_limit` - (Optional) The maximum total size (in bytes) of packages to retain. Must be between `0` and `20000000000` up to the maximum size of 20 GB (20,000,000,000 bytes). * `retention_package_query_string` - (Optional) A package search expression which, if provided, filters the packages to be deleted. For example, `name:foo` will only delete packages called 'foo'. ## Import