Commit 46ba91ca authored by Huijie Shi's avatar Huijie Shi Committed by Patrick Rice
Browse files

feat: update events

Changelog: Improvements
parent 8508c178
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -32,13 +32,16 @@ const (
	EventConfidentialNote        EventType = "Confidential Note Hook"
	EventTypeBuild               EventType = "Build Hook"
	EventTypeDeployment          EventType = "Deployment Hook"
	EventTypeEmoji               EventType = "Emoji Hook"
	EventTypeFeatureFlag         EventType = "Feature Flag Hook"
	EventTypeIssue               EventType = "Issue Hook"
	EventTypeJob                 EventType = "Job Hook"
	EventTypeMember              EventType = "Member Hook"
	EventTypeMergeRequest        EventType = "Merge Request Hook"
	EventTypeMilestone           EventType = "Milestone Hook"
	EventTypeNote                EventType = "Note Hook"
	EventTypePipeline            EventType = "Pipeline Hook"
	EventTypeProject             EventType = "Project Hook"
	EventTypePush                EventType = "Push Hook"
	EventTypeRelease             EventType = "Release Hook"
	EventTypeResourceAccessToken EventType = "Resource Access Token Hook"
@@ -46,6 +49,7 @@ const (
	EventTypeSubGroup            EventType = "Subgroup Hook"
	EventTypeSystemHook          EventType = "System Hook"
	EventTypeTagPush             EventType = "Tag Push Hook"
	EventTypeVulnerability       EventType = "Vulnerability Hook"
	EventTypeWikiPage            EventType = "Wiki Page Hook"
)

@@ -224,6 +228,8 @@ func ParseWebhook(eventType EventType, payload []byte) (event any, err error) {
		event = &BuildEvent{}
	case EventTypeDeployment:
		event = &DeploymentEvent{}
	case EventTypeEmoji:
		event = &EmojiEvent{}
	case EventTypeFeatureFlag:
		event = &FeatureFlagEvent{}
	case EventTypeIssue, EventConfidentialIssue:
@@ -234,6 +240,8 @@ func ParseWebhook(eventType EventType, payload []byte) (event any, err error) {
		event = &MemberEvent{}
	case EventTypeMergeRequest:
		event = &MergeEvent{}
	case EventTypeMilestone:
		event = &MilestoneWebhookEvent{}
	case EventTypeNote, EventConfidentialNote:
		note := &noteEvent{}
		err := json.Unmarshal(payload, note)
@@ -259,6 +267,8 @@ func ParseWebhook(eventType EventType, payload []byte) (event any, err error) {
		}
	case EventTypePipeline:
		event = &PipelineEvent{}
	case EventTypeProject:
		event = &ProjectWebhookEvent{}
	case EventTypePush:
		event = &PushEvent{}
	case EventTypeRelease:
@@ -301,6 +311,8 @@ func ParseWebhook(eventType EventType, payload []byte) (event any, err error) {
		event = &SubGroupEvent{}
	case EventTypeTagPush:
		event = &TagEvent{}
	case EventTypeVulnerability:
		event = &VulnerabilityEvent{}
	case EventTypeWikiPage:
		event = &WikiPageEvent{}
	default:
+86 −0
Original line number Diff line number Diff line
@@ -358,3 +358,89 @@ func TestParseWikiPageHook(t *testing.T) {
	assert.Equal(t, "http://example.com/root/awesome-project/wikis/home", event.Wiki.WebURL)
	assert.Equal(t, "adding an awesome page to the wiki", event.ObjectAttributes.Message)
}

func TestParseEmojiHook(t *testing.T) {
	t.Parallel()
	raw := loadFixture(t, "testdata/webhooks/emoji.json")

	parsedEvent, err := ParseWebhook("Emoji Hook", raw)
	assert.NoError(t, err)

	event, ok := parsedEvent.(*EmojiEvent)
	assert.True(t, ok, "Expected EmojiEvent, but parsing produced %T", parsedEvent)

	assert.Equal(t, "emoji", event.ObjectKind)
	assert.Equal(t, "award", event.EventType)
	assert.Equal(t, int64(1), event.User.ID)
	assert.Equal(t, "Administrator", event.User.Name)
	assert.Equal(t, int64(7), event.ProjectID)
	assert.Equal(t, "Flight", event.Project.Name)
	assert.Equal(t, "thumbsup", event.ObjectAttributes.Name)
	assert.Equal(t, "Issue", event.ObjectAttributes.AwardableType)
	assert.Equal(t, int64(123), event.ObjectAttributes.AwardableID)
	assert.Equal(t, "award", event.ObjectAttributes.Action)
}

func TestParseMilestoneHook(t *testing.T) {
	t.Parallel()
	raw := loadFixture(t, "testdata/webhooks/milestone.json")

	parsedEvent, err := ParseWebhook("Milestone Hook", raw)
	assert.NoError(t, err)

	event, ok := parsedEvent.(*MilestoneWebhookEvent)
	assert.True(t, ok, "Expected MilestoneWebhookEvent, but parsing produced %T", parsedEvent)

	assert.Equal(t, "milestone", event.ObjectKind)
	assert.Equal(t, "milestone", event.EventType)
	assert.Equal(t, "Flight", event.Project.Name)
	assert.Equal(t, int64(7), event.Project.ID)
	assert.Equal(t, int64(42), event.ObjectAttributes.ID)
	assert.Equal(t, "v1.0.0", event.ObjectAttributes.Title)
	assert.Equal(t, "active", event.ObjectAttributes.State)
	assert.Equal(t, "create", event.Action)
}

func TestParseProjectHook(t *testing.T) {
	t.Parallel()
	raw := loadFixture(t, "testdata/webhooks/project.json")

	parsedEvent, err := ParseWebhook("Project Hook", raw)
	assert.NoError(t, err)

	event, ok := parsedEvent.(*ProjectWebhookEvent)
	assert.True(t, ok, "Expected ProjectWebhookEvent, but parsing produced %T", parsedEvent)

	assert.Equal(t, "project_create", event.EventName)
	assert.Equal(t, "Flight", event.Name)
	assert.Equal(t, "flight", event.Path)
	assert.Equal(t, "flightjs/flight", event.PathWithNamespace)
	assert.Equal(t, int64(7), event.ProjectID)
	assert.Equal(t, int64(35), event.ProjectNamespaceID)
	assert.Equal(t, "private", event.ProjectVisibility)
	assert.Len(t, event.Owners, 1)
	assert.Equal(t, "Administrator", event.Owners[0].Name)
	assert.Equal(t, "admin@example.com", event.Owners[0].Email)
}

func TestParseVulnerabilityHook(t *testing.T) {
	t.Parallel()
	raw := loadFixture(t, "testdata/webhooks/vulnerability.json")

	parsedEvent, err := ParseWebhook("Vulnerability Hook", raw)
	assert.NoError(t, err)

	event, ok := parsedEvent.(*VulnerabilityEvent)
	assert.True(t, ok, "Expected VulnerabilityEvent, but parsing produced %T", parsedEvent)

	assert.Equal(t, "vulnerability", event.ObjectKind)
	assert.Equal(t, int64(42), event.ObjectAttributes.ID)
	assert.Equal(t, "Potential SQL Injection", event.ObjectAttributes.Title)
	assert.Equal(t, "detected", event.ObjectAttributes.State)
	assert.Equal(t, int64(7), event.ObjectAttributes.ProjectID)
	assert.Equal(t, "high", event.ObjectAttributes.Severity)
	assert.Equal(t, "sast", event.ObjectAttributes.ReportType)
	assert.Equal(t, "app/models/user.rb", event.ObjectAttributes.Location.File)
	assert.Len(t, event.ObjectAttributes.Identifiers, 1)
	assert.Equal(t, "CVE-2024-1234", event.ObjectAttributes.Identifiers[0].Name)
}
+246 −0
Original line number Diff line number Diff line
@@ -1351,6 +1351,252 @@ type WikiPageEventObjectAttributes struct {
	DiffURL string `json:"diff_url"`
}

// EmojiEvent represents an emoji event.
//
// GitLab API docs:
// https://docs.gitlab.com/user/project/integrations/webhook_events/#emoji-events
type EmojiEvent struct {
	ObjectKind       string                     `json:"object_kind"`
	EventType        string                     `json:"event_type"`
	User             EventUser                  `json:"user"`
	ProjectID        int64                      `json:"project_id"`
	Project          EmojiEventProject          `json:"project"`
	ObjectAttributes EmojiEventObjectAttributes `json:"object_attributes"`
	Note             *EmojiEventNote            `json:"note,omitempty"`
	Issue            *EmojiEventIssue           `json:"issue,omitempty"`
}

type EmojiEventProject struct {
	ID                int64  `json:"id"`
	Name              string `json:"name"`
	Description       string `json:"description"`
	WebURL            string `json:"web_url"`
	AvatarURL         string `json:"avatar_url"`
	GitSSHURL         string `json:"git_ssh_url"`
	GitHTTPURL        string `json:"git_http_url"`
	Namespace         string `json:"namespace"`
	VisibilityLevel   int64  `json:"visibility_level"`
	PathWithNamespace string `json:"path_with_namespace"`
	DefaultBranch     string `json:"default_branch"`
	CIConfigPath      string `json:"ci_config_path"`
	Homepage          string `json:"homepage"`
	URL               string `json:"url"`
	SSHURL            string `json:"ssh_url"`
	HTTPURL           string `json:"http_url"`
}

type EmojiEventObjectAttributes struct {
	UserID        int64  `json:"user_id"`
	CreatedAt     string `json:"created_at"`
	ID            int64  `json:"id"`
	Name          string `json:"name"`
	AwardableType string `json:"awardable_type"`
	AwardableID   int64  `json:"awardable_id"`
	UpdatedAt     string `json:"updated_at"`
	Action        string `json:"action"`
	AwardedOnURL  string `json:"awarded_on_url"`
}

type EmojiEventNote struct {
	Attachment       *string       `json:"attachment"`
	AuthorID         int64         `json:"author_id"`
	ChangePosition   *NotePosition `json:"change_position"`
	CommitID         *string       `json:"commit_id"`
	CreatedAt        string        `json:"created_at"`
	DiscussionID     string        `json:"discussion_id"`
	ID               int64         `json:"id"`
	LineCode         *string       `json:"line_code"`
	Note             string        `json:"note"`
	NoteableID       int64         `json:"noteable_id"`
	NoteableType     string        `json:"noteable_type"`
	OriginalPosition *NotePosition `json:"original_position"`
	Position         *NotePosition `json:"position"`
	ProjectID        int64         `json:"project_id"`
	ResolvedAt       *string       `json:"resolved_at"`
	ResolvedByID     *int64        `json:"resolved_by_id"`
	ResolvedByPush   *bool         `json:"resolved_by_push"`
	StDiff           *Diff         `json:"st_diff"`
	System           bool          `json:"system"`
	Type             *string       `json:"type"`
	UpdatedAt        string        `json:"updated_at"`
	UpdatedByID      *int64        `json:"updated_by_id"`
	Description      string        `json:"description"`
	URL              string        `json:"url"`
}

type EmojiEventIssue struct {
	ID                  int64         `json:"id"`
	IID                 int64         `json:"iid"`
	ProjectID           int64         `json:"project_id"`
	AuthorID            int64         `json:"author_id"`
	ClosedAt            *string       `json:"closed_at"`
	Confidential        bool          `json:"confidential"`
	CreatedAt           string        `json:"created_at"`
	Description         string        `json:"description"`
	DiscussionLocked    *bool         `json:"discussion_locked"`
	DueDate             *ISOTime      `json:"due_date"`
	LastEditedAt        *string       `json:"last_edited_at"`
	LastEditedByID      *int64        `json:"last_edited_by_id"`
	MilestoneID         *int64        `json:"milestone_id"`
	MovedToID           *int64        `json:"moved_to_id"`
	DuplicatedToID      *int64        `json:"duplicated_to_id"`
	RelativePosition    int64         `json:"relative_position"`
	StateID             StateID       `json:"state_id"`
	TimeEstimate        int64         `json:"time_estimate"`
	Title               string        `json:"title"`
	UpdatedAt           string        `json:"updated_at"`
	UpdatedByID         *int64        `json:"updated_by_id"`
	Weight              *int64        `json:"weight"`
	HealthStatus        *string       `json:"health_status"`
	URL                 string        `json:"url"`
	TotalTimeSpent      int64         `json:"total_time_spent"`
	TimeChange          int64         `json:"time_change"`
	HumanTotalTimeSpent *string       `json:"human_total_time_spent"`
	HumanTimeChange     *string       `json:"human_time_change"`
	HumanTimeEstimate   *string       `json:"human_time_estimate"`
	AssigneeIDs         []int64       `json:"assignee_ids"`
	AssigneeID          *int64        `json:"assignee_id"`
	Labels              []*EventLabel `json:"labels"`
	State               string        `json:"state"`
	Severity            string        `json:"severity"`
}

// MilestoneWebhookEvent represents a milestone webhook event.
//
// GitLab API docs:
// https://docs.gitlab.com/user/project/integrations/webhook_events/#milestone-events
type MilestoneWebhookEvent struct {
	ObjectKind       string                         `json:"object_kind"`
	EventType        string                         `json:"event_type"`
	Project          MilestoneEventProject          `json:"project"`
	ObjectAttributes MilestoneEventObjectAttributes `json:"object_attributes"`
	Action           string                         `json:"action"`
}

type MilestoneEventProject struct {
	ID                int64  `json:"id"`
	Name              string `json:"name"`
	Description       string `json:"description"`
	WebURL            string `json:"web_url"`
	AvatarURL         string `json:"avatar_url"`
	GitSSHURL         string `json:"git_ssh_url"`
	GitHTTPURL        string `json:"git_http_url"`
	Namespace         string `json:"namespace"`
	VisibilityLevel   int64  `json:"visibility_level"`
	PathWithNamespace string `json:"path_with_namespace"`
	DefaultBranch     string `json:"default_branch"`
	CIConfigPath      string `json:"ci_config_path"`
	Homepage          string `json:"homepage"`
	URL               string `json:"url"`
	SSHURL            string `json:"ssh_url"`
	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:
// https://docs.gitlab.com/user/project/integrations/webhook_events/#project-events
type ProjectWebhookEvent struct {
	EventName          string              `json:"event_name"`
	CreatedAt          string              `json:"created_at"`
	UpdatedAt          string              `json:"updated_at"`
	Name               string              `json:"name"`
	Path               string              `json:"path"`
	PathWithNamespace  string              `json:"path_with_namespace"`
	ProjectID          int64               `json:"project_id"`
	ProjectNamespaceID int64               `json:"project_namespace_id"`
	Owners             []ProjectEventOwner `json:"owners"`
	ProjectVisibility  string              `json:"project_visibility"`
}

type ProjectEventOwner struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

// VulnerabilityEvent represents a vulnerability event.
//
// GitLab API docs:
// https://docs.gitlab.com/user/project/integrations/webhook_events/#vulnerability-events
type VulnerabilityEvent struct {
	ObjectKind       string                             `json:"object_kind"`
	ObjectAttributes VulnerabilityEventObjectAttributes `json:"object_attributes"`
}

type VulnerabilityEventObjectAttributes struct {
	ID                      int64                          `json:"id"`
	URL                     string                         `json:"url"`
	Title                   string                         `json:"title"`
	State                   string                         `json:"state"`
	ProjectID               int64                          `json:"project_id"`
	Location                VulnerabilityEventLocation     `json:"location"`
	CVSS                    []VulnerabilityEventCVSS       `json:"cvss"`
	Severity                string                         `json:"severity"`
	SeverityOverridden      bool                           `json:"severity_overridden"`
	Identifiers             []VulnerabilityEventIdentifier `json:"identifiers"`
	Issues                  []VulnerabilityEventIssue      `json:"issues"`
	ReportType              string                         `json:"report_type"`
	Confidence              string                         `json:"confidence"`
	ConfidenceOverridden    bool                           `json:"confidence_overridden"`
	ConfirmedAt             string                         `json:"confirmed_at"`
	ConfirmedByID           int64                          `json:"confirmed_by_id"`
	DismissedAt             string                         `json:"dismissed_at"`
	DismissedByID           int64                          `json:"dismissed_by_id"`
	ResolvedAt              string                         `json:"resolved_at"`
	ResolvedByID            int64                          `json:"resolved_by_id"`
	AutoResolved            bool                           `json:"auto_resolved"`
	ResolvedOnDefaultBranch bool                           `json:"resolved_on_default_branch"`
	CreatedAt               string                         `json:"created_at"`
	UpdatedAt               string                         `json:"updated_at"`
}

type VulnerabilityEventLocation struct {
	File       string                               `json:"file"`
	Dependency VulnerabilityEventLocationDependency `json:"dependency"`
}

type VulnerabilityEventLocationDependency struct {
	Package VulnerabilityEventLocationDependencyPackage `json:"package"`
	Version string                                      `json:"version"`
}

type VulnerabilityEventLocationDependencyPackage struct {
	Name string `json:"name"`
}

type VulnerabilityEventCVSS struct {
	Vector string `json:"vector"`
	Vendor string `json:"vendor"`
}

type VulnerabilityEventIdentifier struct {
	Name         string `json:"name"`
	ExternalID   string `json:"external_id"`
	ExternalType string `json:"external_type"`
	URL          string `json:"url"`
}

type VulnerabilityEventIssue struct {
	Title     string `json:"title"`
	URL       string `json:"url"`
	CreatedAt string `json:"created_at"`
	UpdatedAt string `json:"updated_at"`
}

// EventLabel represents a label inside a webhook event.
//
// GitLab API docs:
+276 −0

File changed.

Preview size limit exceeded, changes collapsed.

+77 −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": "Issue",
    "awardable_id": 123,
    "updated_at": "2024-01-24 16:27:40 UTC",
    "action": "award",
    "awarded_on_url": "https://example.com/flightjs/Flight/-/issues/1"
  },
  "issue": {
    "id": 123,
    "iid": 1,
    "project_id": 7,
    "author_id": 1,
    "closed_at": null,
    "confidential": false,
    "created_at": "2024-01-20 10:00:00 UTC",
    "description": "This is a test issue",
    "discussion_locked": null,
    "due_date": null,
    "last_edited_at": null,
    "last_edited_by_id": null,
    "milestone_id": null,
    "moved_to_id": null,
    "duplicated_to_id": null,
    "relative_position": 1000,
    "state_id": 1,
    "time_estimate": 0,
    "title": "Test Issue",
    "updated_at": "2024-01-24 16:27:40 UTC",
    "updated_by_id": null,
    "weight": null,
    "health_status": null,
    "url": "https://example.com/flightjs/Flight/-/issues/1",
    "total_time_spent": 0,
    "time_change": 0,
    "human_total_time_spent": null,
    "human_time_change": null,
    "human_time_estimate": null,
    "assignee_ids": [],
    "assignee_id": null,
    "labels": [],
    "state": "opened",
    "severity": "unknown"
  }
}
Loading