Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add the contentstack_environment resource #23

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func (p *provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq
func (p *provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceType, diag.Diagnostics) {
return map[string]tfsdk.ResourceType{
"contentstack_content_type": resourceContentTypeType{},
"contentstack_environment": resourceEnvironmentType{},
"contentstack_global_field": resourceGlobalFieldType{},
"contentstack_locale": resourceLocaleType{},
"contentstack_webhook": resourceWebhookType{},
Expand Down
231 changes: 231 additions & 0 deletions internal/provider/resource_environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package provider

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/labd/contentstack-go-sdk/management"
)

type resourceEnvironmentType struct{}

type EnvironmentData struct {
UID types.String `tfsdk:"uid"`
Name types.String `tfsfk:"name"`
URLs []EnvironmentUrlData `tfsdk:"url"`
}

type EnvironmentUrlData struct {
Locale types.String `tfsdk:"locale"`
URL types.String `tfsdk:"url"`
}

// Environment Resource schema
func (r resourceEnvironmentType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
Description: `
Contentstack environment are designated destinations to which you can publish
your content. Environments are global, meaning they are available across all
branches of your stack. An environment can also have a list of URLs to be used
as a prefix for published content.
`,
Attributes: map[string]tfsdk.Attribute{
"uid": {
Type: types.StringType,
Computed: true,
},
"name": {
Type: types.StringType,
Required: true,
},
},
Blocks: map[string]tfsdk.Block{
"url": {
NestingMode: tfsdk.BlockNestingModeList,
Blocks: map[string]tfsdk.Block{},
MinItems: 0,
Attributes: map[string]tfsdk.Attribute{
"locale": {
Type: types.StringType,
Required: true,
},
"url": {
Type: types.StringType,
Required: true,
},
},
},
},
}, nil
}

// New resource instance
func (r resourceEnvironmentType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
return resourceEnvironment{
p: *(p.(*provider)),
}, nil
}

type resourceEnvironment struct {
p provider
}

func (r resourceEnvironment) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var plan EnvironmentData
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

input := NewEnvironmentInput(&plan)
environment, err := r.p.stack.EnvironmentCreate(ctx, *input)
if err != nil {
diags := processRemoteError(err)
resp.Diagnostics.Append(diags...)
return
}

diags = processResponse(environment, input)
resp.Diagnostics.Append(diags...)

// Write to state
state := NewEnvironmentData(environment)
diags = resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}

func (r resourceEnvironment) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var state EnvironmentData
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

environment, err := r.p.stack.EnvironmentFetch(ctx, state.UID.Value)
if err != nil {
if IsNotFoundError(err) {
d := diag.NewErrorDiagnostic(
"Error retrieving environment",
fmt.Sprintf("The environment with UID %s was not found.", state.UID.Value))
resp.Diagnostics.Append(d)
} else {
diags := processRemoteError(err)
resp.Diagnostics.Append(diags...)
}
return
}

curr := NewEnvironmentInput(&state)
diags = processResponse(environment, curr)
resp.Diagnostics.Append(diags...)

// Set state
newState := NewEnvironmentData(environment)
diags = resp.State.Set(ctx, &newState)
resp.Diagnostics.Append(diags...)
}

func (r resourceEnvironment) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var state EnvironmentData
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Delete environment by calling API
err := r.p.stack.EnvironmentDelete(ctx, state.UID.Value)
if err != nil {
diags = processRemoteError(err)
resp.Diagnostics.Append(diags...)
return
}

// Remove resource from state
resp.State.RemoveResource(ctx)
}

func (r resourceEnvironment) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
// Get plan values
var plan EnvironmentData
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Get current state
var state EnvironmentData
diags = req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

input := NewEnvironmentInput(&plan)
environment, err := r.p.stack.EnvironmentUpdate(ctx, state.UID.Value, *input)
if err != nil {
diags = processRemoteError(err)
resp.Diagnostics.Append(diags...)
return
}

diags = processResponse(environment, input)
resp.Diagnostics.Append(diags...)

// Set state
result := NewEnvironmentData(environment)
diags = resp.State.Set(ctx, result)
resp.Diagnostics.Append(diags...)
}

func (r resourceEnvironment) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) {
tfsdk.ResourceImportStatePassthroughID(ctx, tftypes.NewAttributePath().WithAttributeName("id"), req, resp)
}

func NewEnvironmentData(environment *management.Environment) *EnvironmentData {
urls := []EnvironmentUrlData{}
for i := range environment.URLs {
s := environment.URLs[i]

url := EnvironmentUrlData{
Locale: types.String{Value: s.Locale},
URL: types.String{Value: s.URL},
}

urls = append(urls, url)
}

state := &EnvironmentData{
UID: types.String{Value: environment.UID},
Name: types.String{Value: environment.Name},
URLs: urls,
}
return state
}

func NewEnvironmentInput(environment *EnvironmentData) *management.EnvironmentInput {
urls := []management.EnvironmentUrl{}
for i := range environment.URLs {
s := environment.URLs[i]
url := management.EnvironmentUrl{
Locale: s.Locale.Value,
URL: s.URL.Value,
}

urls = append(urls, url)
}

input := &management.EnvironmentInput{
Name: environment.Name.Value,
URLs: urls,
}

return input
}