Skip to content

Commit

Permalink
Improved client error handling and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mmuller-tines committed Dec 4, 2024
1 parent 8c33f0a commit 7913c82
Show file tree
Hide file tree
Showing 14 changed files with 516 additions and 76 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Unshallow
run: git fetch --prune --unshallow
- name: Set up Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
with:
go-version-file: "go.mod"
cache: true
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@111c56156bcc6918c056dbef52164cfa583dc549 # v5.2.0
uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # v6.2.0
id: import_gpg
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@f82d6c1c344bcacabba2c841718984797f664a6b # v4.2.0
uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0
with:
version: latest
args: release --rm-dist
Expand Down
9 changes: 8 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ description: |-
# Tines Provider

The Tines provider is used to interact with resources supported by Tines.
The provider needs to be configured with the proper credentials before it can be used.
The provider needs to be configured with the proper credentials before it can be used.

## Upgrading Versions
Because the Tines Terraform provider is still under active development, breaking changes
may occur in minor versions for any 0.x.x release. Future stable versions (1.x.x and above)
will follow SemVer principles for backwards compatibility in minor and patch version updates.

Be sure to read the version upgrade guides to understand any breaking changes before upgrading.

## Example Usage

Expand Down
2 changes: 1 addition & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (p *TinesProvider) Configure(ctx context.Context, req provider.ConfigureReq
}

// Create a new Tines client using the configuration values.
c, err := tines_cli.NewClient(&tenant, &apiKey, &p.version)
c, err := tines_cli.NewClient(tenant, apiKey, p.version)
if err != nil {
resp.Diagnostics.AddError(
"Unable to Create Tines API Client",
Expand Down
97 changes: 75 additions & 22 deletions internal/provider/story_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,24 +121,17 @@ func (r *storyResource) Schema(ctx context.Context, _ resource.SchemaRequest, re
Description: "Tines tenant URL",
Optional: true,
DeprecationMessage: "Value will be overridden by the value set in the provider credentials. This field will be removed in a future version.",
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"team_id": schema.Int64Attribute{
Description: "The ID of the team that this story belongs to.",
Required: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.RequiresReplace(),
},
},
"folder_id": schema.Int64Attribute{
Description: "The ID of the folder where this story should be organized. The folder ID must belong to the associated team that owns this story.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.UseStateForUnknown(),
int64planmodifier.RequiresReplace(),
},
},
"name": schema.StringAttribute{
Expand All @@ -152,6 +145,9 @@ func (r *storyResource) Schema(ctx context.Context, _ resource.SchemaRequest, re
"user_id": schema.Int64Attribute{
Description: "ID of the story creator.",
Computed: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.UseStateForUnknown(),
},
},
"description": schema.StringAttribute{
Description: "A user-defined description of the story.",
Expand Down Expand Up @@ -471,8 +467,17 @@ func (r *storyResource) Read(ctx context.Context, req resource.ReadRequest, resp
return
}

status, remoteState, err := r.client.GetStory(localState.ID.ValueInt64())
remoteState, err := r.client.GetStory(localState.ID.ValueInt64())
if err != nil {
// Treat HTTP 404 Not Found status as a signal to recreate resource
// and return early.
if tinesErr, ok := err.(tines_cli.Error); ok {
if tinesErr.StatusCode == 404 {
resp.State.RemoveResource(ctx)
return
}
}

resp.Diagnostics.AddError(
"Unable to Refresh Resource",
"An unexpected error occurred while attempting to refresh resource state. "+
Expand All @@ -482,13 +487,6 @@ func (r *storyResource) Read(ctx context.Context, req resource.ReadRequest, resp
return
}

// Treat HTTP 404 Not Found status as a signal to recreate resource
// and return early.
if status == 404 {
resp.State.RemoveResource(ctx)
return
}

diags := r.convertStoryToPlan(ctx, &localState, remoteState)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
Expand All @@ -507,15 +505,20 @@ func (r *storyResource) Read(ctx context.Context, req resource.ReadRequest, resp
func (r *storyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
tflog.Info(ctx, "Updating Story")

var plan storyResourceModel
var plan, state storyResourceModel
var story *tines_cli.Story
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
diags = req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

if !plan.Data.IsNull() {
if !plan.Data.IsNull() && !plan.Data.Equal(state.Data) {
tflog.Info(ctx, "Exported Story payload detected, using the Import strategy")
story, diags = r.runImportStory(&plan)
resp.Diagnostics.Append(diags...)
Expand Down Expand Up @@ -675,13 +678,60 @@ func (r *storyResource) convertPlanToStory(ctx context.Context, plan *storyResou
story.KeepEventsFor = plan.KeepEventsFor.ValueInt64()
}

if !plan.Disabled.IsNull() && !plan.Disabled.IsUnknown() {
story.Disabled = plan.Disabled.ValueBool()
}

if !plan.Locked.IsNull() && !plan.Locked.IsUnknown() {
story.Locked = plan.Locked.ValueBool()
}

if !plan.Priority.IsNull() && !plan.Priority.IsUnknown() {
story.Priority = plan.Priority.ValueBool()
}

if !plan.STSEnabled.IsNull() && !plan.Priority.IsUnknown() {
story.STSEnabled = plan.STSEnabled.ValueBool()
}

if !plan.STSAccessSource.IsNull() && !plan.STSAccessSource.IsUnknown() {
story.STSAccessSource = plan.STSAccessSource.ValueString()
}

if !plan.STSAccess.IsNull() && !plan.STSAccess.IsUnknown() {
story.STSAccess = plan.STSAccess.ValueString()
}

if !plan.SharedTeamSlugs.IsNull() && !plan.SharedTeamSlugs.IsUnknown() {
diags = plan.SharedTeamSlugs.ElementsAs(ctx, story.SharedTeamSlugs, false)
if diags.HasError() {
return
}
}

if !plan.STSSkillConfirmation.IsNull() && !plan.STSSkillConfirmation.IsUnknown() {
story.STSSkillConfirmation = plan.STSSkillConfirmation.ValueBool()
}

if !plan.EntryAgentID.IsNull() && !plan.EntryAgentID.IsUnknown() {
story.EntryAgentID = plan.EntryAgentID.ValueInt64()
}

if !plan.ExitAgents.IsNull() && !plan.ExitAgents.IsUnknown() {
diags = plan.ExitAgents.ElementsAs(ctx, story.ExitAgents, false)
if diags.HasError() {
return
}
}

if !plan.TeamID.IsNull() && !plan.TeamID.IsUnknown() {
story.TeamID = plan.TeamID.ValueInt64()
}

if !plan.FolderID.IsNull() && !plan.FolderID.IsUnknown() {
story.FolderID = plan.FolderID.ValueInt64()
}

return diags
}

Expand Down Expand Up @@ -752,11 +802,14 @@ func (r *storyResource) runImportStory(plan *storyResourceModel) (story *tines_c
}

var importRequest = tines_cli.StoryImportRequest{
NewName: name,
Data: data,
TeamID: plan.TeamID.ValueInt64(),
FolderID: plan.FolderID.ValueInt64(),
Mode: "versionReplace",
NewName: name,
Data: data,
TeamID: plan.TeamID.ValueInt64(),
Mode: "versionReplace",
}

if !plan.FolderID.IsNull() && !plan.FolderID.IsUnknown() {
importRequest.FolderID = plan.FolderID.ValueInt64()
}

story, err = r.client.ImportStory(&importRequest)
Expand Down
Loading

0 comments on commit 7913c82

Please sign in to comment.