Skip to content

Commit 17da14c

Browse files
authored
feat: Adds Difffix/feat: SuppressFunc and DiffSuppressOnRefresh to resources that have etag properties to suppress etag-related diffs (#2840)
* Adds DiffSuppressFunc and DiffSuppressOnRefresh to resources that have etag properties to suppress etag-related diffs * Add tests that verify the functional diff suppression * Add optional property to allow DiffSuppressFunc * Coverage for new optional property
1 parent 0f3f802 commit 17da14c

9 files changed

+225
-0
lines changed

github/resource_github_branch.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@ func resourceGithubBranch() *schema.Resource {
4949
},
5050
"etag": {
5151
Type: schema.TypeString,
52+
Optional: true,
5253
Computed: true,
5354
Description: "An etag representing the Branch object.",
55+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
56+
return true
57+
},
58+
DiffSuppressOnRefresh: true,
5459
},
5560
"ref": {
5661
Type: schema.TypeString,

github/resource_github_branch_default.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ func resourceGithubBranchDefault() *schema.Resource {
3939
},
4040
"etag": {
4141
Type: schema.TypeString,
42+
Optional: true,
4243
Computed: true,
44+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
45+
return true
46+
},
47+
DiffSuppressOnRefresh: true,
4348
},
4449
},
4550
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package github
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
)
10+
11+
// TestAccGithubRepositoryEtagPresent tests that etag field is populated
12+
func TestAccGithubRepositoryEtagPresent(t *testing.T) {
13+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
14+
repoName := fmt.Sprintf("tf-acc-test-etag-%s", randomID)
15+
16+
config := fmt.Sprintf(`
17+
resource "github_repository" "test" {
18+
name = "%s"
19+
auto_init = true
20+
}
21+
`, repoName)
22+
23+
resource.Test(t, resource.TestCase{
24+
PreCheck: func() { testAccPreCheck(t) },
25+
Providers: testAccProviders,
26+
Steps: []resource.TestStep{
27+
{
28+
Config: config,
29+
Check: resource.ComposeTestCheckFunc(
30+
resource.TestCheckResourceAttr("github_repository.test", "name", repoName),
31+
resource.TestCheckResourceAttrSet("github_repository.test", "etag"),
32+
),
33+
},
34+
},
35+
})
36+
}
37+
38+
// TestAccGithubRepositoryEtagNoDiff tests that re-running the same config shows no changes
39+
func TestAccGithubRepositoryEtagNoDiff(t *testing.T) {
40+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
41+
repoName := fmt.Sprintf("tf-acc-test-etag-nodiff-%s", randomID)
42+
43+
config := fmt.Sprintf(`
44+
resource "github_repository" "test" {
45+
name = "%s"
46+
description = "Test repository for etag diff suppression"
47+
auto_init = true
48+
}
49+
`, repoName)
50+
51+
resource.Test(t, resource.TestCase{
52+
PreCheck: func() { testAccPreCheck(t) },
53+
Providers: testAccProviders,
54+
Steps: []resource.TestStep{
55+
{
56+
Config: config,
57+
Check: resource.ComposeTestCheckFunc(
58+
resource.TestCheckResourceAttr("github_repository.test", "name", repoName),
59+
resource.TestCheckResourceAttrSet("github_repository.test", "etag"),
60+
),
61+
},
62+
{
63+
// Re-run the same config - should not show any changes - etag diff suppression
64+
Config: config,
65+
PlanOnly: true,
66+
},
67+
},
68+
})
69+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package github
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7+
)
8+
9+
// TestEtagDiffSuppressFunction tests that the etag diff suppress function
10+
// always returns true, suppressing all etag differences
11+
func TestEtagDiffSuppressFunction(t *testing.T) {
12+
repositoryResource := resourceGithubRepository()
13+
etagField := repositoryResource.Schema["etag"]
14+
15+
if etagField == nil {
16+
t.Fatal("etag field not found in repository schema")
17+
}
18+
19+
if etagField.DiffSuppressFunc == nil {
20+
t.Fatal("etag should have DiffSuppressFunc")
21+
}
22+
23+
if !etagField.DiffSuppressOnRefresh {
24+
t.Fatal("etag should have DiffSuppressOnRefresh enabled")
25+
}
26+
27+
testCases := []struct {
28+
name string
29+
key string
30+
old string
31+
new string
32+
}{
33+
{
34+
name: "different etag values",
35+
key: "etag",
36+
old: `"abc123"`,
37+
new: `"def456"`,
38+
},
39+
{
40+
name: "empty to non-empty etag",
41+
key: "etag",
42+
old: "",
43+
new: `"abc123"`,
44+
},
45+
{
46+
name: "non-empty to empty etag",
47+
key: "etag",
48+
old: `"abc123"`,
49+
new: "",
50+
},
51+
{
52+
name: "same etag values",
53+
key: "etag",
54+
old: `"abc123"`,
55+
new: `"abc123"`,
56+
},
57+
}
58+
59+
for _, tc := range testCases {
60+
t.Run(tc.name, func(t *testing.T) {
61+
d := schema.TestResourceDataRaw(t, repositoryResource.Schema, map[string]interface{}{
62+
"name": "test-repo",
63+
})
64+
65+
result := etagField.DiffSuppressFunc(tc.key, tc.old, tc.new, d)
66+
if !result {
67+
t.Errorf("DiffSuppressFunc should always return true for etag field")
68+
}
69+
})
70+
}
71+
}
72+
73+
// TestEtagSchemaConsistency ensure DiffSuppressFunc and DiffSuppressOnRefresh are consistently applied
74+
func TestEtagSchemaConsistency(t *testing.T) {
75+
resourcesWithEtag := map[string]*schema.Resource{
76+
"github_repository": resourceGithubRepository(),
77+
"github_branch": resourceGithubBranch(),
78+
"github_branch_default": resourceGithubBranchDefault(),
79+
"github_issue_label": resourceGithubIssueLabel(),
80+
"github_repository_webhook": resourceGithubRepositoryWebhook(),
81+
"github_repository_deployment_branch_policy": resourceGithubRepositoryDeploymentBranchPolicy(),
82+
"github_repository_project": resourceGithubRepositoryProject(),
83+
}
84+
85+
for resourceName, resource := range resourcesWithEtag {
86+
t.Run(resourceName, func(t *testing.T) {
87+
etagField, exists := resource.Schema["etag"]
88+
if !exists {
89+
t.Errorf("Resource %s should have etag field", resourceName)
90+
return
91+
}
92+
93+
// Verify etag is optional and computed
94+
if !etagField.Optional {
95+
t.Errorf("etag should be optional in %s", resourceName)
96+
}
97+
if !etagField.Computed {
98+
t.Errorf("etag should be computed in %s", resourceName)
99+
}
100+
101+
// Verify etag has DiffSuppressFunc
102+
if etagField.DiffSuppressFunc == nil {
103+
t.Errorf("etag should have DiffSuppressFunc in %s", resourceName)
104+
}
105+
106+
// Verify DiffSuppressOnRefresh is enabled
107+
if !etagField.DiffSuppressOnRefresh {
108+
t.Errorf("etag should have DiffSuppressOnRefresh enabled in %s", resourceName)
109+
}
110+
111+
// Verify the DiffSuppressFunc always returns true
112+
if etagField.DiffSuppressFunc != nil {
113+
d := schema.TestResourceDataRaw(t, resource.Schema, map[string]interface{}{})
114+
result := etagField.DiffSuppressFunc("etag", "old", "new", d)
115+
if !result {
116+
t.Errorf("DiffSuppressFunc should return true in %s", resourceName)
117+
}
118+
}
119+
})
120+
}
121+
}

