1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
// 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"
metaKeyJiraBaseUrl = "jira-base-url"
metaKeyJiraExportTime = "jira-export-time"
metaKeyJiraLogin = "jira-login"
confKeyBaseUrl = "base-url"
confKeyProject = "project"
confKeyDefaultLogin = "default-login"
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
}
|