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