github/resource_github_issue_label.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ func resourceGithubIssueLabel() *schema.Resource {
4848
},
4949
"etag": {
5050
Type: schema.TypeString,
51+
Optional: true,
5152
Computed: true,
53+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
54+
return true
55+
},
56+
DiffSuppressOnRefresh: true,
5257
},
5358
},
5459
}

github/resource_github_repository.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,12 @@ func resourceGithubRepository() *schema.Resource {
360360
},
361361
"etag": {
362362
Type: schema.TypeString,
363+
Optional: true,
363364
Computed: true,
365+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
366+
return true
367+
},
368+
DiffSuppressOnRefresh: true,
364369
},
365370
"primary_language": {
366371
Type: schema.TypeString,

github/resource_github_repository_deployment_branch_policy.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,13 @@ func resourceGithubRepositoryDeploymentBranchPolicy() *schema.Resource {
4040
},
4141
"etag": {
4242
Type: schema.TypeString,
43+
Optional: true,
4344
Computed: true,
4445
Description: "An etag representing the Branch object.",
46+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
47+
return true
48+
},
49+
DiffSuppressOnRefresh: true,
4550
},
4651
},
4752
}

github/resource_github_repository_project.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ func resourceGithubRepositoryProject() *schema.Resource {
5858
},
5959
"etag": {
6060
Type: schema.TypeString,
61+
Optional: true,
6162
Computed: true,
63+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
64+
return true
65+
},
66+
DiffSuppressOnRefresh: true,
6267
},
6368
},
6469
}

github/resource_github_repository_webhook.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ func resourceGithubRepositoryWebhook() *schema.Resource {
6363
},
6464
"etag": {
6565
Type: schema.TypeString,
66+
Optional: true,
6667
Computed: true,
68+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
69+
return true
70+
},
71+
DiffSuppressOnRefresh: true,
6772
},
6873
},
6974
}

0 commit comments

Comments
 (0)