package trigger import ( "encoding/json" "fmt" "strings" "time" ) type Event interface { Validate() error EventKind() string } type PushEvent struct { Kind string `json:"kind"` Repo string `json:"repo"` Old string `json:"old"` New string `json:"new"` Ref string `json:"ref"` } func (e PushEvent) EventKind() string { return "push" } func (e PushEvent) Validate() error { if e.Kind != "push" { return fmt.Errorf("push event kind must be push") } if strings.TrimSpace(e.Repo) == "" || strings.TrimSpace(e.New) == "" || strings.TrimSpace(e.Ref) == "" { return fmt.Errorf("push event requires repo, new, and ref") } return nil } type ScheduleEvent struct { Kind string `json:"kind"` Repo string `json:"repo"` Job string `json:"job"` Rev string `json:"rev"` Ref string `json:"ref"` Minute string `json:"minute"` } func (e ScheduleEvent) EventKind() string { return "schedule" } func (e ScheduleEvent) Validate() error { if e.Kind != "schedule" { return fmt.Errorf("schedule event kind must be schedule") } if strings.TrimSpace(e.Repo) == "" || strings.TrimSpace(e.Job) == "" || strings.TrimSpace(e.Rev) == "" || strings.TrimSpace(e.Ref) == "" { return fmt.Errorf("schedule event requires repo, job, revision, and ref") } if _, err := time.Parse("2006-01-02T15:04Z", e.Minute); err != nil { return fmt.Errorf("schedule event has invalid minute %q", e.Minute) } return nil } type ManualEvent struct { Kind string `json:"kind"` Repo string `json:"repo"` Job string `json:"job"` Ref *string `json:"ref"` Rev *string `json:"rev"` RequestedBy string `json:"requested_by"` ResolvedRev string `json:"resolved_rev,omitempty"` } func (e ManualEvent) EventKind() string { return "manual" } func (e ManualEvent) Validate() error { if e.Kind != "manual" { return fmt.Errorf("manual event kind must be manual") } if strings.TrimSpace(e.Repo) == "" || strings.TrimSpace(e.Job) == "" { return fmt.Errorf("manual event requires repo and job") } hasRef := e.Ref != nil && strings.TrimSpace(*e.Ref) != "" hasRev := e.Rev != nil && strings.TrimSpace(*e.Rev) != "" if hasRef == hasRev { return fmt.Errorf("manual event requires exactly one of ref or rev") } return nil } func Decode(data []byte) (Event, error) { var header struct { Kind string `json:"kind"` } if err := json.Unmarshal(data, &header); err != nil { return nil, err } switch header.Kind { case "push": var event PushEvent if err := json.Unmarshal(data, &event); err != nil { return nil, err } return event, event.Validate() case "manual": var event ManualEvent if err := json.Unmarshal(data, &event); err != nil { return nil, err } return event, event.Validate() case "schedule": var event ScheduleEvent if err := json.Unmarshal(data, &event); err != nil { return nil, err } return event, event.Validate() default: return nil, fmt.Errorf("unknown trigger kind %q", header.Kind) } }