diff options
Diffstat (limited to 'bridge/github')
-rw-r--r-- | bridge/github/github.go | 4 | ||||
-rw-r--r-- | bridge/github/import.go | 34 | ||||
-rw-r--r-- | bridge/github/import_test.go | 148 | ||||
-rw-r--r-- | bridge/github/iterator.go | 154 |
4 files changed, 169 insertions, 171 deletions
diff --git a/bridge/github/github.go b/bridge/github/github.go index b3f8d763..5fee7487 100644 --- a/bridge/github/github.go +++ b/bridge/github/github.go @@ -27,9 +27,9 @@ func (*Github) NewExporter() core.Exporter { return nil } -func buildClient(conf core.Configuration) *githubv4.Client { +func buildClient(token string) *githubv4.Client { src := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: conf[keyToken]}, + &oauth2.Token{AccessToken: token}, ) httpClient := oauth2.NewClient(context.TODO(), src) diff --git a/bridge/github/import.go b/bridge/github/import.go index 5f99b5ea..ad9d5046 100644 --- a/bridge/github/import.go +++ b/bridge/github/import.go @@ -22,29 +22,27 @@ const ( // githubImporter implement the Importer interface type githubImporter struct { - iterator *iterator - conf core.Configuration + conf core.Configuration } func (gi *githubImporter) Init(conf core.Configuration) error { gi.conf = conf - gi.iterator = newIterator(conf) return nil } // ImportAll . func (gi *githubImporter) ImportAll(repo *cache.RepoCache, since time.Time) error { - gi.iterator.since = since + iterator := NewIterator(gi.conf[keyUser], gi.conf[keyProject], gi.conf[keyToken], since) // Loop over all matching issues - for gi.iterator.NextIssue() { - issue := gi.iterator.IssueValue() + for iterator.NextIssue() { + issue := iterator.IssueValue() - fmt.Printf("importing issue: %v %v\n", gi.iterator.count, issue.Title) + fmt.Printf("importing issue: %v %v\n", iterator.importedIssues, issue.Title) // get issue edits issueEdits := []userContentEdit{} - for gi.iterator.NextIssueEdit() { - if issueEdit := gi.iterator.IssueEditValue(); issueEdit.Diff != nil && string(*issueEdit.Diff) != "" { + for iterator.NextIssueEdit() { + if issueEdit := iterator.IssueEditValue(); issueEdit.Diff != nil && string(*issueEdit.Diff) != "" { issueEdits = append(issueEdits, issueEdit) } } @@ -56,15 +54,15 @@ func (gi *githubImporter) ImportAll(repo *cache.RepoCache, since time.Time) erro } // loop over timeline items - for gi.iterator.NextTimeline() { - item := gi.iterator.TimelineValue() + for iterator.NextTimeline() { + item := iterator.TimelineValue() // if item is comment if item.Typename == "IssueComment" { // collect all edits commentEdits := []userContentEdit{} - for gi.iterator.NextCommentEdit() { - if commentEdit := gi.iterator.CommentEditValue(); commentEdit.Diff != nil && string(*commentEdit.Diff) != "" { + for iterator.NextCommentEdit() { + if commentEdit := iterator.CommentEditValue(); commentEdit.Diff != nil && string(*commentEdit.Diff) != "" { commentEdits = append(commentEdits, commentEdit) } } @@ -87,12 +85,12 @@ func (gi *githubImporter) ImportAll(repo *cache.RepoCache, since time.Time) erro } } - if err := gi.iterator.Error(); err != nil { + if err := iterator.Error(); err != nil { fmt.Printf("import error: %v\n", err) return err } - fmt.Printf("Successfully imported %v issues from Github\n", gi.iterator.Count()) + fmt.Printf("Successfully imported %v issues from Github\n", iterator.ImportedIssues()) return nil } @@ -389,7 +387,7 @@ func (gi *githubImporter) ensureCommentEdit(repo *cache.RepoCache, b *cache.BugC switch { case edit.DeletedAt != nil: // comment deletion, not supported yet - fmt.Println("comment deletion ....") + fmt.Println("comment deletion is not supported yet") case edit.DeletedAt == nil: @@ -475,7 +473,9 @@ func (gi *githubImporter) getGhost(repo *cache.RepoCache) (*cache.IdentityCache, "login": githubv4.String("ghost"), } - err = gi.iterator.gc.Query(context.TODO(), &q, variables) + gc := buildClient(gi.conf[keyToken]) + + err = gc.Query(context.TODO(), &q, variables) if err != nil { return nil, err } diff --git a/bridge/github/import_test.go b/bridge/github/import_test.go index d64f0b4b..79af8450 100644 --- a/bridge/github/import_test.go +++ b/bridge/github/import_test.go @@ -18,15 +18,13 @@ import ( func Test_Importer(t *testing.T) { author := identity.NewIdentity("Michael Muré", "batolettre@gmail.com") tests := []struct { - name string - exist bool - url string - bug *bug.Snapshot + name string + url string + bug *bug.Snapshot }{ { - name: "simple issue", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/1", + name: "simple issue", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/1", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "simple issue", "initial comment", nil), @@ -35,9 +33,8 @@ func Test_Importer(t *testing.T) { }, }, { - name: "empty issue", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/2", + name: "empty issue", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/2", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "empty issue", "", nil), @@ -45,9 +42,8 @@ func Test_Importer(t *testing.T) { }, }, { - name: "complex issue", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/3", + name: "complex issue", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/3", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "complex issue", "initial comment", nil), @@ -63,9 +59,8 @@ func Test_Importer(t *testing.T) { }, }, { - name: "editions", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/4", + name: "editions", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/4", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "editions", "initial comment edited", nil), @@ -76,9 +71,8 @@ func Test_Importer(t *testing.T) { }, }, { - name: "comment deletion", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/5", + name: "comment deletion", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/5", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "comment deletion", "", nil), @@ -86,9 +80,8 @@ func Test_Importer(t *testing.T) { }, }, { - name: "edition deletion", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/6", + name: "edition deletion", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/6", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "edition deletion", "initial comment", nil), @@ -99,9 +92,8 @@ func Test_Importer(t *testing.T) { }, }, { - name: "hidden comment", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/7", + name: "hidden comment", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/7", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "hidden comment", "initial comment", nil), @@ -110,9 +102,8 @@ func Test_Importer(t *testing.T) { }, }, { - name: "transfered issue", - exist: true, - url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/8", + name: "transfered issue", + url: "https://github.com/MichaelMure/git-but-test-github-bridge/issues/8", bug: &bug.Snapshot{ Operations: []bug.Operation{ bug.NewCreateOp(author, 0, "transfered issue", "", nil), @@ -139,11 +130,16 @@ func Test_Importer(t *testing.T) { defer backend.Close() interrupt.RegisterCleaner(backend.Close) + token := os.Getenv("GITHUB_TOKEN") + if token == "" { + t.Skip("Env var GITHUB_TOKEN missing") + } + importer := &githubImporter{} err = importer.Init(core.Configuration{ "user": "MichaelMure", "project": "git-but-test-github-bridge", - "token": os.Getenv("GITHUB_TOKEN"), + "token": token, }) if err != nil { t.Fatal(err) @@ -165,59 +161,53 @@ func Test_Importer(t *testing.T) { } ops := b.Snapshot().Operations - if tt.exist { - assert.Equal(t, len(tt.bug.Operations), len(b.Snapshot().Operations)) - - for i, op := range tt.bug.Operations { - switch op.(type) { - case *bug.CreateOperation: - if op2, ok := ops[i].(*bug.CreateOperation); ok { - assert.Equal(t, op2.Title, op.(*bug.CreateOperation).Title) - assert.Equal(t, op2.Message, op.(*bug.CreateOperation).Message) - continue - } - t.Errorf("bad operation type index = %d expected = CreationOperation", i) - case *bug.SetStatusOperation: - if op2, ok := ops[i].(*bug.SetStatusOperation); ok { - assert.Equal(t, op2.Status, op.(*bug.SetStatusOperation).Status) - continue - } - t.Errorf("bad operation type index = %d expected = SetStatusOperation", i) - case *bug.SetTitleOperation: - if op2, ok := ops[i].(*bug.SetTitleOperation); ok { - assert.Equal(t, op.(*bug.SetTitleOperation).Was, op2.Was) - assert.Equal(t, op.(*bug.SetTitleOperation).Title, op2.Title) - continue - } - t.Errorf("bad operation type index = %d expected = SetTitleOperation", i) - case *bug.LabelChangeOperation: - if op2, ok := ops[i].(*bug.LabelChangeOperation); ok { - assert.ElementsMatch(t, op.(*bug.LabelChangeOperation).Added, op2.Added) - assert.ElementsMatch(t, op.(*bug.LabelChangeOperation).Removed, op2.Removed) - continue - } - t.Errorf("bad operation type index = %d expected = ChangeLabelOperation", i) - case *bug.AddCommentOperation: - if op2, ok := ops[i].(*bug.AddCommentOperation); ok { - assert.Equal(t, op.(*bug.AddCommentOperation).Message, op2.Message) - continue - } - t.Errorf("bad operation type index = %d expected = AddCommentOperation", i) - case *bug.EditCommentOperation: - if op2, ok := ops[i].(*bug.EditCommentOperation); ok { - assert.Equal(t, op.(*bug.EditCommentOperation).Message, op2.Message) - continue - } - t.Errorf("bad operation type index = %d expected = EditCommentOperation", i) - default: - + assert.Equal(t, len(tt.bug.Operations), len(b.Snapshot().Operations)) + + for i, op := range tt.bug.Operations { + switch op.(type) { + case *bug.CreateOperation: + if op2, ok := ops[i].(*bug.CreateOperation); ok { + assert.Equal(t, op2.Title, op.(*bug.CreateOperation).Title) + assert.Equal(t, op2.Message, op.(*bug.CreateOperation).Message) + continue + } + t.Errorf("bad operation type index = %d expected = CreationOperation", i) + case *bug.SetStatusOperation: + if op2, ok := ops[i].(*bug.SetStatusOperation); ok { + assert.Equal(t, op2.Status, op.(*bug.SetStatusOperation).Status) + continue + } + t.Errorf("bad operation type index = %d expected = SetStatusOperation", i) + case *bug.SetTitleOperation: + if op2, ok := ops[i].(*bug.SetTitleOperation); ok { + assert.Equal(t, op.(*bug.SetTitleOperation).Was, op2.Was) + assert.Equal(t, op.(*bug.SetTitleOperation).Title, op2.Title) + continue } + t.Errorf("bad operation type index = %d expected = SetTitleOperation", i) + case *bug.LabelChangeOperation: + if op2, ok := ops[i].(*bug.LabelChangeOperation); ok { + assert.ElementsMatch(t, op.(*bug.LabelChangeOperation).Added, op2.Added) + assert.ElementsMatch(t, op.(*bug.LabelChangeOperation).Removed, op2.Removed) + continue + } + t.Errorf("bad operation type index = %d expected = ChangeLabelOperation", i) + case *bug.AddCommentOperation: + if op2, ok := ops[i].(*bug.AddCommentOperation); ok { + assert.Equal(t, op.(*bug.AddCommentOperation).Message, op2.Message) + continue + } + t.Errorf("bad operation type index = %d expected = AddCommentOperation", i) + case *bug.EditCommentOperation: + if op2, ok := ops[i].(*bug.EditCommentOperation); ok { + assert.Equal(t, op.(*bug.EditCommentOperation).Message, op2.Message) + continue + } + t.Errorf("bad operation type index = %d expected = EditCommentOperation", i) + default: + panic("Unknown operation type") } - - } else { - assert.Equal(t, b, nil) } }) } - } diff --git a/bridge/github/iterator.go b/bridge/github/iterator.go index 281f8a6b..239b49bd 100644 --- a/bridge/github/iterator.go +++ b/bridge/github/iterator.go @@ -4,7 +4,6 @@ import ( "context" "time" - "github.com/MichaelMure/git-bug/bridge/core" "github.com/shurcooL/githubv4" ) @@ -50,8 +49,8 @@ type iterator struct { // sticky error err error - // count to keep track of the number of imported issues - count int + // number of imported issues + importedIssues int // timeline iterator timeline timelineIterator @@ -63,32 +62,32 @@ type iterator struct { commentEdit commentEditIterator } -func newIterator(conf core.Configuration) *iterator { +func NewIterator(user, project, token string, since time.Time) *iterator { return &iterator{ - gc: buildClient(conf), + gc: buildClient(token), + since: since, capacity: 10, - count: 0, timeline: timelineIterator{ index: -1, issueEdit: indexer{-1}, commentEdit: indexer{-1}, variables: map[string]interface{}{ - "owner": githubv4.String(conf["user"]), - "name": githubv4.String(conf["project"]), + "owner": githubv4.String(user), + "name": githubv4.String(project), }, }, commentEdit: commentEditIterator{ index: -1, variables: map[string]interface{}{ - "owner": githubv4.String(conf["user"]), - "name": githubv4.String(conf["project"]), + "owner": githubv4.String(user), + "name": githubv4.String(project), }, }, issueEdit: issueEditIterator{ index: -1, variables: map[string]interface{}{ - "owner": githubv4.String(conf["user"]), - "name": githubv4.String(conf["project"]), + "owner": githubv4.String(user), + "name": githubv4.String(project), }, }, } @@ -130,10 +129,11 @@ func (i *iterator) initCommentEditQueryVariables() { // reverse UserContentEdits arrays in both of the issue and // comment timelines func (i *iterator) reverseTimelineEditNodes() { - reverseEdits(i.timeline.query.Repository.Issues.Nodes[0].UserContentEdits.Nodes) - for index, ce := range i.timeline.query.Repository.Issues.Nodes[0].Timeline.Edges { - if ce.Node.Typename == "IssueComment" && len(i.timeline.query.Repository.Issues.Nodes[0].Timeline.Edges) != 0 { - reverseEdits(i.timeline.query.Repository.Issues.Nodes[0].Timeline.Edges[index].Node.IssueComment.UserContentEdits.Nodes) + node := i.timeline.query.Repository.Issues.Nodes[0] + reverseEdits(node.UserContentEdits.Nodes) + for index, ce := range node.Timeline.Edges { + if ce.Node.Typename == "IssueComment" && len(node.Timeline.Edges) != 0 { + reverseEdits(node.Timeline.Edges[index].Node.IssueComment.UserContentEdits.Nodes) } } } @@ -143,19 +143,34 @@ func (i *iterator) Error() error { return i.err } -// Count return number of issues we iterated over -func (i *iterator) Count() int { - return i.count +// ImportedIssues return the number of issues we iterated over +func (i *iterator) ImportedIssues() int { + return i.importedIssues +} + +func (i *iterator) queryIssue() bool { + if err := i.gc.Query(context.TODO(), &i.timeline.query, i.timeline.variables); err != nil { + i.err = err + return false + } + + if len(i.timeline.query.Repository.Issues.Nodes) == 0 { + return false + } + + i.reverseTimelineEditNodes() + i.importedIssues++ + return true } // Next issue func (i *iterator) NextIssue() bool { // we make the first move - if i.count == 0 { + if i.importedIssues == 0 { // init variables and goto queryIssue block i.initTimelineQueryVariables() - goto queryIssue + return i.queryIssue() } if i.err != nil { @@ -175,19 +190,7 @@ func (i *iterator) NextIssue() bool { i.timeline.lastEndCursor = i.timeline.query.Repository.Issues.Nodes[0].Timeline.PageInfo.EndCursor // query issue block -queryIssue: - if err := i.gc.Query(context.TODO(), &i.timeline.query, i.timeline.variables); err != nil { - i.err = err - return false - } - - if len(i.timeline.query.Repository.Issues.Nodes) == 0 { - return false - } - - i.reverseTimelineEditNodes() - i.count++ - return true + return i.queryIssue() } func (i *iterator) IssueValue() issueTimeline { @@ -230,6 +233,27 @@ func (i *iterator) TimelineValue() timelineItem { return i.timeline.query.Repository.Issues.Nodes[0].Timeline.Edges[i.timeline.index].Node } +func (i *iterator) queryIssueEdit() bool { + if err := i.gc.Query(context.TODO(), &i.issueEdit.query, i.issueEdit.variables); err != nil { + i.err = err + //i.timeline.issueEdit.index = -1 + return false + } + + // reverse issue edits because github + reverseEdits(i.issueEdit.query.Repository.Issues.Nodes[0].UserContentEdits.Nodes) + + // this is not supposed to happen + if len(i.issueEdit.query.Repository.Issues.Nodes[0].UserContentEdits.Nodes) == 0 { + i.timeline.issueEdit.index = -1 + return false + } + + i.issueEdit.index = 0 + i.timeline.issueEdit.index = -2 + return true +} + func (i *iterator) NextIssueEdit() bool { if i.err != nil { return false @@ -251,7 +275,7 @@ func (i *iterator) NextIssueEdit() bool { // if there is more edits, query them i.issueEdit.variables["issueEditBefore"] = i.issueEdit.query.Repository.Issues.Nodes[0].UserContentEdits.PageInfo.StartCursor - goto queryIssueEdit + return i.queryIssueEdit() } // if there is no edits @@ -273,26 +297,7 @@ func (i *iterator) NextIssueEdit() bool { // if there is more edits, query them i.initIssueEditQueryVariables() i.issueEdit.variables["issueEditBefore"] = i.timeline.query.Repository.Issues.Nodes[0].UserContentEdits.PageInfo.StartCursor - -queryIssueEdit: - if err := i.gc.Query(context.TODO(), &i.issueEdit.query, i.issueEdit.variables); err != nil { - i.err = err - //i.timeline.issueEdit.index = -1 - return false - } - - // reverse issue edits because github - reverseEdits(i.issueEdit.query.Repository.Issues.Nodes[0].UserContentEdits.Nodes) - - // this is not supposed to happen - if len(i.issueEdit.query.Repository.Issues.Nodes[0].UserContentEdits.Nodes) == 0 { - i.timeline.issueEdit.index = -1 - return false - } - - i.issueEdit.index = 0 - i.timeline.issueEdit.index = -2 - return true + return i.queryIssueEdit() } func (i *iterator) IssueEditValue() userContentEdit { @@ -305,6 +310,25 @@ func (i *iterator) IssueEditValue() userContentEdit { return i.timeline.query.Repository.Issues.Nodes[0].UserContentEdits.Nodes[i.timeline.issueEdit.index] } +func (i *iterator) queryCommentEdit() bool { + if err := i.gc.Query(context.TODO(), &i.commentEdit.query, i.commentEdit.variables); err != nil { + i.err = err + return false + } + + // this is not supposed to happen + if len(i.commentEdit.query.Repository.Issues.Nodes[0].Timeline.Nodes[0].IssueComment.UserContentEdits.Nodes) == 0 { + i.timeline.commentEdit.index = -1 + return false + } + + reverseEdits(i.commentEdit.query.Repository.Issues.Nodes[0].Timeline.Nodes[0].IssueComment.UserContentEdits.Nodes) + + i.commentEdit.index = 0 + i.timeline.commentEdit.index = -2 + return true +} + func (i *iterator) NextCommentEdit() bool { if i.err != nil { return false @@ -326,7 +350,7 @@ func (i *iterator) NextCommentEdit() bool { // if there is more comment edits, query them i.commentEdit.variables["commentEditBefore"] = i.commentEdit.query.Repository.Issues.Nodes[0].Timeline.Nodes[0].IssueComment.UserContentEdits.PageInfo.StartCursor - goto queryCommentEdit + return i.queryCommentEdit() } // if there is no comment edits @@ -354,23 +378,7 @@ func (i *iterator) NextCommentEdit() bool { i.commentEdit.variables["commentEditBefore"] = i.timeline.query.Repository.Issues.Nodes[0].Timeline.Edges[i.timeline.index].Node.IssueComment.UserContentEdits.PageInfo.StartCursor -queryCommentEdit: - if err := i.gc.Query(context.TODO(), &i.commentEdit.query, i.commentEdit.variables); err != nil { - i.err = err - return false - } - - // this is not supposed to happen - if len(i.commentEdit.query.Repository.Issues.Nodes[0].Timeline.Nodes[0].IssueComment.UserContentEdits.Nodes) == 0 { - i.timeline.commentEdit.index = -1 - return false - } - - reverseEdits(i.commentEdit.query.Repository.Issues.Nodes[0].Timeline.Nodes[0].IssueComment.UserContentEdits.Nodes) - - i.commentEdit.index = 0 - i.timeline.commentEdit.index = -2 - return true + return i.queryCommentEdit() } func (i *iterator) CommentEditValue() userContentEdit { |