diff options
Diffstat (limited to 'bridge/jira/jira.go')
-rw-r--r-- | bridge/jira/jira.go | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/bridge/jira/jira.go b/bridge/jira/jira.go new file mode 100644 index 00000000..b891ee3d --- /dev/null +++ b/bridge/jira/jira.go @@ -0,0 +1,143 @@ +// Package jira contains the Jira bridge implementation +package jira + +import ( + "context" + "fmt" + "sort" + "time" + + "github.com/MichaelMure/git-bug/bridge/core" + "github.com/MichaelMure/git-bug/bridge/core/auth" + "github.com/MichaelMure/git-bug/input" +) + +const ( + target = "jira" + + metaKeyJiraId = "jira-id" + metaKeyJiraDerivedId = "jira-derived-id" + metaKeyJiraKey = "jira-key" + metaKeyJiraUser = "jira-user" + metaKeyJiraProject = "jira-project" + metaKeyJiraExportTime = "jira-export-time" + metaKeyJiraLogin = "jira-login" + + confKeyBaseUrl = "base-url" + confKeyProject = "project" + confKeyCredentialType = "credentials-type" // "SESSION" or "TOKEN" + confKeyIDMap = "bug-id-map" + confKeyIDRevMap = "bug-id-revmap" + // the issue type when exporting a new bug. Default is Story (10001) + confKeyCreateDefaults = "create-issue-defaults" + // if set, the bridge fill this JIRA field with the `git-bug` id when exporting + confKeyCreateGitBug = "create-issue-gitbug-id" + + defaultTimeout = 60 * time.Second +) + +var _ core.BridgeImpl = &Jira{} + +// Jira Main object for the bridge +type Jira struct{} + +// Target returns "jira" +func (*Jira) Target() string { + return target +} + +func (*Jira) LoginMetaKey() string { + return metaKeyJiraLogin +} + +// NewImporter returns the jira importer +func (*Jira) NewImporter() core.Importer { + return &jiraImporter{} +} + +// NewExporter returns the jira exporter +func (*Jira) NewExporter() core.Exporter { + return &jiraExporter{} +} + +func buildClient(ctx context.Context, baseURL string, credType string, cred auth.Credential) (*Client, error) { + client := NewClient(ctx, baseURL) + + var login, password string + + switch cred := cred.(type) { + case *auth.LoginPassword: + login = cred.Login + password = cred.Password + case *auth.Login: + login = cred.Login + p, err := input.PromptPassword(fmt.Sprintf("Password for %s", login), "password", input.Required) + if err != nil { + return nil, err + } + password = p + } + + err := client.Login(credType, login, password) + if err != nil { + return nil, err + } + + return client, nil +} + +// stringInSlice returns true if needle is found in haystack +func stringInSlice(needle string, haystack []string) bool { + for _, match := range haystack { + if match == needle { + return true + } + } + return false +} + +// Given two string slices, return three lists containing: +// 1. elements found only in the first input list +// 2. elements found only in the second input list +// 3. elements found in both input lists +func setSymmetricDifference(setA, setB []string) ([]string, []string, []string) { + sort.Strings(setA) + sort.Strings(setB) + + maxLen := len(setA) + len(setB) + onlyA := make([]string, 0, maxLen) + onlyB := make([]string, 0, maxLen) + both := make([]string, 0, maxLen) + + idxA := 0 + idxB := 0 + + for idxA < len(setA) && idxB < len(setB) { + if setA[idxA] < setB[idxB] { + // In the first set, but not the second + onlyA = append(onlyA, setA[idxA]) + idxA++ + } else if setA[idxA] > setB[idxB] { + // In the second set, but not the first + onlyB = append(onlyB, setB[idxB]) + idxB++ + } else { + // In both + both = append(both, setA[idxA]) + idxA++ + idxB++ + } + } + + for ; idxA < len(setA); idxA++ { + // Leftovers in the first set, not the second + onlyA = append(onlyA, setA[idxA]) + } + + for ; idxB < len(setB); idxB++ { + // Leftovers in the second set, not the first + onlyB = append(onlyB, setB[idxB]) + } + + return onlyA, onlyB, both +} |