From 5536973de177a3c7a8002bc9e054b5aa95e0ec8c Mon Sep 17 00:00:00 2001
From: Carlos Treminio
Date: Sun, 30 Jan 2022 00:56:57 -0600
Subject: [PATCH 1/3] :memo: Added the avelino/awesome-go badge
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index abf0e413..dbfa1b76 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@
+
Communicate with the [Atlassian API's](https://developer.atlassian.com/cloud/) quickly and easily
From f6049e4a2907ff758827d8ec217e5121f65386e9 Mon Sep 17 00:00:00 2001
From: Carlos Treminio
Date: Sun, 30 Jan 2022 13:03:39 -0600
Subject: [PATCH 2/3] :sparkles: Added the Jira Project Feature service
---
jira/mocks/get-project-features.json | 24 ++
jira/v2/jira.go | 1 +
jira/v2/project.go | 1 +
jira/v2/projectFeature.go | 73 ++++++
jira/v2/projectFeature_test.go | 313 +++++++++++++++++++++++
jira/v3/jira.go | 1 +
jira/v3/project.go | 1 +
jira/v3/projectFeature.go | 73 ++++++
jira/v3/projectFeature_test.go | 313 +++++++++++++++++++++++
pkg/infra/models/errors.go | 1 +
pkg/infra/models/jira_project_feature.go | 16 ++
11 files changed, 817 insertions(+)
create mode 100644 jira/mocks/get-project-features.json
create mode 100644 jira/v2/projectFeature.go
create mode 100644 jira/v2/projectFeature_test.go
create mode 100644 jira/v3/projectFeature.go
create mode 100644 jira/v3/projectFeature_test.go
create mode 100644 pkg/infra/models/jira_project_feature.go
diff --git a/jira/mocks/get-project-features.json b/jira/mocks/get-project-features.json
new file mode 100644
index 00000000..fe3ee32b
--- /dev/null
+++ b/jira/mocks/get-project-features.json
@@ -0,0 +1,24 @@
+{
+ "features": [
+ {
+ "projectId": 10001,
+ "state": "ENABLED",
+ "toggleLocked": true,
+ "feature": "jsw.classic.roadmap",
+ "prerequisites": [],
+ "localisedName": "Roadmap",
+ "localisedDescription": "Your roadmap is an optimized location to create and manage your epics.",
+ "imageUri": "https://jira.atlassian.com/s/sb53l8/b/3/ab8a7691e4738b4f147e293f0864adfd5b8d3c85/_/download/resources/com.atlassian.jira.rest:classic-project-features/simple-roadmap-feature.svg"
+ },
+ {
+ "projectId": 10001,
+ "state": "ENABLED",
+ "toggleLocked": true,
+ "feature": "jsw.classic.backlog",
+ "prerequisites": [],
+ "localisedName": "Backlog",
+ "localisedDescription": "Plan and prioritize work in a dedicated space. To enable and configure the backlog for each board, go to board settings.",
+ "imageUri": "https://jira.atlassian.com/s/sb53l8/b/3/ab8a7691e4738b4f147e293f0864adfd5b8d3c85/_/download/resources/com.atlassian.jira.rest:classic-project-features/simple-backlog-feature.svg"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/jira/v2/jira.go b/jira/v2/jira.go
index 41f1ae12..bf948bcc 100644
--- a/jira/v2/jira.go
+++ b/jira/v2/jira.go
@@ -145,6 +145,7 @@ func New(httpClient *http.Client, site string) (client *Client, err error) {
Type: &ProjectTypeService{client: client},
Version: &ProjectVersionService{client: client},
+ Feature: &ProjectFeatureService{client: client},
}
client.User = &UserService{
diff --git a/jira/v2/project.go b/jira/v2/project.go
index fe105f6d..9c20589d 100644
--- a/jira/v2/project.go
+++ b/jira/v2/project.go
@@ -19,6 +19,7 @@ type ProjectService struct {
Role *ProjectRoleService
Type *ProjectTypeService
Version *ProjectVersionService
+ Feature *ProjectFeatureService
}
// Create creates a project based on a project type template, as shown in the following table:
diff --git a/jira/v2/projectFeature.go b/jira/v2/projectFeature.go
new file mode 100644
index 00000000..0a73b2b3
--- /dev/null
+++ b/jira/v2/projectFeature.go
@@ -0,0 +1,73 @@
+package v2
+
+import (
+ "context"
+ "fmt"
+ "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+ "net/http"
+)
+
+type ProjectFeatureService struct{ client *Client }
+
+// Gets returns the list of features for a project.
+// Docs: https://docs.go-atlassian.io/jira-software-cloud/projects/features#get-project-features
+func (p *ProjectFeatureService) Gets(ctx context.Context, projectKeyOrID string) (result *models.ProjectFeaturesScheme, response *ResponseScheme, err error) {
+
+ if projectKeyOrID == "" {
+ return nil, nil, models.ErrNoProjectIDError
+ }
+
+ var endpoint = fmt.Sprintf("rest/api/2/project/%v/features", projectKeyOrID)
+
+ request, err := p.client.newRequest(ctx, http.MethodGet, endpoint, nil)
+ if err != nil {
+ return
+ }
+
+ request.Header.Set("Accept", "application/json")
+
+ response, err = p.client.call(request, &result)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// Set sets the state of a project feature.
+// Docs: https://docs.go-atlassian.io/jira-software-cloud/projects/features#set-project-feature-state
+func (p *ProjectFeatureService) Set(ctx context.Context, projectKeyOrID, featureKey, state string) (result *models.ProjectFeaturesScheme, response *ResponseScheme, err error) {
+
+ if projectKeyOrID == "" {
+ return nil, nil, models.ErrNoProjectIDError
+ }
+
+ if featureKey == "" {
+ return nil, nil, models.ErrNoProjectFeatureKeyError
+ }
+
+ payload := struct {
+ State string `json:"state,omitempty"`
+ }{
+ State: state,
+ }
+
+ payloadAsReader, _ := transformStructToReader(&payload)
+
+ var endpoint = fmt.Sprintf("rest/api/2/project/%v/features/%v", projectKeyOrID, featureKey)
+
+ request, err := p.client.newRequest(ctx, http.MethodPut, endpoint, payloadAsReader)
+ if err != nil {
+ return
+ }
+
+ request.Header.Set("Accept", "application/json")
+ request.Header.Set("Content-Type", "application/json")
+
+ response, err = p.client.call(request, &result)
+ if err != nil {
+ return
+ }
+
+ return
+}
diff --git a/jira/v2/projectFeature_test.go b/jira/v2/projectFeature_test.go
new file mode 100644
index 00000000..01aedb4c
--- /dev/null
+++ b/jira/v2/projectFeature_test.go
@@ -0,0 +1,313 @@
+package v2
+
+import (
+ "context"
+ "fmt"
+ "github.com/stretchr/testify/assert"
+ "net/http"
+ "net/url"
+ "testing"
+)
+
+func Test_ProjectFeatureService_Gets(t *testing.T) {
+
+ testCases := []struct {
+ name string
+ projectKeyOrID string
+ mockFile string
+ wantHTTPMethod string
+ endpoint string
+ context context.Context
+ wantHTTPCodeReturn int
+ wantErr bool
+ expectedError string
+ }{
+ {
+ name: "when the parameters are correct",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/2/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ },
+ {
+ name: "when the project key or id not provided",
+ projectKeyOrID: "",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/2/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "jira: no project id set",
+ },
+ {
+ name: "when the context is not provided",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/2/project/DUMMY/features",
+ context: nil,
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "request creation failed: net/http: nil Context",
+ },
+
+ {
+ name: "when the response status is incorrect",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/2/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusBadRequest,
+ wantErr: true,
+ expectedError: "request failed. Please analyze the request body for more details. Status Code: 400",
+ },
+
+ {
+ name: "when the response body is empty",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/empty-json.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/2/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "unexpected end of JSON input",
+ },
+ }
+
+ for _, testCase := range testCases {
+
+ t.Run(testCase.name, func(t *testing.T) {
+
+ //Init a new HTTP mock server
+ mockOptions := mockServerOptions{
+ Endpoint: testCase.endpoint,
+ MockFilePath: testCase.mockFile,
+ MethodAccepted: testCase.wantHTTPMethod,
+ ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+ }
+
+ mockServer, err := startMockServer(&mockOptions)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer mockServer.Close()
+
+ //Init the library instance
+ mockClient, err := startMockClient(mockServer.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ i := &ProjectFeatureService{client: mockClient}
+
+ gotResult, gotResponse, err := i.Gets(testCase.context, testCase.projectKeyOrID)
+
+ if testCase.wantErr {
+
+ if err != nil {
+ t.Logf("error returned: %v", err.Error())
+ }
+
+ assert.EqualError(t, err, testCase.expectedError)
+
+ if gotResponse != nil {
+ t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+ }
+
+ } else {
+
+ assert.NoError(t, err)
+ assert.NotEqual(t, gotResponse, nil)
+ assert.NotEqual(t, gotResult, nil)
+
+ apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var endpointToAssert string
+
+ if apiEndpoint.Query().Encode() != "" {
+ endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+ } else {
+ endpointToAssert = apiEndpoint.Path
+ }
+
+ t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+ assert.Equal(t, testCase.endpoint, endpointToAssert)
+ }
+ })
+
+ }
+
+}
+
+func Test_ProjectFeatureService_Set(t *testing.T) {
+
+ testCases := []struct {
+ name string
+ projectKeyOrID string
+ featureKey, state string
+ mockFile string
+ wantHTTPMethod string
+ endpoint string
+ context context.Context
+ wantHTTPCodeReturn int
+ wantErr bool
+ expectedError string
+ }{
+ {
+ name: "when the parameters are correct",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/2/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ },
+
+ {
+ name: "when the feature key is not provided",
+ projectKeyOrID: "DUMMY",
+ featureKey: "",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/2/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "jira: no project feature key set",
+ },
+ {
+ name: "when the project key or id not provided",
+ projectKeyOrID: "",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/2/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "jira: no project id set",
+ },
+ {
+ name: "when the context is not provided",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/2/project/DUMMY/features/jsw.classic.roadmap",
+ context: nil,
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "request creation failed: net/http: nil Context",
+ },
+
+ {
+ name: "when the response status is incorrect",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/2/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusBadRequest,
+ wantErr: true,
+ expectedError: "request failed. Please analyze the request body for more details. Status Code: 400",
+ },
+
+ {
+ name: "when the response body is empty",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/empty-json.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/2/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "unexpected end of JSON input",
+ },
+ }
+
+ for _, testCase := range testCases {
+
+ t.Run(testCase.name, func(t *testing.T) {
+
+ //Init a new HTTP mock server
+ mockOptions := mockServerOptions{
+ Endpoint: testCase.endpoint,
+ MockFilePath: testCase.mockFile,
+ MethodAccepted: testCase.wantHTTPMethod,
+ ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+ }
+
+ mockServer, err := startMockServer(&mockOptions)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer mockServer.Close()
+
+ //Init the library instance
+ mockClient, err := startMockClient(mockServer.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ i := &ProjectFeatureService{client: mockClient}
+
+ gotResult, gotResponse, err := i.Set(testCase.context, testCase.projectKeyOrID, testCase.featureKey, testCase.state)
+
+ if testCase.wantErr {
+
+ if err != nil {
+ t.Logf("error returned: %v", err.Error())
+ }
+
+ assert.EqualError(t, err, testCase.expectedError)
+
+ if gotResponse != nil {
+ t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+ }
+
+ } else {
+
+ assert.NoError(t, err)
+ assert.NotEqual(t, gotResponse, nil)
+ assert.NotEqual(t, gotResult, nil)
+
+ apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var endpointToAssert string
+
+ if apiEndpoint.Query().Encode() != "" {
+ endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+ } else {
+ endpointToAssert = apiEndpoint.Path
+ }
+
+ t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+ assert.Equal(t, testCase.endpoint, endpointToAssert)
+ }
+ })
+
+ }
+
+}
diff --git a/jira/v3/jira.go b/jira/v3/jira.go
index 8df437a4..21310f3c 100644
--- a/jira/v3/jira.go
+++ b/jira/v3/jira.go
@@ -147,6 +147,7 @@ func New(httpClient *http.Client, site string) (client *Client, err error) {
Type: &ProjectTypeService{client: client},
Version: &ProjectVersionService{client: client},
+ Feature: &ProjectFeatureService{client: client},
}
client.User = &UserService{
diff --git a/jira/v3/project.go b/jira/v3/project.go
index 59eb2fbb..8bb08dcc 100644
--- a/jira/v3/project.go
+++ b/jira/v3/project.go
@@ -19,6 +19,7 @@ type ProjectService struct {
Role *ProjectRoleService
Type *ProjectTypeService
Version *ProjectVersionService
+ Feature *ProjectFeatureService
}
// Create creates a project based on a project type template, as shown in the following table:
diff --git a/jira/v3/projectFeature.go b/jira/v3/projectFeature.go
new file mode 100644
index 00000000..668d5eeb
--- /dev/null
+++ b/jira/v3/projectFeature.go
@@ -0,0 +1,73 @@
+package v3
+
+import (
+ "context"
+ "fmt"
+ "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+ "net/http"
+)
+
+type ProjectFeatureService struct{ client *Client }
+
+// Gets returns the list of features for a project.
+// Docs: https://docs.go-atlassian.io/jira-software-cloud/projects/features#get-project-features
+func (p *ProjectFeatureService) Gets(ctx context.Context, projectKeyOrID string) (result *models.ProjectFeaturesScheme, response *ResponseScheme, err error) {
+
+ if projectKeyOrID == "" {
+ return nil, nil, models.ErrNoProjectIDError
+ }
+
+ var endpoint = fmt.Sprintf("rest/api/3/project/%v/features", projectKeyOrID)
+
+ request, err := p.client.newRequest(ctx, http.MethodGet, endpoint, nil)
+ if err != nil {
+ return
+ }
+
+ request.Header.Set("Accept", "application/json")
+
+ response, err = p.client.call(request, &result)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// Set sets the state of a project feature.
+// Docs: https://docs.go-atlassian.io/jira-software-cloud/projects/features#set-project-feature-state
+func (p *ProjectFeatureService) Set(ctx context.Context, projectKeyOrID, featureKey, state string) (result *models.ProjectFeaturesScheme, response *ResponseScheme, err error) {
+
+ if projectKeyOrID == "" {
+ return nil, nil, models.ErrNoProjectIDError
+ }
+
+ if featureKey == "" {
+ return nil, nil, models.ErrNoProjectFeatureKeyError
+ }
+
+ payload := struct {
+ State string `json:"state,omitempty"`
+ }{
+ State: state,
+ }
+
+ payloadAsReader, _ := transformStructToReader(&payload)
+
+ var endpoint = fmt.Sprintf("rest/api/3/project/%v/features/%v", projectKeyOrID, featureKey)
+
+ request, err := p.client.newRequest(ctx, http.MethodPut, endpoint, payloadAsReader)
+ if err != nil {
+ return
+ }
+
+ request.Header.Set("Accept", "application/json")
+ request.Header.Set("Content-Type", "application/json")
+
+ response, err = p.client.call(request, &result)
+ if err != nil {
+ return
+ }
+
+ return
+}
diff --git a/jira/v3/projectFeature_test.go b/jira/v3/projectFeature_test.go
new file mode 100644
index 00000000..16681568
--- /dev/null
+++ b/jira/v3/projectFeature_test.go
@@ -0,0 +1,313 @@
+package v3
+
+import (
+ "context"
+ "fmt"
+ "github.com/stretchr/testify/assert"
+ "net/http"
+ "net/url"
+ "testing"
+)
+
+func Test_ProjectFeatureService_Gets(t *testing.T) {
+
+ testCases := []struct {
+ name string
+ projectKeyOrID string
+ mockFile string
+ wantHTTPMethod string
+ endpoint string
+ context context.Context
+ wantHTTPCodeReturn int
+ wantErr bool
+ expectedError string
+ }{
+ {
+ name: "when the parameters are correct",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/3/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ },
+ {
+ name: "when the project key or id not provided",
+ projectKeyOrID: "",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/3/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "jira: no project id set",
+ },
+ {
+ name: "when the context is not provided",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/3/project/DUMMY/features",
+ context: nil,
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "request creation failed: net/http: nil Context",
+ },
+
+ {
+ name: "when the response status is incorrect",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/3/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusBadRequest,
+ wantErr: true,
+ expectedError: "request failed. Please analyze the request body for more details. Status Code: 400",
+ },
+
+ {
+ name: "when the response body is empty",
+ projectKeyOrID: "DUMMY",
+ mockFile: "../mocks/empty-json.json",
+ wantHTTPMethod: http.MethodGet,
+ endpoint: "/rest/api/3/project/DUMMY/features",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "unexpected end of JSON input",
+ },
+ }
+
+ for _, testCase := range testCases {
+
+ t.Run(testCase.name, func(t *testing.T) {
+
+ //Init a new HTTP mock server
+ mockOptions := mockServerOptions{
+ Endpoint: testCase.endpoint,
+ MockFilePath: testCase.mockFile,
+ MethodAccepted: testCase.wantHTTPMethod,
+ ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+ }
+
+ mockServer, err := startMockServer(&mockOptions)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer mockServer.Close()
+
+ //Init the library instance
+ mockClient, err := startMockClient(mockServer.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ i := &ProjectFeatureService{client: mockClient}
+
+ gotResult, gotResponse, err := i.Gets(testCase.context, testCase.projectKeyOrID)
+
+ if testCase.wantErr {
+
+ if err != nil {
+ t.Logf("error returned: %v", err.Error())
+ }
+
+ assert.EqualError(t, err, testCase.expectedError)
+
+ if gotResponse != nil {
+ t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+ }
+
+ } else {
+
+ assert.NoError(t, err)
+ assert.NotEqual(t, gotResponse, nil)
+ assert.NotEqual(t, gotResult, nil)
+
+ apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var endpointToAssert string
+
+ if apiEndpoint.Query().Encode() != "" {
+ endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+ } else {
+ endpointToAssert = apiEndpoint.Path
+ }
+
+ t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+ assert.Equal(t, testCase.endpoint, endpointToAssert)
+ }
+ })
+
+ }
+
+}
+
+func Test_ProjectFeatureService_Set(t *testing.T) {
+
+ testCases := []struct {
+ name string
+ projectKeyOrID string
+ featureKey, state string
+ mockFile string
+ wantHTTPMethod string
+ endpoint string
+ context context.Context
+ wantHTTPCodeReturn int
+ wantErr bool
+ expectedError string
+ }{
+ {
+ name: "when the parameters are correct",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/3/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ },
+
+ {
+ name: "when the feature key is not provided",
+ projectKeyOrID: "DUMMY",
+ featureKey: "",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/3/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "jira: no project feature key set",
+ },
+ {
+ name: "when the project key or id not provided",
+ projectKeyOrID: "",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/3/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "jira: no project id set",
+ },
+ {
+ name: "when the context is not provided",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/3/project/DUMMY/features/jsw.classic.roadmap",
+ context: nil,
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "request creation failed: net/http: nil Context",
+ },
+
+ {
+ name: "when the response status is incorrect",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/get-project-features.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/3/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusBadRequest,
+ wantErr: true,
+ expectedError: "request failed. Please analyze the request body for more details. Status Code: 400",
+ },
+
+ {
+ name: "when the response body is empty",
+ projectKeyOrID: "DUMMY",
+ featureKey: "jsw.classic.roadmap",
+ state: "ENABLED",
+ mockFile: "../mocks/empty-json.json",
+ wantHTTPMethod: http.MethodPut,
+ endpoint: "/rest/api/3/project/DUMMY/features/jsw.classic.roadmap",
+ context: context.Background(),
+ wantHTTPCodeReturn: http.StatusOK,
+ wantErr: true,
+ expectedError: "unexpected end of JSON input",
+ },
+ }
+
+ for _, testCase := range testCases {
+
+ t.Run(testCase.name, func(t *testing.T) {
+
+ //Init a new HTTP mock server
+ mockOptions := mockServerOptions{
+ Endpoint: testCase.endpoint,
+ MockFilePath: testCase.mockFile,
+ MethodAccepted: testCase.wantHTTPMethod,
+ ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+ }
+
+ mockServer, err := startMockServer(&mockOptions)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer mockServer.Close()
+
+ //Init the library instance
+ mockClient, err := startMockClient(mockServer.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ i := &ProjectFeatureService{client: mockClient}
+
+ gotResult, gotResponse, err := i.Set(testCase.context, testCase.projectKeyOrID, testCase.featureKey, testCase.state)
+
+ if testCase.wantErr {
+
+ if err != nil {
+ t.Logf("error returned: %v", err.Error())
+ }
+
+ assert.EqualError(t, err, testCase.expectedError)
+
+ if gotResponse != nil {
+ t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+ }
+
+ } else {
+
+ assert.NoError(t, err)
+ assert.NotEqual(t, gotResponse, nil)
+ assert.NotEqual(t, gotResult, nil)
+
+ apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var endpointToAssert string
+
+ if apiEndpoint.Query().Encode() != "" {
+ endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+ } else {
+ endpointToAssert = apiEndpoint.Path
+ }
+
+ t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+ assert.Equal(t, testCase.endpoint, endpointToAssert)
+ }
+ })
+
+ }
+
+}
diff --git a/pkg/infra/models/errors.go b/pkg/infra/models/errors.go
index e7e82938..e9991f54 100644
--- a/pkg/infra/models/errors.go
+++ b/pkg/infra/models/errors.go
@@ -56,6 +56,7 @@ var (
ErrNoReaderError = errors.New("jira: no reader set")
ErrNoCommentIDError = errors.New("jira: no comment id set")
ErrNoProjectIDError = errors.New("jira: no project id set")
+ ErrNoProjectFeatureKeyError = errors.New("jira: no project feature key set")
ErrNoFieldIDError = errors.New("jira: no field id set")
ErrNoFieldContextIDError = errors.New("jira: no field context id set")
ErrNoIssueTypesError = errors.New("jira: no issue types id's set")
diff --git a/pkg/infra/models/jira_project_feature.go b/pkg/infra/models/jira_project_feature.go
new file mode 100644
index 00000000..8bf0ca45
--- /dev/null
+++ b/pkg/infra/models/jira_project_feature.go
@@ -0,0 +1,16 @@
+package models
+
+type ProjectFeaturesScheme struct {
+ Features []*ProjectFeatureScheme `json:"features,omitempty"`
+}
+
+type ProjectFeatureScheme struct {
+ ProjectID int `json:"projectId,omitempty"`
+ State string `json:"state,omitempty"`
+ ToggleLocked bool `json:"toggleLocked,omitempty"`
+ Feature string `json:"feature,omitempty"`
+ Prerequisites []string `json:"prerequisites,omitempty"`
+ LocalisedName string `json:"localisedName,omitempty"`
+ LocalisedDescription string `json:"localisedDescription,omitempty"`
+ ImageURI string `json:"imageUri,omitempty"`
+}
From 7a14d84209e149ce6acc72d2715762c32bfeb8f8 Mon Sep 17 00:00:00 2001
From: Carlos Treminio
Date: Sun, 30 Jan 2022 22:29:42 -0600
Subject: [PATCH 3/3] :label: Parsed more structures
1. Added the Confluence History tag under the Confluence Content Scheme History.
2. Fixed the Content Version scheme (it was using the Jira version format).
---
pkg/infra/models/confluence_content.go | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/pkg/infra/models/confluence_content.go b/pkg/infra/models/confluence_content.go
index c78e1a30..1942ee44 100644
--- a/pkg/infra/models/confluence_content.go
+++ b/pkg/infra/models/confluence_content.go
@@ -46,6 +46,7 @@ type ContentScheme struct {
Version *ContentVersionScheme `json:"version,omitempty"`
Extensions *ContentExtensionScheme `json:"extensions,omitempty"`
Ancestors []*ContentScheme `json:"ancestors,omitempty"`
+ History *ContentHistoryScheme `json:"history,omitempty"`
}
type ContentExtensionScheme struct {
@@ -141,10 +142,10 @@ type ContentHistoryScheme struct {
Latest bool `json:"latest,omitempty"`
CreatedBy *ContentUserScheme `json:"createdBy,omitempty"`
CreatedDate string `json:"createdDate,omitempty"`
- LastUpdated *VersionScheme `json:"lastUpdated,omitempty"`
- PreviousVersion *VersionScheme `json:"previousVersion,omitempty"`
+ LastUpdated *ContentVersionScheme `json:"lastUpdated,omitempty"`
+ PreviousVersion *ContentVersionScheme `json:"previousVersion,omitempty"`
Contributors *ContentHistoryContributorsScheme `json:"contributors,omitempty"`
- NextVersion *VersionScheme `json:"nextVersion,omitempty"`
+ NextVersion *ContentVersionScheme `json:"nextVersion,omitempty"`
Expandable *ExpandableScheme `json:"_expandable,omitempty"`
Links *LinkScheme `json:"_links,omitempty"`
}