diff options
Diffstat (limited to 'bridge/gitlab')
-rw-r--r-- | bridge/gitlab/export.go | 195 | ||||
-rw-r--r-- | bridge/gitlab/export_test.go | 11 |
2 files changed, 135 insertions, 71 deletions
diff --git a/bridge/gitlab/export.go b/bridge/gitlab/export.go index 3f339354..5b7c35d0 100644 --- a/bridge/gitlab/export.go +++ b/bridge/gitlab/export.go @@ -1,6 +1,7 @@ package gitlab import ( + "context" "fmt" "strconv" "time" @@ -74,7 +75,7 @@ func (ge *gitlabExporter) getIdentityClient(id entity.Id) (*gitlab.Client, error } // ExportAll export all event made by the current user to Gitlab -func (ge *gitlabExporter) ExportAll(repo *cache.RepoCache, since time.Time) (<-chan core.ExportResult, error) { +func (ge *gitlabExporter) ExportAll(ctx context.Context, repo *cache.RepoCache, since time.Time) (<-chan core.ExportResult, error) { out := make(chan core.ExportResult) user, err := repo.GetUserIdentity() @@ -115,7 +116,7 @@ func (ge *gitlabExporter) ExportAll(repo *cache.RepoCache, since time.Time) (<-c if snapshot.HasAnyActor(allIdentitiesIds...) { // try to export the bug and it associated events - ge.exportBug(b, since, out) + ge.exportBug(ctx, b, since, out) } else { out <- core.NewExportNothing(id, "not an actor") } @@ -126,7 +127,7 @@ func (ge *gitlabExporter) ExportAll(repo *cache.RepoCache, since time.Time) (<-c } // exportBug publish bugs and related events -func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan<- core.ExportResult) { +func (ge *gitlabExporter) exportBug(ctx context.Context, b *cache.BugCache, since time.Time, out chan<- core.ExportResult) { snapshot := b.Snapshot() var err error @@ -181,7 +182,7 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan } // create bug - id, url, err := createGitlabIssue(client, ge.repositoryID, createOp.Title, createOp.Message) + id, url, err := createGitlabIssue(ctx, client, ge.repositoryID, createOp.Title, createOp.Message) if err != nil { err := errors.Wrap(err, "exporting gitlab issue") out <- core.NewExportError(err, b.Id()) @@ -189,7 +190,6 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan } idString := strconv.Itoa(id) - out <- core.NewExportBug(b.Id()) // mark bug creation operation as exported @@ -215,6 +215,7 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan // cache operation gitlab id ge.cachedOperationIDs[bugCreationId] = bugGitlabIDString + var actualLabels []string for _, op := range snapshot.Operations[1:] { // ignore SetMetadata operations if _, ok := op.(*bug.SetMetadataOperation); ok { @@ -243,7 +244,7 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan opr := op.(*bug.AddCommentOperation) // send operation to gitlab - id, err = addCommentGitlabIssue(client, ge.repositoryID, bugGitlabID, opr.Message) + id, err = addCommentGitlabIssue(ctx, client, ge.repositoryID, bugGitlabID, opr.Message) if err != nil { err := errors.Wrap(err, "adding comment") out <- core.NewExportError(err, b.Id()) @@ -264,7 +265,7 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan if targetId == bugCreationId { // case bug creation operation: we need to edit the Gitlab issue - if err := updateGitlabIssueBody(client, ge.repositoryID, bugGitlabID, opr.Message); err != nil { + if err := updateGitlabIssueBody(ctx, client, ge.repositoryID, bugGitlabID, opr.Message); err != nil { err := errors.Wrap(err, "editing issue") out <- core.NewExportError(err, b.Id()) return @@ -286,7 +287,7 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan panic("unexpected comment id format") } - if err := editCommentGitlabIssue(client, ge.repositoryID, commentIDint, id, opr.Message); err != nil { + if err := editCommentGitlabIssue(ctx, client, ge.repositoryID, commentIDint, id, opr.Message); err != nil { err := errors.Wrap(err, "editing comment") out <- core.NewExportError(err, b.Id()) return @@ -298,7 +299,7 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan case *bug.SetStatusOperation: opr := op.(*bug.SetStatusOperation) - if err := updateGitlabIssueStatus(client, idString, id, opr.Status); err != nil { + if err := updateGitlabIssueStatus(ctx, client, idString, id, opr.Status); err != nil { err := errors.Wrap(err, "editing status") out <- core.NewExportError(err, b.Id()) return @@ -309,7 +310,7 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan case *bug.SetTitleOperation: opr := op.(*bug.SetTitleOperation) - if err := updateGitlabIssueTitle(client, ge.repositoryID, id, opr.Title); err != nil { + if err := updateGitlabIssueTitle(ctx, client, ge.repositoryID, id, opr.Title); err != nil { err := errors.Wrap(err, "editing title") out <- core.NewExportError(err, b.Id()) return @@ -319,8 +320,31 @@ func (ge *gitlabExporter) exportBug(b *cache.BugCache, since time.Time, out chan id = bugGitlabID case *bug.LabelChangeOperation: - _ = op.(*bug.LabelChangeOperation) - if err := updateGitlabIssueLabels(client, ge.repositoryID, bugGitlabID, []string{}); err != nil { + opr := op.(*bug.LabelChangeOperation) + // we need to set the actual list of labels at each label change operation + // because gitlab update issue requests need directly the latest list of the verison + + if len(opr.Added) != 0 { + for _, label := range opr.Added { + actualLabels = append(actualLabels, string(label)) + } + } + + if len(opr.Removed) != 0 { + var newActualLabels []string + for _, label := range actualLabels { + for _, l := range opr.Removed { + if label == string(l) { + continue + } + + newActualLabels = append(newActualLabels, label) + } + } + actualLabels = newActualLabels + } + + if err := updateGitlabIssueLabels(ctx, client, ge.repositoryID, bugGitlabID, actualLabels); err != nil { err := errors.Wrap(err, "updating labels") out <- core.NewExportError(err, b.Id()) return @@ -370,35 +394,25 @@ func (ge *gitlabExporter) getGitlabLabelID(label string) (string, error) { } // get label from gitlab -func (ge *gitlabExporter) loadLabelsFromGitlab(gc *gitlab.Client) error { - labels, _, err := gc.Labels.ListLabels( - ge.repositoryID, - &gitlab.ListLabelsOptions{ - Page: 0, - }, - ) - - if err != nil { - return err - } - - for _, label := range labels { - ge.cachedLabels[label.Name] = strconv.Itoa(label.ID) - } - - for page := 2; len(labels) != 0; page++ { - - labels, _, err = gc.Labels.ListLabels( +func (ge *gitlabExporter) loadLabelsFromGitlab(ctx context.Context, gc *gitlab.Client) error { + page := 1 + for ; ; page++ { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + labels, _, err := gc.Labels.ListLabels( ge.repositoryID, &gitlab.ListLabelsOptions{ Page: page, }, + gitlab.WithContext(ctx), ) - if err != nil { return err } + if len(labels) == 0 { + break + } for _, label := range labels { ge.cachedLabels[label.Name] = strconv.Itoa(label.ID) } @@ -407,7 +421,7 @@ func (ge *gitlabExporter) loadLabelsFromGitlab(gc *gitlab.Client) error { return nil } -func (ge *gitlabExporter) createGitlabLabel(gc *gitlab.Client, label bug.Label) error { +func (ge *gitlabExporter) createGitlabLabel(ctx context.Context, gc *gitlab.Client, label bug.Label) error { client := buildClient(ge.conf[keyToken]) // RGBA to hex color @@ -415,21 +429,31 @@ func (ge *gitlabExporter) createGitlabLabel(gc *gitlab.Client, label bug.Label) hexColor := fmt.Sprintf("%.2x%.2x%.2x", rgba.R, rgba.G, rgba.B) name := label.String() - _, _, err := client.Labels.CreateLabel(ge.repositoryID, &gitlab.CreateLabelOptions{ - Name: &name, - Color: &hexColor, - }) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + _, _, err := client.Labels.CreateLabel(ge.repositoryID, + &gitlab.CreateLabelOptions{ + Name: &name, + Color: &hexColor, + }, + gitlab.WithContext(ctx), + ) return err } // create a gitlab. issue and return it ID -func createGitlabIssue(gc *gitlab.Client, repositoryID, title, body string) (int, string, error) { - issue, _, err := gc.Issues.CreateIssue(repositoryID, &gitlab.CreateIssueOptions{ - Title: &title, - Description: &body, - }) - +func createGitlabIssue(ctx context.Context, gc *gitlab.Client, repositoryID, title, body string) (int, string, error) { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + issue, _, err := gc.Issues.CreateIssue( + repositoryID, + &gitlab.CreateIssueOptions{ + Title: &title, + Description: &body, + }, + gitlab.WithContext(ctx), + ) if err != nil { return 0, "", err } @@ -438,11 +462,16 @@ func createGitlabIssue(gc *gitlab.Client, repositoryID, title, body string) (int } // add a comment to an issue and return it ID -func addCommentGitlabIssue(gc *gitlab.Client, repositoryID string, issueID int, body string) (int, error) { - note, _, err := gc.Notes.CreateIssueNote(repositoryID, issueID, &gitlab.CreateIssueNoteOptions{ - Body: &body, - }) - +func addCommentGitlabIssue(ctx context.Context, gc *gitlab.Client, repositoryID string, issueID int, body string) (int, error) { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + note, _, err := gc.Notes.CreateIssueNote( + repositoryID, issueID, + &gitlab.CreateIssueNoteOptions{ + Body: &body, + }, + gitlab.WithContext(ctx), + ) if err != nil { return 0, err } @@ -450,15 +479,21 @@ func addCommentGitlabIssue(gc *gitlab.Client, repositoryID string, issueID int, return note.ID, nil } -func editCommentGitlabIssue(gc *gitlab.Client, repositoryID string, issueID, noteID int, body string) error { - _, _, err := gc.Notes.UpdateIssueNote(repositoryID, issueID, noteID, &gitlab.UpdateIssueNoteOptions{ - Body: &body, - }) +func editCommentGitlabIssue(ctx context.Context, gc *gitlab.Client, repositoryID string, issueID, noteID int, body string) error { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + _, _, err := gc.Notes.UpdateIssueNote( + repositoryID, issueID, noteID, + &gitlab.UpdateIssueNoteOptions{ + Body: &body, + }, + gitlab.WithContext(ctx), + ) return err } -func updateGitlabIssueStatus(gc *gitlab.Client, repositoryID string, issueID int, status bug.Status) error { +func updateGitlabIssueStatus(ctx context.Context, gc *gitlab.Client, repositoryID string, issueID int, status bug.Status) error { var state string switch status { @@ -470,34 +505,58 @@ func updateGitlabIssueStatus(gc *gitlab.Client, repositoryID string, issueID int panic("unknown bug state") } - _, _, err := gc.Issues.UpdateIssue(repositoryID, issueID, &gitlab.UpdateIssueOptions{ - StateEvent: &state, - }) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + _, _, err := gc.Issues.UpdateIssue( + repositoryID, issueID, + &gitlab.UpdateIssueOptions{ + StateEvent: &state, + }, + gitlab.WithContext(ctx), + ) return err } -func updateGitlabIssueBody(gc *gitlab.Client, repositoryID string, issueID int, body string) error { - _, _, err := gc.Issues.UpdateIssue(repositoryID, issueID, &gitlab.UpdateIssueOptions{ - Description: &body, - }) +func updateGitlabIssueBody(ctx context.Context, gc *gitlab.Client, repositoryID string, issueID int, body string) error { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + _, _, err := gc.Issues.UpdateIssue( + repositoryID, issueID, + &gitlab.UpdateIssueOptions{ + Description: &body, + }, + gitlab.WithContext(ctx), + ) return err } -func updateGitlabIssueTitle(gc *gitlab.Client, repositoryID string, issueID int, title string) error { - _, _, err := gc.Issues.UpdateIssue(repositoryID, issueID, &gitlab.UpdateIssueOptions{ - Title: &title, - }) +func updateGitlabIssueTitle(ctx context.Context, gc *gitlab.Client, repositoryID string, issueID int, title string) error { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + _, _, err := gc.Issues.UpdateIssue( + repositoryID, issueID, + &gitlab.UpdateIssueOptions{ + Title: &title, + }, + gitlab.WithContext(ctx), + ) return err } // update gitlab. issue labels -func updateGitlabIssueLabels(gc *gitlab.Client, repositoryID string, issueID int, labels []string) error { - _, _, err := gc.Issues.UpdateIssue(repositoryID, issueID, &gitlab.UpdateIssueOptions{ - Labels: labels, - }) +func updateGitlabIssueLabels(ctx context.Context, gc *gitlab.Client, repositoryID string, issueID int, labels []string) error { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + _, _, err := gc.Issues.UpdateIssue( + repositoryID, issueID, + &gitlab.UpdateIssueOptions{ + Labels: labels, + }, + gitlab.WithContext(ctx), + ) return err } diff --git a/bridge/gitlab/export_test.go b/bridge/gitlab/export_test.go index 43403361..f7a99610 100644 --- a/bridge/gitlab/export_test.go +++ b/bridge/gitlab/export_test.go @@ -174,13 +174,14 @@ func TestPushPull(t *testing.T) { }) require.NoError(t, err) + ctx := context.Background() start := time.Now() // export all bugs - events, err := exporter.ExportAll(backend, time.Time{}) + exportEvents, err := exporter.ExportAll(ctx, backend, time.Time{}) require.NoError(t, err) - for result := range events { + for result := range exportEvents { require.NoError(t, result.Err) } require.NoError(t, err) @@ -202,9 +203,13 @@ func TestPushPull(t *testing.T) { require.NoError(t, err) // import all exported bugs to the second backend - err = importer.ImportAll(backendTwo, time.Time{}) + importEvents, err := importer.ImportAll(ctx, backendTwo, time.Time{}) require.NoError(t, err) + for result := range importEvents { + require.NoError(t, result.Err) + } + require.Len(t, backendTwo.AllBugsIds(), len(tests)) for _, tt := range tests { |