From e9274aef7acb2f42cdf6bb983975e46c4b9eecd1 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 14 Feb 2026 01:52:11 +0200 Subject: [PATCH 1/6] Fix missing Set of Computed field in Org Repo Role Signed-off-by: Timo Sand --- github/resource_github_organization_repository_role.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/github/resource_github_organization_repository_role.go b/github/resource_github_organization_repository_role.go index b7bf49ab67..389980cd87 100644 --- a/github/resource_github_organization_repository_role.go +++ b/github/resource_github_organization_repository_role.go @@ -81,6 +81,10 @@ func resourceGithubOrganizationRepositoryRoleCreate(ctx context.Context, d *sche return diag.FromErr(fmt.Errorf("error creating GitHub organization repository role (%s/%s): %w", orgName, d.Get("name").(string), err)) } + if err = d.Set("role_id", role.GetID()); err != nil { + return diag.FromErr(err) + } + d.SetId(fmt.Sprint(role.GetID())) return nil } @@ -177,11 +181,15 @@ func resourceGithubOrganizationRepositoryRoleUpdate(ctx context.Context, d *sche Permissions: permissionsStr, } - _, _, err = client.Organizations.UpdateCustomRepoRole(ctx, orgName, roleId, update) + role, _, err := client.Organizations.UpdateCustomRepoRole(ctx, orgName, roleId, update) if err != nil { return diag.FromErr(fmt.Errorf("error updating GitHub organization repository role (%s/%s): %w", orgName, d.Get("name").(string), err)) } + if err = d.Set("role_id", role.GetID()); err != nil { + return diag.FromErr(err) + } + return nil } From 15c13e3b58858a32487d30cc3c5eef82cfc3ebd3 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 14 Feb 2026 01:52:50 +0200 Subject: [PATCH 2/6] Ensure tests are configured correctly Signed-off-by: Timo Sand --- github/resource_github_organization_repository_role_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/github/resource_github_organization_repository_role_test.go b/github/resource_github_organization_repository_role_test.go index 72116c55a3..22e3bc1ad9 100644 --- a/github/resource_github_organization_repository_role_test.go +++ b/github/resource_github_organization_repository_role_test.go @@ -13,7 +13,7 @@ func TestAccGithubOrganizationRepositoryRole(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) name := fmt.Sprintf("tf-acc-org-repo-role-%s", randomID) description := "This is a test org repo role." - baseRole := "write" + baseRole := "read" permission0 := "reopen_issue" permission1 := "reopen_pull_request" @@ -59,6 +59,7 @@ func TestAccGithubOrganizationRepositoryRole(t *testing.T) { config := fmt.Sprintf(` resource "github_organization_repository_role" "test" { name = "%s" + base_role = "read" permissions = [ "%s" ] From a1ddfc36b0b14ffa28a16c62ba54fbb2b9a553f2 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 14 Feb 2026 02:00:57 +0200 Subject: [PATCH 3/6] Add validation of `permissions` values Signed-off-by: Timo Sand --- ...rce_github_organization_repository_role.go | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/github/resource_github_organization_repository_role.go b/github/resource_github_organization_repository_role.go index 389980cd87..092c5e3d07 100644 --- a/github/resource_github_organization_repository_role.go +++ b/github/resource_github_organization_repository_role.go @@ -4,9 +4,11 @@ import ( "context" "fmt" "log" + "slices" "strconv" "github.com/google/go-github/v82/github" + "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -53,6 +55,8 @@ func resourceGithubOrganizationRepositoryRole() *schema.Resource { MinItems: 1, }, }, + + CustomizeDiff: resourceGithubOrganizationRepositoryRoleCustomizeDiff, } } @@ -214,3 +218,75 @@ func resourceGithubOrganizationRepositoryRoleDelete(ctx context.Context, d *sche return nil } + +// Snapshot of the response to https://docs.github.com/en/enterprise-cloud@latest/rest/orgs/custom-roles?apiVersion=2022-11-28#list-repository-fine-grained-permissions-for-an-organization +// The endpoint isn't covered in the SDK yet. +var validRolePermissions = []string{ + "add_assignee", + "add_label", + "bypass_branch_protection", + "close_discussion", + "close_issue", + "close_pull_request", + "convert_issues_to_discussions", + "create_discussion_category", + "create_solo_merge_queue_entry", + "create_tag", + "delete_alerts_code_scanning", + "delete_discussion", + "delete_discussion_comment", + "delete_issue", + "delete_tag", + "edit_category_on_discussion", + "edit_discussion_category", + "edit_discussion_comment", + "edit_repo_custom_properties_values", + "edit_repo_metadata", + "edit_repo_protections", + "jump_merge_queue", + "manage_deploy_keys", + "manage_settings_merge_types", + "manage_settings_pages", + "manage_settings_projects", + "manage_settings_wiki", + "manage_webhooks", + "mark_as_duplicate", + "push_protected_branch", + "read_code_quality", + "read_code_scanning", + "reopen_discussion", + "reopen_issue", + "reopen_pull_request", + "request_pr_review", + "resolve_dependabot_alerts", + "resolve_secret_scanning_alerts", + "set_interaction_limits", + "set_issue_type", + "set_milestone", + "set_social_preview", + "toggle_discussion_answer", + "toggle_discussion_comment_minimize", + "view_dependabot_alerts", + "view_secret_scanning_alerts", + "write_code_quality", + "write_code_scanning", + "write_repository_actions_environments", + "write_repository_actions_runners", + "write_repository_actions_secrets", + "write_repository_actions_settings", + "write_repository_actions_variables", +} + +func resourceGithubOrganizationRepositoryRoleCustomizeDiff(ctx context.Context, d *schema.ResourceDiff, m any) error { + tflog.Debug(ctx, "Customizing diff for GitHub organization repository role", map[string]any{"permissionsChanged": d.HasChange("permissions")}) + if d.HasChange("permissions") { + newPermissions := d.Get("permissions").(*schema.Set).List() + tflog.Debug(ctx, "Validating permissions values", map[string]any{"newPermissions": newPermissions}) + for _, permission := range newPermissions { + if !slices.Contains(validRolePermissions, permission.(string)) { + return fmt.Errorf("invalid permission: %+v", permission) + } + } + } + return nil +} From df7d643f1b2244200d224a88f9e1f30f6977de37 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 14 Feb 2026 02:01:42 +0200 Subject: [PATCH 4/6] Update to use new SDK methods Signed-off-by: Timo Sand --- ...rce_github_organization_repository_role.go | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/github/resource_github_organization_repository_role.go b/github/resource_github_organization_repository_role.go index 092c5e3d07..7b189c80e3 100644 --- a/github/resource_github_organization_repository_role.go +++ b/github/resource_github_organization_repository_role.go @@ -2,8 +2,9 @@ package github import ( "context" + "errors" "fmt" - "log" + "net/http" "slices" "strconv" @@ -107,36 +108,20 @@ func resourceGithubOrganizationRepositoryRoleRead(ctx context.Context, d *schema return diag.FromErr(err) } - // TODO: Use this code when go-github is v68+ - // role, _, err := client.Organizations.GetCustomRepoRole(ctx, orgName, roleId) - // if err != nil { - // if ghErr, ok := err.(*github.ErrorResponse); ok { - // if ghErr.Response.StatusCode == http.StatusNotFound { - // log.Printf("[WARN] GitHub organization repository role (%s/%d) not found, removing from state", orgName, roleId) - // d.SetId("") - // return nil - // } - // } - // return err - // } - - roles, _, err := client.Organizations.ListCustomRepoRoles(ctx, orgName) + role, _, err := client.Organizations.GetCustomRepoRole(ctx, orgName, roleId) if err != nil { - return diag.FromErr(err) - } - - var role *github.CustomRepoRoles - for _, r := range roles.CustomRepoRoles { - if r.GetID() == roleId { - role = r - break + var ghErr *github.ErrorResponse + if errors.As(err, &ghErr) { + if ghErr.Response.StatusCode == http.StatusNotFound { + tflog.Warn(ctx, "GitHub organization repository role not found, removing from state", map[string]any{ + "orgName": orgName, + "roleId": roleId, + }) + d.SetId("") + return nil + } } - } - - if role == nil { - log.Printf("[WARN] GitHub organization repository role (%s/%d) not found, removing from state", orgName, roleId) - d.SetId("") - return nil + return diag.FromErr(err) } if err = d.Set("role_id", role.GetID()); err != nil { From b7790fd422135fcda427eaee32d00ad34ec22cae Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 14 Feb 2026 02:03:36 +0200 Subject: [PATCH 5/6] Update DS to use new SDK methods Signed-off-by: Timo Sand --- ...rce_github_organization_repository_role.go | 21 +------------------ ...ithub_organization_repository_role_test.go | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/github/data_source_github_organization_repository_role.go b/github/data_source_github_organization_repository_role.go index 66ef09aef5..453faf2a67 100644 --- a/github/data_source_github_organization_repository_role.go +++ b/github/data_source_github_organization_repository_role.go @@ -2,10 +2,8 @@ package github import ( "context" - "fmt" "strconv" - "github.com/google/go-github/v82/github" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -53,28 +51,11 @@ func dataSourceGithubOrganizationRepositoryRoleRead(ctx context.Context, d *sche roleId := int64(d.Get("role_id").(int)) - // TODO: Use this code when go-github is at v68+ - // role, _, err := client.Organizations.GetCustomRepoRole(ctx, orgName, roleId) - // if err != nil { - // return diag.FromErr(err) - // } - - roles, _, err := client.Organizations.ListCustomRepoRoles(ctx, orgName) + role, _, err := client.Organizations.GetCustomRepoRole(ctx, orgName, roleId) if err != nil { return diag.FromErr(err) } - var role *github.CustomRepoRoles - for _, r := range roles.CustomRepoRoles { - if r.GetID() == roleId { - role = r - break - } - } - if role == nil { - return diag.FromErr(fmt.Errorf("custom organization repo role with ID %d not found", roleId)) - } - r := map[string]any{ "role_id": role.GetID(), "name": role.GetName(), diff --git a/github/data_source_github_organization_repository_role_test.go b/github/data_source_github_organization_repository_role_test.go index 3367d51356..3ab91f7aab 100644 --- a/github/data_source_github_organization_repository_role_test.go +++ b/github/data_source_github_organization_repository_role_test.go @@ -11,7 +11,7 @@ import ( func TestAccGithubOrganizationRepositoryRoleDataSource(t *testing.T) { t.Run("queries an organization repository role", func(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) - roleName := fmt.Sprintf(`tf-acc-test-%s`, randomID) + roleName := fmt.Sprintf(`%s%s`, testResourcePrefix, randomID) config := fmt.Sprintf(` resource "github_organization_repository_role" "test" { From fc61a0758a7289d2e951001c1b9640f5106d602b Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Mon, 16 Feb 2026 20:45:10 +0200 Subject: [PATCH 6/6] Remove unnecessary `d.Set("role_id")` Signed-off-by: Timo Sand --- github/resource_github_organization_repository_role.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/github/resource_github_organization_repository_role.go b/github/resource_github_organization_repository_role.go index 7b189c80e3..1359e66333 100644 --- a/github/resource_github_organization_repository_role.go +++ b/github/resource_github_organization_repository_role.go @@ -170,15 +170,11 @@ func resourceGithubOrganizationRepositoryRoleUpdate(ctx context.Context, d *sche Permissions: permissionsStr, } - role, _, err := client.Organizations.UpdateCustomRepoRole(ctx, orgName, roleId, update) + _, _, err = client.Organizations.UpdateCustomRepoRole(ctx, orgName, roleId, update) if err != nil { return diag.FromErr(fmt.Errorf("error updating GitHub organization repository role (%s/%s): %w", orgName, d.Get("name").(string), err)) } - if err = d.Set("role_id", role.GetID()); err != nil { - return diag.FromErr(err) - } - return nil }