aboutsummaryrefslogtreecommitdiffstats
path: root/bridge/jira/jira.go
blob: 6423843c4aa5bdb44bc46f2537091a2711ef117b (plain) (blame)
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
}