Skip to content

Commit 6798857

Browse files
committed
feat: Fixup repository environment logic
Signed-off-by: Steve Hipwell <steve.hipwell@gmail.com>
1 parent 68741e0 commit 6798857

11 files changed

+1146
-865
lines changed

github/resource_github_repository_environment.go

Lines changed: 78 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,24 @@ package github
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"log"
78
"net/http"
89
"net/url"
910

1011
"github.com/google/go-github/v82/github"
1112
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
1214
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1315
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
1416
)
1517

1618
func resourceGithubRepositoryEnvironment() *schema.Resource {
1719
return &schema.Resource{
18-
CreateContext: resourceGithubRepositoryEnvironmentCreate,
19-
ReadContext: resourceGithubRepositoryEnvironmentRead,
20-
UpdateContext: resourceGithubRepositoryEnvironmentUpdate,
21-
DeleteContext: resourceGithubRepositoryEnvironmentDelete,
22-
Importer: &schema.ResourceImporter{
23-
StateContext: resourceGithubRepositoryEnvironmentImport,
24-
},
2520
Schema: map[string]*schema.Schema{
2621
"repository": {
2722
Type: schema.TypeString,
2823
Required: true,
29-
ForceNew: true,
3024
Description: "The repository of the environment.",
3125
},
3226
"environment": {
@@ -50,26 +44,28 @@ func resourceGithubRepositoryEnvironment() *schema.Resource {
5044
"wait_timer": {
5145
Type: schema.TypeInt,
5246
Optional: true,
53-
ValidateDiagFunc: toDiagFunc(validation.IntBetween(0, 43200), "wait_timer"),
47+
ValidateDiagFunc: validation.ToDiagFunc(validation.IntBetween(0, 43200)),
5448
Description: "Amount of time to delay a job after the job is initially triggered.",
5549
},
5650
"reviewers": {
5751
Type: schema.TypeList,
5852
Optional: true,
59-
MaxItems: 6,
53+
MaxItems: 1,
6054
Description: "The environment reviewers configuration.",
6155
Elem: &schema.Resource{
6256
Schema: map[string]*schema.Schema{
6357
"teams": {
6458
Type: schema.TypeSet,
65-
Optional: true,
6659
Elem: &schema.Schema{Type: schema.TypeInt},
60+
Optional: true,
61+
MaxItems: 6,
6762
Description: "Up to 6 IDs for teams who may review jobs that reference the environment. Reviewers must have at least read access to the repository. Only one of the required reviewers needs to approve the job for it to proceed.",
6863
},
6964
"users": {
7065
Type: schema.TypeSet,
71-
Optional: true,
7266
Elem: &schema.Schema{Type: schema.TypeInt},
67+
Optional: true,
68+
MaxItems: 6,
7369
Description: "Up to 6 IDs for users who may review jobs that reference the environment. Reviewers must have at least read access to the repository. Only one of the required reviewers needs to approve the job for it to proceed.",
7470
},
7571
},
@@ -96,12 +92,50 @@ func resourceGithubRepositoryEnvironment() *schema.Resource {
9692
},
9793
},
9894
},
95+
96+
CustomizeDiff: customdiff.All(
97+
diffRepository,
98+
resourceGithubRepositoryEnvironmentDiff,
99+
),
100+
101+
CreateContext: resourceGithubRepositoryEnvironmentCreate,
102+
ReadContext: resourceGithubRepositoryEnvironmentRead,
103+
UpdateContext: resourceGithubRepositoryEnvironmentUpdate,
104+
DeleteContext: resourceGithubRepositoryEnvironmentDelete,
105+
Importer: &schema.ResourceImporter{
106+
StateContext: resourceGithubRepositoryEnvironmentImport,
107+
},
99108
}
100109
}
101110

102-
func resourceGithubRepositoryEnvironmentCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
103-
client := meta.(*Owner).v3client
104-
owner := meta.(*Owner).name
111+
func resourceGithubRepositoryEnvironmentDiff(_ context.Context, d *schema.ResourceDiff, _ any) error {
112+
if d.Id() == "" {
113+
return nil
114+
}
115+
116+
if v, ok := d.GetOk("reviewers"); ok {
117+
o := v.([]any)[0]
118+
r := 0
119+
if t, ok := o.(map[string]any)["teams"]; ok {
120+
r += t.(*schema.Set).Len()
121+
}
122+
123+
if t, ok := o.(map[string]any)["users"]; ok {
124+
r += t.(*schema.Set).Len()
125+
}
126+
127+
if r > 6 {
128+
return fmt.Errorf("a maximum of 6 reviewers (users and teams combined) can be set for an environment")
129+
}
130+
}
131+
132+
return nil
133+
}
134+
135+
func resourceGithubRepositoryEnvironmentCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
136+
meta := m.(*Owner)
137+
client := meta.v3client
138+
owner := meta.name
105139

106140
repoName := d.Get("repository").(string)
107141
envName := d.Get("environment").(string)
@@ -121,38 +155,36 @@ func resourceGithubRepositoryEnvironmentCreate(ctx context.Context, d *schema.Re
121155
return nil
122156
}
123157

124-
func resourceGithubRepositoryEnvironmentRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
125-
client := meta.(*Owner).v3client
126-
owner := meta.(*Owner).name
158+
func resourceGithubRepositoryEnvironmentRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
159+
meta := m.(*Owner)
160+
client := meta.v3client
161+
owner := meta.name
127162

128-
repoName, envNamePart, err := parseID2(d.Id())
129-
if err != nil {
130-
return diag.FromErr(err)
131-
}
132-
133-
envName := unescapeIDPart(envNamePart)
163+
repoName := d.Get("repository").(string)
164+
envName := d.Get("environment").(string)
134165

135166
env, _, err := client.Repositories.GetEnvironment(ctx, owner, repoName, url.PathEscape(envName))
136167
if err != nil {
137168
var ghErr *github.ErrorResponse
138169
if errors.As(err, &ghErr) {
139170
if ghErr.Response.StatusCode == http.StatusNotFound {
140-
log.Printf("[INFO] Removing repository environment %s from state because it no longer exists in GitHub",
141-
d.Id())
171+
log.Printf("[INFO] Removing repository environment %s from state because it no longer exists in GitHub", d.Id())
142172
d.SetId("")
143173
return nil
144174
}
145175
}
146176
return diag.FromErr(err)
147177
}
148178

149-
_ = d.Set("repository", repoName)
150-
_ = d.Set("environment", envName)
151-
_ = d.Set("wait_timer", nil)
152-
_ = d.Set("can_admins_bypass", env.CanAdminsBypass)
179+
if err := d.Set("wait_timer", nil); err != nil {
180+
return diag.FromErr(err)
181+
}
182+
if err := d.Set("can_admins_bypass", env.CanAdminsBypass); err != nil {
183+
return diag.FromErr(err)
184+
}
153185

154186
for _, pr := range env.ProtectionRules {
155-
switch *pr.Type {
187+
switch pr.GetType() {
156188
case "wait_timer":
157189
if err = d.Set("wait_timer", pr.WaitTimer); err != nil {
158190
return diag.FromErr(err)
@@ -199,15 +231,18 @@ func resourceGithubRepositoryEnvironmentRead(ctx context.Context, d *schema.Reso
199231
return diag.FromErr(err)
200232
}
201233
} else {
202-
_ = d.Set("deployment_branch_policy", []any{})
234+
if err := d.Set("deployment_branch_policy", []any{}); err != nil {
235+
return diag.FromErr(err)
236+
}
203237
}
204238

205239
return nil
206240
}
207241

208-
func resourceGithubRepositoryEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
209-
client := meta.(*Owner).v3client
210-
owner := meta.(*Owner).name
242+
func resourceGithubRepositoryEnvironmentUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
243+
meta := m.(*Owner)
244+
client := meta.v3client
245+
owner := meta.name
211246

212247
repoName := d.Get("repository").(string)
213248
envName := d.Get("environment").(string)
@@ -227,26 +262,23 @@ func resourceGithubRepositoryEnvironmentUpdate(ctx context.Context, d *schema.Re
227262
return nil
228263
}
229264

230-
func resourceGithubRepositoryEnvironmentDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
231-
client := meta.(*Owner).v3client
232-
owner := meta.(*Owner).name
265+
func resourceGithubRepositoryEnvironmentDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
266+
meta := m.(*Owner)
267+
client := meta.v3client
268+
owner := meta.name
233269

234-
repoName, envNamePart, err := parseID2(d.Id())
235-
if err != nil {
236-
return diag.FromErr(err)
237-
}
238-
239-
envName := unescapeIDPart(envNamePart)
270+
repoName := d.Get("repository").(string)
271+
envName := d.Get("environment").(string)
240272

241-
_, err = client.Repositories.DeleteEnvironment(ctx, owner, repoName, url.PathEscape(envName))
273+
_, err := client.Repositories.DeleteEnvironment(ctx, owner, repoName, url.PathEscape(envName))
242274
if err != nil {
243275
return diag.FromErr(deleteResourceOn404AndSwallow304OtherwiseReturnError(err, d, "environment (%s)", envName))
244276
}
245277

246278
return nil
247279
}
248280

249-
func resourceGithubRepositoryEnvironmentImport(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) {
281+
func resourceGithubRepositoryEnvironmentImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) {
250282
repoName, envNamePart, err := parseID2(d.Id())
251283
if err != nil {
252284
return nil, err

0 commit comments

Comments
 (0)