import.go

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