1package launchpad
2
3import (
4 "fmt"
5 "time"
6
7 "github.com/MichaelMure/git-bug/bridge/core"
8 "github.com/MichaelMure/git-bug/bug"
9 "github.com/MichaelMure/git-bug/cache"
10 "github.com/MichaelMure/git-bug/identity"
11 "github.com/pkg/errors"
12)
13
14type launchpadImporter struct {
15 conf core.Configuration
16}
17
18func (li *launchpadImporter) Init(conf core.Configuration) error {
19 li.conf = conf
20 return nil
21}
22
23const keyLaunchpadID = "launchpad-id"
24const keyLaunchpadLogin = "launchpad-login"
25
26func (li *launchpadImporter) makePerson(repo *cache.RepoCache, owner LPPerson) (*cache.IdentityCache, error) {
27 // Look first in the cache
28 i, err := repo.ResolveIdentityImmutableMetadata(keyLaunchpadLogin, owner.Login)
29 if err == nil {
30 return i, nil
31 }
32 if _, ok := err.(identity.ErrMultipleMatch); ok {
33 return nil, err
34 }
35
36 return repo.NewIdentityRaw(
37 owner.Name,
38 "",
39 owner.Login,
40 "",
41 map[string]string{
42 keyLaunchpadLogin: owner.Login,
43 },
44 )
45}
46
47func (li *launchpadImporter) ImportAll(repo *cache.RepoCache) error {
48 lpAPI := new(launchpadAPI)
49
50 err := lpAPI.Init()
51 if err != nil {
52 return err
53 }
54
55 lpBugs, err := lpAPI.SearchTasks(li.conf["project"])
56 if err != nil {
57 return err
58 }
59
60 for _, lpBug := range lpBugs {
61 var b *cache.BugCache
62 var err error
63
64 lpBugID := fmt.Sprintf("%d", lpBug.ID)
65 b, err = repo.ResolveBugCreateMetadata(keyLaunchpadID, lpBugID)
66 if err != nil && err != bug.ErrBugNotExist {
67 return err
68 }
69
70 owner, err := li.makePerson(repo, lpBug.Owner)
71 if err != nil {
72 return err
73 }
74
75 if err == bug.ErrBugNotExist {
76 createdAt, _ := time.Parse(time.RFC3339, lpBug.CreatedAt)
77 b, err = repo.NewBugRaw(
78 owner,
79 createdAt.Unix(),
80 lpBug.Title,
81 lpBug.Description,
82 nil,
83 map[string]string{
84 keyLaunchpadID: lpBugID,
85 },
86 )
87 if err != nil {
88 return errors.Wrapf(err, "failed to add bug id #%s", lpBugID)
89 }
90 } else {
91 /* TODO: Update bug */
92 fmt.Println("TODO: Update bug")
93 }
94
95 /* Handle messages */
96 if len(lpBug.Messages) == 0 {
97 return errors.Wrapf(err, "failed to fetch comments for bug #%s", lpBugID)
98 }
99
100 // The Launchpad API returns the bug description as the first
101 // comment, so skip it.
102 for _, lpMessage := range lpBug.Messages[1:] {
103 _, err := b.ResolveTargetWithMetadata(keyLaunchpadID, lpMessage.ID)
104 if err != nil && err != cache.ErrNoMatchingOp {
105 return errors.Wrapf(err, "failed to fetch comments for bug #%s", lpBugID)
106 }
107
108 // If this comment already exists, we are probably
109 // updating an existing bug. We do not want to duplicate
110 // the comments, so let us just skip this one.
111 // TODO: Can Launchpad comments be edited?
112 if err == nil {
113 continue
114 }
115
116 owner, err := li.makePerson(repo, lpMessage.Owner)
117 if err != nil {
118 return err
119 }
120
121 // This is a new comment, we can add it.
122 createdAt, _ := time.Parse(time.RFC3339, lpMessage.CreatedAt)
123 err = b.AddCommentRaw(
124 owner,
125 createdAt.Unix(),
126 lpMessage.Content,
127 nil,
128 map[string]string{
129 keyLaunchpadID: lpMessage.ID,
130 })
131 if err != nil {
132 return errors.Wrapf(err, "failed to add comment to bug #%s", lpBugID)
133 }
134 }
135 err = b.CommitAsNeeded()
136 if err != nil {
137 return err
138 }
139 }
140 return nil
141}
142
143func (li *launchpadImporter) Import(repo *cache.RepoCache, id string) error {
144 fmt.Println("IMPORT")
145 return nil
146}