// Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2017 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package structs import ( "errors" "strings" "time" "code.gitea.io/gitea/modules/json" ) // ErrInvalidReceiveHook FIXME var ErrInvalidReceiveHook = errors.New("Invalid JSON payload received over webhook") // Hook a hook is a web hook when one repository changed type Hook struct { ID int64 `json:"id"` Type string `json:"type"` BranchFilter string `json:"branch_filter"` URL string `json:"-"` Config map[string]string `json:"config"` Events []string `json:"events"` AuthorizationHeader string `json:"authorization_header"` Active bool `json:"active"` // swagger:strfmt date-time Updated time.Time `json:"updated_at"` // swagger:strfmt date-time Created time.Time `json:"created_at"` } // HookList represents a list of API hook. type HookList []*Hook // CreateHookOptionConfig has all config options in it // required are "content_type" and "url" Required type CreateHookOptionConfig map[string]string // CreateHookOption options when create a hook type CreateHookOption struct { // required: true // enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,wechatwork,packagist Type string `json:"type" binding:"Required"` // required: true Config CreateHookOptionConfig `json:"config" binding:"Required"` Events []string `json:"events"` BranchFilter string `json:"branch_filter" binding:"GlobPattern"` AuthorizationHeader string `json:"authorization_header"` // default: false Active bool `json:"active"` } // EditHookOption options when modify one hook type EditHookOption struct { Config map[string]string `json:"config"` Events []string `json:"events"` BranchFilter string `json:"branch_filter" binding:"GlobPattern"` AuthorizationHeader string `json:"authorization_header"` Active *bool `json:"active"` } // Payloader payload is some part of one hook type Payloader interface { JSONPayload() ([]byte, error) } // PayloadUser represents the author or committer of a commit type PayloadUser struct { // Full name of the commit author Name string `json:"name"` // swagger:strfmt email Email string `json:"email"` UserName string `json:"username"` } // FIXME: consider using same format as API when commits API are added. // applies to PayloadCommit and PayloadCommitVerification // PayloadCommit represents a commit type PayloadCommit struct { // sha1 hash of the commit ID string `json:"id"` Message string `json:"message"` URL string `json:"url"` Author *PayloadUser `json:"author"` Committer *PayloadUser `json:"committer"` Verification *PayloadCommitVerification `json:"verification"` // swagger:strfmt date-time Timestamp time.Time `json:"timestamp"` Added []string `json:"added"` Removed []string `json:"removed"` Modified []string `json:"modified"` } // PayloadCommitVerification represents the GPG verification of a commit type PayloadCommitVerification struct { Verified bool `json:"verified"` Reason string `json:"reason"` Signature string `json:"signature"` Signer *PayloadUser `json:"signer"` Payload string `json:"payload"` } var ( _ Payloader = &CreatePayload{} _ Payloader = &DeletePayload{} _ Payloader = &ForkPayload{} _ Payloader = &PushPayload{} _ Payloader = &IssuePayload{} _ Payloader = &IssueCommentPayload{} _ Payloader = &PullRequestPayload{} _ Payloader = &RepositoryPayload{} _ Payloader = &ReleasePayload{} _ Payloader = &PackagePayload{} ) // _________ __ // \_ ___ \_______ ____ _____ _/ |_ ____ // / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \ // \ \____| | \/\ ___/ / __ \| | \ ___/ // \______ /|__| \___ >____ /__| \___ > // \/ \/ \/ \/ // CreatePayload FIXME type CreatePayload struct { Sha string `json:"sha"` Ref string `json:"ref"` RefType string `json:"ref_type"` Repo *Repository `json:"repository"` Sender *User `json:"sender"` } // JSONPayload return payload information func (p *CreatePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // ParseCreateHook parses create event hook content. func ParseCreateHook(raw []byte) (*CreatePayload, error) { hook := new(CreatePayload) if err := json.Unmarshal(raw, hook); err != nil { return nil, err } // it is possible the JSON was parsed, however, // was not from Gogs (maybe was from Bitbucket) // So we'll check to be sure certain key fields // were populated switch { case hook.Repo == nil: return nil, ErrInvalidReceiveHook case len(hook.Ref) == 0: return nil, ErrInvalidReceiveHook } return hook, nil } // ________ .__ __ // \______ \ ____ | | _____/ |_ ____ // | | \_/ __ \| | _/ __ \ __\/ __ \ // | ` \ ___/| |_\ ___/| | \ ___/ // /_______ /\___ >____/\___ >__| \___ > // \/ \/ \/ \/ // PusherType define the type to push type PusherType string // describe all the PusherTypes const ( PusherTypeUser PusherType = "user" ) // DeletePayload represents delete payload type DeletePayload struct { Ref string `json:"ref"` RefType string `json:"ref_type"` PusherType PusherType `json:"pusher_type"` Repo *Repository `json:"repository"` Sender *User `json:"sender"` } // JSONPayload implements Payload func (p *DeletePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // ___________ __ // \_ _____/__________| | __ // | __)/ _ \_ __ \ |/ / // | \( <_> ) | \/ < // \___ / \____/|__| |__|_ \ // \/ \/ // ForkPayload represents fork payload type ForkPayload struct { Forkee *Repository `json:"forkee"` Repo *Repository `json:"repository"` Sender *User `json:"sender"` } // JSONPayload implements Payload func (p *ForkPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // HookIssueCommentAction defines hook issue comment action type HookIssueCommentAction string // all issue comment actions const ( HookIssueCommentCreated HookIssueCommentAction = "created" HookIssueCommentEdited HookIssueCommentAction = "edited" HookIssueCommentDeleted HookIssueCommentAction = "deleted" ) // IssueCommentPayload represents a payload information of issue comment event. type IssueCommentPayload struct { Action HookIssueCommentAction `json:"action"` Issue *Issue `json:"issue"` PullRequest *PullRequest `json:"pull_request,omitempty"` Comment *Comment `json:"comment"` Changes *ChangesPayload `json:"changes,omitempty"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` IsPull bool `json:"is_pull"` } // JSONPayload implements Payload func (p *IssueCommentPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // __________ .__ // \______ \ ____ | | ____ _____ ______ ____ // | _// __ \| | _/ __ \\__ \ / ___// __ \ // | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/ // |____|_ /\___ >____/\___ >____ /____ >\___ > // \/ \/ \/ \/ \/ \/ // HookReleaseAction defines hook release action type type HookReleaseAction string // all release actions const ( HookReleasePublished HookReleaseAction = "published" HookReleaseUpdated HookReleaseAction = "updated" HookReleaseDeleted HookReleaseAction = "deleted" ) // ReleasePayload represents a payload information of release event. type ReleasePayload struct { Action HookReleaseAction `json:"action"` Release *Release `json:"release"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` } // JSONPayload implements Payload func (p *ReleasePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // PushPayload represents a payload information of push event. type PushPayload struct { Ref string `json:"ref"` Before string `json:"before"` After string `json:"after"` CompareURL string `json:"compare_url"` Commits []*PayloadCommit `json:"commits"` TotalCommits int `json:"total_commits"` HeadCommit *PayloadCommit `json:"head_commit"` Repo *Repository `json:"repository"` Pusher *User `json:"pusher"` Sender *User `json:"sender"` } // JSONPayload FIXME func (p *PushPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // ParsePushHook parses push event hook content. func ParsePushHook(raw []byte) (*PushPayload, error) { hook := new(PushPayload) if err := json.Unmarshal(raw, hook); err != nil { return nil, err } switch { case hook.Repo == nil: return nil, ErrInvalidReceiveHook case len(hook.Ref) == 0: return nil, ErrInvalidReceiveHook } return hook, nil } // Branch returns branch name from a payload func (p *PushPayload) Branch() string { return strings.ReplaceAll(p.Ref, "refs/heads/", "") } // .___ // | | ______ ________ __ ____ // | |/ ___// ___/ | \_/ __ \ // | |\___ \ \___ \| | /\ ___/ // |___/____ >____ >____/ \___ > // \/ \/ \/ // HookIssueAction FIXME type HookIssueAction string const ( // HookIssueOpened opened HookIssueOpened HookIssueAction = "opened" // HookIssueClosed closed HookIssueClosed HookIssueAction = "closed" // HookIssueReOpened reopened HookIssueReOpened HookIssueAction = "reopened" // HookIssueEdited edited HookIssueEdited HookIssueAction = "edited" // HookIssueAssigned assigned HookIssueAssigned HookIssueAction = "assigned" // HookIssueUnassigned unassigned HookIssueUnassigned HookIssueAction = "unassigned" // HookIssueLabelUpdated label_updated HookIssueLabelUpdated HookIssueAction = "label_updated" // HookIssueLabelCleared label_cleared HookIssueLabelCleared HookIssueAction = "label_cleared" // HookIssueSynchronized synchronized HookIssueSynchronized HookIssueAction = "synchronized" // HookIssueMilestoned is an issue action for when a milestone is set on an issue. HookIssueMilestoned HookIssueAction = "milestoned" // HookIssueDemilestoned is an issue action for when a milestone is cleared on an issue. HookIssueDemilestoned HookIssueAction = "demilestoned" // HookIssueReviewed is an issue action for when a pull request is reviewed HookIssueReviewed HookIssueAction = "reviewed" // HookIssueReviewRequested is an issue action for when a reviewer is requested for a pull request. HookIssueReviewRequested HookIssueAction = "review_requested" // HookIssueReviewRequestRemoved is an issue action for removing a review request to someone on a pull request. HookIssueReviewRequestRemoved HookIssueAction = "review_request_removed" ) // IssuePayload represents the payload information that is sent along with an issue event. type IssuePayload struct { Action HookIssueAction `json:"action"` Index int64 `json:"number"` Changes *ChangesPayload `json:"changes,omitempty"` Issue *Issue `json:"issue"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` CommitID string `json:"commit_id"` } // JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces. func (p *IssuePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // ChangesFromPayload FIXME type ChangesFromPayload struct { From string `json:"from"` } // ChangesPayload represents the payload information of issue change type ChangesPayload struct { Title *ChangesFromPayload `json:"title,omitempty"` Body *ChangesFromPayload `json:"body,omitempty"` Ref *ChangesFromPayload `json:"ref,omitempty"` } // __________ .__ .__ __________ __ // \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_ // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ // | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | | // |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__| // \/ \/ |__| \/ \/ // PullRequestPayload represents a payload information of pull request event. type PullRequestPayload struct { Action HookIssueAction `json:"action"` Index int64 `json:"number"` Changes *ChangesPayload `json:"changes,omitempty"` PullRequest *PullRequest `json:"pull_request"` RequestedReviewer *User `json:"requested_reviewer"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` CommitID string `json:"commit_id"` Review *ReviewPayload `json:"review"` } // JSONPayload FIXME func (p *PullRequestPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // ReviewPayload FIXME type ReviewPayload struct { Type string `json:"type"` Content string `json:"content"` } // __ __.__ __ .__ // / \ / \__| | _|__| // \ \/\/ / | |/ / | // \ /| | <| | // \__/\ / |__|__|_ \__| // \/ \/ // HookWikiAction an action that happens to a wiki page type HookWikiAction string const ( // HookWikiCreated created HookWikiCreated HookWikiAction = "created" // HookWikiEdited edited HookWikiEdited HookWikiAction = "edited" // HookWikiDeleted deleted HookWikiDeleted HookWikiAction = "deleted" ) // WikiPayload payload for repository webhooks type WikiPayload struct { Action HookWikiAction `json:"action"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` Page string `json:"page"` Comment string `json:"comment"` } // JSONPayload JSON representation of the payload func (p *WikiPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } //__________ .__ __ //\______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | // | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ | // |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____| // \/ \/|__| \/ \/ // HookRepoAction an action that happens to a repo type HookRepoAction string const ( // HookRepoCreated created HookRepoCreated HookRepoAction = "created" // HookRepoDeleted deleted HookRepoDeleted HookRepoAction = "deleted" ) // RepositoryPayload payload for repository webhooks type RepositoryPayload struct { Action HookRepoAction `json:"action"` Repository *Repository `json:"repository"` Organization *User `json:"organization"` Sender *User `json:"sender"` } // JSONPayload JSON representation of the payload func (p *RepositoryPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // HookPackageAction an action that happens to a package type HookPackageAction string const ( // HookPackageCreated created HookPackageCreated HookPackageAction = "created" // HookPackageDeleted deleted HookPackageDeleted HookPackageAction = "deleted" ) // PackagePayload represents a package payload type PackagePayload struct { Action HookPackageAction `json:"action"` Repository *Repository `json:"repository"` Package *Package `json:"package"` Organization *User `json:"organization"` Sender *User `json:"sender"` } // JSONPayload implements Payload func (p *PackagePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // WorkflowDispatchPayload represents a workflow dispatch payload type WorkflowDispatchPayload struct { Workflow string `json:"workflow"` Ref string `json:"ref"` Inputs map[string]any `json:"inputs"` Repository *Repository `json:"repository"` Sender *User `json:"sender"` } // JSONPayload implements Payload func (p *WorkflowDispatchPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } // CommitStatusPayload represents a payload information of commit status event. type CommitStatusPayload struct { // TODO: add Branches per https://docs.github.com/en/webhooks/webhook-events-and-payloads#status Commit *PayloadCommit `json:"commit"` Context string `json:"context"` // swagger:strfmt date-time CreatedAt time.Time `json:"created_at"` Description string `json:"description"` ID int64 `json:"id"` Repo *Repository `json:"repository"` Sender *User `json:"sender"` SHA string `json:"sha"` State string `json:"state"` TargetURL string `json:"target_url"` // swagger:strfmt date-time UpdatedAt *time.Time `json:"updated_at"` } // JSONPayload implements Payload func (p *CommitStatusPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") }