diff --git a/Makefile b/Makefile index 4f6a086c..c0ef1bdb 100644 --- a/Makefile +++ b/Makefile @@ -115,8 +115,7 @@ mock-gen: mockgen -destination=./pkg/cli/session/mocks/sessionMock.go -package=mocks github.com/openshift/backplane-cli/pkg/cli/session BackplaneSessionInterface mockgen -destination=./pkg/utils/mocks/shellCheckerMock.go -package=mocks github.com/openshift/backplane-cli/pkg/utils ShellCheckerInterface mockgen -destination=./pkg/pagerduty/mocks/clientMock.go -package=mocks github.com/openshift/backplane-cli/pkg/pagerduty PagerDutyClient - mockgen -destination=./pkg/utils/mocks/jiraMock.go -package=mocks github.com/openshift/backplane-cli/pkg/utils IssueServiceInterface - mockgen -destination=./pkg/jira/mocks/clientMock.go -package=mocks github.com/openshift/backplane-cli/pkg/jira JiraClient + mockgen -destination=./pkg/jira/mocks/jiraMock.go -package=mocks github.com/openshift/backplane-cli/pkg/jira IssueServiceInterface .PHONY: build-image build-image: diff --git a/cmd/ocm-backplane/login/login.go b/cmd/ocm-backplane/login/login.go index e129e7a7..c42c1cf7 100644 --- a/cmd/ocm-backplane/login/login.go +++ b/cmd/ocm-backplane/login/login.go @@ -80,6 +80,9 @@ var ( RunE: runLogin, SilenceUsage: true, } + + //ohss service + ohssService *jira.OHSSService ) func init() { @@ -150,7 +153,7 @@ func runLogin(cmd *cobra.Command, argv []string) (err error) { clusterKey = info.ClusterID elevateReason = info.WebURL case LoginTypeJira: - ohssIssue, err := getClusterInfoFromJira(bpConfig) + ohssIssue, err := getClusterInfoFromJira() if err != nil { return err } @@ -627,16 +630,12 @@ func getClusterInfoFromPagerduty(bpConfig config.BackplaneConfiguration) (alert } // getClusterInfoFromJira returns a cluster info OHSS card -func getClusterInfoFromJira(bpConfig config.BackplaneConfiguration) (ohss jira.OHSSIssue, err error) { - if bpConfig.JiraAPIToken == "" || bpConfig.JiraBaseURL == "" { - return ohss, fmt.Errorf("please make sure the JIRA url and token are configured correctly in the config file") - } - jiraClient, err := jira.NewJiraFromConfig(bpConfig) - if err != nil { - return ohss, fmt.Errorf("could not initialize the client: %w", err) +func getClusterInfoFromJira() (ohss jira.OHSSIssue, err error) { + if ohssService == nil { + ohssService = jira.NewOHSSService(jira.DefaultIssueService) } - ohss, err = jiraClient.GetIssue(args.ohss) + ohss, err = ohssService.GetIssue(args.ohss) if err != nil { return ohss, err } diff --git a/cmd/ocm-backplane/login/login_test.go b/cmd/ocm-backplane/login/login_test.go index 4fe5a999..0e1c9f4e 100644 --- a/cmd/ocm-backplane/login/login_test.go +++ b/cmd/ocm-backplane/login/login_test.go @@ -14,13 +14,17 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" + "github.com/trivago/tgo/tcontainer" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" + "github.com/andygrunwald/go-jira" "github.com/openshift/backplane-cli/pkg/backplaneapi" backplaneapiMock "github.com/openshift/backplane-cli/pkg/backplaneapi/mocks" "github.com/openshift/backplane-cli/pkg/cli/config" "github.com/openshift/backplane-cli/pkg/client/mocks" + jiraClient "github.com/openshift/backplane-cli/pkg/jira" + jiraMock "github.com/openshift/backplane-cli/pkg/jira/mocks" "github.com/openshift/backplane-cli/pkg/login" "github.com/openshift/backplane-cli/pkg/ocm" ocmMock "github.com/openshift/backplane-cli/pkg/ocm/mocks" @@ -40,6 +44,7 @@ var _ = Describe("Login command", func() { mockClientWithResp *mocks.MockClientWithResponsesInterface mockOcmInterface *ocmMock.MockOCMInterface mockClientUtil *backplaneapiMock.MockClientUtils + mockIssueService *jiraMock.MockIssueServiceInterface testClusterID string testToken string @@ -576,4 +581,62 @@ var _ = Describe("Login command", func() { }) }) + + Context("check JIRA OHSS login", func() { + var ( + testOHSSID string + testIssue jira.Issue + issueFields *jira.IssueFields + ) + BeforeEach(func() { + mockIssueService = jiraMock.NewMockIssueServiceInterface(mockCtrl) + ohssService = jiraClient.NewOHSSService(mockIssueService) + testOHSSID = "OHSS-1000" + }) + + It("should login to ohss card cluster", func() { + + loginType = LoginTypeJira + args.ohss = testOHSSID + err := utils.CreateTempKubeConfig(nil) + args.kubeConfigPath = "" + Expect(err).To(BeNil()) + issueFields = &jira.IssueFields{ + Project: jira.Project{ID: jiraClient.JiraOHSSProjectID}, + Unknowns: tcontainer.MarshalMap{jiraClient.CustomFieldClusterID: testClusterID}, + } + testIssue = jira.Issue{ID: testOHSSID, Fields: issueFields} + globalOpts.ProxyURL = "https://squid.myproxy.com" + mockIssueService.EXPECT().Get(testOHSSID, nil).Return(&testIssue, nil, nil).Times(1) + mockOcmInterface.EXPECT().GetOCMEnvironment().Return(ocmEnv, nil).AnyTimes() + mockClientUtil.EXPECT().SetClientProxyURL(globalOpts.ProxyURL).Return(nil) + mockOcmInterface.EXPECT().GetTargetCluster(testClusterID).Return(testClusterID, testClusterID, nil) + mockOcmInterface.EXPECT().IsClusterHibernating(gomock.Eq(testClusterID)).Return(false, nil).AnyTimes() + mockOcmInterface.EXPECT().GetOCMAccessToken().Return(&testToken, nil) + mockClientUtil.EXPECT().MakeRawBackplaneAPIClientWithAccessToken(backplaneAPIURI, testToken).Return(mockClient, nil) + mockClient.EXPECT().LoginCluster(gomock.Any(), gomock.Eq(testClusterID)).Return(fakeResp, nil) + + err = runLogin(nil, nil) + + Expect(err).To(BeNil()) + }) + + It("should failed missing cluster id ohss cards", func() { + + loginType = LoginTypeJira + args.ohss = testOHSSID + + issueFields = &jira.IssueFields{ + Project: jira.Project{ID: jiraClient.JiraOHSSProjectID}, + } + testIssue = jira.Issue{ID: testOHSSID, Fields: issueFields} + mockIssueService.EXPECT().Get(testOHSSID, nil).Return(&testIssue, nil, nil).Times(1) + mockOcmInterface.EXPECT().GetOCMEnvironment().Return(ocmEnv, nil).AnyTimes() + + err := runLogin(nil, nil) + + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(Equal("clusterID cannot be detected for JIRA issue:OHSS-1000")) + }) + }) }) diff --git a/pkg/accessrequest/accessRequest.go b/pkg/accessrequest/accessRequest.go index abc8dfe0..aac6ff5c 100644 --- a/pkg/accessrequest/accessRequest.go +++ b/pkg/accessrequest/accessRequest.go @@ -9,6 +9,7 @@ import ( ocmsdk "github.com/openshift-online/ocm-sdk-go" acctrspv1 "github.com/openshift-online/ocm-sdk-go/accesstransparency/v1" "github.com/openshift/backplane-cli/pkg/cli/config" + jiraClient "github.com/openshift/backplane-cli/pkg/jira" "github.com/openshift/backplane-cli/pkg/ocm" "github.com/openshift/backplane-cli/pkg/utils" logger "github.com/sirupsen/logrus" @@ -114,7 +115,7 @@ func verifyAndPossiblyRetrieveIssue(bpConfig *config.BackplaneConfiguration, isP return nil, nil } - issue, _, err := utils.DefaultIssueService.Get(issueID, nil) + issue, _, err := jiraClient.DefaultIssueService.Get(issueID, nil) if err != nil { return nil, err } @@ -145,7 +146,7 @@ func createNotificationIssue(bpConfig *config.BackplaneConfiguration, isProd boo }, } - issue, _, err := utils.DefaultIssueService.Create(issue) + issue, _, err := jiraClient.DefaultIssueService.Create(issue) if err != nil { return nil, err } @@ -164,7 +165,7 @@ func getProjectFromIssueID(issueID string) string { } func transitionIssue(issueID, newTransitionName string) { - possibleTransitions, _, err := utils.DefaultIssueService.GetTransitions(issueID) + possibleTransitions, _, err := jiraClient.DefaultIssueService.GetTransitions(issueID) if err != nil { logger.Warnf("won't transition the '%s' JIRA issue to '%s' as it was not possible to retrieve the possible transitions for the issue: %v", issueID, newTransitionName, err) } else { @@ -180,7 +181,7 @@ func transitionIssue(issueID, newTransitionName string) { if transitionID == "" { logger.Warnf("won't transition the '%s' JIRA issue to '%s' as there is no transition named that way", issueID, newTransitionName) } else { - _, err := utils.DefaultIssueService.DoTransition(issueID, transitionID) + _, err := jiraClient.DefaultIssueService.DoTransition(issueID, transitionID) if err != nil { logger.Warnf("failed to transition the '%s' JIRA issue to '%s': %v", issueID, newTransitionName, err) @@ -196,7 +197,7 @@ func updateNotificationIssueDescription(issue *jira.Issue, onApprovalTransitionN onApprovalTransitionName, accessRequest.HREF()), } - _, _, err := utils.DefaultIssueService.Update(issue) + _, _, err := jiraClient.DefaultIssueService.Update(issue) if err != nil { logger.Warnf("failed to update the description of the '%s' JIRA issue: %v", issue.Key, err) } diff --git a/pkg/accessrequest/accessRequest_test.go b/pkg/accessrequest/accessRequest_test.go index e4e99937..e787fc10 100644 --- a/pkg/accessrequest/accessRequest_test.go +++ b/pkg/accessrequest/accessRequest_test.go @@ -17,10 +17,10 @@ import ( cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" "github.com/openshift/backplane-cli/pkg/backplaneapi" backplaneapiMock "github.com/openshift/backplane-cli/pkg/backplaneapi/mocks" + jiraClient "github.com/openshift/backplane-cli/pkg/jira" + jiraMocks "github.com/openshift/backplane-cli/pkg/jira/mocks" "github.com/openshift/backplane-cli/pkg/ocm" ocmMock "github.com/openshift/backplane-cli/pkg/ocm/mocks" - "github.com/openshift/backplane-cli/pkg/utils" - utilsMocks "github.com/openshift/backplane-cli/pkg/utils/mocks" ) const testDesc = "accessrequest package" @@ -57,7 +57,7 @@ var _ = Describe(testDesc, func() { mockCtrl *gomock.Controller mockClientUtil *backplaneapiMock.MockClientUtils mockOcmInterface *ocmMock.MockOCMInterface - mockIssueService *utilsMocks.MockIssueServiceInterface + mockIssueService *jiraMocks.MockIssueServiceInterface clusterID string ocmEnv *cmv1.Environment @@ -81,8 +81,8 @@ var _ = Describe(testDesc, func() { mockOcmInterface = ocmMock.NewMockOCMInterface(mockCtrl) ocm.DefaultOCMInterface = mockOcmInterface - mockIssueService = utilsMocks.NewMockIssueServiceInterface(mockCtrl) - utils.DefaultIssueService = mockIssueService + mockIssueService = jiraMocks.NewMockIssueServiceInterface(mockCtrl) + jiraClient.DefaultIssueService = mockIssueService clusterID = "cluster-12345678" diff --git a/pkg/elevate/England b/pkg/elevate/England new file mode 100644 index 00000000..ca3e6161 --- /dev/null +++ b/pkg/elevate/England @@ -0,0 +1,13 @@ +apiVersion: v1 +clusters: null +contexts: null +current-context: "" +kind: Config +preferences: {} +users: +- name: anonymous + user: + as: backplane-cluster-admin + as-user-extra: + reason: + - Production cluster diff --git a/pkg/jira/client.go b/pkg/jira/client.go deleted file mode 100644 index a93b925d..00000000 --- a/pkg/jira/client.go +++ /dev/null @@ -1,67 +0,0 @@ -package jira - -import ( - "fmt" - - "github.com/andygrunwald/go-jira" -) - -// JiraClient is an interface to handle jira functions -type JiraClient interface { - Connect(baseURL string, jiraToken string) error - SearchIssues(jql string, options *jira.SearchOptions) (issues []jira.Issue, err error) - GetIssue(issueID string, options *jira.GetQueryOptions) (*jira.Issue, error) - CreateIssue(issue *jira.Issue) (*jira.Issue, error) -} - -type DefaultJiraClientImpl struct { - client *jira.Client -} - -// NewClient creates an instance of Jira client and used to connect to the actual jira client. -func NewClient() *DefaultJiraClientImpl { - return &DefaultJiraClientImpl{} -} - -// Connect initiate the Jira connection -func (c *DefaultJiraClientImpl) Connect(baseURL string, jiraToken string) error { - - if baseURL == "" { - return fmt.Errorf("empty Jira base url") - } - - if jiraToken == "" { - return fmt.Errorf("empty Jira token") - } - - transport := jira.PATAuthTransport{ - Token: jiraToken, - } - JiraClient, err := jira.NewClient(transport.Client(), baseURL) - - if err != nil { - return err - } - c.client = JiraClient - return nil -} - -// SearchIssue returns the issues based on JQL -func (c *DefaultJiraClientImpl) SearchIssues(jql string, options *jira.SearchOptions) (issues []jira.Issue, err error) { - issues, _, err = c.client.Issue.Search(jql, options) - return issues, err - -} - -// SearchIssue returns the issues based on JQL -func (c *DefaultJiraClientImpl) GetIssue(issueID string, options *jira.GetQueryOptions) (*jira.Issue, error) { - issue, _, err := c.client.Issue.Get(issueID, options) - return issue, err - -} - -// Create Jira Issue -func (c *DefaultJiraClientImpl) CreateIssue(issue *jira.Issue) (*jira.Issue, error) { - issue, _, err := c.client.Issue.Create(issue) - return issue, err -} diff --git a/pkg/utils/jira.go b/pkg/jira/issueService.go similarity index 99% rename from pkg/utils/jira.go rename to pkg/jira/issueService.go index 0ffa84d9..901935f4 100644 --- a/pkg/utils/jira.go +++ b/pkg/jira/issueService.go @@ -1,4 +1,4 @@ -package utils +package jira import ( "errors" diff --git a/pkg/jira/jira.go b/pkg/jira/jira.go deleted file mode 100644 index 97789466..00000000 --- a/pkg/jira/jira.go +++ /dev/null @@ -1,109 +0,0 @@ -package jira - -import ( - "fmt" - - "github.com/andygrunwald/go-jira" - "github.com/openshift/backplane-cli/pkg/cli/config" -) - -const ( - JiraOHSSProjectID = "OHSS" - CustomFieldClusterID = "customfield_12316349" - JqlGetIssueTemplate = `project = "%s" AND issue = "%s"` - JqlGetIssuesForClusterTemplate = `(project = "%s" AND "Cluster ID" ~ "%s") - OR (project = "%s" AND "Cluster ID" ~ "%s") - ORDER BY created DESC` -) - -type OHSSIssue struct { - ID string - Title string - ProjectID string - WebURL string - ClusterID string -} - -type Jira struct { - client JiraClient -} - -func NewJira(client JiraClient) *Jira { - return &Jira{ - client: client, - } -} - -func NewJiraFromConfig(bpConfig config.BackplaneConfiguration) (*Jira, error) { - jiraClient := NewClient() - err := jiraClient.Connect(bpConfig.JiraBaseURL, bpConfig.JiraAPIToken) - - if err != nil { - return nil, err - } - - return &Jira{ - client: jiraClient, - }, nil - -} - -// GetIssue returns matching issue from OHSS project -func (j *Jira) GetIssue(issueID string) (ohssIssue OHSSIssue, err error) { - - if issueID == "" { - return ohssIssue, fmt.Errorf("empty issue Id") - } - issue, err := j.client.GetIssue(issueID, nil) - if err != nil { - return ohssIssue, err - } - if issue != nil { - formatIssue, err := j.formatIssue(*issue) - if err != nil { - return ohssIssue, err - } - return formatIssue, nil - } else { - return ohssIssue, fmt.Errorf("no matching issue for issueID:%s", issueID) - - } - -} - -// GetJiraIssuesForCluster returns all matching issues for cluster ID -func (j *Jira) GetJiraIssuesForCluster(clusterID string, externalClusterID string) ([]jira.Issue, error) { - - if clusterID == "" && externalClusterID == "" { - return nil, fmt.Errorf("empty cluster id and external cluster id ") - } - - jql := fmt.Sprintf( - JqlGetIssuesForClusterTemplate, - JiraOHSSProjectID, - clusterID, - JiraOHSSProjectID, - externalClusterID, - ) - issues, err := j.client.SearchIssues(jql, nil) - if err != nil { - return nil, err - } - return issues, nil -} - -// formatIssue for -func (j *Jira) formatIssue(issue jira.Issue) (formatIssue OHSSIssue, err error) { - - formatIssue.ID = issue.ID - if issue.Fields != nil { - clusterID, clusterIDExist := issue.Fields.Unknowns[CustomFieldClusterID] - if clusterIDExist { - formatIssue.ClusterID = fmt.Sprintf("%s", clusterID) - } - } - formatIssue.WebURL = issue.Self - formatIssue.Title = issue.Fields.Summary - formatIssue.ProjectID = issue.Fields.Project.ID - return formatIssue, nil -} diff --git a/pkg/jira/jira_suite_test.go b/pkg/jira/jira_suite_test.go index a7f89641..45853149 100644 --- a/pkg/jira/jira_suite_test.go +++ b/pkg/jira/jira_suite_test.go @@ -9,5 +9,5 @@ import ( func TestJira(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Jira Suite") + RunSpecs(t, "Jira Service Suite") } diff --git a/pkg/jira/jira_test.go b/pkg/jira/jira_test.go deleted file mode 100644 index 48d2dcee..00000000 --- a/pkg/jira/jira_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package jira - -import ( - "github.com/andygrunwald/go-jira" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - jiraMock "github.com/openshift/backplane-cli/pkg/jira/mocks" -) - -var _ = Describe("Jira", func() { - var ( - mockCtrl *gomock.Controller - mockJiraClient *jiraMock.MockJiraClient - jiraClient *Jira - testOHSSID string - testIssue jira.Issue - //testGetJql string - ) - - BeforeEach(func() { - mockCtrl = gomock.NewController(GinkgoT()) - mockJiraClient = jiraMock.NewMockJiraClient(mockCtrl) - jiraClient = NewJira(mockJiraClient) - testOHSSID = "OHSS-1000" - testIssue = jira.Issue{ID: testOHSSID} - //testGetJql = fmt.Sprintf(JqlGetIssueTemplate, JiraOHSSProjectName, testOHSSID) - - }) - - AfterEach(func() { - mockCtrl.Finish() - }) - - Context("When Jira client executes", func() { - It("Should return one issue", func() { - - mockJiraClient.EXPECT().GetIssue(testOHSSID, nil).Return(&testIssue, nil).Times(1) - - issue, err := jiraClient.GetIssue(testOHSSID) - Expect(err).To(BeNil()) - Expect(issue.ID).To(Equal(testOHSSID)) - }) - It("Should return error for empty issue", func() { - - mockJiraClient.EXPECT().GetIssue(testOHSSID, nil).Return(nil, nil).Times(1) - - _, err := jiraClient.GetIssue(testOHSSID) - Expect(err).NotTo(BeNil()) - Expect(err.Error()).To(Equal("no matching issue for issueID:OHSS-1000")) - }) - }) -}) diff --git a/pkg/jira/mocks/clientMock.go b/pkg/jira/mocks/clientMock.go deleted file mode 100644 index 7a734a3b..00000000 --- a/pkg/jira/mocks/clientMock.go +++ /dev/null @@ -1,94 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/openshift/backplane-cli/pkg/jira (interfaces: JiraClient) - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - - jira "github.com/andygrunwald/go-jira" - gomock "github.com/golang/mock/gomock" -) - -// MockJiraClient is a mock of JiraClient interface. -type MockJiraClient struct { - ctrl *gomock.Controller - recorder *MockJiraClientMockRecorder -} - -// MockJiraClientMockRecorder is the mock recorder for MockJiraClient. -type MockJiraClientMockRecorder struct { - mock *MockJiraClient -} - -// NewMockJiraClient creates a new mock instance. -func NewMockJiraClient(ctrl *gomock.Controller) *MockJiraClient { - mock := &MockJiraClient{ctrl: ctrl} - mock.recorder = &MockJiraClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockJiraClient) EXPECT() *MockJiraClientMockRecorder { - return m.recorder -} - -// Connect mocks base method. -func (m *MockJiraClient) Connect(arg0, arg1 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Connect", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Connect indicates an expected call of Connect. -func (mr *MockJiraClientMockRecorder) Connect(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockJiraClient)(nil).Connect), arg0, arg1) -} - -// CreateIssue mocks base method. -func (m *MockJiraClient) CreateIssue(arg0 *jira.Issue) (*jira.Issue, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateIssue", arg0) - ret0, _ := ret[0].(*jira.Issue) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateIssue indicates an expected call of CreateIssue. -func (mr *MockJiraClientMockRecorder) CreateIssue(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateIssue", reflect.TypeOf((*MockJiraClient)(nil).CreateIssue), arg0) -} - -// GetIssue mocks base method. -func (m *MockJiraClient) GetIssue(arg0 string, arg1 *jira.GetQueryOptions) (*jira.Issue, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetIssue", arg0, arg1) - ret0, _ := ret[0].(*jira.Issue) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetIssue indicates an expected call of GetIssue. -func (mr *MockJiraClientMockRecorder) GetIssue(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIssue", reflect.TypeOf((*MockJiraClient)(nil).GetIssue), arg0, arg1) -} - -// SearchIssues mocks base method. -func (m *MockJiraClient) SearchIssues(arg0 string, arg1 *jira.SearchOptions) ([]jira.Issue, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SearchIssues", arg0, arg1) - ret0, _ := ret[0].([]jira.Issue) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SearchIssues indicates an expected call of SearchIssues. -func (mr *MockJiraClientMockRecorder) SearchIssues(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchIssues", reflect.TypeOf((*MockJiraClient)(nil).SearchIssues), arg0, arg1) -} diff --git a/pkg/utils/mocks/jiraMock.go b/pkg/jira/mocks/jiraMock.go similarity index 97% rename from pkg/utils/mocks/jiraMock.go rename to pkg/jira/mocks/jiraMock.go index c2a975a3..03c52882 100644 --- a/pkg/utils/mocks/jiraMock.go +++ b/pkg/jira/mocks/jiraMock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/openshift/backplane-cli/pkg/utils (interfaces: IssueServiceInterface) +// Source: github.com/openshift/backplane-cli/pkg/jira (interfaces: IssueServiceInterface) // Package mocks is a generated GoMock package. package mocks diff --git a/pkg/jira/ohssService.go b/pkg/jira/ohssService.go new file mode 100644 index 00000000..90f350df --- /dev/null +++ b/pkg/jira/ohssService.go @@ -0,0 +1,74 @@ +package jira + +import ( + "fmt" + + "github.com/andygrunwald/go-jira" +) + +const ( + JiraOHSSProjectID = "OHSS" + CustomFieldClusterID = "customfield_12316349" +) + +type OHSSIssue struct { + ID string + Title string + ProjectID string + WebURL string + ClusterID string +} + +type OHSSService struct { + issueService IssueServiceInterface +} + +func NewOHSSService(client IssueServiceInterface) *OHSSService { + return &OHSSService{ + issueService: client, + } +} + +// GetIssue returns matching issue from OHSS project +func (j *OHSSService) GetIssue(issueID string) (ohssIssue OHSSIssue, err error) { + + if issueID == "" { + return ohssIssue, fmt.Errorf("empty issue Id") + } + issue, _, err := j.issueService.Get(issueID, nil) + if err != nil { + return ohssIssue, err + } + if issue == nil { + return ohssIssue, fmt.Errorf("no matching issue for issueID:%s", issueID) + } + + if issue.Fields != nil { + if issue.Fields.Project.ID != JiraOHSSProjectID { + return ohssIssue, fmt.Errorf("issue %s is not belongs to OHSS project", issueID) + } + } + formatIssue, err := j.formatIssue(*issue) + if err != nil { + return ohssIssue, err + } + return formatIssue, nil + +} + +// formatIssue format the JIRA issue to OHSS Issue +func (j *OHSSService) formatIssue(issue jira.Issue) (formatIssue OHSSIssue, err error) { + + formatIssue.ID = issue.ID + if issue.Fields != nil { + clusterID, clusterIDExist := issue.Fields.Unknowns[CustomFieldClusterID] + if clusterIDExist { + formatIssue.ClusterID = fmt.Sprintf("%s", clusterID) + } + formatIssue.ProjectID = issue.Fields.Project.ID + formatIssue.Title = issue.Fields.Summary + } + formatIssue.WebURL = issue.Self + + return formatIssue, nil +} diff --git a/pkg/jira/ohssService_test.go b/pkg/jira/ohssService_test.go new file mode 100644 index 00000000..be4b8af4 --- /dev/null +++ b/pkg/jira/ohssService_test.go @@ -0,0 +1,66 @@ +package jira + +import ( + "github.com/andygrunwald/go-jira" + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + jiraMock "github.com/openshift/backplane-cli/pkg/jira/mocks" +) + +var _ = Describe("Jira", func() { + var ( + mockCtrl *gomock.Controller + mockIssueService *jiraMock.MockIssueServiceInterface + ohssService *OHSSService + testOHSSID string + testIssue jira.Issue + issueFields *jira.IssueFields + ) + + BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) + mockIssueService = jiraMock.NewMockIssueServiceInterface(mockCtrl) + ohssService = NewOHSSService(mockIssueService) + testOHSSID = "OHSS-1000" + issueFields = &jira.IssueFields{Project: jira.Project{ID: JiraOHSSProjectID}} + testIssue = jira.Issue{ID: testOHSSID, Fields: issueFields} + + }) + + AfterEach(func() { + mockCtrl.Finish() + }) + + Context("When Jira client executes", func() { + It("Should return one issue", func() { + + mockIssueService.EXPECT().Get(testOHSSID, nil).Return(&testIssue, nil, nil).Times(1) + + issue, err := ohssService.GetIssue(testOHSSID) + Expect(err).To(BeNil()) + Expect(issue.ID).To(Equal(testOHSSID)) + Expect(issue.ProjectID).To(Equal(JiraOHSSProjectID)) + }) + + It("Should return error for issue not belongs to OHSS project", func() { + + nonOHSSfields := &jira.IssueFields{Project: jira.Project{ID: "NON-OHSS"}} + nonOHSSIssue := jira.Issue{ID: testOHSSID, Fields: nonOHSSfields} + mockIssueService.EXPECT().Get(testOHSSID, nil).Return(&nonOHSSIssue, nil, nil).Times(1) + + _, err := ohssService.GetIssue(testOHSSID) + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(Equal("issue OHSS-1000 is not belongs to OHSS project")) + }) + + It("Should return error for empty issue", func() { + + mockIssueService.EXPECT().Get(testOHSSID, nil).Return(nil, nil, nil).Times(1) + + _, err := ohssService.GetIssue(testOHSSID) + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(Equal("no matching issue for issueID:OHSS-1000")) + }) + }) +})