Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new project and group access token events to webhook event types #1916

Merged
merged 2 commits into from Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 37 additions & 18 deletions event_parsing.go
Expand Up @@ -27,24 +27,25 @@ type EventType string

// List of available event types.
const (
EventConfidentialIssue EventType = "Confidential Issue Hook"
EventConfidentialNote EventType = "Confidential Note Hook"
EventTypeBuild EventType = "Build Hook"
EventTypeDeployment EventType = "Deployment Hook"
EventTypeFeatureFlag EventType = "Feature Flag Hook"
EventTypeIssue EventType = "Issue Hook"
EventTypeJob EventType = "Job Hook"
EventTypeMember EventType = "Member Hook"
EventTypeMergeRequest EventType = "Merge Request Hook"
EventTypeNote EventType = "Note Hook"
EventTypePipeline EventType = "Pipeline Hook"
EventTypePush EventType = "Push Hook"
EventTypeRelease EventType = "Release Hook"
EventTypeServiceHook EventType = "Service Hook"
EventTypeSubGroup EventType = "Subgroup Hook"
EventTypeSystemHook EventType = "System Hook"
EventTypeTagPush EventType = "Tag Push Hook"
EventTypeWikiPage EventType = "Wiki Page Hook"
EventConfidentialIssue EventType = "Confidential Issue Hook"
EventConfidentialNote EventType = "Confidential Note Hook"
EventTypeBuild EventType = "Build Hook"
EventTypeDeployment EventType = "Deployment Hook"
EventTypeFeatureFlag EventType = "Feature Flag Hook"
EventTypeIssue EventType = "Issue Hook"
EventTypeJob EventType = "Job Hook"
EventTypeMember EventType = "Member Hook"
EventTypeMergeRequest EventType = "Merge Request Hook"
EventTypeNote EventType = "Note Hook"
EventTypePipeline EventType = "Pipeline Hook"
EventTypePush EventType = "Push Hook"
EventTypeRelease EventType = "Release Hook"
EventTypeResourceAccessToken EventType = "Resource Access Token Hook"
EventTypeServiceHook EventType = "Service Hook"
EventTypeSubGroup EventType = "Subgroup Hook"
EventTypeSystemHook EventType = "System Hook"
EventTypeTagPush EventType = "Tag Push Hook"
EventTypeWikiPage EventType = "Wiki Page Hook"
)

