Loading event_parsing_webhook_test.go +2 −2 Original line number Diff line number Diff line Loading @@ -361,7 +361,7 @@ func TestParseWikiPageHook(t *testing.T) { func TestParseEmojiHook(t *testing.T) { t.Parallel() raw := loadFixture(t, "testdata/webhooks/emoji.json") raw := loadFixture(t, "testdata/webhooks/emoji_issue.json") parsedEvent, err := ParseWebhook("Emoji Hook", raw) assert.NoError(t, err) Loading @@ -383,7 +383,7 @@ func TestParseEmojiHook(t *testing.T) { func TestParseMilestoneHook(t *testing.T) { t.Parallel() raw := loadFixture(t, "testdata/webhooks/milestone.json") raw := loadFixture(t, "testdata/webhooks/milestone_project.json") parsedEvent, err := ParseWebhook("Milestone Hook", raw) assert.NoError(t, err) Loading event_webhook_types.go +119 −25 Original line number Diff line number Diff line Loading @@ -234,10 +234,13 @@ type GroupResourceAccessTokenEvent struct { ObjectAttributes GroupResourceAccessTokenEventObjectAttributes `json:"object_attributes"` } // GroupResourceAccessTokenEventGroup represents a group in a resource access // token event. type GroupResourceAccessTokenEventGroup struct { GroupID int64 `json:"group_id"` GroupName string `json:"group_name"` GroupPath string `json:"group_path"` FullPath string `json:"full_path"` } type GroupResourceAccessTokenEventObjectAttributes struct { Loading Loading @@ -839,7 +842,7 @@ type MergeEventChangesTargetProjectID struct { Current int64 `json:"current"` } // EventUser represents a user record in an event and is used as an even // EventUser represents a user record in an event and is used as an event // initiator or a merge assignee. type EventUser struct { ID int64 `json:"id"` Loading Loading @@ -1364,8 +1367,12 @@ type EmojiEvent struct { ObjectAttributes EmojiEventObjectAttributes `json:"object_attributes"` Note *EmojiEventNote `json:"note,omitempty"` Issue *EmojiEventIssue `json:"issue,omitempty"` MergeRequest *EmojiEventMergeRequest `json:"merge_request,omitempty"` ProjectSnippet *EmojiEventSnippet `json:"project_snippet,omitempty"` Commit *EmojiEventCommit `json:"commit,omitempty"` } // EmojiEventProject represents a project in an emoji event. type EmojiEventProject struct { ID int64 `json:"id"` Name string `json:"name"` Loading Loading @@ -1461,6 +1468,82 @@ type EmojiEventIssue struct { Severity string `json:"severity"` } // EmojiEventMergeRequest represents a merge request in an emoji event. type EmojiEventMergeRequest struct { ID int64 `json:"id"` TargetBranch string `json:"target_branch"` SourceBranch string `json:"source_branch"` SourceProjectID int64 `json:"source_project_id"` AuthorID int64 `json:"author_id"` AssigneeID int64 `json:"assignee_id"` AssigneeIDs []int64 `json:"assignee_ids"` ReviewerIDs []int64 `json:"reviewer_ids"` Title string `json:"title"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` MilestoneID int64 `json:"milestone_id"` State string `json:"state"` MergeStatus string `json:"merge_status"` TargetProjectID int64 `json:"target_project_id"` IID int64 `json:"iid"` Description string `json:"description"` Position int64 `json:"position"` Labels []*EventLabel `json:"labels"` LockedAt string `json:"locked_at"` UpdatedByID int64 `json:"updated_by_id"` MergeError string `json:"merge_error"` MergeParams *MergeParams `json:"merge_params"` MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` MergeUserID int64 `json:"merge_user_id"` MergeCommitSHA string `json:"merge_commit_sha"` DeletedAt string `json:"deleted_at"` InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"` LockVersion int64 `json:"lock_version"` ApprovalsBeforeMerge string `json:"approvals_before_merge"` RebaseCommitSHA string `json:"rebase_commit_sha"` TimeEstimate int64 `json:"time_estimate"` Squash bool `json:"squash"` LastEditedAt string `json:"last_edited_at"` LastEditedByID int64 `json:"last_edited_by_id"` Source *Repository `json:"source"` Target *Repository `json:"target"` LastCommit EventMergeRequestLastCommit `json:"last_commit"` WorkInProgress bool `json:"work_in_progress"` TotalTimeSpent int64 `json:"total_time_spent"` HeadPipelineID int64 `json:"head_pipeline_id"` Assignee *EventUser `json:"assignee"` DetailedMergeStatus string `json:"detailed_merge_status"` URL string `json:"url"` } // EmojiEventSnippet represents a snippet in an emoji event. type EmojiEventSnippet struct { ID int64 `json:"id"` Title string `json:"title"` Content string `json:"content"` AuthorID int64 `json:"author_id"` ProjectID int64 `json:"project_id"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` Filename string `json:"file_name"` ExpiresAt string `json:"expires_at"` Type string `json:"type"` VisibilityLevel int64 `json:"visibility_level"` Description string `json:"description"` Secret bool `json:"secret"` RepositoryReadOnly bool `json:"repository_read_only"` } // EmojiEventCommit represents a commit in an emoji event. type EmojiEventCommit struct { ID string `json:"id"` Title string `json:"title"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author EventCommitAuthor `json:"author"` } // MilestoneWebhookEvent represents a milestone webhook event. // // GitLab API docs: Loading @@ -1469,10 +1552,34 @@ type MilestoneWebhookEvent struct { ObjectKind string `json:"object_kind"` EventType string `json:"event_type"` Project MilestoneEventProject `json:"project"` Group *MilestoneEventGroup `json:"group,omitempty"` ObjectAttributes MilestoneEventObjectAttributes `json:"object_attributes"` Action string `json:"action"` } type MilestoneEventObjectAttributes struct { ID int64 `json:"id"` IID int64 `json:"iid"` Title string `json:"title"` Description string `json:"description"` State string `json:"state"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` DueDate *ISOTime `json:"due_date"` StartDate *ISOTime `json:"start_date"` GroupID *int64 `json:"group_id"` ProjectID int64 `json:"project_id"` } // MilestoneEventGroup represents a group in a milestone event. type MilestoneEventGroup struct { GroupID int64 `json:"group_id"` GroupName string `json:"group_name"` GroupPath string `json:"group_path"` FullPath string `json:"full_path"` } // MilestoneEventProject represents a project in a milestone event. type MilestoneEventProject struct { ID int64 `json:"id"` Name string `json:"name"` Loading @@ -1492,20 +1599,6 @@ type MilestoneEventProject struct { HTTPURL string `json:"http_url"` } type MilestoneEventObjectAttributes struct { ID int64 `json:"id"` IID int64 `json:"iid"` Title string `json:"title"` Description string `json:"description"` State string `json:"state"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` DueDate *ISOTime `json:"due_date"` StartDate *ISOTime `json:"start_date"` GroupID *int64 `json:"group_id"` ProjectID int64 `json:"project_id"` } // ProjectWebhookEvent represents a project webhook event for group webhooks. // // GitLab API docs: Loading @@ -1521,6 +1614,7 @@ type ProjectWebhookEvent struct { ProjectNamespaceID int64 `json:"project_namespace_id"` Owners []ProjectEventOwner `json:"owners"` ProjectVisibility string `json:"project_visibility"` OldPathWithNamespace string `json:"old_path_with_namespace,omitempty"` } type ProjectEventOwner struct { Loading event_webhook_types_test.go +254 −3 Original line number Diff line number Diff line Loading @@ -327,6 +327,7 @@ func TestGroupResourceAccessTokenEventUnmarshal(t *testing.T) { expected.Group.GroupID = 35 expected.Group.GroupName = "Twitter" expected.Group.GroupPath = "twitter" expected.Group.FullPath = "twitter" expected.ObjectAttributes.ID = 25 expected.ObjectAttributes.UserID = 90 Loading Loading @@ -1421,7 +1422,7 @@ func TestEmojiEventUnmarshal(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload jsonObject := loadFixture(t, "testdata/webhooks/emoji.json") jsonObject := loadFixture(t, "testdata/webhooks/emoji_issue.json") // WHEN the JSON is unmarshaled var event *EmojiEvent Loading @@ -1442,6 +1443,7 @@ func TestEmojiEventUnmarshal(t *testing.T) { assert.Equal(t, "admin@example.com", event.User.Email) // Project assertions assert.NotNil(t, event.Project) assert.Equal(t, int64(7), event.Project.ID) assert.Equal(t, "Flight", event.Project.Name) assert.Equal(t, "flightjs/Flight", event.Project.PathWithNamespace) Loading Loading @@ -1469,11 +1471,210 @@ func TestEmojiEventUnmarshal(t *testing.T) { assert.False(t, event.Issue.Confidential) } func TestEmojiEventUnmarshalMergeRequest(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a merge request jsonObject := loadFixture(t, "testdata/webhooks/emoji_merge_request.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "MergeRequest", event.ObjectAttributes.AwardableType) // MergeRequest assertions assert.NotNil(t, event.MergeRequest) assert.Equal(t, int64(123), event.MergeRequest.ID) assert.Equal(t, int64(1), event.MergeRequest.IID) assert.Equal(t, "Test Merge Request", event.MergeRequest.Title) assert.Equal(t, "opened", event.MergeRequest.State) // Issue and Snippet should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.ProjectSnippet) assert.Nil(t, event.Note) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalSnippet(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a snippet jsonObject := loadFixture(t, "testdata/webhooks/emoji_snippet.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Snippet", event.ObjectAttributes.AwardableType) // Snippet assertions assert.NotNil(t, event.ProjectSnippet) assert.Equal(t, int64(456), event.ProjectSnippet.ID) assert.Equal(t, "Test Snippet", event.ProjectSnippet.Title) assert.Equal(t, "ProjectSnippet", event.ProjectSnippet.Type) // Issue and MergeRequest should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.MergeRequest) assert.Nil(t, event.Note) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteIssue(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on an issue jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_issue.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(789), event.Note.ID) assert.Equal(t, "Issue", event.Note.NoteableType) assert.Equal(t, int64(123), event.Note.NoteableID) // Issue assertions assert.NotNil(t, event.Issue) assert.Equal(t, int64(123), event.Issue.ID) // MergeRequest and Snippet should be nil assert.Nil(t, event.MergeRequest) assert.Nil(t, event.ProjectSnippet) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteMergeRequest(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on a merge request jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_merge_request.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(790), event.Note.ID) assert.Equal(t, "MergeRequest", event.Note.NoteableType) // MergeRequest assertions assert.NotNil(t, event.MergeRequest) assert.Equal(t, int64(123), event.MergeRequest.ID) // Issue and Snippet should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.ProjectSnippet) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteSnippet(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on a snippet jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_snippet.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(791), event.Note.ID) assert.Equal(t, "Snippet", event.Note.NoteableType) // Snippet assertions assert.NotNil(t, event.ProjectSnippet) assert.Equal(t, int64(456), event.ProjectSnippet.ID) // Issue and MergeRequest should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.MergeRequest) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteCommit(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on a commit jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_commit.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(792), event.Note.ID) assert.Equal(t, "Commit", event.Note.NoteableType) assert.NotNil(t, event.Note.CommitID) assert.Equal(t, "cfe32cf61b73a0d5e9f13e774abde7ff789b1660", *event.Note.CommitID) // Commit assertions assert.NotNil(t, event.Commit) assert.Equal(t, "cfe32cf61b73a0d5e9f13e774abde7ff789b1660", event.Commit.ID) assert.Equal(t, "Add submodule", event.Commit.Title) // Issue, MergeRequest and Snippet should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.MergeRequest) assert.Nil(t, event.ProjectSnippet) } func TestMilestoneWebhookEventUnmarshal(t *testing.T) { t.Parallel() // GIVEN a milestone webhook event JSON payload jsonObject := loadFixture(t, "testdata/webhooks/milestone.json") jsonObject := loadFixture(t, "testdata/webhooks/milestone_project.json") // WHEN the JSON is unmarshaled var event *MilestoneWebhookEvent Loading @@ -1487,12 +1688,16 @@ func TestMilestoneWebhookEventUnmarshal(t *testing.T) { assert.Equal(t, "milestone", event.EventType) assert.Equal(t, "create", event.Action) // Project assertions // Project assertions (project milestone) assert.NotNil(t, event.Project) assert.Equal(t, int64(7), event.Project.ID) assert.Equal(t, "Flight", event.Project.Name) assert.Equal(t, "flightjs/Flight", event.Project.PathWithNamespace) assert.Equal(t, int64(0), event.Project.VisibilityLevel) // Group should be nil for project milestone assert.Nil(t, event.Group) // Object attributes assertions assert.Equal(t, int64(42), event.ObjectAttributes.ID) assert.Equal(t, int64(1), event.ObjectAttributes.IID) Loading @@ -1512,6 +1717,51 @@ func TestMilestoneWebhookEventUnmarshal(t *testing.T) { assert.Equal(t, &startDate, event.ObjectAttributes.StartDate) } func TestMilestoneWebhookEventUnmarshalGroup(t *testing.T) { t.Parallel() // GIVEN a group milestone webhook event JSON payload jsonObject := loadFixture(t, "testdata/webhooks/milestone_group.json") // WHEN the JSON is unmarshaled var event *MilestoneWebhookEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "milestone", event.ObjectKind) assert.Equal(t, "milestone", event.EventType) assert.Equal(t, "create", event.Action) // Project should be empty for group milestone assert.Empty(t, event.Project) // Group assertions (group milestone) assert.NotNil(t, event.Group) assert.Equal(t, int64(35), event.Group.GroupID) assert.Equal(t, "Flightjs", event.Group.GroupName) assert.Equal(t, "flightjs", event.Group.GroupPath) assert.Equal(t, "flightjs", event.Group.FullPath) // Object attributes assertions assert.Equal(t, int64(42), event.ObjectAttributes.ID) assert.Equal(t, int64(1), event.ObjectAttributes.IID) assert.Equal(t, "v1.0.0", event.ObjectAttributes.Title) assert.Equal(t, int64(35), *event.ObjectAttributes.GroupID) assert.Equal(t, int64(0), event.ObjectAttributes.ProjectID) // Date assertions dueDate, err := ParseISOTime("2024-03-01") assert.NoError(t, err) assert.Equal(t, &dueDate, event.ObjectAttributes.DueDate) startDate, err := ParseISOTime("2024-01-01") assert.NoError(t, err) assert.Equal(t, &startDate, event.ObjectAttributes.StartDate) } func TestProjectWebhookEventUnmarshal(t *testing.T) { t.Parallel() Loading @@ -1535,6 +1785,7 @@ func TestProjectWebhookEventUnmarshal(t *testing.T) { assert.Equal(t, int64(7), event.ProjectID) assert.Equal(t, int64(35), event.ProjectNamespaceID) assert.Equal(t, "private", event.ProjectVisibility) assert.Empty(t, event.OldPathWithNamespace) // Owners assertions assert.Len(t, event.Owners, 1) Loading testdata/webhooks/emoji.json→testdata/webhooks/emoji_issue.json +0 −0 File moved. View file testdata/webhooks/emoji_merge_request.json 0 → 100644 +63 −0 Original line number Diff line number Diff line { "object_kind": "emoji", "event_type": "award", "user": { "id": 1, "name": "Administrator", "username": "root", "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "email": "admin@example.com" }, "project_id": 7, "project": { "id": 7, "name": "Flight", "description": "Eum dolore maxime atque reprehenderit voluptatem.", "web_url": "https://example.com/flightjs/Flight", "avatar_url": null, "git_ssh_url": "ssh://git@example.com/flightjs/Flight.git", "git_http_url": "https://example.com/flightjs/Flight.git", "namespace": "Flightjs", "visibility_level": 0, "path_with_namespace": "flightjs/Flight", "default_branch": "master", "ci_config_path": "", "homepage": "https://example.com/flightjs/Flight", "url": "ssh://git@example.com/flightjs/Flight.git", "ssh_url": "ssh://git@example.com/flightjs/Flight.git", "http_url": "https://example.com/flightjs/Flight.git" }, "object_attributes": { "user_id": 1, "created_at": "2024-01-24 16:27:40 UTC", "id": 42, "name": "thumbsup", "awardable_type": "MergeRequest", "awardable_id": 123, "updated_at": "2024-01-24 16:27:40 UTC", "action": "award", "awarded_on_url": "https://example.com/flightjs/Flight/-/merge_requests/1" }, "merge_request": { "id": 123, "iid": 1, "project_id": 7, "source_project_id": 7, "target_project_id": 7, "author_id": 1, "assignee_id": 0, "assignee_ids": [], "reviewer_ids": [], "title": "Test Merge Request", "description": "This is a test merge request", "state": "opened", "merge_status": "can_be_merged", "target_branch": "master", "source_branch": "feature/test", "created_at": "2024-01-20 10:00:00 UTC", "updated_at": "2024-01-24 16:27:40 UTC", "milestone_id": null, "labels": [], "url": "https://example.com/flightjs/Flight/-/merge_requests/1" } } Loading
event_parsing_webhook_test.go +2 −2 Original line number Diff line number Diff line Loading @@ -361,7 +361,7 @@ func TestParseWikiPageHook(t *testing.T) { func TestParseEmojiHook(t *testing.T) { t.Parallel() raw := loadFixture(t, "testdata/webhooks/emoji.json") raw := loadFixture(t, "testdata/webhooks/emoji_issue.json") parsedEvent, err := ParseWebhook("Emoji Hook", raw) assert.NoError(t, err) Loading @@ -383,7 +383,7 @@ func TestParseEmojiHook(t *testing.T) { func TestParseMilestoneHook(t *testing.T) { t.Parallel() raw := loadFixture(t, "testdata/webhooks/milestone.json") raw := loadFixture(t, "testdata/webhooks/milestone_project.json") parsedEvent, err := ParseWebhook("Milestone Hook", raw) assert.NoError(t, err) Loading
event_webhook_types.go +119 −25 Original line number Diff line number Diff line Loading @@ -234,10 +234,13 @@ type GroupResourceAccessTokenEvent struct { ObjectAttributes GroupResourceAccessTokenEventObjectAttributes `json:"object_attributes"` } // GroupResourceAccessTokenEventGroup represents a group in a resource access // token event. type GroupResourceAccessTokenEventGroup struct { GroupID int64 `json:"group_id"` GroupName string `json:"group_name"` GroupPath string `json:"group_path"` FullPath string `json:"full_path"` } type GroupResourceAccessTokenEventObjectAttributes struct { Loading Loading @@ -839,7 +842,7 @@ type MergeEventChangesTargetProjectID struct { Current int64 `json:"current"` } // EventUser represents a user record in an event and is used as an even // EventUser represents a user record in an event and is used as an event // initiator or a merge assignee. type EventUser struct { ID int64 `json:"id"` Loading Loading @@ -1364,8 +1367,12 @@ type EmojiEvent struct { ObjectAttributes EmojiEventObjectAttributes `json:"object_attributes"` Note *EmojiEventNote `json:"note,omitempty"` Issue *EmojiEventIssue `json:"issue,omitempty"` MergeRequest *EmojiEventMergeRequest `json:"merge_request,omitempty"` ProjectSnippet *EmojiEventSnippet `json:"project_snippet,omitempty"` Commit *EmojiEventCommit `json:"commit,omitempty"` } // EmojiEventProject represents a project in an emoji event. type EmojiEventProject struct { ID int64 `json:"id"` Name string `json:"name"` Loading Loading @@ -1461,6 +1468,82 @@ type EmojiEventIssue struct { Severity string `json:"severity"` } // EmojiEventMergeRequest represents a merge request in an emoji event. type EmojiEventMergeRequest struct { ID int64 `json:"id"` TargetBranch string `json:"target_branch"` SourceBranch string `json:"source_branch"` SourceProjectID int64 `json:"source_project_id"` AuthorID int64 `json:"author_id"` AssigneeID int64 `json:"assignee_id"` AssigneeIDs []int64 `json:"assignee_ids"` ReviewerIDs []int64 `json:"reviewer_ids"` Title string `json:"title"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` MilestoneID int64 `json:"milestone_id"` State string `json:"state"` MergeStatus string `json:"merge_status"` TargetProjectID int64 `json:"target_project_id"` IID int64 `json:"iid"` Description string `json:"description"` Position int64 `json:"position"` Labels []*EventLabel `json:"labels"` LockedAt string `json:"locked_at"` UpdatedByID int64 `json:"updated_by_id"` MergeError string `json:"merge_error"` MergeParams *MergeParams `json:"merge_params"` MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` MergeUserID int64 `json:"merge_user_id"` MergeCommitSHA string `json:"merge_commit_sha"` DeletedAt string `json:"deleted_at"` InProgressMergeCommitSHA string `json:"in_progress_merge_commit_sha"` LockVersion int64 `json:"lock_version"` ApprovalsBeforeMerge string `json:"approvals_before_merge"` RebaseCommitSHA string `json:"rebase_commit_sha"` TimeEstimate int64 `json:"time_estimate"` Squash bool `json:"squash"` LastEditedAt string `json:"last_edited_at"` LastEditedByID int64 `json:"last_edited_by_id"` Source *Repository `json:"source"` Target *Repository `json:"target"` LastCommit EventMergeRequestLastCommit `json:"last_commit"` WorkInProgress bool `json:"work_in_progress"` TotalTimeSpent int64 `json:"total_time_spent"` HeadPipelineID int64 `json:"head_pipeline_id"` Assignee *EventUser `json:"assignee"` DetailedMergeStatus string `json:"detailed_merge_status"` URL string `json:"url"` } // EmojiEventSnippet represents a snippet in an emoji event. type EmojiEventSnippet struct { ID int64 `json:"id"` Title string `json:"title"` Content string `json:"content"` AuthorID int64 `json:"author_id"` ProjectID int64 `json:"project_id"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` Filename string `json:"file_name"` ExpiresAt string `json:"expires_at"` Type string `json:"type"` VisibilityLevel int64 `json:"visibility_level"` Description string `json:"description"` Secret bool `json:"secret"` RepositoryReadOnly bool `json:"repository_read_only"` } // EmojiEventCommit represents a commit in an emoji event. type EmojiEventCommit struct { ID string `json:"id"` Title string `json:"title"` Message string `json:"message"` Timestamp *time.Time `json:"timestamp"` URL string `json:"url"` Author EventCommitAuthor `json:"author"` } // MilestoneWebhookEvent represents a milestone webhook event. // // GitLab API docs: Loading @@ -1469,10 +1552,34 @@ type MilestoneWebhookEvent struct { ObjectKind string `json:"object_kind"` EventType string `json:"event_type"` Project MilestoneEventProject `json:"project"` Group *MilestoneEventGroup `json:"group,omitempty"` ObjectAttributes MilestoneEventObjectAttributes `json:"object_attributes"` Action string `json:"action"` } type MilestoneEventObjectAttributes struct { ID int64 `json:"id"` IID int64 `json:"iid"` Title string `json:"title"` Description string `json:"description"` State string `json:"state"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` DueDate *ISOTime `json:"due_date"` StartDate *ISOTime `json:"start_date"` GroupID *int64 `json:"group_id"` ProjectID int64 `json:"project_id"` } // MilestoneEventGroup represents a group in a milestone event. type MilestoneEventGroup struct { GroupID int64 `json:"group_id"` GroupName string `json:"group_name"` GroupPath string `json:"group_path"` FullPath string `json:"full_path"` } // MilestoneEventProject represents a project in a milestone event. type MilestoneEventProject struct { ID int64 `json:"id"` Name string `json:"name"` Loading @@ -1492,20 +1599,6 @@ type MilestoneEventProject struct { HTTPURL string `json:"http_url"` } type MilestoneEventObjectAttributes struct { ID int64 `json:"id"` IID int64 `json:"iid"` Title string `json:"title"` Description string `json:"description"` State string `json:"state"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` DueDate *ISOTime `json:"due_date"` StartDate *ISOTime `json:"start_date"` GroupID *int64 `json:"group_id"` ProjectID int64 `json:"project_id"` } // ProjectWebhookEvent represents a project webhook event for group webhooks. // // GitLab API docs: Loading @@ -1521,6 +1614,7 @@ type ProjectWebhookEvent struct { ProjectNamespaceID int64 `json:"project_namespace_id"` Owners []ProjectEventOwner `json:"owners"` ProjectVisibility string `json:"project_visibility"` OldPathWithNamespace string `json:"old_path_with_namespace,omitempty"` } type ProjectEventOwner struct { Loading
event_webhook_types_test.go +254 −3 Original line number Diff line number Diff line Loading @@ -327,6 +327,7 @@ func TestGroupResourceAccessTokenEventUnmarshal(t *testing.T) { expected.Group.GroupID = 35 expected.Group.GroupName = "Twitter" expected.Group.GroupPath = "twitter" expected.Group.FullPath = "twitter" expected.ObjectAttributes.ID = 25 expected.ObjectAttributes.UserID = 90 Loading Loading @@ -1421,7 +1422,7 @@ func TestEmojiEventUnmarshal(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload jsonObject := loadFixture(t, "testdata/webhooks/emoji.json") jsonObject := loadFixture(t, "testdata/webhooks/emoji_issue.json") // WHEN the JSON is unmarshaled var event *EmojiEvent Loading @@ -1442,6 +1443,7 @@ func TestEmojiEventUnmarshal(t *testing.T) { assert.Equal(t, "admin@example.com", event.User.Email) // Project assertions assert.NotNil(t, event.Project) assert.Equal(t, int64(7), event.Project.ID) assert.Equal(t, "Flight", event.Project.Name) assert.Equal(t, "flightjs/Flight", event.Project.PathWithNamespace) Loading Loading @@ -1469,11 +1471,210 @@ func TestEmojiEventUnmarshal(t *testing.T) { assert.False(t, event.Issue.Confidential) } func TestEmojiEventUnmarshalMergeRequest(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a merge request jsonObject := loadFixture(t, "testdata/webhooks/emoji_merge_request.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "MergeRequest", event.ObjectAttributes.AwardableType) // MergeRequest assertions assert.NotNil(t, event.MergeRequest) assert.Equal(t, int64(123), event.MergeRequest.ID) assert.Equal(t, int64(1), event.MergeRequest.IID) assert.Equal(t, "Test Merge Request", event.MergeRequest.Title) assert.Equal(t, "opened", event.MergeRequest.State) // Issue and Snippet should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.ProjectSnippet) assert.Nil(t, event.Note) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalSnippet(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a snippet jsonObject := loadFixture(t, "testdata/webhooks/emoji_snippet.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Snippet", event.ObjectAttributes.AwardableType) // Snippet assertions assert.NotNil(t, event.ProjectSnippet) assert.Equal(t, int64(456), event.ProjectSnippet.ID) assert.Equal(t, "Test Snippet", event.ProjectSnippet.Title) assert.Equal(t, "ProjectSnippet", event.ProjectSnippet.Type) // Issue and MergeRequest should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.MergeRequest) assert.Nil(t, event.Note) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteIssue(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on an issue jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_issue.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(789), event.Note.ID) assert.Equal(t, "Issue", event.Note.NoteableType) assert.Equal(t, int64(123), event.Note.NoteableID) // Issue assertions assert.NotNil(t, event.Issue) assert.Equal(t, int64(123), event.Issue.ID) // MergeRequest and Snippet should be nil assert.Nil(t, event.MergeRequest) assert.Nil(t, event.ProjectSnippet) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteMergeRequest(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on a merge request jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_merge_request.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(790), event.Note.ID) assert.Equal(t, "MergeRequest", event.Note.NoteableType) // MergeRequest assertions assert.NotNil(t, event.MergeRequest) assert.Equal(t, int64(123), event.MergeRequest.ID) // Issue and Snippet should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.ProjectSnippet) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteSnippet(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on a snippet jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_snippet.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(791), event.Note.ID) assert.Equal(t, "Snippet", event.Note.NoteableType) // Snippet assertions assert.NotNil(t, event.ProjectSnippet) assert.Equal(t, int64(456), event.ProjectSnippet.ID) // Issue and MergeRequest should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.MergeRequest) assert.Nil(t, event.Commit) } func TestEmojiEventUnmarshalNoteCommit(t *testing.T) { t.Parallel() // GIVEN an emoji event JSON payload on a note on a commit jsonObject := loadFixture(t, "testdata/webhooks/emoji_note_commit.json") // WHEN the JSON is unmarshaled var event *EmojiEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "emoji", event.ObjectKind) assert.Equal(t, "award", event.EventType) assert.Equal(t, "Note", event.ObjectAttributes.AwardableType) // Note assertions assert.NotNil(t, event.Note) assert.Equal(t, int64(792), event.Note.ID) assert.Equal(t, "Commit", event.Note.NoteableType) assert.NotNil(t, event.Note.CommitID) assert.Equal(t, "cfe32cf61b73a0d5e9f13e774abde7ff789b1660", *event.Note.CommitID) // Commit assertions assert.NotNil(t, event.Commit) assert.Equal(t, "cfe32cf61b73a0d5e9f13e774abde7ff789b1660", event.Commit.ID) assert.Equal(t, "Add submodule", event.Commit.Title) // Issue, MergeRequest and Snippet should be nil assert.Nil(t, event.Issue) assert.Nil(t, event.MergeRequest) assert.Nil(t, event.ProjectSnippet) } func TestMilestoneWebhookEventUnmarshal(t *testing.T) { t.Parallel() // GIVEN a milestone webhook event JSON payload jsonObject := loadFixture(t, "testdata/webhooks/milestone.json") jsonObject := loadFixture(t, "testdata/webhooks/milestone_project.json") // WHEN the JSON is unmarshaled var event *MilestoneWebhookEvent Loading @@ -1487,12 +1688,16 @@ func TestMilestoneWebhookEventUnmarshal(t *testing.T) { assert.Equal(t, "milestone", event.EventType) assert.Equal(t, "create", event.Action) // Project assertions // Project assertions (project milestone) assert.NotNil(t, event.Project) assert.Equal(t, int64(7), event.Project.ID) assert.Equal(t, "Flight", event.Project.Name) assert.Equal(t, "flightjs/Flight", event.Project.PathWithNamespace) assert.Equal(t, int64(0), event.Project.VisibilityLevel) // Group should be nil for project milestone assert.Nil(t, event.Group) // Object attributes assertions assert.Equal(t, int64(42), event.ObjectAttributes.ID) assert.Equal(t, int64(1), event.ObjectAttributes.IID) Loading @@ -1512,6 +1717,51 @@ func TestMilestoneWebhookEventUnmarshal(t *testing.T) { assert.Equal(t, &startDate, event.ObjectAttributes.StartDate) } func TestMilestoneWebhookEventUnmarshalGroup(t *testing.T) { t.Parallel() // GIVEN a group milestone webhook event JSON payload jsonObject := loadFixture(t, "testdata/webhooks/milestone_group.json") // WHEN the JSON is unmarshaled var event *MilestoneWebhookEvent err := json.Unmarshal(jsonObject, &event) // THEN no error should occur and the event should be populated correctly assert.NoError(t, err) assert.NotNil(t, event) assert.Equal(t, "milestone", event.ObjectKind) assert.Equal(t, "milestone", event.EventType) assert.Equal(t, "create", event.Action) // Project should be empty for group milestone assert.Empty(t, event.Project) // Group assertions (group milestone) assert.NotNil(t, event.Group) assert.Equal(t, int64(35), event.Group.GroupID) assert.Equal(t, "Flightjs", event.Group.GroupName) assert.Equal(t, "flightjs", event.Group.GroupPath) assert.Equal(t, "flightjs", event.Group.FullPath) // Object attributes assertions assert.Equal(t, int64(42), event.ObjectAttributes.ID) assert.Equal(t, int64(1), event.ObjectAttributes.IID) assert.Equal(t, "v1.0.0", event.ObjectAttributes.Title) assert.Equal(t, int64(35), *event.ObjectAttributes.GroupID) assert.Equal(t, int64(0), event.ObjectAttributes.ProjectID) // Date assertions dueDate, err := ParseISOTime("2024-03-01") assert.NoError(t, err) assert.Equal(t, &dueDate, event.ObjectAttributes.DueDate) startDate, err := ParseISOTime("2024-01-01") assert.NoError(t, err) assert.Equal(t, &startDate, event.ObjectAttributes.StartDate) } func TestProjectWebhookEventUnmarshal(t *testing.T) { t.Parallel() Loading @@ -1535,6 +1785,7 @@ func TestProjectWebhookEventUnmarshal(t *testing.T) { assert.Equal(t, int64(7), event.ProjectID) assert.Equal(t, int64(35), event.ProjectNamespaceID) assert.Equal(t, "private", event.ProjectVisibility) assert.Empty(t, event.OldPathWithNamespace) // Owners assertions assert.Len(t, event.Owners, 1) Loading
testdata/webhooks/emoji_merge_request.json 0 → 100644 +63 −0 Original line number Diff line number Diff line { "object_kind": "emoji", "event_type": "award", "user": { "id": 1, "name": "Administrator", "username": "root", "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "email": "admin@example.com" }, "project_id": 7, "project": { "id": 7, "name": "Flight", "description": "Eum dolore maxime atque reprehenderit voluptatem.", "web_url": "https://example.com/flightjs/Flight", "avatar_url": null, "git_ssh_url": "ssh://git@example.com/flightjs/Flight.git", "git_http_url": "https://example.com/flightjs/Flight.git", "namespace": "Flightjs", "visibility_level": 0, "path_with_namespace": "flightjs/Flight", "default_branch": "master", "ci_config_path": "", "homepage": "https://example.com/flightjs/Flight", "url": "ssh://git@example.com/flightjs/Flight.git", "ssh_url": "ssh://git@example.com/flightjs/Flight.git", "http_url": "https://example.com/flightjs/Flight.git" }, "object_attributes": { "user_id": 1, "created_at": "2024-01-24 16:27:40 UTC", "id": 42, "name": "thumbsup", "awardable_type": "MergeRequest", "awardable_id": 123, "updated_at": "2024-01-24 16:27:40 UTC", "action": "award", "awarded_on_url": "https://example.com/flightjs/Flight/-/merge_requests/1" }, "merge_request": { "id": 123, "iid": 1, "project_id": 7, "source_project_id": 7, "target_project_id": 7, "author_id": 1, "assignee_id": 0, "assignee_ids": [], "reviewer_ids": [], "title": "Test Merge Request", "description": "This is a test merge request", "state": "opened", "merge_status": "can_be_merged", "target_branch": "master", "source_branch": "feature/test", "created_at": "2024-01-20 10:00:00 UTC", "updated_at": "2024-01-24 16:27:40 UTC", "milestone_id": null, "labels": [], "url": "https://example.com/flightjs/Flight/-/merge_requests/1" } }