Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 1 addition & 20 deletions github/data_source_github_organization_repository_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down
123 changes: 94 additions & 29 deletions github/resource_github_organization_repository_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package github

import (
"context"
"errors"
"fmt"
"log"
"net/http"
"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"
)
Expand Down Expand Up @@ -53,6 +56,8 @@ func resourceGithubOrganizationRepositoryRole() *schema.Resource {
MinItems: 1,
},
},

CustomizeDiff: resourceGithubOrganizationRepositoryRoleCustomizeDiff,
}
}

Expand Down Expand Up @@ -81,6 +86,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
}
Expand All @@ -99,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 {
Expand Down Expand Up @@ -206,3 +199,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
}
3 changes: 2 additions & 1 deletion github/resource_github_organization_repository_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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"
]
Expand Down
Loading