const (
Expand Down Expand Up @@ -252,6 +253,24 @@ func ParseWebhook(eventType EventType, payload []byte) (event interface{}, err e
event = &PushEvent{}
case EventTypeRelease:
event = &ReleaseEvent{}
case EventTypeResourceAccessToken:
data := map[string]interface{}{}
err := json.Unmarshal(payload, &data)
if err != nil {
return nil, err
}

_, groupEvent := data["group"]
_, projectEvent := data["project"]

switch {
case groupEvent:
event = &GroupResourceAccessTokenEvent{}
case projectEvent:
event = &ProjectResourceAccessTokenEvent{}
default:
return nil, fmt.Errorf("unexpected resource access token payload")
}
case EventTypeServiceHook:
service := &serviceEvent{}
err := json.Unmarshal(payload, service)
Expand Down
38 changes: 37 additions & 1 deletion event_parsing_webhook_test.go
Expand Up @@ -101,7 +101,7 @@ func TestParseCommitCommentHook(t *testing.T) {
}
}

func TestParseFeatureFLagHook(t *testing.T) {
func TestParseFeatureFlagHook(t *testing.T) {
raw := loadFixture("testdata/webhooks/feature_flag.json")

parsedEvent, err := ParseWebhook("Feature Flag Hook", raw)
Expand Down Expand Up @@ -147,6 +147,24 @@ func TestParseFeatureFLagHook(t *testing.T) {
}
}

func TestParseGroupResourceAccessTokenHook(t *testing.T) {
raw := loadFixture("testdata/webhooks/resource_access_token_group.json")

parsedEvent, err := ParseWebhook("Resource Access Token Hook", raw)
if err != nil {
t.Errorf("Error parsing group resource access token hook: %s", err)
}

event, ok := parsedEvent.(*GroupResourceAccessTokenEvent)
if !ok {
t.Errorf("Expected GroupResourceAccessTokenEvent, but parsing produced %T", parsedEvent)
}

if event.GroupID != 35 {
t.Errorf("GroupID is %v, want %v", event.GroupID, 35)
}
}

func TestParseHookWebHook(t *testing.T) {
parsedEvent1, err := ParseHook("Merge Request Hook", loadFixture("testdata/webhooks/merge_request.json"))
if err != nil {
Expand Down Expand Up @@ -351,6 +369,24 @@ func TestParsePipelineHook(t *testing.T) {
}
}

func TestParseProjectResourceAccessTokenHook(t *testing.T) {
raw := loadFixture("testdata/webhooks/resource_access_token_project.json")

parsedEvent, err := ParseWebhook("Resource Access Token Hook", raw)
if err != nil {
t.Errorf("Error parsing project resource access token hook: %s", err)
}

event, ok := parsedEvent.(*ProjectResourceAccessTokenEvent)
if !ok {
t.Errorf("Expected ProjectResourceAccessTokenEvent, but parsing produced %T", parsedEvent)
}

if event.ProjectID != 7 {
t.Errorf("ProjectID is %v, want %v", event.ProjectID, 7)
}
}

func TestParsePushHook(t *testing.T) {
raw := loadFixture("testdata/webhooks/push.json")

Expand Down
70 changes: 66 additions & 4 deletions event_webhook_types.go
Expand Up @@ -131,7 +131,7 @@ type CommitCommentEvent struct {
} `json:"commit"`
}

// DeploymentEvent represents a deployment event
// DeploymentEvent represents a deployment event.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#deployment-events
Expand Down Expand Up @@ -171,7 +171,7 @@ type DeploymentEvent struct {
CommitTitle string `json:"commit_title"`
}

// FeatureFlagEvent represents a feature flag event
// FeatureFlagEvent represents a feature flag event.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#feature-flag-events
Expand Down Expand Up @@ -205,6 +205,30 @@ type FeatureFlagEvent struct {
} `json:"object_attributes"`
}

// GroupResourceAccessTokenEvent represents a resource access token event for a
// group.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#project-and-group-access-token-events
type GroupResourceAccessTokenEvent struct {
EventName string `json:"event_name"`
ObjectKind string `json:"object_kind"`
GroupID int `json:"group_id"`
Group struct {
GroupID int `json:"group_id"`
GroupName string `json:"group_name"`
GroupPath string `json:"group_path"`
FullPath string `json:"full_path"`
} `json:"group"`
ObjectAttributes struct {
ID int `json:"id"`
UserID int `json:"user_id"`
Name string `json:"name"`
CreatedAt *time.Time `json:"created_at"`
ExpiresAt *ISOTime `json:"expires_at"`
} `json:"object_attributes"`
}

// IssueCommentEvent represents a comment on an issue event.
//
// GitLab API docs:
Expand Down Expand Up @@ -737,7 +761,8 @@ type MergeEvent struct {
Reviewers []*EventUser `json:"reviewers"`
}

// EventUser represents a user record in an event and is used as an even initiator or a merge assignee.
// EventUser represents a user record in an event and is used as an even
// initiator or a merge assignee.
type EventUser struct {
ID int `json:"id"`
Name string `json:"name"`
Expand All @@ -753,7 +778,8 @@ type MergeParams struct {

// UnmarshalJSON decodes the merge parameters
//
// This allows support of ForceRemoveSourceBranch for both type bool (>11.9) and string (<11.9)
// This allows support of ForceRemoveSourceBranch for both type
// bool (>11.9) and string (<11.9)
func (p *MergeParams) UnmarshalJSON(b []byte) error {
type Alias MergeParams
raw := struct {
Expand Down Expand Up @@ -899,6 +925,42 @@ type PipelineEvent struct {
} `json:"builds"`
}

// ProjectResourceAccessTokenEvent represents a resource access token event for
// a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#project-and-group-access-token-events
type ProjectResourceAccessTokenEvent struct {
EventName string `json:"event_name"`
ObjectKind string `json:"object_kind"`
ProjectID int `json:"project_id"`
Project struct {
ID int `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 int `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"`
} `json:"project"`
ObjectAttributes struct {
ID int `json:"id"`
UserID int `json:"user_id"`
Name string `json:"name"`
CreatedAt *time.Time `json:"created_at"`
ExpiresAt *ISOTime `json:"expires_at"`
} `json:"object_attributes"`
}

// PushEvent represents a push event.
//
// GitLab API docs:
Expand Down
96 changes: 96 additions & 0 deletions event_webhook_types_test.go
Expand Up @@ -286,6 +286,48 @@ func TestFeatureFlagEventUnmarshal(t *testing.T) {
}
}

func TestGroupResourceAccessTokenEventUnmarshal(t *testing.T) {
jsonObject := loadFixture("testdata/webhooks/resource_access_token_group.json")
var event *GroupResourceAccessTokenEvent
err := json.Unmarshal(jsonObject, &event)
if err != nil {
t.Errorf("could not unmarshal event: %v\n ", err.Error())
}

if event == nil {
t.Errorf("event is null")
}

createdAt, err := time.Parse(time.RFC3339, "2024-02-05T03:13:44.855Z")
if err != nil {
t.Fatalf("could not parse time: %v", err)
}

expiresAt, err := ParseISOTime("2024-01-26")
if err != nil {
t.Fatalf("could not parse ISO time: %v", err)
}

expected := &GroupResourceAccessTokenEvent{
GroupID: 35,
ObjectKind: "access_token",
EventName: "expiring_access_token",
}

expected.Group.GroupID = 35
expected.Group.GroupName = "Twitter"
expected.Group.GroupPath = "twitter"
expected.Group.FullPath = "twitter"

expected.ObjectAttributes.ID = 25
expected.ObjectAttributes.UserID = 90
expected.ObjectAttributes.Name = "acd"
expected.ObjectAttributes.CreatedAt = &createdAt
expected.ObjectAttributes.ExpiresAt = &expiresAt

assert.Equal(t, expected, event)
}

func TestIssueCommentEventUnmarshal(t *testing.T) {
jsonObject := loadFixture("testdata/webhooks/note_issue.json")

Expand Down Expand Up @@ -1014,6 +1056,60 @@ func TestPipelineEventUnmarshal(t *testing.T) {
}
}

func TestProjectResourceAccessTokenEventUnmarshal(t *testing.T) {
jsonObject := loadFixture("testdata/webhooks/resource_access_token_project.json")
var event *ProjectResourceAccessTokenEvent
err := json.Unmarshal(jsonObject, &event)
if err != nil {
t.Errorf("could not unmarshal event: %v\n ", err.Error())
}

if event == nil {
t.Errorf("event is null")
}

createdAt, err := time.Parse(time.RFC3339, "2024-02-05T03:13:44.855Z")
if err != nil {
t.Fatalf("could not parse time: %v", err)
}

expiresAt, err := ParseISOTime("2024-01-26")
if err != nil {
t.Fatalf("could not parse ISO time: %v", err)
}

expected := &ProjectResourceAccessTokenEvent{
ProjectID: 7,
ObjectKind: "access_token",
EventName: "expiring_access_token",
}

expected.ObjectAttributes.ID = 25
expected.ObjectAttributes.UserID = 90
expected.ObjectAttributes.Name = "acd"
expected.ObjectAttributes.CreatedAt = &createdAt
expected.ObjectAttributes.ExpiresAt = &expiresAt

expected.Project.ID = 7
expected.Project.Name = "Flight"
expected.Project.Description = "Eum dolore maxime atque reprehenderit voluptatem."
expected.Project.WebURL = "https://example.com/flightjs/Flight"
expected.Project.AvatarURL = ""
expected.Project.GitSSHURL = "ssh://git@example.com/flightjs/Flight.git"
expected.Project.GitHTTPURL = "https://example.com/flightjs/Flight.git"
expected.Project.Namespace = "Flightjs"
expected.Project.VisibilityLevel = 0
expected.Project.PathWithNamespace = "flightjs/Flight"
expected.Project.DefaultBranch = "master"
expected.Project.CIConfigPath = ""
expected.Project.Homepage = "https://example.com/flightjs/Flight"
expected.Project.URL = "ssh://git@example.com/flightjs/Flight.git"
expected.Project.SSHURL = "ssh://git@example.com/flightjs/Flight.git"
expected.Project.HTTPURL = "https://example.com/flightjs/Flight.git"

assert.Equal(t, expected, event)
}

func TestPushEventUnmarshal(t *testing.T) {
jsonObject := loadFixture("testdata/webhooks/push.json")
var event *PushEvent
Expand Down
18 changes: 18 additions & 0 deletions testdata/webhooks/resource_access_token_group.json
@@ -0,0 +1,18 @@
{
"object_kind": "access_token",
"group_id": 35,
"group": {
"group_name": "Twitter",
"group_path": "twitter",
"full_path": "twitter",
"group_id": 35
},
"object_attributes": {
"user_id": 90,
"created_at": "2024-02-05T03:13:44.855Z",
"id": 25,
"name": "acd",
"expires_at": "2024-01-26"
},
"event_name": "expiring_access_token"
}
30 changes: 30 additions & 0 deletions testdata/webhooks/resource_access_token_project.json
@@ -0,0 +1,30 @@
{
"object_kind": "access_token",
"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": null,
"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": 90,
"created_at": "2024-02-05T03:13:44.855Z",
"id": 25,
"name": "acd",
"expires_at": "2024-01-26"
},
"event_name": "expiring_access_token"
}