Merge pull request #192 from MichaelMure/github-exporter-label

Amine created

bridge: Github exporter support case sensitive labels

Change summary

bridge/github/export.go       | 58 ++++++++++++++++++++++++++++--------
bridge/github/export_test.go  |  8 ++++
bridge/github/import_query.go | 14 ++++++++
3 files changed, 65 insertions(+), 15 deletions(-)

Detailed changes

bridge/github/export.go 🔗

@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net/http"
+	"strings"
 	"time"
 
 	"github.com/pkg/errors"
@@ -100,6 +101,17 @@ func (ge *githubExporter) ExportAll(ctx context.Context, repo *cache.RepoCache,
 		return nil, err
 	}
 
+	client, err := ge.getIdentityClient(user.Id())
+	if err != nil {
+		return nil, err
+	}
+
+	// query all labels
+	err = ge.cacheGithubLabels(ctx, client)
+	if err != nil {
+		return nil, err
+	}
+
 	go func() {
 		defer close(out)
 
@@ -433,28 +445,46 @@ func markOperationAsExported(b *cache.BugCache, target entity.Id, githubID, gith
 	return err
 }
 
-// get label from github
-func (ge *githubExporter) getGithubLabelID(ctx context.Context, gc *githubv4.Client, label string) (string, error) {
-	q := &labelQuery{}
+func (ge *githubExporter) cacheGithubLabels(ctx context.Context, gc *githubv4.Client) error {
 	variables := map[string]interface{}{
-		"label": githubv4.String(label),
 		"owner": githubv4.String(ge.conf[keyOwner]),
 		"name":  githubv4.String(ge.conf[keyProject]),
+		"first": githubv4.Int(10),
+		"after": (*githubv4.String)(nil),
 	}
 
-	ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
-	defer cancel()
+	q := labelsQuery{}
 
-	if err := gc.Query(ctx, q, variables); err != nil {
-		return "", err
+	hasNextPage := true
+	for hasNextPage {
+		// create a new timeout context at each iteration
+		ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
+		defer cancel()
+
+		if err := gc.Query(ctx, &q, variables); err != nil {
+			return err
+		}
+
+		for _, label := range q.Repository.Labels.Nodes {
+			ge.cachedLabels[label.Name] = label.ID
+		}
+
+		hasNextPage = q.Repository.Labels.PageInfo.HasNextPage
+		variables["after"] = q.Repository.Labels.PageInfo.EndCursor
 	}
 
-	// if label id is empty, it means there is no such label in this Github repository
-	if q.Repository.Label.ID == "" {
-		return "", fmt.Errorf("label not found")
+	return nil
+}
+
+func (ge *githubExporter) getLabelID(gc *githubv4.Client, label string) (string, error) {
+	label = strings.ToLower(label)
+	for cachedLabel, ID := range ge.cachedLabels {
+		if label == strings.ToLower(cachedLabel) {
+			return ID, nil
+		}
 	}
 
-	return q.Repository.Label.ID, nil
+	return "", fmt.Errorf("didn't find label id in cache")
 }
 
 // create a new label and return it github id
@@ -539,8 +569,8 @@ func (ge *githubExporter) createGithubLabelV4(gc *githubv4.Client, label, labelC
 */
 
 func (ge *githubExporter) getOrCreateGithubLabelID(ctx context.Context, gc *githubv4.Client, repositoryID string, label bug.Label) (string, error) {
-	// try to get label id
-	labelID, err := ge.getGithubLabelID(ctx, gc, string(label))
+	// try to get label id from cache
+	labelID, err := ge.getLabelID(gc, string(label))
 	if err == nil {
 		return labelID, nil
 	}

bridge/github/export_test.go 🔗

@@ -55,6 +55,12 @@ func testCases(t *testing.T, repo *cache.RepoCache, identity *cache.IdentityCach
 	_, _, err = bugLabelChange.ChangeLabels(nil, []string{"bug"})
 	require.NoError(t, err)
 
+	_, _, err = bugLabelChange.ChangeLabels([]string{"InVaLiD"}, nil)
+	require.NoError(t, err)
+
+	_, _, err = bugLabelChange.ChangeLabels([]string{"bUG"}, nil)
+	require.NoError(t, err)
+
 	// bug with comments editions
 	bugWithCommentEditions, createOp, err := repo.NewBug("bug with comments editions", "new bug")
 	require.NoError(t, err)
@@ -99,7 +105,7 @@ func testCases(t *testing.T, repo *cache.RepoCache, identity *cache.IdentityCach
 		&testCase{
 			name:    "bug label change",
 			bug:     bugLabelChange,
-			numOrOp: 4,
+			numOrOp: 6,
 		},
 		&testCase{
 			name:    "bug with comment editions",

bridge/github/import_query.go 🔗

@@ -175,3 +175,17 @@ type labelQuery struct {
 		} `graphql:"label(name: $label)"`
 	} `graphql:"repository(owner: $owner, name: $name)"`
 }
+
+type labelsQuery struct {
+	Repository struct {
+		Labels struct {
+			Nodes []struct {
+				ID          string `graphql:"id"`
+				Name        string `graphql:"name"`
+				Color       string `graphql:"color"`
+				Description string `graphql:"description"`
+			}
+			PageInfo pageInfo
+		} `graphql:"labels(first: $first, after: $after)"`
+	} `graphql:"repository(owner: $owner, name: $name)"`
+}