Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

Commit

Permalink
Adding more TP API endpoints (#14)
Browse files Browse the repository at this point in the history
Co-authored-by: Luke Reed <[email protected]>
  • Loading branch information
Andrew Suderman and Luke Reed authored Aug 31, 2020
1 parent ab785de commit eaba407
Show file tree
Hide file tree
Showing 10 changed files with 410 additions and 47 deletions.
1 change: 1 addition & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ func (c *Client) do(out interface{}, req *http.Request, urlPath string) error {
if err != nil {
return errors.Wrapf(err, "HTTP Read error on response for %s", urlPath)
}
c.debugLog(fmt.Sprintf("[targetprocess] raw response: %s", string(b)))
err = json.Unmarshal(b, out)
if err != nil {
return errors.Wrapf(err, "JSON decode failed on %s:\n%s", urlPath, string(b))
Expand Down
59 changes: 59 additions & 0 deletions custom-field.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2020 Fairwinds
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License

package targetprocess

import (
"fmt"

"github.com/pkg/errors"
)

// CustomField are user defined in TargetProcess and are arbitrarily set for many different
// resource types
type CustomField struct {
client *Client

ID int32 `json:"Id,omitempty"`
Type string `json:",omitempty"`
Name string `json:",omitempty"`
Value interface{} `json:",omitempty"`
}

// CustomFieldResponse is a representation of the http response for a group of CustomField
type CustomFieldResponse struct {
Items []CustomField
Next string
Prev string
}

// GetCustomField will return a CustomField object from a name. Returns an error if not found.
func (c *Client) GetCustomField(name string) (CustomField, error) {
c.debugLog(fmt.Sprintf("[targetprocess] attempting to get CustomField: %s", name))
ret := CustomField{}
out := CustomFieldResponse{}
err := c.Get(&out, "CustomField", nil,
Where(fmt.Sprintf("Name eq '%s'", name)),
First(),
)
if err != nil {
return CustomField{}, errors.Wrap(err, fmt.Sprintf("error getting CustomField with name '%s'", name))
}
if len(out.Items) < 1 {
return ret, fmt.Errorf("no items found")
}
ret = out.Items[0]
ret.client = c
return ret, nil
}
58 changes: 58 additions & 0 deletions entity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2020 Fairwinds
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License

package targetprocess

// EntityState contains metadata for the state of an Entity. Collection of EntityStates
// form Workflow for Entity. For example, Bug has four EntityStates by default: Open, Fixed, Invalid and Done
type EntityState struct {
ID int32 `json:"Id,omitempty"`
Name string `json:",omitempty"`
NumericPriority float64 `json:",omitempty"`
ParentEntityState *EntityState `json:",omitempty"`
Process *Process `json:",omitempty"`
IsInital bool `json:",omitempty"`
IsFinal bool `json:",omitempty"`
IsPlanned bool `json:",omitempty"`
IsCommentRequired bool `json:",omitempty"`
}

// EntityStateResponse is a representation of the http response for a group of EntityStates
type EntityStateResponse struct {
Items []EntityState
Next string
Prev string
}

// GetEntityStates will return all EntityStates
func (c *Client) GetEntityStates(filters ...QueryFilter) ([]EntityState, error) {
var ret []EntityState
out := EntityStateResponse{}

err := c.Get(&out, "EntityState", nil, filters...)
if err != nil {
return nil, err
}
ret = append(ret, out.Items...)
for out.Next != "" {
innerOut := EntityStateResponse{}
err := c.GetNext(&innerOut, out.Next)
if err != nil {
return ret, err
}
ret = append(ret, innerOut.Items...)
out = innerOut
}
return ret, nil
}
95 changes: 95 additions & 0 deletions feature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2020 Fairwinds
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License

package targetprocess

import (
"fmt"

"github.com/pkg/errors"
)

// Feature matches up with a targetprocess Feature
type Feature struct {
client *Client

ID int32 `json:"Id,omitempty"`
Name string `json:",omitempty"`
Effort float32 `json:",omitempty"`
UserStoriesCount int64 `json:"UserStories-Count,omitempty"`
Project *Project `json:",omitempty"`
Description string `json:",omitempty"`
NumericPriority float32 `json:",omitempty"`
CustomFields []CustomField `json:",omitempty"`
}

// FeatureResponse is a representation of the http response for a group of Features
type FeatureResponse struct {
Items []Feature
Next string
Prev string
}

// GetFeatures will return all features
func (c *Client) GetFeatures(filters ...QueryFilter) ([]Feature, error) {
var ret []Feature
out := FeatureResponse{}

err := c.Get(&out, "Feature", nil, filters...)
if err != nil {
return nil, err
}
ret = append(ret, out.Items...)
for out.Next != "" {
innerOut := FeatureResponse{}
err := c.GetNext(&innerOut, out.Next)
if err != nil {
return ret, err
}
ret = append(ret, innerOut.Items...)
out = innerOut
}
return ret, nil
}

// GetFeature will return a single feature based on its name. If somehow there are features with the same name,
// this will only return the first one.
func (c *Client) GetFeature(name string) (Feature, error) {
c.debugLog(fmt.Sprintf("[targetprocess] attempting to get feature: %s", name))
ret := Feature{}
out := FeatureResponse{}
err := c.Get(&out, "Feature", nil,
Where(fmt.Sprintf("Name eq '%s'", name)),
First(),
)
if err != nil {
return Feature{}, errors.Wrap(err, fmt.Sprintf("error getting feature with name '%s'", name))
}
if len(out.Items) < 1 {
return ret, fmt.Errorf("no items found")
}
ret = out.Items[0]
ret.client = c
return ret, nil
}

// NewUserStory will make a UserStory with the Feature that this method is built off of
func (f Feature) NewUserStory(name, description, project string) (UserStory, error) {
us, err := NewUserStory(f.client, name, description, project)
if err != nil {
return UserStory{}, nil
}
us.Feature = &f
return us, nil
}
17 changes: 0 additions & 17 deletions general.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,6 @@ package targetprocess
// DateTime currently does nothing special but will represent the TP DateTime objects
type DateTime string

// CustomField are user defined in TargetProcess and are arbitrarily set for many different
// resource types
type CustomField struct {
ID int32 `json:"Id,omitempty"`
Type string `json:",omitempty"`
Name string `json:",omitempty"`
Value interface{} `json:",omitempty"`
}

// EntityState contains metadata for the state of an Entity. Collection of EntityStates
// form Workflow for Entity. For example, Bug has four EntityStates by default: Open, Fixed, Invalid and Done
type EntityState struct {
ID int32 `json:"Id,omitempty"`
Name string `json:",omitempty"`
NumericPriority float64 `json:",omitempty"`
}

// AssignedTeams is used in UserStories and potentially other places.
// The AssignedTeams section of a UserStory response replaces the deprecated usage of the Team field
type AssignedTeams struct {
Expand Down
52 changes: 52 additions & 0 deletions process.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2020 Fairwinds
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License

package targetprocess

// Process contains metadata for the state of a Process. Collection of Processes
// form Process for Entity. For example, Bug has four Processs by default: Open, Fixed, Invalid and Done
type Process struct {
ID int32 `json:"Id,omitempty"`
Name string `json:",omitempty"`
Description string `json:",omitempty"`
}

// ProcessResponse is a representation of the http response for a group of Processs
type ProcessResponse struct {
Items []Process
Next string
Prev string
}

// GetProcesses will return all Processs
func (c *Client) GetProcesses(filters ...QueryFilter) ([]Process, error) {
var ret []Process
out := ProcessResponse{}

err := c.Get(&out, "Process", nil, filters...)
if err != nil {
return nil, err
}
ret = append(ret, out.Items...)
for out.Next != "" {
innerOut := ProcessResponse{}
err := c.GetNext(&innerOut, out.Next)
if err != nil {
return ret, err
}
ret = append(ret, innerOut.Items...)
out = innerOut
}
return ret, nil
}
20 changes: 19 additions & 1 deletion project.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Project struct {
IsActive bool `json:",omitempty"`
Abbreviation string `json:",omitempty"`
Color string `json:",omitempty"`
Process *Process `json:",omitempty"`
}

// ProjectResponse is a representation of the http response for a group of Projects
Expand Down Expand Up @@ -82,6 +83,9 @@ func (c *Client) GetProject(name string) (Project, error) {
if err != nil {
return Project{}, errors.Wrap(err, fmt.Sprintf("error getting project with name '%s'", name))
}
if len(out.Items) < 1 {
return ret, fmt.Errorf("no items found")
}
ret = out.Items[0]
ret.client = c
return ret, nil
Expand All @@ -94,7 +98,7 @@ func (p Project) NewUserStory(name, description, team string) (UserStory, error)
Name: name,
Description: description,
}
p.client.debugLog(fmt.Sprintf("Attempting to Get Team: %s", team))
p.client.debugLog(fmt.Sprintf("[targetprocess] Attempting to Get Team: %s", team))
t, err := p.client.GetTeam(team)
if err != nil {
return UserStory{}, err
Expand All @@ -103,3 +107,17 @@ func (p Project) NewUserStory(name, description, team string) (UserStory, error)
us.Team = &t
return us, nil
}

// GetProcess returns the process associated with a project
func (p Project) GetProcess() (*Process, error) {
processList, err := p.client.GetProcesses(
Where(fmt.Sprintf("Id eq %d", p.Process.ID)),
)
if err != nil {
return nil, err
}
if len(processList) != 1 {
return nil, fmt.Errorf("cannot determine process for project. got list: %v", processList)
}
return &processList[0], nil
}
14 changes: 5 additions & 9 deletions team.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,20 @@ func (c *Client) GetTeam(name string) (Team, error) {
if err != nil {
return ret, errors.Wrap(err, fmt.Sprintf("error getting team with name '%s'", name))
}
if len(out.Items) < 1 {
return ret, fmt.Errorf("no items found")
}
ret = out.Items[0]
ret.client = c
return ret, nil
}

// NewUserStory will make a UserStory for assigned to the Team that this method is built off of and for the given Project
// NewUserStory will make a UserStory assigned to the Team that this method is built off of
func (t Team) NewUserStory(name, description, project string) (UserStory, error) {
us := UserStory{
client: t.client,
Name: name,
Description: description,
}
t.client.debugLog(fmt.Sprintf("Attempting to Get Project: %s", project))
p, err := t.client.GetProject(project)
us, err := NewUserStory(t.client, name, description, project)
if err != nil {
return UserStory{}, err
}
us.Project = &p
us.Team = &t
return us, nil
}
Loading

0 comments on commit eaba407

Please sign in to comment.