From 23a52ec98b89cf77cdd8f0b1783ee58162b19e2e Mon Sep 17 00:00:00 2001 From: Andrew Grigorev Date: Mon, 30 Mar 2026 12:47:00 +0300 Subject: [PATCH 1/5] fix: Add DiffSuppressFunc and DiffSuppressOnRefresh to remaining etag fields PR #2840 added etag diff suppression to 7 resources but missed the remaining 22. This causes spurious diffs on every plan/apply for resources like github_team, github_membership, github_team_repository, github_repository_deploy_key, and others. Apply the same pattern (Optional + DiffSuppressFunc returning true + DiffSuppressOnRefresh) to all remaining resource etag schema fields and extend the unit test to cover all 29 resources. Fixes #3103 Fixes #3291 Co-Authored-By: Claude --- .../resource_github_actions_runner_group.go | 5 ++++ .../resource_github_branch_protection_v3.go | 5 ++++ github/resource_github_emu_group_mapping.go | 5 ++++ ..._github_enterprise_actions_runner_group.go | 5 ++++ github/resource_github_etag_unit_test.go | 26 +++++++++++++++++-- github/resource_github_issue.go | 5 ++++ github/resource_github_membership.go | 5 ++++ .../resource_github_organization_project.go | 5 ++++ .../resource_github_organization_ruleset.go | 5 ++++ .../resource_github_organization_webhook.go | 5 ++++ github/resource_github_project_card.go | 5 ++++ github/resource_github_project_column.go | 5 ++++ github/resource_github_release.go | 5 ++++ ...ce_github_repository_autolink_reference.go | 5 ++++ .../resource_github_repository_deploy_key.go | 5 ++++ github/resource_github_repository_ruleset.go | 5 ++++ github/resource_github_team.go | 5 ++++ github/resource_github_team_membership.go | 5 ++++ github/resource_github_team_repository.go | 5 ++++ ...resource_github_team_sync_group_mapping.go | 5 ++++ github/resource_github_user_gpg_key.go | 5 ++++ github/resource_github_user_ssh_key.go | 5 ++++ github/resource_organization_block.go | 5 ++++ 23 files changed, 134 insertions(+), 2 deletions(-) diff --git a/github/resource_github_actions_runner_group.go b/github/resource_github_actions_runner_group.go index 394ff56a1c..c89f2c5b53 100644 --- a/github/resource_github_actions_runner_group.go +++ b/github/resource_github_actions_runner_group.go @@ -42,8 +42,13 @@ func resourceGithubActionsRunnerGroup() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the runner group object", + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, "inherited": { Type: schema.TypeBool, diff --git a/github/resource_github_branch_protection_v3.go b/github/resource_github_branch_protection_v3.go index e238def1fd..1076aedd2e 100644 --- a/github/resource_github_branch_protection_v3.go +++ b/github/resource_github_branch_protection_v3.go @@ -213,7 +213,12 @@ func resourceGithubBranchProtectionV3() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_emu_group_mapping.go b/github/resource_github_emu_group_mapping.go index 244ea3348a..7fc5f03a4f 100644 --- a/github/resource_github_emu_group_mapping.go +++ b/github/resource_github_emu_group_mapping.go @@ -46,7 +46,12 @@ func resourceGithubEMUGroupMapping() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, SchemaVersion: 1, diff --git a/github/resource_github_enterprise_actions_runner_group.go b/github/resource_github_enterprise_actions_runner_group.go index c37ebd8bef..e23b0ca011 100644 --- a/github/resource_github_enterprise_actions_runner_group.go +++ b/github/resource_github_enterprise_actions_runner_group.go @@ -43,8 +43,13 @@ func resourceGithubActionsEnterpriseRunnerGroup() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the runner group object", + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, "name": { Type: schema.TypeString, diff --git a/github/resource_github_etag_unit_test.go b/github/resource_github_etag_unit_test.go index 267f40f485..468a5ed5ea 100644 --- a/github/resource_github_etag_unit_test.go +++ b/github/resource_github_etag_unit_test.go @@ -74,13 +74,35 @@ func TestEtagDiffSuppressFunction(t *testing.T) { // TestEtagSchemaConsistency ensure DiffSuppressFunc and DiffSuppressOnRefresh are consistently applied. func TestEtagSchemaConsistency(t *testing.T) { resourcesWithEtag := map[string]*schema.Resource{ - "github_repository": resourceGithubRepository(), + "github_actions_runner_group": resourceGithubActionsRunnerGroup(), "github_branch": resourceGithubBranch(), "github_branch_default": resourceGithubBranchDefault(), + "github_branch_protection_v3": resourceGithubBranchProtectionV3(), + "github_emu_group_mapping": resourceGithubEMUGroupMapping(), + "github_enterprise_actions_runner_group": resourceGithubActionsEnterpriseRunnerGroup(), + "github_issue": resourceGithubIssue(), "github_issue_label": resourceGithubIssueLabel(), - "github_repository_webhook": resourceGithubRepositoryWebhook(), + "github_membership": resourceGithubMembership(), + "github_organization_project": resourceGithubOrganizationProject(), + "github_organization_ruleset": resourceGithubOrganizationRuleset(), + "github_organization_webhook": resourceGithubOrganizationWebhook(), + "github_project_card": resourceGithubProjectCard(), + "github_project_column": resourceGithubProjectColumn(), + "github_release": resourceGithubRelease(), + "github_repository": resourceGithubRepository(), + "github_repository_autolink_reference": resourceGithubRepositoryAutolinkReference(), + "github_repository_deploy_key": resourceGithubRepositoryDeployKey(), "github_repository_deployment_branch_policy": resourceGithubRepositoryDeploymentBranchPolicy(), "github_repository_project": resourceGithubRepositoryProject(), + "github_repository_ruleset": resourceGithubRepositoryRuleset(), + "github_repository_webhook": resourceGithubRepositoryWebhook(), + "github_team": resourceGithubTeam(), + "github_team_membership": resourceGithubTeamMembership(), + "github_team_repository": resourceGithubTeamRepository(), + "github_team_sync_group_mapping": resourceGithubTeamSyncGroupMapping(), + "github_user_gpg_key": resourceGithubUserGpgKey(), + "github_user_ssh_key": resourceGithubUserSshKey(), + "organization_block": resourceOrganizationBlock(), } for resourceName, resource := range resourcesWithEtag { diff --git a/github/resource_github_issue.go b/github/resource_github_issue.go index 3588c81c6d..c09c436555 100644 --- a/github/resource_github_issue.go +++ b/github/resource_github_issue.go @@ -69,7 +69,12 @@ func resourceGithubIssue() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_membership.go b/github/resource_github_membership.go index d1ddfacab2..72dc400ebd 100644 --- a/github/resource_github_membership.go +++ b/github/resource_github_membership.go @@ -39,7 +39,12 @@ func resourceGithubMembership() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, "downgrade_on_destroy": { Type: schema.TypeBool, diff --git a/github/resource_github_organization_project.go b/github/resource_github_organization_project.go index 005bc0a181..3edf01df06 100644 --- a/github/resource_github_organization_project.go +++ b/github/resource_github_organization_project.go @@ -36,7 +36,12 @@ func resourceGithubOrganizationProject() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_organization_ruleset.go b/github/resource_github_organization_ruleset.go index 8624250883..b7c06d3d49 100644 --- a/github/resource_github_organization_ruleset.go +++ b/github/resource_github_organization_ruleset.go @@ -675,8 +675,13 @@ func resourceGithubOrganizationRuleset() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the ruleset for caching purposes.", + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_organization_webhook.go b/github/resource_github_organization_webhook.go index 62c9a8926f..8ef38a929e 100644 --- a/github/resource_github_organization_webhook.go +++ b/github/resource_github_organization_webhook.go @@ -53,7 +53,12 @@ func resourceGithubOrganizationWebhook() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_project_card.go b/github/resource_github_project_card.go index 5e746dbe50..22445433b7 100644 --- a/github/resource_github_project_card.go +++ b/github/resource_github_project_card.go @@ -41,7 +41,12 @@ func resourceGithubProjectCard() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, "card_id": { Type: schema.TypeInt, diff --git a/github/resource_github_project_column.go b/github/resource_github_project_column.go index 830a6bb349..981a4e019e 100644 --- a/github/resource_github_project_column.go +++ b/github/resource_github_project_column.go @@ -37,7 +37,12 @@ func resourceGithubProjectColumn() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_release.go b/github/resource_github_release.go index 98949c9cd0..bf43ae7c3a 100644 --- a/github/resource_github_release.go +++ b/github/resource_github_release.go @@ -82,7 +82,12 @@ func resourceGithubRelease() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, "release_id": { Type: schema.TypeInt, diff --git a/github/resource_github_repository_autolink_reference.go b/github/resource_github_repository_autolink_reference.go index 9ee8c90eee..4e0329189a 100644 --- a/github/resource_github_repository_autolink_reference.go +++ b/github/resource_github_repository_autolink_reference.go @@ -86,7 +86,12 @@ func resourceGithubRepositoryAutolinkReference() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_repository_deploy_key.go b/github/resource_github_repository_deploy_key.go index 9cd12c2836..4067fdc95c 100644 --- a/github/resource_github_repository_deploy_key.go +++ b/github/resource_github_repository_deploy_key.go @@ -52,7 +52,12 @@ func resourceGithubRepositoryDeployKey() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_repository_ruleset.go b/github/resource_github_repository_ruleset.go index 460473e857..3a2c9b05d7 100644 --- a/github/resource_github_repository_ruleset.go +++ b/github/resource_github_repository_ruleset.go @@ -678,7 +678,12 @@ func resourceGithubRepositoryRuleset() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_team.go b/github/resource_github_team.go index 6f823e730d..be234f9211 100644 --- a/github/resource_github_team.go +++ b/github/resource_github_team.go @@ -106,7 +106,12 @@ func resourceGithubTeam() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_team_membership.go b/github/resource_github_team_membership.go index e0a296e657..2b5c4296c9 100644 --- a/github/resource_github_team_membership.go +++ b/github/resource_github_team_membership.go @@ -57,7 +57,12 @@ func resourceGithubTeamMembership() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_team_repository.go b/github/resource_github_team_repository.go index fa912b7de4..e2bc7bc71f 100644 --- a/github/resource_github_team_repository.go +++ b/github/resource_github_team_repository.go @@ -56,7 +56,12 @@ func resourceGithubTeamRepository() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_team_sync_group_mapping.go b/github/resource_github_team_sync_group_mapping.go index 53d7363bf3..fda9e23a20 100644 --- a/github/resource_github_team_sync_group_mapping.go +++ b/github/resource_github_team_sync_group_mapping.go @@ -60,7 +60,12 @@ func resourceGithubTeamSyncGroupMapping() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_user_gpg_key.go b/github/resource_github_user_gpg_key.go index cc6c2d21b8..9e255d0f24 100644 --- a/github/resource_github_user_gpg_key.go +++ b/github/resource_github_user_gpg_key.go @@ -31,7 +31,12 @@ func resourceGithubUserGpgKey() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_github_user_ssh_key.go b/github/resource_github_user_ssh_key.go index 681a68220f..ec727b7551 100644 --- a/github/resource_github_user_ssh_key.go +++ b/github/resource_github_user_ssh_key.go @@ -45,7 +45,12 @@ func resourceGithubUserSshKey() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } diff --git a/github/resource_organization_block.go b/github/resource_organization_block.go index 013e49d1dc..137296aa7d 100644 --- a/github/resource_organization_block.go +++ b/github/resource_organization_block.go @@ -29,7 +29,12 @@ func resourceOrganizationBlock() *schema.Resource { "etag": { Type: schema.TypeString, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, }, }, } From 1dafd3976769b00d918c65f20ed51223a5e3a363 Mon Sep 17 00:00:00 2001 From: Andrew Grigorev Date: Wed, 1 Apr 2026 09:55:45 +0300 Subject: [PATCH 2/5] fix: Remove Optional from etag fields per review feedback etag is server-computed and should not be user-editable. Remove Optional: true from all etag schema fields (both the 22 new ones and the 7 from PR #2840) and update the unit test accordingly. Co-Authored-By: Claude --- github/resource_github_actions_runner_group.go | 1 - github/resource_github_branch.go | 1 - github/resource_github_branch_default.go | 1 - github/resource_github_branch_protection_v3.go | 1 - github/resource_github_emu_group_mapping.go | 1 - github/resource_github_enterprise_actions_runner_group.go | 1 - github/resource_github_etag_unit_test.go | 5 +---- github/resource_github_issue.go | 1 - github/resource_github_issue_label.go | 1 - github/resource_github_membership.go | 1 - github/resource_github_organization_project.go | 1 - github/resource_github_organization_ruleset.go | 1 - github/resource_github_organization_webhook.go | 1 - github/resource_github_project_card.go | 1 - github/resource_github_project_column.go | 1 - github/resource_github_release.go | 1 - github/resource_github_repository.go | 1 - github/resource_github_repository_autolink_reference.go | 1 - github/resource_github_repository_deploy_key.go | 1 - .../resource_github_repository_deployment_branch_policy.go | 1 - github/resource_github_repository_project.go | 1 - github/resource_github_repository_ruleset.go | 1 - github/resource_github_repository_webhook.go | 1 - github/resource_github_team.go | 1 - github/resource_github_team_membership.go | 1 - github/resource_github_team_repository.go | 1 - github/resource_github_team_sync_group_mapping.go | 1 - github/resource_github_user_gpg_key.go | 1 - github/resource_github_user_ssh_key.go | 1 - github/resource_organization_block.go | 1 - 30 files changed, 1 insertion(+), 33 deletions(-) diff --git a/github/resource_github_actions_runner_group.go b/github/resource_github_actions_runner_group.go index c89f2c5b53..9874db8999 100644 --- a/github/resource_github_actions_runner_group.go +++ b/github/resource_github_actions_runner_group.go @@ -42,7 +42,6 @@ func resourceGithubActionsRunnerGroup() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "An etag representing the runner group object", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_branch.go b/github/resource_github_branch.go index d7c34d36bd..2d7ea597a2 100644 --- a/github/resource_github_branch.go +++ b/github/resource_github_branch.go @@ -50,7 +50,6 @@ func resourceGithubBranch() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "An etag representing the Branch object.", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index b137d92730..4eb0d43110 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -40,7 +40,6 @@ func resourceGithubBranchDefault() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_branch_protection_v3.go b/github/resource_github_branch_protection_v3.go index 1076aedd2e..86bd22ecbf 100644 --- a/github/resource_github_branch_protection_v3.go +++ b/github/resource_github_branch_protection_v3.go @@ -213,7 +213,6 @@ func resourceGithubBranchProtectionV3() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_emu_group_mapping.go b/github/resource_github_emu_group_mapping.go index 7fc5f03a4f..8c670a2e17 100644 --- a/github/resource_github_emu_group_mapping.go +++ b/github/resource_github_emu_group_mapping.go @@ -46,7 +46,6 @@ func resourceGithubEMUGroupMapping() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_enterprise_actions_runner_group.go b/github/resource_github_enterprise_actions_runner_group.go index e23b0ca011..368ae6b271 100644 --- a/github/resource_github_enterprise_actions_runner_group.go +++ b/github/resource_github_enterprise_actions_runner_group.go @@ -43,7 +43,6 @@ func resourceGithubActionsEnterpriseRunnerGroup() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "An etag representing the runner group object", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_etag_unit_test.go b/github/resource_github_etag_unit_test.go index 468a5ed5ea..95df3c610b 100644 --- a/github/resource_github_etag_unit_test.go +++ b/github/resource_github_etag_unit_test.go @@ -113,10 +113,7 @@ func TestEtagSchemaConsistency(t *testing.T) { return } - // Verify etag is optional and computed - if !etagField.Optional { - t.Errorf("etag should be optional in %s", resourceName) - } + // Verify etag is computed if !etagField.Computed { t.Errorf("etag should be computed in %s", resourceName) } diff --git a/github/resource_github_issue.go b/github/resource_github_issue.go index c09c436555..196cd1221a 100644 --- a/github/resource_github_issue.go +++ b/github/resource_github_issue.go @@ -69,7 +69,6 @@ func resourceGithubIssue() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_issue_label.go b/github/resource_github_issue_label.go index adaefc8c8e..7f23372029 100644 --- a/github/resource_github_issue_label.go +++ b/github/resource_github_issue_label.go @@ -49,7 +49,6 @@ func resourceGithubIssueLabel() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_membership.go b/github/resource_github_membership.go index 72dc400ebd..88f0443f82 100644 --- a/github/resource_github_membership.go +++ b/github/resource_github_membership.go @@ -39,7 +39,6 @@ func resourceGithubMembership() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_organization_project.go b/github/resource_github_organization_project.go index 3edf01df06..28ede56920 100644 --- a/github/resource_github_organization_project.go +++ b/github/resource_github_organization_project.go @@ -36,7 +36,6 @@ func resourceGithubOrganizationProject() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_organization_ruleset.go b/github/resource_github_organization_ruleset.go index b7c06d3d49..577f0c6b53 100644 --- a/github/resource_github_organization_ruleset.go +++ b/github/resource_github_organization_ruleset.go @@ -675,7 +675,6 @@ func resourceGithubOrganizationRuleset() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "An etag representing the ruleset for caching purposes.", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_organization_webhook.go b/github/resource_github_organization_webhook.go index 8ef38a929e..83ae542455 100644 --- a/github/resource_github_organization_webhook.go +++ b/github/resource_github_organization_webhook.go @@ -53,7 +53,6 @@ func resourceGithubOrganizationWebhook() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_project_card.go b/github/resource_github_project_card.go index 22445433b7..68594d2418 100644 --- a/github/resource_github_project_card.go +++ b/github/resource_github_project_card.go @@ -41,7 +41,6 @@ func resourceGithubProjectCard() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_project_column.go b/github/resource_github_project_column.go index 981a4e019e..354c680c6a 100644 --- a/github/resource_github_project_column.go +++ b/github/resource_github_project_column.go @@ -37,7 +37,6 @@ func resourceGithubProjectColumn() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_release.go b/github/resource_github_release.go index bf43ae7c3a..00169fec90 100644 --- a/github/resource_github_release.go +++ b/github/resource_github_release.go @@ -82,7 +82,6 @@ func resourceGithubRelease() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 9d756ac6c9..70bddbba9e 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -439,7 +439,6 @@ func resourceGithubRepository() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_autolink_reference.go b/github/resource_github_repository_autolink_reference.go index 4e0329189a..039a6b6e0b 100644 --- a/github/resource_github_repository_autolink_reference.go +++ b/github/resource_github_repository_autolink_reference.go @@ -86,7 +86,6 @@ func resourceGithubRepositoryAutolinkReference() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_deploy_key.go b/github/resource_github_repository_deploy_key.go index 4067fdc95c..817c2b5161 100644 --- a/github/resource_github_repository_deploy_key.go +++ b/github/resource_github_repository_deploy_key.go @@ -52,7 +52,6 @@ func resourceGithubRepositoryDeployKey() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_deployment_branch_policy.go b/github/resource_github_repository_deployment_branch_policy.go index a66c73afb1..2926194079 100644 --- a/github/resource_github_repository_deployment_branch_policy.go +++ b/github/resource_github_repository_deployment_branch_policy.go @@ -43,7 +43,6 @@ func resourceGithubRepositoryDeploymentBranchPolicy() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "An etag representing the Branch object.", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_repository_project.go b/github/resource_github_repository_project.go index f83c9aaed7..86ccb6a1eb 100644 --- a/github/resource_github_repository_project.go +++ b/github/resource_github_repository_project.go @@ -53,7 +53,6 @@ func resourceGithubRepositoryProject() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_ruleset.go b/github/resource_github_repository_ruleset.go index 3a2c9b05d7..2382bcab11 100644 --- a/github/resource_github_repository_ruleset.go +++ b/github/resource_github_repository_ruleset.go @@ -678,7 +678,6 @@ func resourceGithubRepositoryRuleset() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_webhook.go b/github/resource_github_repository_webhook.go index 3defdb23ee..3b71568e9a 100644 --- a/github/resource_github_repository_webhook.go +++ b/github/resource_github_repository_webhook.go @@ -71,7 +71,6 @@ func resourceGithubRepositoryWebhook() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team.go b/github/resource_github_team.go index be234f9211..771007f87f 100644 --- a/github/resource_github_team.go +++ b/github/resource_github_team.go @@ -106,7 +106,6 @@ func resourceGithubTeam() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team_membership.go b/github/resource_github_team_membership.go index 2b5c4296c9..37719ee27a 100644 --- a/github/resource_github_team_membership.go +++ b/github/resource_github_team_membership.go @@ -57,7 +57,6 @@ func resourceGithubTeamMembership() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team_repository.go b/github/resource_github_team_repository.go index e2bc7bc71f..1a394a5106 100644 --- a/github/resource_github_team_repository.go +++ b/github/resource_github_team_repository.go @@ -56,7 +56,6 @@ func resourceGithubTeamRepository() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team_sync_group_mapping.go b/github/resource_github_team_sync_group_mapping.go index fda9e23a20..8dc21f28ee 100644 --- a/github/resource_github_team_sync_group_mapping.go +++ b/github/resource_github_team_sync_group_mapping.go @@ -60,7 +60,6 @@ func resourceGithubTeamSyncGroupMapping() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_user_gpg_key.go b/github/resource_github_user_gpg_key.go index 9e255d0f24..594db03546 100644 --- a/github/resource_github_user_gpg_key.go +++ b/github/resource_github_user_gpg_key.go @@ -31,7 +31,6 @@ func resourceGithubUserGpgKey() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_user_ssh_key.go b/github/resource_github_user_ssh_key.go index ec727b7551..33f01ba1c0 100644 --- a/github/resource_github_user_ssh_key.go +++ b/github/resource_github_user_ssh_key.go @@ -45,7 +45,6 @@ func resourceGithubUserSshKey() *schema.Resource { }, "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_organization_block.go b/github/resource_organization_block.go index 137296aa7d..8e56fba5a6 100644 --- a/github/resource_organization_block.go +++ b/github/resource_organization_block.go @@ -29,7 +29,6 @@ func resourceOrganizationBlock() *schema.Resource { "etag": { Type: schema.TypeString, - Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true From df1d435c181c8fa2cb195e4016e23143f28c0c0c Mon Sep 17 00:00:00 2001 From: Andrew Grigorev Date: Wed, 1 Apr 2026 10:09:35 +0300 Subject: [PATCH 3/5] test: Add SDK validation proving Optional is required for DiffSuppressFunc The SDK explicitly rejects DiffSuppressFunc on Computed-only fields (InternalValidate returns: "DiffSuppressFunc is for suppressing differences between config and state representation. There is no config for computed-only field, nothing to compare."). Add tests demonstrating this SDK constraint, and verify all 29 resources pass InternalValidate with their current schema. Co-Authored-By: Claude --- github/resource_github_etag_unit_test.go | 65 ++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/github/resource_github_etag_unit_test.go b/github/resource_github_etag_unit_test.go index 95df3c610b..6510705955 100644 --- a/github/resource_github_etag_unit_test.go +++ b/github/resource_github_etag_unit_test.go @@ -1,6 +1,7 @@ package github import ( + "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -71,6 +72,60 @@ func TestEtagDiffSuppressFunction(t *testing.T) { } } +// TestEtagComputedOnlyRejectsSuppress verifies that the SDK rejects +// DiffSuppressFunc on Computed-only fields, proving Optional is required. +func TestEtagComputedOnlyRejectsSuppress(t *testing.T) { + p := &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "test": { + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, + }, + }, + }, + }, + } + err := p.InternalValidate() + if err == nil { + t.Fatal("expected SDK to reject DiffSuppressFunc on Computed-only field") + } + if !strings.Contains(err.Error(), "DiffSuppressFunc") { + t.Fatalf("unexpected error: %s", err) + } +} + +// TestEtagOptionalComputedAcceptsSuppress verifies that the SDK accepts +// DiffSuppressFunc on Optional+Computed fields. +func TestEtagOptionalComputedAcceptsSuppress(t *testing.T) { + p := &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "test": { + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + Computed: true, + DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { + return true + }, + DiffSuppressOnRefresh: true, + }, + }, + }, + }, + } + err := p.InternalValidate() + if err != nil { + t.Fatalf("Optional+Computed with DiffSuppressFunc should be valid, got: %s", err) + } +} + // TestEtagSchemaConsistency ensure DiffSuppressFunc and DiffSuppressOnRefresh are consistently applied. func TestEtagSchemaConsistency(t *testing.T) { resourcesWithEtag := map[string]*schema.Resource{ @@ -136,6 +191,16 @@ func TestEtagSchemaConsistency(t *testing.T) { t.Errorf("DiffSuppressFunc should return true in %s", resourceName) } } + + // Verify the schema passes SDK internal validation + p := &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + resourceName: resource, + }, + } + if err := p.InternalValidate(); err != nil { + t.Errorf("SDK validation failed for %s: %s", resourceName, err) + } }) } } From 97001abf0a8ee985c0aa582695989c071d00d4a7 Mon Sep 17 00:00:00 2001 From: Andrew Grigorev Date: Wed, 1 Apr 2026 10:10:54 +0300 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20Restore=20Optional=20on=20etag=20fie?= =?UTF-8?q?lds=20=E2=80=94=20required=20by=20SDK=20for=20DiffSuppressFunc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The terraform-plugin-sdk v2 InternalValidate rejects DiffSuppressFunc on Computed-only fields with: "There is no config for computed-only field, nothing to compare." Optional: true is required to use DiffSuppressFunc, as demonstrated by the new tests. Co-Authored-By: Claude --- github/resource_github_actions_runner_group.go | 1 + github/resource_github_branch.go | 1 + github/resource_github_branch_default.go | 1 + github/resource_github_branch_protection_v3.go | 1 + github/resource_github_emu_group_mapping.go | 1 + github/resource_github_enterprise_actions_runner_group.go | 1 + github/resource_github_etag_unit_test.go | 6 +++++- github/resource_github_issue.go | 1 + github/resource_github_issue_label.go | 1 + github/resource_github_membership.go | 1 + github/resource_github_organization_project.go | 1 + github/resource_github_organization_ruleset.go | 1 + github/resource_github_organization_webhook.go | 1 + github/resource_github_project_card.go | 1 + github/resource_github_project_column.go | 1 + github/resource_github_release.go | 1 + github/resource_github_repository.go | 1 + github/resource_github_repository_autolink_reference.go | 1 + github/resource_github_repository_deploy_key.go | 1 + .../resource_github_repository_deployment_branch_policy.go | 1 + github/resource_github_repository_project.go | 1 + github/resource_github_repository_ruleset.go | 1 + github/resource_github_repository_webhook.go | 1 + github/resource_github_team.go | 1 + github/resource_github_team_membership.go | 1 + github/resource_github_team_repository.go | 1 + github/resource_github_team_sync_group_mapping.go | 1 + github/resource_github_user_gpg_key.go | 1 + github/resource_github_user_ssh_key.go | 1 + github/resource_organization_block.go | 1 + 30 files changed, 34 insertions(+), 1 deletion(-) diff --git a/github/resource_github_actions_runner_group.go b/github/resource_github_actions_runner_group.go index 9874db8999..c89f2c5b53 100644 --- a/github/resource_github_actions_runner_group.go +++ b/github/resource_github_actions_runner_group.go @@ -42,6 +42,7 @@ func resourceGithubActionsRunnerGroup() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the runner group object", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_branch.go b/github/resource_github_branch.go index 2d7ea597a2..d7c34d36bd 100644 --- a/github/resource_github_branch.go +++ b/github/resource_github_branch.go @@ -50,6 +50,7 @@ func resourceGithubBranch() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the Branch object.", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index 4eb0d43110..b137d92730 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -40,6 +40,7 @@ func resourceGithubBranchDefault() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_branch_protection_v3.go b/github/resource_github_branch_protection_v3.go index 86bd22ecbf..1076aedd2e 100644 --- a/github/resource_github_branch_protection_v3.go +++ b/github/resource_github_branch_protection_v3.go @@ -213,6 +213,7 @@ func resourceGithubBranchProtectionV3() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_emu_group_mapping.go b/github/resource_github_emu_group_mapping.go index 8c670a2e17..7fc5f03a4f 100644 --- a/github/resource_github_emu_group_mapping.go +++ b/github/resource_github_emu_group_mapping.go @@ -46,6 +46,7 @@ func resourceGithubEMUGroupMapping() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_enterprise_actions_runner_group.go b/github/resource_github_enterprise_actions_runner_group.go index 368ae6b271..e23b0ca011 100644 --- a/github/resource_github_enterprise_actions_runner_group.go +++ b/github/resource_github_enterprise_actions_runner_group.go @@ -43,6 +43,7 @@ func resourceGithubActionsEnterpriseRunnerGroup() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the runner group object", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_etag_unit_test.go b/github/resource_github_etag_unit_test.go index 6510705955..f4162fcb45 100644 --- a/github/resource_github_etag_unit_test.go +++ b/github/resource_github_etag_unit_test.go @@ -168,7 +168,11 @@ func TestEtagSchemaConsistency(t *testing.T) { return } - // Verify etag is computed + // Verify etag is optional+computed (Optional is required by the SDK + // for DiffSuppressFunc, see TestEtagComputedOnlyRejectsSuppress) + if !etagField.Optional { + t.Errorf("etag should be optional in %s", resourceName) + } if !etagField.Computed { t.Errorf("etag should be computed in %s", resourceName) } diff --git a/github/resource_github_issue.go b/github/resource_github_issue.go index 196cd1221a..c09c436555 100644 --- a/github/resource_github_issue.go +++ b/github/resource_github_issue.go @@ -69,6 +69,7 @@ func resourceGithubIssue() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_issue_label.go b/github/resource_github_issue_label.go index 7f23372029..adaefc8c8e 100644 --- a/github/resource_github_issue_label.go +++ b/github/resource_github_issue_label.go @@ -49,6 +49,7 @@ func resourceGithubIssueLabel() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_membership.go b/github/resource_github_membership.go index 88f0443f82..72dc400ebd 100644 --- a/github/resource_github_membership.go +++ b/github/resource_github_membership.go @@ -39,6 +39,7 @@ func resourceGithubMembership() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_organization_project.go b/github/resource_github_organization_project.go index 28ede56920..3edf01df06 100644 --- a/github/resource_github_organization_project.go +++ b/github/resource_github_organization_project.go @@ -36,6 +36,7 @@ func resourceGithubOrganizationProject() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_organization_ruleset.go b/github/resource_github_organization_ruleset.go index 577f0c6b53..b7c06d3d49 100644 --- a/github/resource_github_organization_ruleset.go +++ b/github/resource_github_organization_ruleset.go @@ -675,6 +675,7 @@ func resourceGithubOrganizationRuleset() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the ruleset for caching purposes.", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_organization_webhook.go b/github/resource_github_organization_webhook.go index 83ae542455..8ef38a929e 100644 --- a/github/resource_github_organization_webhook.go +++ b/github/resource_github_organization_webhook.go @@ -53,6 +53,7 @@ func resourceGithubOrganizationWebhook() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_project_card.go b/github/resource_github_project_card.go index 68594d2418..22445433b7 100644 --- a/github/resource_github_project_card.go +++ b/github/resource_github_project_card.go @@ -41,6 +41,7 @@ func resourceGithubProjectCard() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_project_column.go b/github/resource_github_project_column.go index 354c680c6a..981a4e019e 100644 --- a/github/resource_github_project_column.go +++ b/github/resource_github_project_column.go @@ -37,6 +37,7 @@ func resourceGithubProjectColumn() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_release.go b/github/resource_github_release.go index 00169fec90..bf43ae7c3a 100644 --- a/github/resource_github_release.go +++ b/github/resource_github_release.go @@ -82,6 +82,7 @@ func resourceGithubRelease() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 70bddbba9e..9d756ac6c9 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -439,6 +439,7 @@ func resourceGithubRepository() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_autolink_reference.go b/github/resource_github_repository_autolink_reference.go index 039a6b6e0b..4e0329189a 100644 --- a/github/resource_github_repository_autolink_reference.go +++ b/github/resource_github_repository_autolink_reference.go @@ -86,6 +86,7 @@ func resourceGithubRepositoryAutolinkReference() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_deploy_key.go b/github/resource_github_repository_deploy_key.go index 817c2b5161..4067fdc95c 100644 --- a/github/resource_github_repository_deploy_key.go +++ b/github/resource_github_repository_deploy_key.go @@ -52,6 +52,7 @@ func resourceGithubRepositoryDeployKey() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_deployment_branch_policy.go b/github/resource_github_repository_deployment_branch_policy.go index 2926194079..a66c73afb1 100644 --- a/github/resource_github_repository_deployment_branch_policy.go +++ b/github/resource_github_repository_deployment_branch_policy.go @@ -43,6 +43,7 @@ func resourceGithubRepositoryDeploymentBranchPolicy() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, Description: "An etag representing the Branch object.", DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { diff --git a/github/resource_github_repository_project.go b/github/resource_github_repository_project.go index 86ccb6a1eb..f83c9aaed7 100644 --- a/github/resource_github_repository_project.go +++ b/github/resource_github_repository_project.go @@ -53,6 +53,7 @@ func resourceGithubRepositoryProject() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_ruleset.go b/github/resource_github_repository_ruleset.go index 2382bcab11..3a2c9b05d7 100644 --- a/github/resource_github_repository_ruleset.go +++ b/github/resource_github_repository_ruleset.go @@ -678,6 +678,7 @@ func resourceGithubRepositoryRuleset() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_repository_webhook.go b/github/resource_github_repository_webhook.go index 3b71568e9a..3defdb23ee 100644 --- a/github/resource_github_repository_webhook.go +++ b/github/resource_github_repository_webhook.go @@ -71,6 +71,7 @@ func resourceGithubRepositoryWebhook() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team.go b/github/resource_github_team.go index 771007f87f..be234f9211 100644 --- a/github/resource_github_team.go +++ b/github/resource_github_team.go @@ -106,6 +106,7 @@ func resourceGithubTeam() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team_membership.go b/github/resource_github_team_membership.go index 37719ee27a..2b5c4296c9 100644 --- a/github/resource_github_team_membership.go +++ b/github/resource_github_team_membership.go @@ -57,6 +57,7 @@ func resourceGithubTeamMembership() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team_repository.go b/github/resource_github_team_repository.go index 1a394a5106..e2bc7bc71f 100644 --- a/github/resource_github_team_repository.go +++ b/github/resource_github_team_repository.go @@ -56,6 +56,7 @@ func resourceGithubTeamRepository() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_team_sync_group_mapping.go b/github/resource_github_team_sync_group_mapping.go index 8dc21f28ee..fda9e23a20 100644 --- a/github/resource_github_team_sync_group_mapping.go +++ b/github/resource_github_team_sync_group_mapping.go @@ -60,6 +60,7 @@ func resourceGithubTeamSyncGroupMapping() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_user_gpg_key.go b/github/resource_github_user_gpg_key.go index 594db03546..9e255d0f24 100644 --- a/github/resource_github_user_gpg_key.go +++ b/github/resource_github_user_gpg_key.go @@ -31,6 +31,7 @@ func resourceGithubUserGpgKey() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_github_user_ssh_key.go b/github/resource_github_user_ssh_key.go index 33f01ba1c0..ec727b7551 100644 --- a/github/resource_github_user_ssh_key.go +++ b/github/resource_github_user_ssh_key.go @@ -45,6 +45,7 @@ func resourceGithubUserSshKey() *schema.Resource { }, "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true diff --git a/github/resource_organization_block.go b/github/resource_organization_block.go index 8e56fba5a6..137296aa7d 100644 --- a/github/resource_organization_block.go +++ b/github/resource_organization_block.go @@ -29,6 +29,7 @@ func resourceOrganizationBlock() *schema.Resource { "etag": { Type: schema.TypeString, + Optional: true, Computed: true, DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { return true From c28a943af1bcbe134d41a12a341e5ff5071de78f Mon Sep 17 00:00:00 2001 From: Andrew Grigorev Date: Wed, 1 Apr 2026 13:22:44 +0300 Subject: [PATCH 5/5] test: Remove standalone SDK validation tests, covered by InternalValidate in consistency test Co-Authored-By: Claude --- github/resource_github_etag_unit_test.go | 55 ------------------------ 1 file changed, 55 deletions(-) diff --git a/github/resource_github_etag_unit_test.go b/github/resource_github_etag_unit_test.go index f4162fcb45..ba3c50e162 100644 --- a/github/resource_github_etag_unit_test.go +++ b/github/resource_github_etag_unit_test.go @@ -1,7 +1,6 @@ package github import ( - "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -72,60 +71,6 @@ func TestEtagDiffSuppressFunction(t *testing.T) { } } -// TestEtagComputedOnlyRejectsSuppress verifies that the SDK rejects -// DiffSuppressFunc on Computed-only fields, proving Optional is required. -func TestEtagComputedOnlyRejectsSuppress(t *testing.T) { - p := &schema.Provider{ - ResourcesMap: map[string]*schema.Resource{ - "test": { - Schema: map[string]*schema.Schema{ - "etag": { - Type: schema.TypeString, - Computed: true, - DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { - return true - }, - DiffSuppressOnRefresh: true, - }, - }, - }, - }, - } - err := p.InternalValidate() - if err == nil { - t.Fatal("expected SDK to reject DiffSuppressFunc on Computed-only field") - } - if !strings.Contains(err.Error(), "DiffSuppressFunc") { - t.Fatalf("unexpected error: %s", err) - } -} - -// TestEtagOptionalComputedAcceptsSuppress verifies that the SDK accepts -// DiffSuppressFunc on Optional+Computed fields. -func TestEtagOptionalComputedAcceptsSuppress(t *testing.T) { - p := &schema.Provider{ - ResourcesMap: map[string]*schema.Resource{ - "test": { - Schema: map[string]*schema.Schema{ - "etag": { - Type: schema.TypeString, - Optional: true, - Computed: true, - DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool { - return true - }, - DiffSuppressOnRefresh: true, - }, - }, - }, - }, - } - err := p.InternalValidate() - if err != nil { - t.Fatalf("Optional+Computed with DiffSuppressFunc should be valid, got: %s", err) - } -} - // TestEtagSchemaConsistency ensure DiffSuppressFunc and DiffSuppressOnRefresh are consistently applied. func TestEtagSchemaConsistency(t *testing.T) { resourcesWithEtag := map[string]*schema.Resource{