@@ -3,32 +3,40 @@ package github
33import (
44 "context"
55 "errors"
6- "log "
6+ "fmt "
77 "net/http"
88 "net/url"
99
1010 "github.com/google/go-github/v83/github"
11+ "github.com/hashicorp/terraform-plugin-log/tflog"
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 ,
20+ SchemaVersion : 1 ,
21+ StateUpgraders : []schema.StateUpgrader {
22+ {
23+ Type : resourceGithubRepositoryEnvironmentV0 ().CoreConfigSchema ().ImpliedType (),
24+ Upgrade : resourceGithubRepositoryEnvironmentStateUpgradeV0 ,
25+ Version : 0 ,
26+ },
2427 },
28+
2529 Schema : map [string ]* schema.Schema {
2630 "repository" : {
2731 Type : schema .TypeString ,
2832 Required : true ,
29- ForceNew : true ,
3033 Description : "The repository of the environment." ,
3134 },
35+ "repository_id" : {
36+ Description : "The ID of the GitHub repository." ,
37+ Type : schema .TypeInt ,
38+ Computed : true ,
39+ },
3240 "environment" : {
3341 Type : schema .TypeString ,
3442 Required : true ,
@@ -56,20 +64,22 @@ func resourceGithubRepositoryEnvironment() *schema.Resource {
5664 "reviewers" : {
5765 Type : schema .TypeList ,
5866 Optional : true ,
59- MaxItems : 6 ,
67+ MaxItems : 1 ,
6068 Description : "The environment reviewers configuration." ,
6169 Elem : & schema.Resource {
6270 Schema : map [string ]* schema.Schema {
6371 "teams" : {
6472 Type : schema .TypeSet ,
65- Optional : true ,
6673 Elem : & schema.Schema {Type : schema .TypeInt },
74+ Optional : true ,
75+ MaxItems : 6 ,
6776 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." ,
6877 },
6978 "users" : {
7079 Type : schema .TypeSet ,
71- Optional : true ,
7280 Elem : & schema.Schema {Type : schema .TypeInt },
81+ Optional : true ,
82+ MaxItems : 6 ,
7383 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." ,
7484 },
7585 },
@@ -96,12 +106,50 @@ func resourceGithubRepositoryEnvironment() *schema.Resource {
96106 },
97107 },
98108 },
109+
110+ CustomizeDiff : customdiff .All (
111+ diffRepository ,
112+ resourceGithubRepositoryEnvironmentDiff ,
113+ ),
114+
115+ CreateContext : resourceGithubRepositoryEnvironmentCreate ,
116+ ReadContext : resourceGithubRepositoryEnvironmentRead ,
117+ UpdateContext : resourceGithubRepositoryEnvironmentUpdate ,
118+ DeleteContext : resourceGithubRepositoryEnvironmentDelete ,
119+ Importer : & schema.ResourceImporter {
120+ StateContext : resourceGithubRepositoryEnvironmentImport ,
121+ },
122+ }
123+ }
124+
125+ func resourceGithubRepositoryEnvironmentDiff (_ context.Context , d * schema.ResourceDiff , _ any ) error {
126+ if d .Id () == "" {
127+ return nil
128+ }
129+
130+ if v , ok := d .GetOk ("reviewers" ); ok {
131+ count := 0
132+ o := v .([]any )[0 ]
133+ if t , ok := o .(map [string ]any )["teams" ]; ok {
134+ count += t .(* schema.Set ).Len ()
135+ }
136+
137+ if t , ok := o .(map [string ]any )["users" ]; ok {
138+ count += t .(* schema.Set ).Len ()
139+ }
140+
141+ if count > 6 {
142+ return fmt .Errorf ("a maximum of 6 reviewers (users and teams combined) can be set for an environment" )
143+ }
99144 }
145+
146+ return nil
100147}
101148
102- func resourceGithubRepositoryEnvironmentCreate (ctx context.Context , d * schema.ResourceData , meta any ) diag.Diagnostics {
103- client := meta .(* Owner ).v3client
104- owner := meta .(* Owner ).name
149+ func resourceGithubRepositoryEnvironmentCreate (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
150+ meta := m .(* Owner )
151+ client := meta .v3client
152+ owner := meta .name
105153
106154 repoName := d .Get ("repository" ).(string )
107155 envName := d .Get ("environment" ).(string )
@@ -118,41 +166,50 @@ func resourceGithubRepositoryEnvironmentCreate(ctx context.Context, d *schema.Re
118166 }
119167 d .SetId (id )
120168
169+ repo , _ , err := client .Repositories .Get (ctx , owner , repoName )
170+ if err != nil {
171+ return diag .FromErr (err )
172+ }
173+
174+ if err := d .Set ("repository_id" , int (repo .GetID ())); err != nil {
175+ return diag .FromErr (err )
176+ }
177+
121178 return nil
122179}
123180
124- func resourceGithubRepositoryEnvironmentRead (ctx context.Context , d * schema.ResourceData , meta any ) diag.Diagnostics {
125- client := meta .(* Owner ).v3client
126- owner := meta .(* Owner ).name
181+ func resourceGithubRepositoryEnvironmentRead (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
182+ ctx = tflog .SetField (ctx , "id" , d .Id ())
127183
128- repoName , envNamePart , err := parseID2 (d .Id ())
129- if err != nil {
130- return diag .FromErr (err )
131- }
184+ meta := m .(* Owner )
185+ client := meta .v3client
186+ owner := meta .name
132187
133- envName := unescapeIDPart (envNamePart )
188+ repoName := d .Get ("repository" ).(string )
189+ envName := d .Get ("environment" ).(string )
134190
135191 env , _ , err := client .Repositories .GetEnvironment (ctx , owner , repoName , url .PathEscape (envName ))
136192 if err != nil {
137193 var ghErr * github.ErrorResponse
138194 if errors .As (err , & ghErr ) {
139195 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 ())
196+ tflog .Info (ctx , "Repository environment not found, removing from state." , map [string ]any {"repository" : repoName , "environment" : envName })
142197 d .SetId ("" )
143198 return nil
144199 }
145200 }
146201 return diag .FromErr (err )
147202 }
148203
149- _ = d .Set ("repository" , repoName )
150- _ = d .Set ("environment" , envName )
151- _ = d .Set ("wait_timer" , nil )
152- _ = d .Set ("can_admins_bypass" , env .CanAdminsBypass )
204+ if err := d .Set ("wait_timer" , nil ); err != nil {
205+ return diag .FromErr (err )
206+ }
207+ if err := d .Set ("can_admins_bypass" , env .CanAdminsBypass ); err != nil {
208+ return diag .FromErr (err )
209+ }
153210
154211 for _ , pr := range env .ProtectionRules {
155- switch * pr .Type {
212+ switch pr .GetType () {
156213 case "wait_timer" :
157214 if err = d .Set ("wait_timer" , pr .WaitTimer ); err != nil {
158215 return diag .FromErr (err )
@@ -199,15 +256,18 @@ func resourceGithubRepositoryEnvironmentRead(ctx context.Context, d *schema.Reso
199256 return diag .FromErr (err )
200257 }
201258 } else {
202- _ = d .Set ("deployment_branch_policy" , []any {})
259+ if err := d .Set ("deployment_branch_policy" , []any {}); err != nil {
260+ return diag .FromErr (err )
261+ }
203262 }
204263
205264 return nil
206265}
207266
208- func resourceGithubRepositoryEnvironmentUpdate (ctx context.Context , d * schema.ResourceData , meta any ) diag.Diagnostics {
209- client := meta .(* Owner ).v3client
210- owner := meta .(* Owner ).name
267+ func resourceGithubRepositoryEnvironmentUpdate (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
268+ meta := m .(* Owner )
269+ client := meta .v3client
270+ owner := meta .name
211271
212272 repoName := d .Get ("repository" ).(string )
213273 envName := d .Get ("environment" ).(string )
@@ -227,34 +287,43 @@ func resourceGithubRepositoryEnvironmentUpdate(ctx context.Context, d *schema.Re
227287 return nil
228288}
229289
230- func resourceGithubRepositoryEnvironmentDelete (ctx context.Context , d * schema.ResourceData , meta any ) diag.Diagnostics {
231- client := meta .(* Owner ).v3client
232- owner := meta .(* Owner ).name
290+ func resourceGithubRepositoryEnvironmentDelete (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
291+ meta := m .(* Owner )
292+ client := meta .v3client
293+ owner := meta .name
233294
234- repoName , envNamePart , err := parseID2 (d .Id ())
235- if err != nil {
236- return diag .FromErr (err )
237- }
238-
239- envName := unescapeIDPart (envNamePart )
295+ repoName := d .Get ("repository" ).(string )
296+ envName := d .Get ("environment" ).(string )
240297
241- _ , err = client .Repositories .DeleteEnvironment (ctx , owner , repoName , url .PathEscape (envName ))
298+ _ , err : = client .Repositories .DeleteEnvironment (ctx , owner , repoName , url .PathEscape (envName ))
242299 if err != nil {
243300 return diag .FromErr (deleteResourceOn404AndSwallow304OtherwiseReturnError (err , d , "environment (%s)" , envName ))
244301 }
245302
246303 return nil
247304}
248305
249- func resourceGithubRepositoryEnvironmentImport (ctx context.Context , d * schema.ResourceData , meta any ) ([]* schema.ResourceData , error ) {
306+ func resourceGithubRepositoryEnvironmentImport (ctx context.Context , d * schema.ResourceData , m any ) ([]* schema.ResourceData , error ) {
307+ meta := m .(* Owner )
308+ client := meta .v3client
309+ owner := meta .name
310+
250311 repoName , envNamePart , err := parseID2 (d .Id ())
251312 if err != nil {
252- return nil , err
313+ return nil , fmt .Errorf ("invalid id (%s), expected format <repository>:<environment>" , d .Id ())
314+ }
315+
316+ repo , _ , err := client .Repositories .Get (ctx , owner , repoName )
317+ if err != nil {
318+ return nil , fmt .Errorf ("failed to retrieve repository %s: %w" , repoName , err )
253319 }
254320
255321 if err := d .Set ("repository" , repoName ); err != nil {
256322 return nil , err
257323 }
324+ if err := d .Set ("repository_id" , int (repo .GetID ())); err != nil {
325+ return nil , err
326+ }
258327 if err := d .Set ("environment" , unescapeIDPart (envNamePart )); err != nil {
259328 return nil , err
260329 }
0 commit comments