Skip to content

Commit 0e8bafd

Browse files
committed
Add top-level notify to enable setting it without review_request_delegation
Mark nested `notify` as deprecated Signed-off-by: Timo Sand <timo.sand@f-secure.com>
1 parent c7ac7d1 commit 0e8bafd

File tree

3 files changed

+252
-20
lines changed

3 files changed

+252
-20
lines changed

github/resource_github_team_settings.go

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ func resourceGithubTeamSettings() *schema.Resource {
3838
Computed: true,
3939
Description: "The unique ID of the Team on GitHub. Corresponds to the ID of the 'github_team_settings' resource.",
4040
},
41+
"notify": {
42+
Type: schema.TypeBool,
43+
Optional: true,
44+
Default: false,
45+
Description: "Whether to notify the entire team when at least one member is also assigned to the pull request.",
46+
ConflictsWith: []string{"review_request_delegation.0.notify"},
47+
},
4148
"review_request_delegation": {
4249
Type: schema.TypeList,
4350
MaxItems: 1,
@@ -62,10 +69,12 @@ func resourceGithubTeamSettings() *schema.Resource {
6269
)),
6370
},
6471
"notify": {
65-
Type: schema.TypeBool,
66-
Optional: true,
67-
Default: false,
68-
Description: "whether to notify the entire team when at least one member is also assigned to the pull request.",
72+
Type: schema.TypeBool,
73+
Optional: true,
74+
Default: false,
75+
Description: "whether to notify the entire team when at least one member is also assigned to the pull request.",
76+
Deprecated: "Use the top-level notify attribute instead.",
77+
ConflictsWith: []string{"notify"},
6978
},
7079
},
7180
},
@@ -119,13 +128,19 @@ func resourceGithubTeamSettingsCreate(ctx context.Context, d *schema.ResourceDat
119128
"length_of_settings": len(reviewRequestDelegation),
120129
})
121130

131+
notify := resolveNotify(ctx, d)
132+
122133
if len(reviewRequestDelegation) == 0 {
123134
tflog.Debug(ctx, "No review request delegation settings provided, disabling review request delegation", map[string]any{
124135
"team_id": d.Id(),
125136
"team_slug": slug,
137+
"notify": notify,
126138
})
127139

128-
err := graphql.Mutate(ctx, &mutation, defaultTeamReviewAssignmentSettings(d.Id()), nil)
140+
input := defaultTeamReviewAssignmentSettings(d.Id())
141+
input.NotifyTeam = githubv4.NewBoolean(githubv4.Boolean(notify))
142+
143+
err := graphql.Mutate(ctx, &mutation, input, nil)
129144
if err != nil {
130145
return diag.FromErr(err)
131146
}
@@ -134,6 +149,7 @@ func resourceGithubTeamSettingsCreate(ctx context.Context, d *schema.ResourceDat
134149
"team_id": d.Id(),
135150
"team_slug": slug,
136151
"review_request_delegation": reviewRequestDelegation,
152+
"notify": notify,
137153
})
138154
settings := reviewRequestDelegation[0].(map[string]any)
139155

@@ -143,7 +159,7 @@ func resourceGithubTeamSettingsCreate(ctx context.Context, d *schema.ResourceDat
143159
Enabled: githubv4.Boolean(true),
144160
Algorithm: &teamReviewAlgorithm,
145161
TeamMemberCount: githubv4.NewInt(githubv4.Int(settings["member_count"].(int))),
146-
NotifyTeam: githubv4.NewBoolean(githubv4.Boolean(settings["notify"].(bool))),
162+
NotifyTeam: githubv4.NewBoolean(githubv4.Boolean(notify)),
147163
}
148164

149165
err := graphql.Mutate(ctx, &mutation, updateTeamReviewAssignmentInput, nil)
@@ -175,11 +191,29 @@ func resourceGithubTeamSettingsRead(ctx context.Context, d *schema.ResourceData,
175191
return diag.FromErr(err)
176192
}
177193

