-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #158 from ctreminiom/feature/157
Feature/157
- Loading branch information
Showing
6 changed files
with
341 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package internal | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
model "github.com/ctreminiom/go-atlassian/pkg/infra/models" | ||
"github.com/ctreminiom/go-atlassian/service" | ||
"github.com/ctreminiom/go-atlassian/service/jira" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
) | ||
|
||
func NewJQLService(client service.Client, version string) (*JQLService, error) { | ||
|
||
if version == "" { | ||
return nil, model.ErrNoVersionProvided | ||
} | ||
|
||
return &JQLService{ | ||
internalClient: &internalJQLServiceImpl{c: client, version: version}, | ||
}, nil | ||
} | ||
|
||
type JQLService struct { | ||
internalClient jira.JQLConnector | ||
} | ||
|
||
// Parse parses and validates JQL queries. | ||
// | ||
// Validation is performed in context of the current user. | ||
// | ||
// POST /rest/api/{2-3}/jql/parse | ||
// | ||
// https://docs.go-atlassian.io/jira-software-cloud/jql#parse-jql-query | ||
func (j *JQLService) Parse(ctx context.Context, validationType string, JqlQueries []string) (*model.ParsedQueryPageScheme, *model.ResponseScheme, error) { | ||
return j.internalClient.Parse(ctx, validationType, JqlQueries) | ||
} | ||
|
||
type internalJQLServiceImpl struct { | ||
c service.Client | ||
version string | ||
} | ||
|
||
func (i *internalJQLServiceImpl) Parse(ctx context.Context, validationType string, JqlQueries []string) (*model.ParsedQueryPageScheme, *model.ResponseScheme, error) { | ||
|
||
var endpoint strings.Builder | ||
endpoint.WriteString(fmt.Sprintf("/rest/api/%v/jql/parse", i.version)) | ||
|
||
if validationType != "" { | ||
params := url.Values{} | ||
params.Add("validation", validationType) | ||
|
||
endpoint.WriteString(fmt.Sprintf("?%v", params.Encode())) | ||
} | ||
|
||
payload := struct { | ||
Queries []string `json:"queries,omitempty"` | ||
}{ | ||
Queries: JqlQueries, | ||
} | ||
|
||
reader, err := i.c.TransformStructToReader(&payload) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint.String(), reader) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
page := new(model.ParsedQueryPageScheme) | ||
response, err := i.c.Call(request, page) | ||
if err != nil { | ||
return nil, response, err | ||
} | ||
|
||
return page, response, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package internal | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"errors" | ||
model "github.com/ctreminiom/go-atlassian/pkg/infra/models" | ||
"github.com/ctreminiom/go-atlassian/service" | ||
"github.com/ctreminiom/go-atlassian/service/mocks" | ||
"github.com/stretchr/testify/assert" | ||
"net/http" | ||
"testing" | ||
) | ||
|
||
func Test_internalJQLServiceImpl_Parse(t *testing.T) { | ||
|
||
payloadMocked := &struct { | ||
Queries []string "json:\"queries,omitempty\"" | ||
}{Queries: []string{"summary ~ test AND (labels in (urgent, blocker) OR lastCommentedBy = currentUser()) AND status CHANGED AFTER startOfMonth(-1M) ORDER BY updated DESC", "invalid query", "summary = test", "summary in test", "project = INVALID", "universe = 42"}} | ||
|
||
type fields struct { | ||
c service.Client | ||
version string | ||
} | ||
|
||
type args struct { | ||
ctx context.Context | ||
validationType string | ||
JqlQueries []string | ||
} | ||
|
||
testCases := []struct { | ||
name string | ||
fields fields | ||
args args | ||
on func(*fields) | ||
wantErr bool | ||
Err error | ||
}{ | ||
{ | ||
name: "when the api version is v3", | ||
fields: fields{version: "3"}, | ||
args: args{ | ||
ctx: context.TODO(), | ||
validationType: "strict", | ||
JqlQueries: []string{ | ||
"summary ~ test AND (labels in (urgent, blocker) OR lastCommentedBy = currentUser()) AND status CHANGED AFTER startOfMonth(-1M) ORDER BY updated DESC", | ||
"invalid query", | ||
"summary = test", | ||
"summary in test", | ||
"project = INVALID", | ||
"universe = 42"}, | ||
}, | ||
on: func(fields *fields) { | ||
|
||
client := mocks.NewClient(t) | ||
|
||
client.On("TransformStructToReader", | ||
payloadMocked). | ||
Return(bytes.NewReader([]byte{}), nil) | ||
|
||
client.On("NewRequest", | ||
context.Background(), | ||
http.MethodPost, | ||
"/rest/api/3/jql/parse?validation=strict", | ||
bytes.NewReader([]byte{})). | ||
Return(&http.Request{}, nil) | ||
|
||
client.On("Call", | ||
&http.Request{}, | ||
&model.ParsedQueryPageScheme{}). | ||
Return(&model.ResponseScheme{}, nil) | ||
|
||
fields.c = client | ||
|
||
}, | ||
wantErr: false, | ||
Err: nil, | ||
}, | ||
|
||
{ | ||
name: "when the api version is v2", | ||
fields: fields{version: "2"}, | ||
args: args{ | ||
ctx: context.TODO(), | ||
validationType: "strict", | ||
JqlQueries: []string{ | ||
"summary ~ test AND (labels in (urgent, blocker) OR lastCommentedBy = currentUser()) AND status CHANGED AFTER startOfMonth(-1M) ORDER BY updated DESC", | ||
"invalid query", | ||
"summary = test", | ||
"summary in test", | ||
"project = INVALID", | ||
"universe = 42"}, | ||
}, | ||
on: func(fields *fields) { | ||
|
||
client := mocks.NewClient(t) | ||
|
||
client.On("TransformStructToReader", | ||
payloadMocked). | ||
Return(bytes.NewReader([]byte{}), nil) | ||
|
||
client.On("NewRequest", | ||
context.Background(), | ||
http.MethodPost, | ||
"/rest/api/2/jql/parse?validation=strict", | ||
bytes.NewReader([]byte{})). | ||
Return(&http.Request{}, nil) | ||
|
||
client.On("Call", | ||
&http.Request{}, | ||
&model.ParsedQueryPageScheme{}). | ||
Return(&model.ResponseScheme{}, nil) | ||
|
||
fields.c = client | ||
|
||
}, | ||
wantErr: false, | ||
Err: nil, | ||
}, | ||
|
||
{ | ||
name: "when the http request cannot be created", | ||
fields: fields{version: "3"}, | ||
args: args{ | ||
ctx: context.TODO(), | ||
validationType: "strict", | ||
JqlQueries: []string{ | ||
"summary ~ test AND (labels in (urgent, blocker) OR lastCommentedBy = currentUser()) AND status CHANGED AFTER startOfMonth(-1M) ORDER BY updated DESC", | ||
"invalid query", | ||
"summary = test", | ||
"summary in test", | ||
"project = INVALID", | ||
"universe = 42"}, | ||
}, | ||
on: func(fields *fields) { | ||
|
||
client := mocks.NewClient(t) | ||
|
||
client.On("TransformStructToReader", | ||
payloadMocked). | ||
Return(bytes.NewReader([]byte{}), nil) | ||
|
||
client.On("NewRequest", | ||
context.Background(), | ||
http.MethodPost, | ||
"/rest/api/3/jql/parse?validation=strict", | ||
bytes.NewReader([]byte{})). | ||
Return(&http.Request{}, errors.New("error, unable to create the http request")) | ||
|
||
fields.c = client | ||
|
||
}, | ||
wantErr: true, | ||
Err: errors.New("error, unable to create the http request"), | ||
}, | ||
} | ||
|
||
for _, testCase := range testCases { | ||
t.Run(testCase.name, func(t *testing.T) { | ||
|
||
if testCase.on != nil { | ||
testCase.on(&testCase.fields) | ||
} | ||
|
||
fieldService, err := NewJQLService(testCase.fields.c, testCase.fields.version) | ||
assert.NoError(t, err) | ||
|
||
gotResult, gotResponse, err := fieldService.Parse(testCase.args.ctx, testCase.args.validationType, | ||
testCase.args.JqlQueries) | ||
|
||
if testCase.wantErr { | ||
|
||
if err != nil { | ||
t.Logf("error returned: %v", err.Error()) | ||
} | ||
|
||
assert.EqualError(t, err, testCase.Err.Error()) | ||
|
||
} else { | ||
|
||
assert.NoError(t, err) | ||
assert.NotEqual(t, gotResponse, nil) | ||
assert.NotEqual(t, gotResult, nil) | ||
} | ||
|
||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package models | ||
|
||
type ParsedQueryPageScheme struct { | ||
Queries []*ParseQueryScheme `json:"queries"` | ||
} | ||
|
||
type ParseQueryScheme struct { | ||
Query string `json:"query"` | ||
Structure struct { | ||
Where struct { | ||
} `json:"where"` | ||
OrderBy *QueryStructureOrderScheme `json:"orderBy"` | ||
} `json:"structure"` | ||
Errors []string `json:"errors"` | ||
} | ||
|
||
type QueryStructureScheme struct { | ||
OrderBy *QueryStructureOrderScheme `json:"orderBy"` | ||
} | ||
|
||
type QueryStructureOrderScheme struct { | ||
Fields []*QueryStructureOrderFieldScheme `json:"fields"` | ||
} | ||
|
||
type QueryStructureOrderFieldScheme struct { | ||
Field *QueryStructureOrderFieldNodeScheme `json:"field"` | ||
Direction string `json:"direction"` | ||
} | ||
|
||
type QueryStructureOrderFieldNodeScheme struct { | ||
Name string `json:"name"` | ||
Property []*QueryPropertyScheme `json:"property"` | ||
} | ||
|
||
type QueryPropertyScheme struct { | ||
Entity string `json:"entity"` | ||
Key string `json:"key"` | ||
Path string `json:"path"` | ||
Type string `json:"type"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package jira | ||
|
||
import ( | ||
"context" | ||
"github.com/ctreminiom/go-atlassian/pkg/infra/models" | ||
) | ||
|
||
type JQLConnector interface { | ||
|
||
// Parse parses and validates JQL queries. | ||
// | ||
// Validation is performed in context of the current user. | ||
// | ||
// POST /rest/api/{2-3}/jql/parse | ||
// | ||
// https://docs.go-atlassian.io/jira-software-cloud/jql#parse-jql-query | ||
Parse(ctx context.Context, validationType string, JqlQueries []string) (*models.ParsedQueryPageScheme, *models.ResponseScheme, error) | ||
} |