Skip to content

Commit 97ea997

Browse files
author
Alex Hung
committed
Fix HTTP response error handling
Previous version of Resty will set error to non-nil even for HTTP response error. Now it no longer does (matching Golang Http client). Thus we need to add code to handle http response error. Update project resource doc for import
1 parent 6529c0f commit 97ea997

14 files changed

+277
-61
lines changed

docs/resources/project.md

+8
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,11 @@ Required:
141141
Optional:
142142

143143
- `description` (String)
144+
145+
## Import
146+
147+
Import is supported using the following syntax:
148+
149+
```shell
150+
terraform import project.myproject myproj
151+
```

examples/resources/project/import.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
terraform import project.myproject myproj

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0
1111
github.com/hashicorp/terraform-plugin-testing v1.7.0
1212
github.com/jfrog/terraform-provider-shared v1.22.0
13+
github.com/samber/lo v1.39.0
1314
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
1415
)
1516

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO
177177
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
178178
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
179179
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
180+
github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
181+
github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
180182
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
181183
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
182184
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=

pkg/project/membership.go

+22-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package project
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67

78
"github.com/hashicorp/terraform-plugin-log/tflog"
89
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -101,16 +102,21 @@ var readMembers = func(ctx context.Context, projectKey string, membershipType st
101102

102103
membership := Membership{}
103104

104-
_, err := m.(util.ProvderMetadata).Client.R().
105+
var projectError ProjectErrorsResponse
106+
resp, err := m.(util.ProvderMetadata).Client.R().
105107
SetPathParams(map[string]string{
106108
"projectKey": projectKey,
107109
"membershipType": membershipType,
108110
}).
109111
SetResult(&membership).
112+
SetError(&projectError).
110113
Get(projectMembershipsUrl)
111114
if err != nil {
112115
return nil, err
113116
}
117+
if resp.IsError() {
118+
return nil, fmt.Errorf("%s", projectError.String())
119+
}
114120

115121
tflog.Trace(ctx, fmt.Sprintf("readMembers: %+v\n", membership))
116122

@@ -163,14 +169,22 @@ var updateMember = func(ctx context.Context, projectKey string, membershipType s
163169
return fmt.Errorf("invalid membershipType: %s", membershipType)
164170
}
165171

166-
_, err := m.(util.ProvderMetadata).Client.R().
172+
var projectError ProjectErrorsResponse
173+
resp, err := m.(util.ProvderMetadata).Client.R().
167174
SetPathParams(map[string]string{
168175
"projectKey": projectKey,
169176
"membershipType": membershipType,
170177
"memberName": member.Name,
171178
}).
172179
SetBody(member).
180+
SetError(&projectError).
173181
Put(projectMembershipUrl)
182+
if err != nil {
183+
return err
184+
}
185+
if resp.IsError() {
186+
return fmt.Errorf("%s", projectError.String())
187+
}
174188

175189
return err
176190
}
@@ -196,16 +210,21 @@ var deleteMember = func(ctx context.Context, projectKey string, membershipType s
196210
return fmt.Errorf("invalid membershipType: %s", membershipType)
197211
}
198212

199-
_, err := m.(util.ProvderMetadata).Client.R().
213+
var projectError ProjectErrorsResponse
214+
resp, err := m.(util.ProvderMetadata).Client.R().
200215
SetPathParams(map[string]string{
201216
"projectKey": projectKey,
202217
"membershipType": membershipType,
203218
"memberName": member.Name,
204219
}).
220+
SetError(&projectError).
205221
Delete(projectMembershipUrl)
206222
if err != nil {
207223
return err
208224
}
225+
if resp.IsError() && resp.StatusCode() != http.StatusNotFound {
226+
return fmt.Errorf("%s", projectError.String())
227+
}
209228

210229
return nil
211230
}

pkg/project/repo.go

