Skip to content

Commit

Permalink
[chore] Re-enable remaining linters (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
ph-ph authored Aug 13, 2024
1 parent ed3781d commit 472154a
Show file tree
Hide file tree
Showing 15 changed files with 225 additions and 216 deletions.
9 changes: 0 additions & 9 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,4 @@ issues:
linters:
- gosec
exclude:
- "var-naming:.*Id.* should be .*ID"
- "var-naming:.*Api.* should be .*API"
- "var-naming:.*Http.* should be .*HTTP"
- "exported: exported .* should have comment"
- "exported: comment on exported .* should be of the form"
- "unused-parameter:"
- "ifElseChain:"
- "var-naming:.*ALL_CAPS.*"
- "superfluous-else"
- "Error return value of .* is not checked"
12 changes: 3 additions & 9 deletions internal/acctest/acctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,14 @@ import (
"github.com/tryretool/terraform-provider-retool/internal/sdk/api"
)

const (
ProviderTestConfig = `
provider "retool" {
}
`
)

// This file borrows heavily from Auth0's Terraform provider: https://github.com/auth0/terraform-provider-auth0/blob/main/internal/acctest/acctest.go

var (
providerTestFactories = map[string]func() (tfprotov6.ProviderServer, error){
"retool": providerserver.NewProtocol6WithError(provider.New("test")()),
}
)

// Wrapper around resource.Test that allows for HTTP recordings.
func Test(t *testing.T, testCase resource.TestCase) {
if httpRecordingsAreEnabled() {
httpRecorder := newHTTPRecorder(t)
Expand All @@ -43,6 +36,7 @@ func Test(t *testing.T, testCase resource.TestCase) {
resource.Test(t, testCase)
}

// Init API client to be used by the test sweepers.
func SweeperClient() (*api.APIClient, error) {
host := os.Getenv("RETOOL_HOST")
if host == "" {
Expand Down Expand Up @@ -78,7 +72,7 @@ func httpRecordingsAreEnabled() bool {
func testFactoriesWithHTTPRecordings(httpRecorder *recorder.Recorder) map[string]func() (tfprotov6.ProviderServer, error) {
return map[string]func() (tfprotov6.ProviderServer, error){
"retool": func() (tfprotov6.ProviderServer, error) {
retoolProvider := provider.NewWithHttpClient("test", httpRecorder.GetDefaultClient())()
retoolProvider := provider.NewWithHTTPClient("test", httpRecorder.GetDefaultClient())()
return providerserver.NewProtocol6WithError(retoolProvider)()
},
}
Expand Down
8 changes: 4 additions & 4 deletions internal/acctest/http_recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ const (

// RecordingsHost is used for testing with our recorded http interactions.
// The idea is that no matter which domain you're using to record the requests, the playback will always use this domain.
RecordingsHost = "recorded.retool.dev"
RecordingsScheme = "https"
recordingsHost = "recorded.retool.dev"
recordingsScheme = "https"
)

// NewHTTPRecorder creates a new instance of our http recorder used in tests.
Expand Down Expand Up @@ -99,6 +99,6 @@ func redactHeaders(i *cassette.Interaction) {
}

func redactHostAndScheme(i *cassette.Interaction, host string, scheme string) {
i.Request.Host = strings.ReplaceAll(i.Request.Host, host, RecordingsHost)
i.Request.URL = strings.ReplaceAll(i.Request.URL, scheme+"://"+host, RecordingsScheme+"://"+RecordingsHost)
i.Request.Host = strings.ReplaceAll(i.Request.Host, host, recordingsHost)
i.Request.URL = strings.ReplaceAll(i.Request.URL, scheme+"://"+host, recordingsScheme+"://"+recordingsHost)
}
19 changes: 10 additions & 9 deletions internal/provider/folder/data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/tryretool/terraform-provider-retool/internal/sdk/api"
)

// NewDataSource creates a new data source for folders.
func NewDataSource() datasource.DataSource {
return &foldersDataSource{}
}
Expand All @@ -26,18 +27,18 @@ var (

type foldersDataSource struct {
client *api.APIClient
rootFolderIdCache *map[string]string
rootFolderIDCache *map[string]string
}

type foldersDataSourceModel struct {
Folders []folderModel `tfsdk:"folders"`
}

type folderModel struct {
Id types.String `tfsdk:"id"`
LegacyId types.String `tfsdk:"legacy_id"`
ID types.String `tfsdk:"id"`
LegacyID types.String `tfsdk:"legacy_id"`
Name types.String `tfsdk:"name"`
ParentFolderId types.String `tfsdk:"parent_folder_id"`
ParentFolderID types.String `tfsdk:"parent_folder_id"`
IsSystemFolder types.Bool `tfsdk:"is_system_folder"`
FolderType types.String `tfsdk:"folder_type"`
}
Expand All @@ -61,7 +62,7 @@ func (d *foldersDataSource) Configure(_ context.Context, req datasource.Configur
}

d.client = providerData.Client
d.rootFolderIdCache = providerData.RootFolderIdCache
d.rootFolderIDCache = providerData.RootFolderIDCache
}

func (d *foldersDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
Expand Down Expand Up @@ -107,7 +108,7 @@ func (d *foldersDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
}
}

func (d *foldersDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
func (d *foldersDataSource) Read(ctx context.Context, _ datasource.ReadRequest, resp *datasource.ReadResponse) {
var state foldersDataSourceModel

folders, _, err := d.client.FoldersAPI.FoldersGet(ctx).Execute()
Expand All @@ -123,10 +124,10 @@ func (d *foldersDataSource) Read(ctx context.Context, req datasource.ReadRequest
// Fun fact: even though the response has next_token and has_more fields, the API does not support pagination and always returns all folders.
for _, folder := range folders.Data {
state.Folders = append(state.Folders, folderModel{
Id: types.StringValue(folder.Id),
LegacyId: types.StringValue(folder.LegacyId),
ID: types.StringValue(folder.Id),
LegacyID: types.StringValue(folder.LegacyId),
Name: types.StringValue(folder.Name),
ParentFolderId: types.StringPointerValue(maybeReplaceRootFolderIdWithConstant(ctx, folder.FolderType, folder.ParentFolderId.Get(), d.client, d.rootFolderIdCache, &resp.Diagnostics)),
ParentFolderID: types.StringPointerValue(maybeReplaceRootFolderIDWithConstant(ctx, folder.FolderType, folder.ParentFolderId.Get(), d.client, d.rootFolderIDCache, &resp.Diagnostics)),
IsSystemFolder: types.BoolValue(folder.IsSystemFolder),
FolderType: types.StringValue(folder.FolderType),
})
Expand Down
66 changes: 33 additions & 33 deletions internal/provider/folder/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func NewResource() resource.Resource {
// folderResource is the resource implementation.
type folderResource struct {
client *api.APIClient
rootFolderIdCache *map[string]string
rootFolderIDCache *map[string]string
}

// Configure adds the provider configured client to the resource.
Expand All @@ -54,7 +54,7 @@ func (r *folderResource) Configure(_ context.Context, req resource.ConfigureRequ
)
}
r.client = providerData.Client
r.rootFolderIdCache = providerData.RootFolderIdCache
r.rootFolderIDCache = providerData.RootFolderIDCache
}

// Metadata returns the resource type name.
Expand Down Expand Up @@ -88,7 +88,7 @@ func (r *folderResource) Schema(_ context.Context, _ resource.SchemaRequest, res
Computed: true,
Optional: true,
Description: "The id of the parent folder.",
Default: stringdefault.StaticString(ROOT_FOLDER_ID),
Default: stringdefault.StaticString(RootFolderID),
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
Expand All @@ -114,20 +114,20 @@ func (r *folderResource) Schema(_ context.Context, _ resource.SchemaRequest, res
}
}

func (r *folderResource) getTrueParentFolderId(ctx context.Context, folderType, parentFolderId string, diags *diag.Diagnostics) string {
if parentFolderId == ROOT_FOLDER_ID {
func (r *folderResource) getTrueParentFolderID(ctx context.Context, folderType, parentFolderID string, diags *diag.Diagnostics) string {
if parentFolderID == RootFolderID {
// Get root folder ID.
rootFolderId, err := getRootFolderId(ctx, folderType, r.client, r.rootFolderIdCache)
rootFolderID, err := getRootFolderID(ctx, folderType, r.client, r.rootFolderIDCache)
if err != nil {
diags.AddError(
"Error converting root folder id to the actual id",
"Could not find root folder for type "+folderType+": "+err.Error(),
)
return parentFolderId
return parentFolderID
}
return rootFolderId
return rootFolderID
}
return parentFolderId
return parentFolderID
}

// Create creates the resource and sets the initial Terraform state.
Expand All @@ -142,16 +142,16 @@ func (r *folderResource) Create(ctx context.Context, req resource.CreateRequest,

// Generate API request body from plan.
var folder api.FoldersPostRequest
parentFolderId := r.getTrueParentFolderId(ctx, plan.FolderType.ValueString(), plan.ParentFolderId.ValueString(), &resp.Diagnostics)
parentFolderID := r.getTrueParentFolderID(ctx, plan.FolderType.ValueString(), plan.ParentFolderID.ValueString(), &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

folder.Name = plan.Name.ValueString()
folder.ParentFolderId.Set(&parentFolderId)
folder.ParentFolderId.Set(&parentFolderID)
folder.FolderType = plan.FolderType.ValueString()

tflog.Info(ctx, "Creating a folder", map[string]any{"name": plan.Name.ValueString(), "folderType": plan.FolderType.ValueString(), "parentFolderId": parentFolderId})
tflog.Info(ctx, "Creating a folder", map[string]any{"name": plan.Name.ValueString(), "folderType": plan.FolderType.ValueString(), "parentFolderId": parentFolderID})
// Create new folder.
response, httpResponse, err := r.client.FoldersAPI.FoldersPost(ctx).FoldersPostRequest(folder).Execute()

Expand All @@ -160,14 +160,14 @@ func (r *folderResource) Create(ctx context.Context, req resource.CreateRequest,
"Error creating folder",
"Could not create folder, unexpected error: "+err.Error(),
)
tflog.Error(ctx, "Error creating folder", utils.AddHttpStatusCode(map[string]any{"error": err.Error()}, httpResponse))
tflog.Error(ctx, "Error creating folder", utils.AddHTTPStatusCode(map[string]any{"error": err.Error()}, httpResponse))
return
}
tflog.Info(ctx, "Folder created", map[string]any{"id": response.Data.Id, "legacyId": response.Data.LegacyId, "isSystemFolder": response.Data.IsSystemFolder})

// Map response body to schema and populate Computed attribute values.
plan.Id = types.StringValue(response.Data.Id)
plan.LegacyId = types.StringValue(response.Data.LegacyId)
plan.ID = types.StringValue(response.Data.Id)
plan.LegacyID = types.StringValue(response.Data.LegacyId)
plan.IsSystemFolder = types.BoolValue(response.Data.IsSystemFolder)

// Set state to fully populated data.
Expand All @@ -189,27 +189,27 @@ func (r *folderResource) Read(ctx context.Context, req resource.ReadRequest, res
}

// Get refreshed folder value from Retool API.
tflog.Info(ctx, "Reading folder", map[string]any{"id": state.Id})
response, httpResponse, err := r.client.FoldersAPI.FoldersFolderIdGet(ctx, state.Id.ValueString()).Execute()
tflog.Info(ctx, "Reading folder", map[string]any{"id": state.ID})
response, httpResponse, err := r.client.FoldersAPI.FoldersFolderIdGet(ctx, state.ID.ValueString()).Execute()
if err != nil {
if httpResponse != nil && httpResponse.StatusCode == 404 {
tflog.Info(ctx, "Folder not found", map[string]any{"id": state.Id})
tflog.Info(ctx, "Folder not found", map[string]any{"id": state.ID})
resp.State.RemoveResource(ctx)
return
}
resp.Diagnostics.AddError(
"Error Reading Folder",
"Could not read folder ID "+state.Id.ValueString()+": "+err.Error(),
"Could not read folder ID "+state.ID.ValueString()+": "+err.Error(),
)
tflog.Error(ctx, "Error Reading Folder", utils.AddHttpStatusCode(map[string]any{"error": err.Error()}, httpResponse))
tflog.Error(ctx, "Error Reading Folder", utils.AddHTTPStatusCode(map[string]any{"error": err.Error()}, httpResponse))
return
}

// Update the state.
state.LegacyId = types.StringValue(response.Data.LegacyId)
state.LegacyID = types.StringValue(response.Data.LegacyId)
state.Name = types.StringValue(response.Data.Name)
// To keep the state consistent, we need to convert the root folder ID to the string constant ROOT_FOLDER_ID.
state.ParentFolderId = types.StringPointerValue(maybeReplaceRootFolderIdWithConstant(ctx, response.Data.FolderType, response.Data.ParentFolderId.Get(), r.client, r.rootFolderIdCache, &resp.Diagnostics))
state.ParentFolderID = types.StringPointerValue(maybeReplaceRootFolderIDWithConstant(ctx, response.Data.FolderType, response.Data.ParentFolderId.Get(), r.client, r.rootFolderIDCache, &resp.Diagnostics))
state.IsSystemFolder = types.BoolValue(response.Data.IsSystemFolder)
state.FolderType = types.StringValue(response.Data.FolderType)
if resp.Diagnostics.HasError() {
Expand Down Expand Up @@ -240,9 +240,9 @@ func (r *folderResource) Update(ctx context.Context, req resource.UpdateRequest,
return
}

if plan.Name.Equal(state.Name) && plan.ParentFolderId.Equal(state.ParentFolderId) {
if plan.Name.Equal(state.Name) && plan.ParentFolderID.Equal(state.ParentFolderID) {
// No changes.
tflog.Info(ctx, "No changes detected for folder", map[string]any{"id": state.Id})
tflog.Info(ctx, "No changes detected for folder", map[string]any{"id": state.ID})
return
}

Expand All @@ -253,22 +253,22 @@ func (r *folderResource) Update(ctx context.Context, req resource.UpdateRequest,
op.Value = plan.Name.ValueString()
patchReq.Operations = append(patchReq.Operations, api.FoldersFolderIdPatchRequestOperationsInner{UsersUserIdPatchRequestOperationsInnerAnyOf: op})
}
if !plan.ParentFolderId.Equal(state.ParentFolderId) {
parentFolderId := r.getTrueParentFolderId(ctx, plan.FolderType.ValueString(), plan.ParentFolderId.ValueString(), &resp.Diagnostics)
if !plan.ParentFolderID.Equal(state.ParentFolderID) {
parentFolderID := r.getTrueParentFolderID(ctx, plan.FolderType.ValueString(), plan.ParentFolderID.ValueString(), &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
op := api.NewUsersUserIdPatchRequestOperationsInnerAnyOf("replace", "/parent_folder_id")
op.Value = parentFolderId
op.Value = parentFolderID
patchReq.Operations = append(patchReq.Operations, api.FoldersFolderIdPatchRequestOperationsInner{UsersUserIdPatchRequestOperationsInnerAnyOf: op})
}
_, httpResponse, err := r.client.FoldersAPI.FoldersFolderIdPatch(ctx, state.Id.ValueString()).FoldersFolderIdPatchRequest(patchReq).Execute()
_, httpResponse, err := r.client.FoldersAPI.FoldersFolderIdPatch(ctx, state.ID.ValueString()).FoldersFolderIdPatchRequest(patchReq).Execute()
if err != nil {
resp.Diagnostics.AddError(
"Error Updating Folder",
"Could not update folder "+state.Id.ValueString()+", unexpected error: "+err.Error(),
"Could not update folder "+state.ID.ValueString()+", unexpected error: "+err.Error(),
)
tflog.Error(ctx, "Error Updating Folder", utils.AddHttpStatusCode(map[string]any{"error": err.Error()}, httpResponse))
tflog.Error(ctx, "Error Updating Folder", utils.AddHTTPStatusCode(map[string]any{"error": err.Error()}, httpResponse))
return
}

Expand All @@ -294,13 +294,13 @@ func (r *folderResource) Delete(ctx context.Context, req resource.DeleteRequest,
deleteRequest := api.FoldersFolderIdDeleteRequest{}
deleteRequest.Recursive = &recursive

httpResponse, err := r.client.FoldersAPI.FoldersFolderIdDelete(ctx, state.Id.ValueString()).FoldersFolderIdDeleteRequest(deleteRequest).Execute()
httpResponse, err := r.client.FoldersAPI.FoldersFolderIdDelete(ctx, state.ID.ValueString()).FoldersFolderIdDeleteRequest(deleteRequest).Execute()
if err != nil && !(httpResponse != nil && httpResponse.StatusCode == 404) { // It's ok to not find the resource being deleted.
resp.Diagnostics.AddError(
"Error Deleting Folder",
"Could not delete folder"+state.Id.ValueString()+", unexpected error: "+err.Error(),
"Could not delete folder"+state.ID.ValueString()+", unexpected error: "+err.Error(),
)
tflog.Error(ctx, "Error Deleting Folder", utils.AddHttpStatusCode(map[string]any{"error": err.Error()}, httpResponse))
tflog.Error(ctx, "Error Deleting Folder", utils.AddHTTPStatusCode(map[string]any{"error": err.Error()}, httpResponse))
return
}
}
Expand Down
23 changes: 12 additions & 11 deletions internal/provider/folder/root_folder_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ import (
"github.com/tryretool/terraform-provider-retool/internal/sdk/api"
)

const ROOT_FOLDER_ID string = "ROOT"
// Fake "id" that we use to represent the root folder.
const RootFolderID string = "ROOT"

func getRootFolderId(ctx context.Context, folderType string, client *api.APIClient, cache *map[string]string) (string, error) {
func getRootFolderID(ctx context.Context, folderType string, client *api.APIClient, cache *map[string]string) (string, error) {
if cache != nil {
if rootFolderId, ok := (*cache)[folderType]; ok {
return rootFolderId, nil
if rootFolderID, ok := (*cache)[folderType]; ok {
return rootFolderID, nil
}
}
tflog.Info(ctx, "Getting root folder ID", map[string]any{"folderType": folderType})
response, httpResponse, err := client.FoldersAPI.FoldersGet(ctx).Execute()
if err != nil {
tflog.Error(ctx, "Error getting root folder ID", utils.AddHttpStatusCode(map[string]any{"error": err.Error()}, httpResponse))
tflog.Error(ctx, "Error getting root folder ID", utils.AddHTTPStatusCode(map[string]any{"error": err.Error()}, httpResponse))
return "", err
}

Expand All @@ -39,20 +40,20 @@ func getRootFolderId(ctx context.Context, folderType string, client *api.APIClie
return "", fmt.Errorf("root folder not found for type %s", folderType)
}

func maybeReplaceRootFolderIdWithConstant(ctx context.Context, folderType string, folderId *string, client *api.APIClient, cache *map[string]string, diags *diag.Diagnostics) *string {
if folderId != nil {
rootFolderId, err := getRootFolderId(ctx, folderType, client, cache)
func maybeReplaceRootFolderIDWithConstant(ctx context.Context, folderType string, folderID *string, client *api.APIClient, cache *map[string]string, diags *diag.Diagnostics) *string {
if folderID != nil {
rootFolderID, err := getRootFolderID(ctx, folderType, client, cache)
if err != nil {
diags.AddError(
"Error reading folder",
"Could not find root folder for type "+folderType+": "+err.Error(),
)
return nil
}
if *folderId == rootFolderId {
tempStr := ROOT_FOLDER_ID
if *folderID == rootFolderID {
tempStr := RootFolderID
return &tempStr
}
}
return folderId
return folderID
}
Loading

0 comments on commit 472154a

Please sign in to comment.