Skip to content

Commit

Permalink
Added linear_team_label resource
Browse files Browse the repository at this point in the history
  • Loading branch information
pksunkara committed Jul 3, 2022
1 parent 12b2342 commit 22fe296
Show file tree
Hide file tree
Showing 12 changed files with 1,013 additions and 4 deletions.
3 changes: 2 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
page_title: "Linear Provider"
description: |-
---

# Linear Provider

Expand Down
2 changes: 1 addition & 1 deletion docs/resources/team.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ Optional:
Import is supported using the following syntax:

```shell
terraform import linear_team.team SOME
terraform import linear_team.example SOME
```
45 changes: 45 additions & 0 deletions docs/resources/team_label.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "linear_team_label Resource - terraform-provider-linear"
subcategory: ""
description: |-
Linear team label.
---

# linear_team_label (Resource)

Linear team label.

## Example Usage

```terraform
resource "linear_team_label" "example" {
name = "Tech Debt"
team_id = linear_team.example.id
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) Name of the label.
- `team_id` (String) Identifier of the team.

### Optional

- `color` (String) Color of the label.
- `description` (String) Description of the label.

### Read-Only

- `id` (String) Identifier of the team.

## Import

Import is supported using the following syntax:

```shell
terraform import linear_team_label.example Bug:SOME
```
2 changes: 1 addition & 1 deletion examples/resources/linear_team/import.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
terraform import linear_team.team SOME
terraform import linear_team.example SOME
1 change: 1 addition & 0 deletions examples/resources/linear_team_label/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import linear_team_label.example Bug:SOME
4 changes: 4 additions & 0 deletions examples/resources/linear_team_label/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "linear_team_label" "example" {
name = "Tech Debt"
team_id = linear_team.example.id
}
532 changes: 532 additions & 0 deletions internal/provider/generated.go

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ func (p *provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq

func (p *provider) GetResources(ctx context.Context) (map[string]tfsdk.ResourceType, diag.Diagnostics) {
return map[string]tfsdk.ResourceType{
"linear_team": teamResourceType{},
"linear_team": teamResourceType{},
"linear_team_label": teamLabelResourceType{},
}, nil
}

Expand Down
235 changes: 235 additions & 0 deletions internal/provider/resource_team_label.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package provider

import (
"context"
"fmt"
"strings"

"github.com/frankgreco/terraform-helpers/validators"
"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/hashicorp/terraform-plugin-log/tflog"
)

// Ensure provider defined types fully satisfy framework interfaces
var _ tfsdk.ResourceType = teamLabelResourceType{}
var _ tfsdk.Resource = teamLabelResource{}
var _ tfsdk.ResourceWithImportState = teamLabelResource{}

type teamLabelResourceType struct{}

func (t teamLabelResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
MarkdownDescription: "Linear team label.",
Attributes: map[string]tfsdk.Attribute{
"id": {
MarkdownDescription: "Identifier of the team.",
Type: types.StringType,
Computed: true,
PlanModifiers: tfsdk.AttributePlanModifiers{
tfsdk.UseStateForUnknown(),
},
},
"name": {
MarkdownDescription: "Name of the label.",
Type: types.StringType,
Required: true,
Validators: []tfsdk.AttributeValidator{
validators.MinLength(1),
},
},
"description": {
MarkdownDescription: "Description of the label.",
Type: types.StringType,
Optional: true,
Computed: true,
PlanModifiers: tfsdk.AttributePlanModifiers{
tfsdk.UseStateForUnknown(),
},
},
"color": {
MarkdownDescription: "Color of the label.",
Type: types.StringType,
Optional: true,
Computed: true,
PlanModifiers: tfsdk.AttributePlanModifiers{
tfsdk.UseStateForUnknown(),
},
Validators: []tfsdk.AttributeValidator{
// TODO: Color value validation
},
},
"team_id": {
MarkdownDescription: "Identifier of the team.",
Type: types.StringType,
Required: true,
PlanModifiers: tfsdk.AttributePlanModifiers{
tfsdk.RequiresReplace(),
},
Validators: []tfsdk.AttributeValidator{
// TODO: UUID validation
validators.MinLength(1),
},
},
},
}, nil
}

func (t teamLabelResourceType) NewResource(ctx context.Context, in tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) {
provider, diags := convertProviderType(in)

return teamLabelResource{
provider: provider,
}, diags
}

type teamLabelResourceData struct {
Id types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
Color types.String `tfsdk:"color"`
TeamId types.String `tfsdk:"team_id"`
}

type teamLabelResource struct {
provider provider
}

func (r teamLabelResource) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) {
var data teamLabelResourceData

diags := req.Config.Get(ctx, &data)
resp.Diagnostics.Append(diags...)

if resp.Diagnostics.HasError() {
return
}

input := IssueLabelCreateInput{
Name: data.Name.Value,
Description: data.Description.Value,
Color: data.Color.Value,
TeamId: data.TeamId.Value,
}

response, err := createTeamLabel(context.Background(), r.provider.client, input)

if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create team label, got error: %s", err))
return
}

tflog.Trace(ctx, "created a team label")

data.Id = types.String{Value: response.IssueLabelCreate.IssueLabel.Id}
data.Description = types.String{Value: response.IssueLabelCreate.IssueLabel.Description}
data.Color = types.String{Value: response.IssueLabelCreate.IssueLabel.Color}

diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
}

func (r teamLabelResource) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) {
var data teamLabelResourceData

diags := req.State.Get(ctx, &data)
resp.Diagnostics.Append(diags...)

if resp.Diagnostics.HasError() {
return
}

response, err := getTeamLabel(context.Background(), r.provider.client, data.Id.Value)

if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read team label, got error: %s", err))
return
}

data.Name = types.String{Value: response.IssueLabel.Name}
data.Description = types.String{Value: response.IssueLabel.Description}
data.Color = types.String{Value: response.IssueLabel.Color}
data.TeamId = types.String{Value: response.IssueLabel.Team.Id}

diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
}

func (r teamLabelResource) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) {
var data teamLabelResourceData

diags := req.Plan.Get(ctx, &data)
resp.Diagnostics.Append(diags...)

if resp.Diagnostics.HasError() {
return
}

input := IssueLabelUpdateInput{
Name: data.Name.Value,
Description: data.Description.Value,
Color: data.Color.Value,
}

response, err := updateTeamLabel(context.Background(), r.provider.client, input, data.Id.Value)

if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update team label, got error: %s", err))
return
}

tflog.Trace(ctx, "updated a team label")

data.Name = types.String{Value: response.IssueLabelUpdate.IssueLabel.Name}
data.Description = types.String{Value: response.IssueLabelUpdate.IssueLabel.Description}
data.Color = types.String{Value: response.IssueLabelUpdate.IssueLabel.Color}

diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
}

func (r teamLabelResource) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) {
var data teamLabelResourceData

diags := req.State.Get(ctx, &data)
resp.Diagnostics.Append(diags...)

if resp.Diagnostics.HasError() {
return
}

_, err := deleteTeamLabel(context.Background(), r.provider.client, data.Id.Value)

if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete team label, got error: %s", err))
return
}

tflog.Trace(ctx, "deleted a team label")
}

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

parts := strings.Split(req.ID, ":")

if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
resp.Diagnostics.AddError(
"Unexpected Import Identifier",
fmt.Sprintf("Expected import identifier with format: label_name:team_key. Got: %q", req.ID),
)

return
}

response, err := findTeamLabel(context.Background(), r.provider.client, parts[0], parts[1])

if err != nil || len(response.IssueLabels.Nodes) != 1 {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to import team label, got error: %s", err))
return
}

resp.Diagnostics.Append(resp.State.SetAttribute(ctx, tftypes.NewAttributePath().WithAttributeName("id"), response.IssueLabels.Nodes[0].Id)...)
}
73 changes: 73 additions & 0 deletions internal/provider/resource_team_label.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
query getTeamLabel($id: String!) {
issueLabel(id: $id) {
id
name
description
color
team {
id
}
}
}

query findTeamLabel($name: String!, $key: String!) {
issueLabels(filter: {
name: {
eq: $name
},
team: {
key: {
eq: $key
}
}
}) {
nodes {
id
}
}
}

# @genqlient(for: "IssueLabelCreateInput.id", omitempty: true)
# @genqlient(for: "IssueLabelCreateInput.description", omitempty: true)
# @genqlient(for: "IssueLabelCreateInput.color", omitempty: true)
mutation createTeamLabel(
$input: IssueLabelCreateInput!
) {
issueLabelCreate(input: $input) {
issueLabel {
id
name
description
color
team {
id
}
}
}
}

# @genqlient(for: "IssueLabelUpdateInput.name", omitempty: true)
# @genqlient(for: "IssueLabelUpdateInput.description", omitempty: true)
# @genqlient(for: "IssueLabelUpdateInput.color", omitempty: true)
mutation updateTeamLabel(
$input: IssueLabelUpdateInput!,
$id: String!
) {
issueLabelUpdate(input: $input, id: $id) {
issueLabel {
id
name
description
color
team {
id
}
}
}
}

mutation deleteTeamLabel($id: String!) {
issueLabelDelete(id: $id) {
success
}
}
Loading

0 comments on commit 22fe296

Please sign in to comment.