194+
notifyValue := query.Organization.Team.ReviewRequestDelegationNotifyAll
195+
196+
// Set notify in the location matching the user's config: top-level or
197+
// deprecated nested field inside review_request_delegation.
198+
_, usesDeprecatedNotify := d.GetOk("review_request_delegation.0.notify")
199+
tflog.Debug(ctx, "Uses deprecated notify", map[string]any{
200+
"uses_deprecated_notify": usesDeprecatedNotify,
201+
"notify_value": notifyValue,
202+
})
203+
204+
if !usesDeprecatedNotify {
205+
if err = d.Set("notify", notifyValue); err != nil {
206+
return diag.FromErr(err)
207+
}
208+
}
209+
178210
if query.Organization.Team.ReviewRequestDelegation {
179211
reviewRequestDelegation := make(map[string]any)
180212
reviewRequestDelegation["algorithm"] = query.Organization.Team.ReviewRequestDelegationAlgorithm
181213
reviewRequestDelegation["member_count"] = query.Organization.Team.ReviewRequestDelegationCount
182-
reviewRequestDelegation["notify"] = query.Organization.Team.ReviewRequestDelegationNotifyAll
214+
if usesDeprecatedNotify {
215+
reviewRequestDelegation["notify"] = notifyValue
216+
}
183217
if err = d.Set("review_request_delegation", []any{reviewRequestDelegation}); err != nil {
184218
return diag.FromErr(err)
185219
}
@@ -193,10 +227,11 @@ func resourceGithubTeamSettingsRead(ctx context.Context, d *schema.ResourceData,
193227
}
194228

195229
func resourceGithubTeamSettingsUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
196-
if d.HasChange("review_request_delegation") {
230+
if d.HasChange("review_request_delegation") || d.HasChange("notify") {
197231
meta := m.(*Owner)
198232
graphql := meta.v4client
199233
reviewRequestDelegation := d.Get("review_request_delegation").([]any)
234+
notify := resolveNotify(ctx, d)
200235

201236
var mutation struct {
202237
UpdateTeamReviewAssignment struct {
@@ -208,9 +243,13 @@ func resourceGithubTeamSettingsUpdate(ctx context.Context, d *schema.ResourceDat
208243
tflog.Debug(ctx, "No review request delegation settings provided, disabling review request delegation", map[string]any{
209244
"team_id": d.Id(),
210245
"team_slug": d.Get("team_slug").(string),
246+
"notify": notify,
211247
})
212248

213-
err := graphql.Mutate(ctx, &mutation, defaultTeamReviewAssignmentSettings(d.Id()), nil)
249+
input := defaultTeamReviewAssignmentSettings(d.Id())
250+
input.NotifyTeam = githubv4.NewBoolean(githubv4.Boolean(notify))
251+
252+
err := graphql.Mutate(ctx, &mutation, input, nil)
214253
if err != nil {
215254
return diag.FromErr(err)
216255
}
@@ -223,7 +262,7 @@ func resourceGithubTeamSettingsUpdate(ctx context.Context, d *schema.ResourceDat
223262
Enabled: githubv4.Boolean(true),
224263
Algorithm: &teamReviewAlgorithm,
225264
TeamMemberCount: githubv4.NewInt(githubv4.Int(settings["member_count"].(int))),
226-
NotifyTeam: githubv4.NewBoolean(githubv4.Boolean(settings["notify"].(bool))),
265+
NotifyTeam: githubv4.NewBoolean(githubv4.Boolean(notify)),
227266
}
228267
err := graphql.Mutate(ctx, &mutation, updateTeamReviewAssignmentInput, nil)
229268
if err != nil {
@@ -299,6 +338,30 @@ func resolveTeamIDs(idOrSlug string, meta *Owner, ctx context.Context) (nodeId,
299338
}
300339
}
301340

341+
// resolveNotify returns the notify value from the top-level attribute or the
342+
// deprecated nested attribute inside review_request_delegation. The top-level
343+
// attribute takes precedence. Since ConflictsWith prevents both from being set,
344+
// only one source can be active at a time.
345+
func resolveNotify(ctx context.Context, d *schema.ResourceData) bool {
346+
// Check if top-level notify is explicitly configured.
347+
if v, ok := d.GetOk("notify"); ok {
348+
tflog.Debug(ctx, "Top-level notify is explicitly configured", map[string]any{
349+
"notify": v,
350+
})
351+
return v.(bool)
352+
}
353+
354+
// Fall back to deprecated nested field
355+
if v, ok := d.GetOk("review_request_delegation.0.notify"); ok {
356+
tflog.Debug(ctx, "Deprecated nested notify is explicitly configured", map[string]any{
357+
"notify": v,
358+
})
359+
return v.(bool)
360+
}
361+
362+
return false
363+
}
364+
302365
func defaultTeamReviewAssignmentSettings(id string) githubv4.UpdateTeamReviewAssignmentInput {
303366
roundRobinAlgo := githubv4.TeamReviewAssignmentAlgorithmRoundRobin
304367
return githubv4.UpdateTeamReviewAssignmentInput{

github/resource_github_team_settings_test.go

Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
1212
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
1313
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
14+
"github.com/hashicorp/terraform-plugin-testing/plancheck"
1415
"github.com/hashicorp/terraform-plugin-testing/statecheck"
1516
"github.com/hashicorp/terraform-plugin-testing/terraform"
1617
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
@@ -373,10 +374,10 @@ func TestAccGithubTeamSettings(t *testing.T) {
373374
374375
resource "github_team_settings" "test" {
375376
team_id = github_team.test.id
377+
notify = true
376378
review_request_delegation {
377379
algorithm = "ROUND_ROBIN"
378380
member_count = 2
379-
notify = true
380381
}
381382
}
382383
`, teamName)
@@ -397,13 +398,22 @@ func TestAccGithubTeamSettings(t *testing.T) {
397398
knownvalue.Int64Exact(2)),
398399
statecheck.ExpectKnownValue("github_team_settings.test",
399400
tfjsonpath.New("review_request_delegation").AtSliceIndex(0).AtMapKey("notify"),
401+
knownvalue.Bool(false)),
402+
statecheck.ExpectKnownValue("github_team_settings.test",
403+
tfjsonpath.New("notify"),
400404
knownvalue.Bool(true)),
401405
},
402406
},
403407
{
404-
ResourceName: "github_team_settings.test",
405-
ImportState: true,
406-
ImportStateVerify: true,
408+
ResourceName: "github_team_settings.test",
409+
ImportStateKind: resource.ImportBlockWithID,
410+
ImportState: true,
411+
ImportPlanChecks: resource.ImportPlanChecks{
412+
PreApply: []plancheck.PlanCheck{
413+
plancheck.ExpectKnownValue("github_team_settings.test", tfjsonpath.New("review_request_delegation").AtSliceIndex(0).AtMapKey("notify"), knownvalue.Bool(false)),
414+
plancheck.ExpectKnownValue("github_team_settings.test", tfjsonpath.New("notify"), knownvalue.Bool(true)),
415+
},
416+
},
407417
ImportStateIdFunc: func(s *terraform.State) (string, error) {
408418
rs, ok := s.RootModule().Resources["github_team.test"]
409419
if !ok {
@@ -478,6 +488,149 @@ func TestAccGithubTeamSettings(t *testing.T) {
478488
})
479489
})
480490

491+
t.Run("manages top-level notify without delegation", func(t *testing.T) {
492+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
493+
teamName := fmt.Sprintf("%steam-settings-%s", testResourcePrefix, randomID)
494+
495+
config := `
496+
resource "github_team" "test" {
497+
name = "%s"
498+
description = "generated by terraform provider automated testing"
499+
}
500+
501+
resource "github_team_settings" "test" {
502+
team_id = "${github_team.test.id}"
503+
notify = %t
504+
}
505+
`
506+
507+
resource.ParallelTest(t, resource.TestCase{
508+
PreCheck: func() { skipUnlessHasOrgs(t) },
509+
ProviderFactories: providerFactories,
510+
CheckDestroy: testAccCheckGithubTeamSettingsDestroy,
511+
Steps: []resource.TestStep{
512+
{
513+
Config: fmt.Sprintf(config, teamName, true),
514+
ConfigStateChecks: []statecheck.StateCheck{
515+
statecheck.ExpectKnownValue("github_team_settings.test",
516+
tfjsonpath.New("notify"),
517+
knownvalue.Bool(true)),
518+
statecheck.ExpectKnownValue("github_team_settings.test",
519+
tfjsonpath.New("review_request_delegation"),
520+
knownvalue.ListExact([]knownvalue.Check{})),
521+
},
522+
},
523+
{
524+
Config: fmt.Sprintf(config, teamName, false),
525+
ConfigStateChecks: []statecheck.StateCheck{
526+
statecheck.ExpectKnownValue("github_team_settings.test",
527+
tfjsonpath.New("notify"),
528+
knownvalue.Bool(false)),
529+
statecheck.ExpectKnownValue("github_team_settings.test",
530+
tfjsonpath.New("review_request_delegation"),
531+
knownvalue.ListExact([]knownvalue.Check{})),
532+
},
533+
},
534+
},
535+
})
536+
})
537+
538+
t.Run("manages top-level notify with delegation", func(t *testing.T) {
539+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
540+
teamName := fmt.Sprintf("%steam-settings-%s", testResourcePrefix, randomID)
541+
542+
config := `
543+
resource "github_team" "test" {
544+
name = "%s"
545+
description = "generated by terraform provider automated testing"
546+
}
547+
548+
resource "github_team_settings" "test" {
549+
team_id = "${github_team.test.id}"
550+
notify = %t
551+
review_request_delegation {
552+
algorithm = "ROUND_ROBIN"
553+
member_count = 2
554+
}
555+
}
556+
`
557+
558+
resource.ParallelTest(t, resource.TestCase{
559+
PreCheck: func() { skipUnlessHasOrgs(t) },
560+
ProviderFactories: providerFactories,
561+
CheckDestroy: testAccCheckGithubTeamSettingsDestroy,
562+
Steps: []resource.TestStep{
563+
{
564+
Config: fmt.Sprintf(config, teamName, true),
565+
ConfigStateChecks: []statecheck.StateCheck{
566+
statecheck.ExpectKnownValue("github_team_settings.test",
567+
tfjsonpath.New("notify"),
568+
knownvalue.Bool(true)),
569+
statecheck.ExpectKnownValue("github_team_settings.test",
570+
tfjsonpath.New("review_request_delegation").AtSliceIndex(0).AtMapKey("algorithm"),
571+
knownvalue.StringExact("ROUND_ROBIN")),
572+
statecheck.ExpectKnownValue("github_team_settings.test",
573+
tfjsonpath.New("review_request_delegation").AtSliceIndex(0).AtMapKey("member_count"),
574+
knownvalue.Int64Exact(2)),
575+
},
576+
},
577+
{
578+
Config: fmt.Sprintf(config, teamName, false),
579+
ConfigStateChecks: []statecheck.StateCheck{
580+
statecheck.ExpectKnownValue("github_team_settings.test",
581+
tfjsonpath.New("notify"),
582+
knownvalue.Bool(false)),
583+
},
584+
},
585+
},
586+
})
587+
})
588+
589+
t.Run("imports team settings with top-level notify", func(t *testing.T) {
590+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
591+
teamName := fmt.Sprintf("%steam-settings-%s", testResourcePrefix, randomID)
592+
593+
config := fmt.Sprintf(`
594+
resource "github_team" "test" {
595+
name = "%s"
596+
description = "generated by terraform provider automated testing"
597+
}
598+
599+
resource "github_team_settings" "test" {
600+
team_id = github_team.test.id
601+
notify = true
602+
}
603+
`, teamName)
604+
605+
resource.ParallelTest(t, resource.TestCase{
606+
PreCheck: func() { skipUnlessHasOrgs(t) },
607+
ProviderFactories: providerFactories,
608+
CheckDestroy: testAccCheckGithubTeamSettingsDestroy,
609+
Steps: []resource.TestStep{
610+
{
611+
Config: config,
612+
ConfigStateChecks: []statecheck.StateCheck{
613+
statecheck.ExpectKnownValue("github_team_settings.test",
614+
tfjsonpath.New("notify"),
615+
knownvalue.Bool(true)),
616+
},
617+
},
618+
{
619+
ResourceName: "github_team_settings.test",
620+
ImportState: true,
621+
ImportStateVerify: true,
622+
ImportStateIdFunc: func(s *terraform.State) (string, error) {
623+
rs, ok := s.RootModule().Resources["github_team.test"]
624+
if !ok {
625+
return "", fmt.Errorf("not found: github_team.test")
626+
}
627+
return rs.Primary.Attributes["id"], nil
628+
},
629+
},
630+
},
631+
})
632+
})
633+
481634
t.Run("manages updating only notify field", func(t *testing.T) {
482635
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
483636
teamName := fmt.Sprintf("%steam-settings-%s", testResourcePrefix, randomID)

0 commit comments

Comments
 (0)