@@ -3,30 +3,24 @@ package github
33import (
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
1618func 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