@@ -3,21 +3,22 @@ package github
33import (
44 "context"
55 "errors"
6- "log"
76 "net/http"
87
98 "github.com/google/go-github/v88/github"
9+ "github.com/hashicorp/terraform-plugin-log/tflog"
10+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1011 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1112)
1213
1314func resourceGithubIssueLabel () * schema.Resource {
1415 return & schema.Resource {
15- Create : resourceGithubIssueLabelCreateOrUpdate ,
16- Read : resourceGithubIssueLabelRead ,
17- Update : resourceGithubIssueLabelCreateOrUpdate ,
18- Delete : resourceGithubIssueLabelDelete ,
16+ CreateContext : resourceGithubIssueLabelCreate ,
17+ ReadContext : resourceGithubIssueLabelRead ,
18+ UpdateContext : resourceGithubIssueLabelUpdate ,
19+ DeleteContext : resourceGithubIssueLabelDelete ,
1920 Importer : & schema.ResourceImporter {
20- StateContext : schema . ImportStatePassthroughContext ,
21+ StateContext : resourceGithubIssueLabelImport ,
2122 },
2223
2324 Schema : map [string ]* schema.Schema {
@@ -60,150 +61,220 @@ func resourceGithubIssueLabel() *schema.Resource {
6061 }
6162}
6263
63- // resourceGithubIssueLabelCreateOrUpdate idempotently creates or updates an
64- // issue label. Issue labels are keyed off of their "name", so pre-existing
65- // issue labels result in a 422 HTTP error if they exist outside of Terraform.
66- // Normally this would not be an issue, except new repositories are created with
67- // a "default" set of labels, and those labels easily conflict with custom ones.
68- //
69- // This function will first check if the label exists, and then issue an update,
70- // otherwise it will create. This is also advantageous in that we get to use the
71- // same function for two schema funcs.
72-
73- func resourceGithubIssueLabelCreateOrUpdate (d * schema.ResourceData , meta any ) error {
74- client := meta .(* Owner ).v3client
75- orgName := meta .(* Owner ).name
76- repoName := d .Get ("repository" ).(string )
77- name := d .Get ("name" ).(string )
78- color := d .Get ("color" ).(string )
64+ // resourceGithubIssueLabelCreate creates an issue label.
65+ func resourceGithubIssueLabelCreate (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
66+ meta , diags := getIssueLabelOwner (m )
67+ if diags .HasError () {
68+ return diags
69+ }
70+ client := meta .v3client
71+ orgName := meta .name
72+ repoName , diags := getIssueLabelStringAttribute (d , "repository" )
73+ if diags .HasError () {
74+ return diags
75+ }
76+ name , diags := getIssueLabelStringAttribute (d , "name" )
77+ if diags .HasError () {
78+ return diags
79+ }
80+ color , diags := getIssueLabelStringAttribute (d , "color" )
81+ if diags .HasError () {
82+ return diags
83+ }
7984
8085 label := & github.Label {
8186 Name : new (name ),
8287 Color : new (color ),
8388 }
84- ctx := context .Background ()
85- if ! d .IsNewResource () {
86- ctx = context .WithValue (ctx , ctxId , d .Id ())
87- }
88-
89- // Pull out the original name. If we already have a resource, this is the
90- // parsed ID. If not, it's the value given to the resource.
91- var originalName string
92- if d .Id () == "" {
93- originalName = name
94- } else {
95- var err error
96- _ , originalName , err = parseID2 (d .Id ())
97- if err != nil {
98- return err
89+
90+ if v , ok := d .GetOk ("description" ); ok {
91+ description , ok := v .(string )
92+ if ! ok {
93+ return diag .Errorf (`expected "description" to be string` )
9994 }
95+ label .Description = & description
10096 }
10197
102- existing , resp , err := client .Issues .GetLabel (ctx ,
103- orgName , repoName , originalName )
104- if err != nil && resp .StatusCode != http .StatusNotFound {
105- return err
98+ githubLabel , resp , err := client .Issues .CreateLabel (ctx , orgName , repoName , label )
99+ if err != nil {
100+ return diag .FromErr (err )
106101 }
107-
108- if existing != nil {
109- label .Description = new (d.Get ("description" ).(string ))
110-
111- // Pull out the original name. If we already have a resource, this is the
112- // parsed ID. If not, it's the value given to the resource.
113- var originalName string
114- if d .Id () == "" {
115- originalName = name
116- } else {
117- var err error
118- _ , originalName , err = parseID2 (d .Id ())
119- if err != nil {
120- return err
121- }
122- }
123-
124- _ , _ , err := client .Issues .EditLabel (ctx ,
125- orgName , repoName , originalName , label )
126- if err != nil {
127- return err
128- }
129- } else {
130- if v , ok := d .GetOk ("description" ); ok {
131- label .Description = new (v .(string ))
132- }
133-
134- _ , _ , err := client .Issues .CreateLabel (ctx ,
135- orgName , repoName , label )
136- if err != nil {
137- return err
138- }
102+ id , err := buildID (repoName , name )
103+ if err != nil {
104+ return diag .FromErr (err )
105+ }
106+ d .SetId (id )
107+ if err := d .Set ("url" , githubLabel .GetURL ()); err != nil {
108+ return diag .FromErr (err )
139109 }
140110
141- d .SetId (buildTwoPartID (repoName , name ))
142-
143- return resourceGithubIssueLabelRead (d , meta )
111+ if err := d .Set ("etag" , resp .Header .Get ("ETag" )); err != nil {
112+ return diag .FromErr (err )
113+ }
114+ return nil
144115}
145116
146- func resourceGithubIssueLabelRead (d * schema.ResourceData , meta any ) error {
147- client := meta .(* Owner ).v3client
148- repoName , name , err := parseID2 (d .Id ())
149- if err != nil {
150- return err
117+ func resourceGithubIssueLabelRead (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
118+ meta , diags := getIssueLabelOwner (m )
119+ if diags .HasError () {
120+ return diags
121+ }
122+ client := meta .v3client
123+ repoName , diags := getIssueLabelStringAttribute (d , "repository" )
124+ if diags .HasError () {
125+ return diags
126+ }
127+ name , diags := getIssueLabelStringAttribute (d , "name" )
128+ if diags .HasError () {
129+ return diags
151130 }
152131
153- orgName := meta .(* Owner ).name
154- ctx := context .WithValue (context .Background (), ctxId , d .Id ())
132+ orgName := meta .name
155133 if ! d .IsNewResource () {
156- ctx = context .WithValue (ctx , ctxEtag , d .Get ("etag" ).(string ))
134+ etag , diags := getIssueLabelStringAttribute (d , "etag" )
135+ if diags .HasError () {
136+ return diags
137+ }
138+ ctx = context .WithValue (ctx , ctxEtag , etag )
157139 }
158140
159- githubLabel , resp , err := client .Issues .GetLabel (ctx ,
160- orgName , repoName , name )
141+ githubLabel , resp , err := client .Issues .GetLabel (ctx , orgName , repoName , name )
161142 if err != nil {
162143 var ghErr * github.ErrorResponse
163144 if errors .As (err , & ghErr ) {
164145 if ghErr .Response .StatusCode == http .StatusNotModified {
165146 return nil
166147 }
167148 if ghErr .Response .StatusCode == http .StatusNotFound {
168- log .Printf ("[INFO] Removing label %s (%s/%s) from state because it no longer exists in GitHub" ,
169- name , orgName , repoName )
149+ tflog .Info (ctx , "Removing label from state because it no longer exists in GitHub" , map [string ]any {"name" : name , "org_name" : orgName , "repo_name" : repoName })
170150 d .SetId ("" )
171151 return nil
172152 }
173153 }
174- return err
154+ return diag . FromErr ( err )
175155 }
176156
177157 if err = d .Set ("etag" , resp .Header .Get ("ETag" )); err != nil {
178- return err
158+ return diag . FromErr ( err )
179159 }
180- if err = d .Set ("repository" , repoName ); err != nil {
181- return err
160+ if err = d .Set ("url" , githubLabel .GetURL ()); err != nil {
161+ return diag .FromErr (err )
162+ }
163+
164+ return nil
165+ }
166+
167+ func resourceGithubIssueLabelUpdate (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
168+ meta , diags := getIssueLabelOwner (m )
169+ if diags .HasError () {
170+ return diags
182171 }
183- if err = d .Set ("name" , name ); err != nil {
184- return err
172+ client := meta .v3client
173+ orgName := meta .name
174+ repoName , diags := getIssueLabelStringAttribute (d , "repository" )
175+ if diags .HasError () {
176+ return diags
185177 }
186- if err = d .Set ("color" , githubLabel .GetColor ()); err != nil {
187- return err
178+ name , diags := getIssueLabelStringAttribute (d , "name" )
179+ if diags .HasError () {
180+ return diags
188181 }
189- if err = d .Set ("description" , githubLabel .GetDescription ()); err != nil {
190- return err
182+ color , diags := getIssueLabelStringAttribute (d , "color" )
183+ if diags .HasError () {
184+ return diags
191185 }
192- if err = d .Set ("url" , githubLabel .GetURL ()); err != nil {
193- return err
186+
187+ originalName := name
188+ if d .HasChange ("name" ) {
189+ oldName , _ := d .GetChange ("name" )
190+ oldNameString , ok := oldName .(string )
191+ if ! ok {
192+ return diag .Errorf (`expected old "name" to be string` )
193+ }
194+ originalName = oldNameString
195+ }
196+ label := & github.Label {
197+ Name : new (name ),
198+ Color : new (color ),
199+ }
200+ if v , ok := d .GetOk ("description" ); ok {
201+ description , ok := v .(string )
202+ if ! ok {
203+ return diag .Errorf (`expected "description" to be string` )
204+ }
205+ label .Description = & description
206+ }
207+ githubLabel , resp , err := client .Issues .EditLabel (ctx , orgName , repoName , originalName , label )
208+ if err != nil {
209+ return diag .FromErr (err )
210+ }
211+ id , err := buildID (repoName , name )
212+ if err != nil {
213+ return diag .FromErr (err )
214+ }
215+ d .SetId (id )
216+
217+ if err := d .Set ("url" , githubLabel .GetURL ()); err != nil {
218+ return diag .FromErr (err )
219+ }
220+
221+ if err := d .Set ("etag" , resp .Header .Get ("ETag" )); err != nil {
222+ return diag .FromErr (err )
194223 }
195224
196225 return nil
197226}
198227
199- func resourceGithubIssueLabelDelete (d * schema.ResourceData , meta any ) error {
200- client := meta .(* Owner ).v3client
228+ func resourceGithubIssueLabelDelete (ctx context.Context , d * schema.ResourceData , m any ) diag.Diagnostics {
229+ meta , diags := getIssueLabelOwner (m )
230+ if diags .HasError () {
231+ return diags
232+ }
233+ client := meta .v3client
201234
202- orgName := meta .(* Owner ).name
203- repoName := d .Get ("repository" ).(string )
204- name := d .Get ("name" ).(string )
205- ctx := context .WithValue (context .Background (), ctxId , d .Id ())
235+ orgName := meta .name
236+ repoName , diags := getIssueLabelStringAttribute (d , "repository" )
237+ if diags .HasError () {
238+ return diags
239+ }
240+ name , diags := getIssueLabelStringAttribute (d , "name" )
241+ if diags .HasError () {
242+ return diags
243+ }
206244
207245 _ , err := client .Issues .DeleteLabel (ctx , orgName , repoName , name )
208- return handleArchivedRepoDelete (err , "issue label" , name , orgName , repoName )
246+ return diag .FromErr (handleArchivedRepoDelete (err , "issue label" , name , orgName , repoName ))
247+ }
248+
249+ func resourceGithubIssueLabelImport (_ context.Context , d * schema.ResourceData , _ any ) ([]* schema.ResourceData , error ) {
250+ repoName , name , err := parseID2 (d .Id ())
251+ if err != nil {
252+ return nil , err
253+ }
254+
255+ if err := d .Set ("repository" , repoName ); err != nil {
256+ return nil , err
257+ }
258+
259+ if err := d .Set ("name" , name ); err != nil {
260+ return nil , err
261+ }
262+
263+ return []* schema.ResourceData {d }, nil
264+ }
265+
266+ func getIssueLabelOwner (m any ) (* Owner , diag.Diagnostics ) {
267+ meta , ok := m .(* Owner )
268+ if ! ok {
269+ return nil , diag .Errorf ("expected *Owner, got %T" , m )
270+ }
271+ return meta , nil
272+ }
273+
274+ func getIssueLabelStringAttribute (d * schema.ResourceData , key string ) (string , diag.Diagnostics ) {
275+ value , ok := d .Get (key ).(string )
276+ if ! ok {
277+ return "" , diag .Errorf ("expected %q to be string" , key )
278+ }
279+ return value , nil
209280}
0 commit comments