+28-19
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,19 @@ var readRepos = func(ctx context.Context, projectKey string, m interface{}) ([]R
5454

5555
artifactoryRepos := []ArtifactoryRepo{}
5656

57-
_, err := m.(util.ProvderMetadata).Client.R().
57+
var projectError ProjectErrorsResponse
58+
resp, err := m.(util.ProvderMetadata).Client.R().
5859
SetPathParam("projectKey", projectKey).
5960
SetResult(&artifactoryRepos).
61+
SetError(&projectError).
6062
Get("/artifactory/api/repositories?project={projectKey}")
6163

6264
if err != nil {
6365
return nil, err
6466
}
67+
if resp.IsError() {
68+
return nil, fmt.Errorf("%s", projectError.String())
69+
}
6570

6671
tflog.Trace(ctx, fmt.Sprintf("artifactoryRepos: %+v\n", artifactoryRepos))
6772

@@ -127,13 +132,21 @@ var addRepos = func(ctx context.Context, projectKey string, repoKeys []RepoKey,
127132
var addRepo = func(ctx context.Context, projectKey string, repoKey RepoKey, req *resty.Request) error {
128133
tflog.Debug(ctx, fmt.Sprintf("addRepo: %s", repoKey))
129134

130-
_, err := req.
135+
var projectError ProjectErrorsResponse
136+
resp, err := req.
131137
SetPathParams(map[string]string{
132138
"projectKey": projectKey,
133139
"repoKey": string(repoKey),
134140
}).
135141
SetQueryParam("force", "true").
142+
SetError(&projectError).
136143
Put(projectsUrl + "/_/attach/repositories/{repoKey}/{projectKey}")
144+
if err != nil {
145+
return err
146+
}
147+
if resp.IsError() {
148+
return fmt.Errorf("%s", projectError.String())
149+
}
137150

138151
return err
139152
}
@@ -159,32 +172,28 @@ var deleteRepos = func(ctx context.Context, repoKeys []RepoKey, m interface{}) e
159172
var deleteRepo = func(ctx context.Context, repoKey RepoKey, req *resty.Request) error {
160173
tflog.Debug(ctx, fmt.Sprintf("deleteRepo: %s", repoKey))
161174

162-
type Error struct {
163-
Code string `json:"code"`
164-
Message string `json:"message"`
165-
}
166-
167-
type ErrorResponse struct {
168-
Errors []Error `json:"errors"`
169-
}
170-
171-
var errorResp ErrorResponse
172-
175+
var projectError ProjectErrorsResponse
173176
resp, err := req.
174177
SetPathParam("repoKey", string(repoKey)).
175-
SetError(&errorResp).
178+
SetError(&projectError).
176179
Delete(projectsUrl + "/_/attach/repositories/{repoKey}")
177180

181+
if err != nil {
182+
return err
183+
}
184+
178185
// Ignore 404 NOT_FOUND error when unassigning repo from project
179186
// Possible that repo was deleted out-of-band from TF
180-
if resp.StatusCode() == http.StatusNotFound && len(errorResp.Errors) > 0 {
181-
for _, error := range errorResp.Errors {
182-
if error.Code == "NOT_FOUND" {
183-
tflog.Warn(ctx, fmt.Sprintf("failed to unassign repo: %s", error.Message))
187+
if resp.StatusCode() == http.StatusNotFound && len(projectError.Errors) > 0 {
188+
for _, e := range projectError.Errors {
189+
if e.Code == "NOT_FOUND" {
190+
tflog.Warn(ctx, fmt.Sprintf("failed to unassign repo: %s", e.Message))
184191
return nil
185192
}
186193
}
194+
} else if resp.IsError() {
195+
return fmt.Errorf("%s", projectError.String())
187196
}
188197

189-
return err
198+
return nil
190199
}

pkg/project/resource_project.go

+33-7
Original file line numberDiff line numberDiff line change
@@ -437,13 +437,23 @@ func projectResource() *schema.Resource {
437437
var readProject = func(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics {
438438
project := Project{}
439439

440-
_, err := m.(util.ProvderMetadata).Client.R().
440+
var projectError ProjectErrorsResponse
441+
resp, err := m.(util.ProvderMetadata).Client.R().
441442
SetPathParam("projectKey", data.Id()).
442443
SetResult(&project).
444+
SetError(&projectError).
443445
Get(projectUrl)
446+
444447
if err != nil {
445448
return diag.FromErr(err)
446449
}
450+
if resp.StatusCode() == http.StatusNotFound {
451+
data.SetId("")
452+
return nil
453+
}
454+
if resp.IsError() {
455+
return diag.Errorf("%s", projectError.String())
456+
}
447457

448458
users := []Member{}
449459
useProjectUserResource := data.Get("use_project_user_resource").(bool)
@@ -493,12 +503,17 @@ func projectResource() *schema.Resource {
493503
return diag.FromErr(err)
494504
}
495505

496-
_, err = m.(util.ProvderMetadata).Client.R().
506+
var projectError ProjectErrorsResponse
507+
resp, err := m.(util.ProvderMetadata).Client.R().
497508
SetBody(project).
509+
SetError(&projectError).
498510
Post(projectsUrl)
499511
if err != nil {
500512
return diag.FromErr(err)
501513
}
514+
if resp.IsError() {
515+
return diag.Errorf("%s", projectError.String())
516+
}
502517

503518
data.SetId(project.Id())
504519

@@ -547,13 +562,18 @@ func projectResource() *schema.Resource {
547562
return diag.FromErr(err)
548563
}
549564

550-
_, err = m.(util.ProvderMetadata).Client.R().
565+
var projectError ProjectErrorsResponse
566+
resp, err := m.(util.ProvderMetadata).Client.R().
551567
SetPathParam("projectKey", data.Id()).
552568
SetBody(project).
569+
SetError(&projectError).
553570
Put(projectUrl)
554571
if err != nil {
555572
return diag.FromErr(err)
556573
}
574+
if resp.IsError() {
575+
return diag.Errorf("%s", projectError.String())
576+
}
557577

558578
data.SetId(project.Id())
559579

@@ -615,16 +635,22 @@ func projectResource() *schema.Resource {
615635
},
616636
)
617637

618-
resp, err := req.
638+
var projectError ProjectErrorsResponse
639+
res, err := req.
619640
SetPathParam("projectKey", data.Id()).
641+
SetError(&projectError).
620642
Delete(projectUrl)
621643

622644
if err != nil {
623-
if resp.StatusCode() == http.StatusNotFound {
624-
data.SetId("")
625-
}
626645
return diag.FromErr(err)
627646
}
647+
if res.StatusCode() == http.StatusNotFound {
648+
data.SetId("")
649+
return nil
650+
}
651+
if res.IsError() {
652+
return diag.Errorf("%s", projectError.String())
653+
}
628654

629655
return nil
630656
}

pkg/project/resource_project_environment.go

+30-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package project
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"regexp"
78
"strings"
89

@@ -57,13 +58,22 @@ func projectEnvironmentResource() *schema.Resource {
5758
projectKey := data.Get("project_key").(string)
5859
var envs []ProjectEnvironment
5960

60-
_, err := m.(util.ProvderMetadata).Client.R().
61+
var projectError ProjectErrorsResponse
62+
resp, err := m.(util.ProvderMetadata).Client.R().
6163
SetPathParam("projectKey", projectKey).
6264
SetResult(&envs).
65+
SetError(&projectError).
6366
Get(projectEnvironmentUrl)
6467
if err != nil {
6568
return diag.FromErr(err)
6669
}
70+
if resp.StatusCode() == http.StatusNotFound {
71+
data.SetId("")
72+
return nil
73+
}
74+
if resp.IsError() {
75+
return diag.Errorf("%s", projectError.String())
76+
}
6777

6878
var matchedEnv *ProjectEnvironment
6979
for _, env := range envs {
@@ -91,13 +101,18 @@ func projectEnvironmentResource() *schema.Resource {
91101
Name: fmt.Sprintf("%s-%s", projectKey, data.Get("name").(string)),
92102
}
93103

94-
_, err := m.(util.ProvderMetadata).Client.R().
104+
var projectError ProjectErrorsResponse
105+
resp, err := m.(util.ProvderMetadata).Client.R().
95106
SetPathParam("projectKey", projectKey).
96107
SetBody(projectEnvironment).
108+
SetError(&projectError).
97109
Post(projectEnvironmentUrl)
98110
if err != nil {
99111
return diag.FromErr(err)
100112
}
113+
if resp.IsError() {
114+
return diag.Errorf("%s", projectError.String())
115+
}
101116

102117
data.SetId(projectEnvironment.Id())
103118

@@ -112,16 +127,21 @@ func projectEnvironmentResource() *schema.Resource {
112127
NewName: fmt.Sprintf("%s-%s", projectKey, newName),
113128
}
114129

115-
_, err := m.(util.ProvderMetadata).Client.R().
130+
var projectError ProjectErrorsResponse
131+
resp, err := m.(util.ProvderMetadata).Client.R().
116132
SetPathParams(map[string]string{
117133
"projectKey": projectKey,
118134
"environmentName": fmt.Sprintf("%s-%s", projectKey, oldName),
119135
}).
120136
SetBody(projectEnvironmentUpdate).
137+
SetError(&projectError).
121138
Post(projectEnvironmentUrl + "/{environmentName}/rename")
122139
if err != nil {
123140
return diag.FromErr(err)
124141
}
142+
if resp.IsError() {
143+
return diag.Errorf("%s", projectError.String())
144+
}
125145

126146
data.SetId(projectEnvironmentUpdate.Id())
127147
data.Set("name", newName)
@@ -131,15 +151,21 @@ func projectEnvironmentResource() *schema.Resource {
131151

132152
var deleteProjectEnvironment = func(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics {
133153
projectKey := data.Get("project_key").(string)
134-
_, err := m.(util.ProvderMetadata).Client.R().
154+
155+
var projectError ProjectErrorsResponse
156+
resp, err := m.(util.ProvderMetadata).Client.R().
135157
SetPathParams(map[string]string{
136158
"projectKey": projectKey,
137159
"environmentName": fmt.Sprintf("%s-%s", projectKey, data.Get("name")),
138160
}).
161+
SetError(&projectError).
139162
Delete(projectEnvironmentUrl + "/{environmentName}")
140163
if err != nil {
141164
return diag.FromErr(err)
142165
}
166+
if resp.IsError() && resp.StatusCode() != http.StatusNotFound {
167+
return diag.Errorf("%s", projectError.String())
168+
}
143169

144170
data.SetId("")
145171

0 commit comments

Comments
 (0)