...

Source file src/github.com/xanzy/go-gitlab/event_parsing.go

Documentation: github.com/xanzy/go-gitlab

     1  //
     2  // Copyright 2021, Sander van Harmelen
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package gitlab
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"net/http"
    23  )
    24  
    25  // EventType represents a Gitlab event type.
    26  type EventType string
    27  
    28  // List of available event types.
    29  const (
    30  	EventConfidentialIssue EventType = "Confidential Issue Hook"
    31  	EventConfidentialNote  EventType = "Confidential Note Hook"
    32  	EventTypeBuild         EventType = "Build Hook"
    33  	EventTypeDeployment    EventType = "Deployment Hook"
    34  	EventTypeFeatureFlag   EventType = "Feature Flag Hook"
    35  	EventTypeIssue         EventType = "Issue Hook"
    36  	EventTypeJob           EventType = "Job Hook"
    37  	EventTypeMember        EventType = "Member Hook"
    38  	EventTypeMergeRequest  EventType = "Merge Request Hook"
    39  	EventTypeNote          EventType = "Note Hook"
    40  	EventTypePipeline      EventType = "Pipeline Hook"
    41  	EventTypePush          EventType = "Push Hook"
    42  	EventTypeRelease       EventType = "Release Hook"
    43  	EventTypeServiceHook   EventType = "Service Hook"
    44  	EventTypeSubGroup      EventType = "Subgroup Hook"
    45  	EventTypeSystemHook    EventType = "System Hook"
    46  	EventTypeTagPush       EventType = "Tag Push Hook"
    47  	EventTypeWikiPage      EventType = "Wiki Page Hook"
    48  )
    49  
    50  const (
    51  	eventObjectKindPush         = "push"
    52  	eventObjectKindTagPush      = "tag_push"
    53  	eventObjectKindMergeRequest = "merge_request"
    54  )
    55  
    56  const (
    57  	noteableTypeCommit       = "Commit"
    58  	noteableTypeIssue        = "Issue"
    59  	noteableTypeMergeRequest = "MergeRequest"
    60  	noteableTypeSnippet      = "Snippet"
    61  )
    62  
    63  type noteEvent struct {
    64  	ObjectKind       string `json:"object_kind"`
    65  	ObjectAttributes struct {
    66  		NoteableType string `json:"noteable_type"`
    67  	} `json:"object_attributes"`
    68  }
    69  
    70  type serviceEvent struct {
    71  	ObjectKind string `json:"object_kind"`
    72  }
    73  
    74  const eventTypeHeader = "X-Gitlab-Event"
    75  
    76  // HookEventType returns the event type for the given request.
    77  func HookEventType(r *http.Request) EventType {
    78  	return EventType(r.Header.Get(eventTypeHeader))
    79  }
    80  
    81  // ParseHook tries to parse both web- and system hooks.
    82  //
    83  // Example usage:
    84  //
    85  //	func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    86  //	    payload, err := ioutil.ReadAll(r.Body)
    87  //	    if err != nil { ... }
    88  //	    event, err := gitlab.ParseHook(gitlab.HookEventType(r), payload)
    89  //	    if err != nil { ... }
    90  //	    switch event := event.(type) {
    91  //	    case *gitlab.PushEvent:
    92  //	        processPushEvent(event)
    93  //	    case *gitlab.MergeEvent:
    94  //	        processMergeEvent(event)
    95  //	    ...
    96  //	    }
    97  //	}
    98  func ParseHook(eventType EventType, payload []byte) (event interface{}, err error) {
    99  	switch eventType {
   100  	case EventTypeSystemHook:
   101  		return ParseSystemhook(payload)
   102  	default:
   103  		return ParseWebhook(eventType, payload)
   104  	}
   105  }
   106  
   107  // ParseSystemhook parses the event payload. For recognized event types, a
   108  // value of the corresponding struct type will be returned. An error will be
   109  // returned for unrecognized event types.
   110  //
   111  // Example usage:
   112  //
   113  //	func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   114  //	    payload, err := ioutil.ReadAll(r.Body)
   115  //	    if err != nil { ... }
   116  //	    event, err := gitlab.ParseSystemhook(payload)
   117  //	    if err != nil { ... }
   118  //	    switch event := event.(type) {
   119  //	    case *gitlab.PushSystemEvent:
   120  //	        processPushSystemEvent(event)
   121  //	    case *gitlab.MergeSystemEvent:
   122  //	        processMergeSystemEvent(event)
   123  //	    ...
   124  //	    }
   125  //	}
   126  func ParseSystemhook(payload []byte) (event interface{}, err error) {
   127  	e := &systemHookEvent{}
   128  	err = json.Unmarshal(payload, e)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	switch e.EventName {
   134  	case eventObjectKindPush:
   135  		event = &PushSystemEvent{}
   136  	case eventObjectKindTagPush:
   137  		event = &TagPushSystemEvent{}
   138  	case "repository_update":
   139  		event = &RepositoryUpdateSystemEvent{}
   140  	case
   141  		"project_create",
   142  		"project_update",
   143  		"project_destroy",
   144  		"project_transfer",
   145  		"project_rename":
   146  		event = &ProjectSystemEvent{}
   147  	case
   148  		"group_create",
   149  		"group_destroy",
   150  		"group_rename":
   151  		event = &GroupSystemEvent{}
   152  	case "key_create", "key_destroy":
   153  		event = &KeySystemEvent{}
   154  	case
   155  		"user_create",
   156  		"user_destroy",
   157  		"user_rename",
   158  		"user_failed_login":
   159  		event = &UserSystemEvent{}
   160  	case
   161  		"user_add_to_group",
   162  		"user_remove_from_group",
   163  		"user_update_for_group":
   164  		event = &UserGroupSystemEvent{}
   165  	case
   166  		"user_add_to_team",
   167  		"user_remove_from_team",
   168  		"user_update_for_team":
   169  		event = &UserTeamSystemEvent{}
   170  	default:
   171  		switch e.ObjectKind {
   172  		case string(MergeRequestEventTargetType):
   173  			event = &MergeEvent{}
   174  		default:
   175  			return nil, fmt.Errorf("unexpected system hook type %s", e.EventName)
   176  		}
   177  	}
   178  
   179  	if err := json.Unmarshal(payload, event); err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	return event, nil
   184  }
   185  
   186  // WebhookEventType returns the event type for the given request.
   187  func WebhookEventType(r *http.Request) EventType {
   188  	return EventType(r.Header.Get(eventTypeHeader))
   189  }
   190  
   191  // ParseWebhook parses the event payload. For recognized event types, a
   192  // value of the corresponding struct type will be returned. An error will
   193  // be returned for unrecognized event types.
   194  //
   195  // Example usage:
   196  //
   197  //	func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   198  //	    payload, err := ioutil.ReadAll(r.Body)
   199  //	    if err != nil { ... }
   200  //	    event, err := gitlab.ParseWebhook(gitlab.HookEventType(r), payload)
   201  //	    if err != nil { ... }
   202  //	    switch event := event.(type) {
   203  //	    case *gitlab.PushEvent:
   204  //	        processPushEvent(event)
   205  //	    case *gitlab.MergeEvent:
   206  //	        processMergeEvent(event)
   207  //	    ...
   208  //	    }
   209  //	}
   210  func ParseWebhook(eventType EventType, payload []byte) (event interface{}, err error) {
   211  	switch eventType {
   212  	case EventTypeBuild:
   213  		event = &BuildEvent{}
   214  	case EventTypeDeployment:
   215  		event = &DeploymentEvent{}
   216  	case EventTypeFeatureFlag:
   217  		event = &FeatureFlagEvent{}
   218  	case EventTypeIssue, EventConfidentialIssue:
   219  		event = &IssueEvent{}
   220  	case EventTypeJob:
   221  		event = &JobEvent{}
   222  	case EventTypeMember:
   223  		event = &MemberEvent{}
   224  	case EventTypeMergeRequest:
   225  		event = &MergeEvent{}
   226  	case EventTypeNote, EventConfidentialNote:
   227  		note := &noteEvent{}
   228  		err := json.Unmarshal(payload, note)
   229  		if err != nil {
   230  			return nil, err
   231  		}
   232  
   233  		if note.ObjectKind != string(NoteEventTargetType) {
   234  			return nil, fmt.Errorf("unexpected object kind %s", note.ObjectKind)
   235  		}
   236  
   237  		switch note.ObjectAttributes.NoteableType {
   238  		case noteableTypeCommit:
   239  			event = &CommitCommentEvent{}
   240  		case noteableTypeMergeRequest:
   241  			event = &MergeCommentEvent{}
   242  		case noteableTypeIssue:
   243  			event = &IssueCommentEvent{}
   244  		case noteableTypeSnippet:
   245  			event = &SnippetCommentEvent{}
   246  		default:
   247  			return nil, fmt.Errorf("unexpected noteable type %s", note.ObjectAttributes.NoteableType)
   248  		}
   249  	case EventTypePipeline:
   250  		event = &PipelineEvent{}
   251  	case EventTypePush:
   252  		event = &PushEvent{}
   253  	case EventTypeRelease:
   254  		event = &ReleaseEvent{}
   255  	case EventTypeServiceHook:
   256  		service := &serviceEvent{}
   257  		err := json.Unmarshal(payload, service)
   258  		if err != nil {
   259  			return nil, err
   260  		}
   261  		switch service.ObjectKind {
   262  		case eventObjectKindPush:
   263  			event = &PushEvent{}
   264  		case eventObjectKindTagPush:
   265  			event = &TagEvent{}
   266  		case eventObjectKindMergeRequest:
   267  			event = &MergeEvent{}
   268  		default:
   269  			return nil, fmt.Errorf("unexpected service type %s", service.ObjectKind)
   270  		}
   271  	case EventTypeSubGroup:
   272  		event = &SubGroupEvent{}
   273  	case EventTypeTagPush:
   274  		event = &TagEvent{}
   275  	case EventTypeWikiPage:
   276  		event = &WikiPageEvent{}
   277  	default:
   278  		return nil, fmt.Errorf("unexpected event type: %s", eventType)
   279  	}
   280  
   281  	if err := json.Unmarshal(payload, event); err != nil {
   282  		return nil, err
   283  	}
   284  
   285  	return event, nil
   286  }
   287  

View as plain text