Skip to content

Commit 1a70927

Browse files
feat: allow emtpy invitation IDs (#1488)
* feat: allow emtpy invitation IDs With this, for_each can be used with github_user_invitation_accepter resources without producing errors for an empty invitation_id attribute. * docs: improve documentation for current error states * fix: set ForceNew * fixup! feat: allow emtpy invitation IDs * fix: allow resource to be saved --------- Co-authored-by: Keegan Campbell <[email protected]>
1 parent 9a39905 commit 1a70927

3 files changed

+68
-3
lines changed

github/resource_github_user_invitation_accepter.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"strconv"
77

8+
"github.com/google/uuid"
89
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
910
)
1011

@@ -17,7 +18,13 @@ func resourceGithubUserInvitationAccepter() *schema.Resource {
1718
Schema: map[string]*schema.Schema{
1819
"invitation_id": {
1920
Type: schema.TypeString,
20-
Required: true,
21+
Optional: true,
22+
ForceNew: true,
23+
},
24+
"allow_empty_id": {
25+
Type: schema.TypeBool,
26+
Optional: true,
27+
Default: false,
2128
ForceNew: true,
2229
},
2330
},
@@ -28,6 +35,19 @@ func resourceGithubUserInvitationAccepterCreate(d *schema.ResourceData, meta int
2835
client := meta.(*Owner).v3client
2936

3037
invitationIdString := d.Get("invitation_id").(string)
38+
allowEmptyId := d.Get("allow_empty_id").(bool)
39+
40+
if invitationIdString == "" {
41+
if allowEmptyId {
42+
// We're setting a random UUID as resource ID since every resource needs an ID
43+
// and we can't destroy the resource while we create it.
44+
d.SetId(uuid.NewString())
45+
return nil
46+
} else {
47+
return fmt.Errorf("invitation_id is not set and allow_empty_id is false")
48+
}
49+
}
50+
3151
invitationId, err := strconv.Atoi(invitationIdString)
3252
if err != nil {
3353
return fmt.Errorf("failed to parse invitation ID: %s", err)

github/resource_github_user_invitation_accepter_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ func TestAccGithubUserInvitationAccepter_basic(t *testing.T) {
3939
})
4040
}
4141

42+
func TestAccGithubUserInvitationAccepterAllowEmptyId(t *testing.T) {
43+
rn := "github_user_invitation_accepter.test"
44+
45+
var providers []*schema.Provider
46+
47+
resource.ParallelTest(t, resource.TestCase{
48+
PreCheck: func() { testAccPreCheck(t) },
49+
ProviderFactories: testAccProviderFactories(&providers),
50+
CheckDestroy: testAccCheckGithubUserInvitationAccepterDestroy,
51+
Steps: []resource.TestStep{
52+
{
53+
Config: testAccGithubUserInvitationAccepterAllowEmptyId(),
54+
Check: resource.ComposeTestCheckFunc(
55+
resource.TestCheckResourceAttr(rn, "invitation_id", ""),
56+
resource.TestCheckResourceAttr(rn, "allow_empty_id", "true"),
57+
),
58+
},
59+
},
60+
})
61+
}
62+
4263
func testAccCheckGithubUserInvitationAccepterDestroy(s *terraform.State) error {
4364
return nil
4465
}
@@ -72,3 +93,14 @@ resource "github_user_invitation_accepter" "test" {
7293
}
7394
`, inviteeToken, repoName, testCollaborator)
7495
}
96+
97+
func testAccGithubUserInvitationAccepterAllowEmptyId() string {
98+
return `
99+
provider "github" {}
100+
101+
resource "github_user_invitation_accepter" "test" {
102+
invitation_id = ""
103+
allow_empty_id = true
104+
}
105+
`
106+
}

website/docs/r/user_invitation_accepter.html.markdown

+15-2
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,24 @@ provider "github" {
3030
resource "github_user_invitation_accepter" "example" {
3131
provider = "github.invitee"
3232
invitation_id = github_repository_collaborator.example.invitation_id
33-
}
33+
}
3434
```
3535

36+
## Allowing empty invitation IDs
37+
38+
Set `allow_empty_id` when using `for_each` over a list of `github_repository_collaborator.invitation_id`'s.
39+
40+
This allows applying a module again when a new `github_repository_collaborator` resource is added to the `for_each` loop.
41+
This is needed as the `github_repository_collaborator.invitation_id` will be empty after a state refresh when the invitation has been accepted.
42+
43+
Note that when an invitation is accepted manually or by another tool between a state refresh and a `terraform apply` using that refreshed state,
44+
the plan will contain the invitation ID, but the apply will receive an HTTP 404 from the API since the invitation has already been accepted.
45+
46+
This is tracked in [#1157](https://github.com/integrations/terraform-provider-github/issues/1157).
47+
3648
## Argument Reference
3749

3850
The following arguments are supported:
3951

40-
* `invitation_id` - (Required) ID of the invitation to accept
52+
* `invitation_id` - (Optional) ID of the invitation to accept. Must be set when `allow_empty_id` is `false`.
53+
* `allow_empty_id` - (Optional) Allow the ID to be unset. This will result in the resource being skipped when the ID is not set instead of returning an error.

0 commit comments

Comments
 (0)