Skip to content

Commit

Permalink
feat: Add merge request note events
Browse files Browse the repository at this point in the history
  • Loading branch information
cluttrdev committed Sep 16, 2024
1 parent 053d870 commit 9480e4d
Show file tree
Hide file tree
Showing 13 changed files with 828 additions and 316 deletions.
2 changes: 2 additions & 0 deletions configs/gitlab-exporter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ project_defaults:
# requires fetching entire job logs to parse for embedded metrics.
enabled: true

note_events: true

mergerequests:
# Whether or not to export merge request data
enabled: true
Expand Down
12 changes: 12 additions & 0 deletions grpc/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ func RecordMergeRequests(c *Client, ctx context.Context, data []*typespb.MergeRe
return nil
}

func RecordMergeRequestNoteEvents(c *Client, ctx context.Context, data []*typespb.MergeRequestNoteEvent) error {
req := &servicepb.RecordMergeRequestNoteEventsRequest{
Data: data,
}
_, err := c.stub.RecordMergeRequestNoteEvents(ctx, req /* opts ...grpc.CallOption */)
if err != nil {
return fmt.Errorf("error recording merge request note events: %w", err)
}

return nil
}

func RecordMetrics(c *Client, ctx context.Context, data []*typespb.Metric) error {
req := &servicepb.RecordMetricsRequest{
Data: data,
Expand Down
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ type ProjectExportMetrics struct {

type ProjectExportMergeRequests struct {
Enabled bool `default:"true" yaml:"enabled"`

NoteEvents bool `default:"true" yaml:"note_events"`
}

type ProjectCatchUp struct {
Expand Down
4 changes: 4 additions & 0 deletions internal/exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func (e *Exporter) ExportMergeRequests(ctx context.Context, data []*typespb.Merg
return export[*typespb.MergeRequest](e, ctx, data, grpc_client.RecordMergeRequests)
}

func (e *Exporter) ExportMergeRequestNoteEvents(ctx context.Context, data []*typespb.MergeRequestNoteEvent) error {
return export[*typespb.MergeRequestNoteEvent](e, ctx, data, grpc_client.RecordMergeRequestNoteEvents)
}

func (e *Exporter) ExportMetrics(ctx context.Context, data []*typespb.Metric) error {
return export[*typespb.Metric](e, ctx, data, grpc_client.RecordMetrics)
}
Expand Down
24 changes: 24 additions & 0 deletions internal/jobs/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ func (j *ProjectExportJob) exportProjectMergeRequests(ctx context.Context) {
j.WorkerPool.Submit(func(ctx context.Context) {
defer wg.Done()
mergerequests := make([]*typespb.MergeRequest, 0, len(iids))
mrNoteEvents := make([]*typespb.MergeRequestNoteEvent, 0, len(iids))

opt := _gitlab.GetMergeRequestsOptions{}
for _, iid := range iids {
Expand All @@ -181,13 +182,36 @@ func (j *ProjectExportJob) exportProjectMergeRequests(ctx context.Context) {
}

mergerequests = append(mergerequests, types.ConvertMergeRequest(mr))

if j.Config.Export.MergeRequests.NoteEvents {
notes, err := tasks.FetchMergeRequestNotes(ctx, glab, projectID, iid)
if err != nil {
if errors.Is(err, context.Canceled) {
break
}
slog.Error("error fetching merge request note events", "project_id", projectID, "iid", iid)
continue
}

for _, note := range notes {
if ev := types.ConvertToMergeRequestNoteEvent(note); ev != nil {
mrNoteEvents = append(mrNoteEvents, ev)
}
}
}
}

if len(mergerequests) > 0 {
if err := j.Exporter.ExportMergeRequests(ctx, mergerequests); err != nil {
slog.Error(fmt.Sprintf("error exporting merge requests: %v", err))
}
}

if len(mrNoteEvents) > 0 {
if err := j.Exporter.ExportMergeRequestNoteEvents(ctx, mrNoteEvents); err != nil {
slog.Error(fmt.Sprintf("error exporting merge request note events: %v", err))
}
}
})

if resp.NextLink == "" {
Expand Down
54 changes: 54 additions & 0 deletions internal/tasks/mergerequests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package tasks

import (
"context"

gitlab "github.com/xanzy/go-gitlab"
)

func FetchProjectMergeRequest(ctx context.Context, glab *gitlab.Client, pid int64, iid int64) (*gitlab.MergeRequest, error) {
opt := gitlab.GetMergeRequestsOptions{}

mr, _, err := glab.MergeRequests.GetMergeRequest(int(pid), int(iid), &opt, gitlab.WithContext(ctx))
if err != nil {
return nil, err
}

return mr, nil
}

func FetchMergeRequestNotes(ctx context.Context, glab *gitlab.Client, pid interface{}, iid int) ([]*gitlab.Note, error) {
opts := gitlab.ListMergeRequestNotesOptions{
ListOptions: gitlab.ListOptions{
Pagination: "keyset",
PerPage: 100,
OrderBy: "created_at",
Sort: "desc",
},
}

options := []gitlab.RequestOptionFunc{
gitlab.WithContext(ctx),
}

var notes []*gitlab.Note
for {
ns, resp, err := glab.Notes.ListMergeRequestNotes(pid, iid, &opts, options...)
if err != nil {
return nil, err
}

notes = append(notes, ns...)

if resp.NextLink == "" {
break
}

options = []gitlab.RequestOptionFunc{
gitlab.WithContext(ctx),
gitlab.WithKeysetPaginationParameters(resp.NextLink),
}
}

return notes, nil
}
69 changes: 69 additions & 0 deletions internal/types/mergerequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,75 @@ func ConvertMergeRequest(mr *gitlab.MergeRequest) *typespb.MergeRequest {
}
}

func ConvertToMergeRequestNoteEvent(note *gitlab.Note) *typespb.MergeRequestNoteEvent {
if note.NoteableType != "MergeRequest" {
return nil
}

evType := getNoteEventType(note)
if evType == "" {
return nil
}

return &typespb.MergeRequestNoteEvent{
Id: int64(note.ID),
MergerequestId: int64(note.NoteableID),
MergerequestIid: int64(note.NoteableIID),
ProjectId: int64(note.ProjectID),
CreatedAt: ConvertTime(note.CreatedAt),
UpdatedAt: ConvertTime(note.UpdatedAt),
Type: evType,
System: note.System,
AuthorId: int64(note.Author.ID),
Resolveable: note.Resolvable,
Resolved: note.Resolved,
ResolverId: int64(note.ResolvedBy.ID),
Confidential: note.Confidential,
Internal: note.Internal,
}
}

func getNoteEventType(note *gitlab.Note) string {
if t := string(note.Type); t != "" {
switch t {
case "DiffNote", "DiscussionNote":
return t
}
}

if note.System {
switch {
case note.Body == "resolved all threads":
return "AllThreadsResolved"

case note.Body == "approved this merge request":
return "Approved"
case note.Body == "unapproved this merge request":
return "Unapproved"

case note.Body == "changed the description":
return "DescriptionChanged"

case note.Body == "marked this merge request as **draft**":
return "MarkedDraft"
case note.Body == "marked this merge request as **ready**":
return "MarkedReady"

case strings.HasPrefix(note.Body, "assigned to"):
return "Assigned"
case strings.HasPrefix(note.Body, "unassigned"):
return "Unassigned"

case strings.HasPrefix(note.Body, "requested review"):
return "ReviewRequested"
case strings.HasPrefix(note.Body, "removed review requested"):
return "ReviewRequestRemoved"
}
}

return ""
}

func convertBasicUser(u *gitlab.BasicUser) *typespb.User {
if u == nil {
return nil
Expand Down
Loading

0 comments on commit 9480e4d

Please sign in to comment.