Skip to content

Commit

Permalink
Merge pull request #106 from jfrog/fix-api-error-handling
Browse files Browse the repository at this point in the history
Fix api error handling
  • Loading branch information
alexhung authored Mar 14, 2024
2 parents 6529c0f + 13b00fe commit 41ce2b5
Show file tree
Hide file tree
Showing 16 changed files with 284 additions and 63 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.5.1 (March 14, 2024)

BUG FIXES:

* Fix HTTP response error handling due to change of behavior (for better consistency) from Resty client. PR: [#106](https://github.com/jfrog/terraform-provider-project/pull/106)

## 1.5.0 (March 13, 2024)

FEATURES:
Expand Down
8 changes: 8 additions & 0 deletions docs/resources/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,11 @@ Required:
Optional:

- `description` (String)

## Import

Import is supported using the following syntax:

```shell
terraform import project.myproject myproj
```
1 change: 1 addition & 0 deletions examples/resources/project/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import project.myproject myproj
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0
github.com/hashicorp/terraform-plugin-testing v1.7.0
github.com/jfrog/terraform-provider-shared v1.22.0
github.com/samber/lo v1.39.0
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
Expand Down
25 changes: 22 additions & 3 deletions pkg/project/membership.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package project
import (
"context"
"fmt"
"net/http"

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

membership := Membership{}

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParams(map[string]string{
"projectKey": projectKey,
"membershipType": membershipType,
}).
SetResult(&membership).
SetError(&projectError).
Get(projectMembershipsUrl)
if err != nil {
return nil, err
}
if resp.IsError() {
return nil, fmt.Errorf("%s", projectError.String())
}

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

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

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParams(map[string]string{
"projectKey": projectKey,
"membershipType": membershipType,
"memberName": member.Name,
}).
SetBody(member).
SetError(&projectError).
Put(projectMembershipUrl)
if err != nil {
return err
}
if resp.IsError() {
return fmt.Errorf("%s", projectError.String())
}

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

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParams(map[string]string{
"projectKey": projectKey,
"membershipType": membershipType,
"memberName": member.Name,
}).
SetError(&projectError).
Delete(projectMembershipUrl)
if err != nil {
return err
}
if resp.IsError() && resp.StatusCode() != http.StatusNotFound {
return fmt.Errorf("%s", projectError.String())
}

return nil
}
47 changes: 28 additions & 19 deletions pkg/project/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,19 @@ var readRepos = func(ctx context.Context, projectKey string, m interface{}) ([]R

artifactoryRepos := []ArtifactoryRepo{}

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParam("projectKey", projectKey).
SetResult(&artifactoryRepos).
SetError(&projectError).
Get("/artifactory/api/repositories?project={projectKey}")

if err != nil {
return nil, err
}
if resp.IsError() {
return nil, fmt.Errorf("%s", projectError.String())
}

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

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

_, err := req.
var projectError ProjectErrorsResponse
resp, err := req.
SetPathParams(map[string]string{
"projectKey": projectKey,
"repoKey": string(repoKey),
}).
SetQueryParam("force", "true").
SetError(&projectError).
Put(projectsUrl + "/_/attach/repositories/{repoKey}/{projectKey}")
if err != nil {
return err
}
if resp.IsError() {
return fmt.Errorf("%s", projectError.String())
}

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

type Error struct {
Code string `json:"code"`
Message string `json:"message"`
}

type ErrorResponse struct {
Errors []Error `json:"errors"`
}

var errorResp ErrorResponse

var projectError ProjectErrorsResponse
resp, err := req.
SetPathParam("repoKey", string(repoKey)).
SetError(&errorResp).
SetError(&projectError).
Delete(projectsUrl + "/_/attach/repositories/{repoKey}")

if err != nil {
return err
}

// Ignore 404 NOT_FOUND error when unassigning repo from project
// Possible that repo was deleted out-of-band from TF
if resp.StatusCode() == http.StatusNotFound && len(errorResp.Errors) > 0 {
for _, error := range errorResp.Errors {
if error.Code == "NOT_FOUND" {
tflog.Warn(ctx, fmt.Sprintf("failed to unassign repo: %s", error.Message))
if resp.StatusCode() == http.StatusNotFound && len(projectError.Errors) > 0 {
for _, e := range projectError.Errors {
if e.Code == "NOT_FOUND" {
tflog.Warn(ctx, fmt.Sprintf("failed to unassign repo: %s", e.Message))
return nil
}
}
} else if resp.IsError() {
return fmt.Errorf("%s", projectError.String())
}

return err
return nil
}
40 changes: 33 additions & 7 deletions pkg/project/resource_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,23 @@ func projectResource() *schema.Resource {
var readProject = func(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics {
project := Project{}

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParam("projectKey", data.Id()).
SetResult(&project).
SetError(&projectError).
Get(projectUrl)

if err != nil {
return diag.FromErr(err)
}
if resp.StatusCode() == http.StatusNotFound {
data.SetId("")
return nil
}
if resp.IsError() {
return diag.Errorf("%s", projectError.String())
}

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

_, err = m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetBody(project).
SetError(&projectError).
Post(projectsUrl)
if err != nil {
return diag.FromErr(err)
}
if resp.IsError() {
return diag.Errorf("%s", projectError.String())
}

data.SetId(project.Id())

Expand Down Expand Up @@ -547,13 +562,18 @@ func projectResource() *schema.Resource {
return diag.FromErr(err)
}

_, err = m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParam("projectKey", data.Id()).
SetBody(project).
SetError(&projectError).
Put(projectUrl)
if err != nil {
return diag.FromErr(err)
}
if resp.IsError() {
return diag.Errorf("%s", projectError.String())
}

data.SetId(project.Id())

Expand Down Expand Up @@ -615,16 +635,22 @@ func projectResource() *schema.Resource {
},
)

resp, err := req.
var projectError ProjectErrorsResponse
res, err := req.
SetPathParam("projectKey", data.Id()).
SetError(&projectError).
Delete(projectUrl)

if err != nil {
if resp.StatusCode() == http.StatusNotFound {
data.SetId("")
}
return diag.FromErr(err)
}
if res.StatusCode() == http.StatusNotFound {
data.SetId("")
return nil
}
if res.IsError() {
return diag.Errorf("%s", projectError.String())
}

return nil
}
Expand Down
34 changes: 30 additions & 4 deletions pkg/project/resource_project_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package project
import (
"context"
"fmt"
"net/http"
"regexp"
"strings"

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

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParam("projectKey", projectKey).
SetResult(&envs).
SetError(&projectError).
Get(projectEnvironmentUrl)
if err != nil {
return diag.FromErr(err)
}
if resp.StatusCode() == http.StatusNotFound {
data.SetId("")
return nil
}
if resp.IsError() {
return diag.Errorf("%s", projectError.String())
}

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

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParam("projectKey", projectKey).
SetBody(projectEnvironment).
SetError(&projectError).
Post(projectEnvironmentUrl)
if err != nil {
return diag.FromErr(err)
}
if resp.IsError() {
return diag.Errorf("%s", projectError.String())
}

data.SetId(projectEnvironment.Id())

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

_, err := m.(util.ProvderMetadata).Client.R().
var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParams(map[string]string{
"projectKey": projectKey,
"environmentName": fmt.Sprintf("%s-%s", projectKey, oldName),
}).
SetBody(projectEnvironmentUpdate).
SetError(&projectError).
Post(projectEnvironmentUrl + "/{environmentName}/rename")
if err != nil {
return diag.FromErr(err)
}
if resp.IsError() {
return diag.Errorf("%s", projectError.String())
}

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

var deleteProjectEnvironment = func(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics {
projectKey := data.Get("project_key").(string)
_, err := m.(util.ProvderMetadata).Client.R().

var projectError ProjectErrorsResponse
resp, err := m.(util.ProvderMetadata).Client.R().
SetPathParams(map[string]string{
"projectKey": projectKey,
"environmentName": fmt.Sprintf("%s-%s", projectKey, data.Get("name")),
}).
SetError(&projectError).
Delete(projectEnvironmentUrl + "/{environmentName}")
if err != nil {
return diag.FromErr(err)
}
if resp.IsError() && resp.StatusCode() != http.StatusNotFound {
return diag.Errorf("%s", projectError.String())
}

data.SetId("")

Expand Down
Loading

0 comments on commit 41ce2b5

Please sign in to comment.