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

Added ParseCustomField & ParseCustomFields using golang 1.18 generics #268

Open
wants to merge 7 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
11 changes: 10 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
module github.com/ctreminiom/go-atlassian

go 1.14
go 1.18

require (
dario.cat/mergo v1.0.0
github.com/google/uuid v1.6.0
github.com/stretchr/testify v1.9.0
github.com/tidwall/gjson v1.17.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 0 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
Expand All @@ -25,6 +18,5 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
1 change: 1 addition & 0 deletions pkg/infra/models/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ var (
ErrNoCheckBoxTypeError = errors.New("custom-field: no check-box type set")
ErrNoCascadingParentError = errors.New("custom-field: no cascading parent value set")
ErrNoCascadingChildError = errors.New("custom-field: no cascading child value set")
ErrNoCustomTypeError = errors.New("custom-field: no custom type set")
ErrNoAttachmentIdsError = errors.New("sm: no attachment id's set")
ErrNoLabelsError = errors.New("sm: no label names set")
ErrNoComponentsError = errors.New("sm: no components set")
Expand Down
3 changes: 2 additions & 1 deletion pkg/infra/models/jira_issue_custom_fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/tidwall/gjson"
"reflect"
"time"

"github.com/tidwall/gjson"
)

// ParseMultiSelectCustomField parses a multi-select custom field from the given buffer data
Expand Down
141 changes: 141 additions & 0 deletions pkg/infra/models/jira_issue_custom_fields_go118.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//go:build go1.18
// +build go1.18

package models

import (
"bytes"
"encoding/json"
"fmt"

"github.com/tidwall/gjson"
)

// ParseCustomField parses a generic custom field from the given buffer data associated
// with the specified custom field ID and returns a pointers to the generic T.
//
// Parameters:
// - customfieldID: A string representing the unique identifier of the custom field.
// - buffer: A bytes.Buffer containing the serialized data to be parsed.
//
// Returns:
// - *T: A pointer to CustomFieldContextOptionSchema
// structs representing the parsed generic custom field values.
//
// The ParseCustomField method is responsible for extracting and parsing the serialized
// data from the provided buffer, which is expected to be in a specific format.
// It then constructs and returns a pointer to T that represent the parsed generic
// custom field.
//
// Example usage:
//
// type MyType struct {
// FieldInsideCustomField string
// }
// customfieldID := "customfield_10001"
// buffer := bytes.NewBuffer([]byte{ /* Serialized data */ })
// options, err := ParseCustomField[MyType](customfieldID, buffer)
// if err != nil {
// log.Fatal(err)
// }
// fmt.Printf("Custom Field Value: %+v\n", customFieldValue.FieldInsideCustomField)
//
// Docs: https://docs.go-atlassian.io/cookbooks/extract-customfields-from-issue-s#parse-customfield
func ParseCustomField[T any](buffer bytes.Buffer, customField string) (*T, error) {
raw := gjson.ParseBytes(buffer.Bytes())
path := fmt.Sprintf("fields.%v", customField)

// Check if the buffer contains the "issues" object
if !raw.Get("fields").Exists() {
return nil, ErrNoFieldInformationError
}

// Check if the issue iteration contains information on the customfield selected,
// if not, continue
if raw.Get(path).Type == gjson.Null {
return nil, ErrNoCustomTypeError
}

var value *T
if err := json.Unmarshal([]byte(raw.Get(path).String()), &value); err != nil {
return nil, ErrNoCustomTypeError
}

return value, nil
}

// ParseCustomFields extracts and parses generic custom field data from a given bytes.Buffer from multiple issues
//
// This function takes the name of the custom field to parse and a bytes.Buffer containing
// JSON data representing the custom field values associated with different issues. It returns
// a map where the key is the issue key and the value is a pointer of T a generic type,
// representing the parsed custom field values.
//
// If the custom field data cannot be parsed successfully, an error is returned.
//
// Example Usage:
//
// type MyType struct {
// FieldInsideCustomField string
// }
// customFieldName := "customfield_10001"
// buffer := // Populate the buffer with JSON data
// customFields, err := ParseCustomFields[MyType](customFieldName, buffer)
// if err != nil {
// // Handle the error
// }
//
// // Iterate through the parsed custom fields
// for issueKey, customFieldValue := range customFields {
// fmt.Printf("Issue Key: %s\n", issueKey)
// fmt.Printf("Custom Field Value: %+v\n", customFieldValue.FieldInsideCustomField)
// }
//
// Parameters:
// - customField: The name of the generic custom field to parse.
// - buffer: A bytes.Buffer containing JSON data representing custom field values.
//
// Returns:
// - map[string]*T: A map where the key is the issue key and the
// value is a pointer of T representing the parsed generic custom field values.
// - error: An error if there was a problem parsing the custom field data or if the JSON data
// did not conform to the expected structure.
//
// Docs: https://docs.go-atlassian.io/cookbooks/extract-customfields-from-issue-s#parse-customfields
func ParseCustomFields[T any](buffer bytes.Buffer, customField string) (map[string]*T, error) {
raw := gjson.ParseBytes(buffer.Bytes())

// Check if the buffer contains the "issues" object
if !raw.Get("issues").Exists() {
return nil, ErrNoIssuesSliceError
}

// Loop through each custom field, extract the information and stores the data on a map
customFieldsAsMap := make(map[string]*T)
raw.Get("issues").ForEach(func(key, value gjson.Result) bool {

path, issueKey := fmt.Sprintf("fields.%v", customField), value.Get("key").String()

// Check if the issue iteration contains information on the customfield selected,
// if not, continue
if value.Get(path).Type == gjson.Null {
return true
}

var customFields *T
if err := json.Unmarshal([]byte(value.Get(path).String()), &customFields); err != nil {
return true
}

customFieldsAsMap[issueKey] = customFields
return true
})

// Check if the map processed contains elements
// if so, return an error interface
if len(customFieldsAsMap) == 0 {
return nil, ErrNoMapValuesError
}

return customFieldsAsMap, nil
}
Loading
Loading