feat: Expose re_requested and state on merge request webhook reviewers

event_webhook_types.go models both merge-request reviewer fields with EventUser:

type MergeEvent struct {
    ...
    Reviewers []*EventUser `json:"reviewers"`
}

type MergeEventChanges struct {
    ...
    Reviewers MergeEventChangesReviewers `json:"reviewers"`
}

type MergeEventChangesReviewers struct {
    Previous []*EventUser `json:"previous"`
    Current  []*EventUser `json:"current"`
}

type EventUser struct {
    ID        int64  `json:"id"`
    Name      string `json:"name"`
    Username  string `json:"username"`
    AvatarURL string `json:"avatar_url"`
    Email     string `json:"email"`
}

Every reviewer object GitLab emits — in the top-level reviewers array and inside changes.reviewers.previous / changes.reviewers.current — includes a reviewer state and a re_requested flag that EventUser has no fields for. Both are silently discarded on json.Unmarshal, so consumers cannot read reviewer approval state or detect re-request-review events. Documented under Reviewer state tracking and Re-request review events:

  • state: unreviewed, review_started, reviewed, requested_changes, approved, unapproved
  • re_requested: falsetrue when a reviewer is re-requested

Evidence (real captured webhook payload)

Top-level reviewers array (emails redacted):

"reviewers": [
  { "id": 23211065, "username": "m.ferreira2", "state": "approved", "re_requested": false, "avatar_url": "…", "email": "[REDACTED]" }
]

changes.reviewers on a re-request (note the state transition and re_requested: true):

"changes": {
  "reviewers": {
    "previous": [
      { "id": 23211065, "username": "m.ferreira2", "state": "approved", "re_requested": false }
    ],
    "current": [
      { "id": 23211065, "username": "m.ferreira2", "state": "unreviewed", "re_requested": true }
    ]
  }
}

The { "previous": [...], "current": [...] } container matches MergeEventChangesReviewers correctly - the only gap is the missing per-reviewer fields.

Note: the GitLab public docs' Re-request review events / Submit review events examples render changes.reviewers as a positional array of arrays ([[previous], [current]]). That is a docs inaccuracy: the actual webhook payload uses the { previous, current } object shown above, which the Go type already models correctly.

Fix

A dedicated EventReviewer type carries the reviewer-specific fields alongside the standard user fields:

type EventReviewer struct {
    ID          int64  `json:"id"`
    Name        string `json:"name"`
    Username    string `json:"username"`
    AvatarURL   string `json:"avatar_url"`
    Email       string `json:"email"`
    State       string `json:"state"`
    ReRequested bool   `json:"re_requested"`
}

MergeEvent.Reviewers and MergeEventChangesReviewers.Previous/Current now use []*EventReviewer. This changes exported field types, so it's a breaking change and targets the next major (release-client-3.0).

Merge request reports

Loading
Loading