diff --git a/scm/const.go b/scm/const.go index 73fa7a9e6..1a62d5e98 100644 --- a/scm/const.go +++ b/scm/const.go @@ -283,4 +283,66 @@ func (v Visibility) String() (s string) { } } +// Status defines an enum for execution status +type ExecutionStatus int + +const ( + StatusUnknown ExecutionStatus = iota + StatusPending + StatusRunning + StatusSuccess + StatusFailed + StatusCanceled +) + +// String returns the string representation of ExecutionStatus. +func (k ExecutionStatus) String() string { + switch k { + case StatusSuccess: + return "success" + case StatusPending: + return "pending" + case StatusRunning: + return "running" + case StatusFailed: + return "failed" + case StatusCanceled: + return "canceled" + case StatusUnknown: + return "Unknown" + default: + return "unsupported" + } +} + +// MarshalJSON returns the JSON-encoded Action. +func (k ExecutionStatus) MarshalJSON() ([]byte, error) { + return json.Marshal(k.String()) +} + +// UnmarshalJSON unmarshales the JSON-encoded ExecutionStatus. +func (k *ExecutionStatus) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + switch s { + case StatusSuccess.String(): + *k = StatusSuccess + case StatusPending.String(): + *k = StatusPending + case StatusPending.String(): + *k = StatusPending + case StatusRunning.String(): + *k = StatusRunning + case StatusFailed.String(): + *k = StatusFailed + case StatusCanceled.String(): + *k = StatusCanceled + default: + *k = StatusUnknown + } + return nil +} + const SearchTimeFormat = "2006-01-02T15:04:05Z" diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json new file mode 100644 index 000000000..02c506c67 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json @@ -0,0 +1,175 @@ +{ + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "scm": "git", + "website": null, + "owner": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "workspace": { + "type": "workspace", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "name": "Automationtestharness", + "slug": "automationtestharness", + "links": { + "avatar": { + "href": "https://bitbucket.org/workspaces/automationtestharness/avatar/?ts=1740994558" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness" + } + } + }, + "is_private": true, + "project": { + "type": "project", + "key": "TEST", + "uuid": "{af6d7f47-6ce6-48b6-9beb-d5ad6b674ba0}", + "name": "test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST/avatar/32?ts=1738907820" + } + } + }, + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "parent": null + }, + "actor": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "commit_status": { + "key": "3343801", + "type": "build", + "state": "INPROGRESS", + "name": "Pipeline #4 for main", + "refname": "main", + "commit": { + "type": "commit", + "hash": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "date": "2025-03-24T08:48:15+00:00", + "author": { + "type": "author", + "raw": "Shivam Negi ", + "user": { + "display_name": "Shivam Negi", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "html": { + "href": "https://bitbucket.org/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D/" + } + }, + "type": "user", + "uuid": "{ce7d5dfc-83c9-4878-beaf-7b91610e104a}", + "account_id": "601ba1bdb7bda90068ed5d1b", + "nickname": "Shivam Negi" + } + }, + "message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/diff/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/approve" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/comments" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses" + } + } + }, + "url": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4", + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}" + }, + "description": "", + "created_on": "2025-03-24T08:48:56.572438+00:00", + "updated_on": "2025-03-24T08:48:56.572450+00:00", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses/build/3343801" + }, + "commit": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + } + } + } + } \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json.golden b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json.golden new file mode 100644 index 000000000..b0e6c2a38 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_created.json.golden @@ -0,0 +1,39 @@ +{ + "Repo": { + "ID": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "Namespace": "automationtestharness", + "Name": "testrepo", + "Clone": "https://bitbucket.org/automationtestharness/testrepo", + "CloneSSH": "", + "Branch": "main", + "Private": true + }, + "Commit": { + "Sha": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "Message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "Author": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Committer": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Link": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "Execution": { + "Number": 4, + "Status": "running", + "Created": "2025-03-24T08:48:56.572438+00:00", + "URL": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4" + }, + "Sender": { + "Login": "automationtestharness", + "Name": "Automationtestharness", + "Email": "", + "Avatar": "https://bitbucket.org/account/automationtestharness/avatar/", + "ID": "{612f7b18-b167-4bff-8ee9-d43570117ff1}" + } +} diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json new file mode 100644 index 000000000..10655dd05 --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json @@ -0,0 +1,175 @@ +{ + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "scm": "git", + "website": null, + "owner": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "workspace": { + "type": "workspace", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "name": "Automationtestharness", + "slug": "automationtestharness", + "links": { + "avatar": { + "href": "https://bitbucket.org/workspaces/automationtestharness/avatar/?ts=1740994558" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness" + } + } + }, + "is_private": true, + "project": { + "type": "project", + "key": "TEST", + "uuid": "{af6d7f47-6ce6-48b6-9beb-d5ad6b674ba0}", + "name": "test", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/automationtestharness/projects/TEST" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST" + }, + "avatar": { + "href": "https://bitbucket.org/automationtestharness/workspace/projects/TEST/avatar/32?ts=1738907820" + } + } + }, + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "parent": null + }, + "actor": { + "display_name": "Automationtestharness", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D" + }, + "avatar": { + "href": "https://bitbucket.org/account/automationtestharness/avatar/" + }, + "html": { + "href": "https://bitbucket.org/%7B612f7b18-b167-4bff-8ee9-d43570117ff1%7D/" + } + }, + "type": "team", + "uuid": "{612f7b18-b167-4bff-8ee9-d43570117ff1}", + "username": "automationtestharness" + }, + "commit_status": { + "key": "3343801", + "type": "build", + "state": "SUCCESSFUL", + "name": "Pipeline #4 for main", + "refname": "main", + "commit": { + "type": "commit", + "hash": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "date": "2025-03-24T08:48:15+00:00", + "author": { + "type": "author", + "raw": "Shivam Negi ", + "user": { + "display_name": "Shivam Negi", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "html": { + "href": "https://bitbucket.org/%7Bce7d5dfc-83c9-4878-beaf-7b91610e104a%7D/" + } + }, + "type": "user", + "uuid": "{ce7d5dfc-83c9-4878-beaf-7b91610e104a}", + "account_id": "601ba1bdb7bda90068ed5d1b", + "nickname": "Shivam Negi" + } + }, + "message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "diff": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/diff/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "approve": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/approve" + }, + "comments": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/comments" + }, + "statuses": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses" + } + } + }, + "url": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4", + "repository": { + "type": "repository", + "full_name": "automationtestharness/testrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo" + }, + "html": { + "href": "https://bitbucket.org/automationtestharness/testrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B2b922c6d-3824-4e91-a7be-90c8b8392f84%7D?ts=default" + } + }, + "name": "testRepo", + "uuid": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}" + }, + "description": "", + "created_on": "2025-03-24T08:48:56.572438+00:00", + "updated_on": "2025-03-24T08:49:42.838984+00:00", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9/statuses/build/3343801" + }, + "commit": { + "href": "https://api.bitbucket.org/2.0/repositories/automationtestharness/testrepo/commit/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + } + } + } + } \ No newline at end of file diff --git a/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json.golden b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json.golden new file mode 100644 index 000000000..1b0b7623f --- /dev/null +++ b/scm/driver/bitbucket/testdata/webhooks/pipeline_hook_update.json.golden @@ -0,0 +1,39 @@ +{ + "Repo": { + "ID": "{2b922c6d-3824-4e91-a7be-90c8b8392f84}", + "Namespace": "automationtestharness", + "Name": "testrepo", + "Clone": "https://bitbucket.org/automationtestharness/testrepo", + "CloneSSH": "", + "Branch": "main", + "Private": true + }, + "Commit": { + "Sha": "bdf6fac0519ffd1562461eb82e018ff62efffbc9", + "Message": "Merged in Shivam-Negi/testyaml-edited-online-with-bitbucket-1742806076994 (pull request #13)\n\ntest.yaml edited online with Bitbucket\n", + "Author": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Committer": { + "Name": "Shivam Negi", + "Email": "shivamnegi94@gmail.com", + "Avatar": "https://secure.gravatar.com/avatar/39b64ab2df0f61fcce00db05f94c600b?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FSN-2.png" + }, + "Link": "https://bitbucket.org/automationtestharness/testrepo/commits/bdf6fac0519ffd1562461eb82e018ff62efffbc9" + }, + "Execution": { + "Number": 4, + "Status": "success", + "Created": "2025-03-24T08:48:56.572438+00:00", + "URL": "https://bitbucket.org/automationtestharness/testrepo/addon/pipelines/home#!/results/4" + }, + "Sender": { + "Login": "automationtestharness", + "Name": "Automationtestharness", + "Email": "", + "Avatar": "https://bitbucket.org/account/automationtestharness/avatar/", + "ID": "{612f7b18-b167-4bff-8ee9-d43570117ff1}" + } +} diff --git a/scm/driver/bitbucket/webhook.go b/scm/driver/bitbucket/webhook.go index d254bba54..3b1836220 100644 --- a/scm/driver/bitbucket/webhook.go +++ b/scm/driver/bitbucket/webhook.go @@ -11,6 +11,8 @@ import ( "io" "io/ioutil" "net/http" + "regexp" + "strconv" "time" "github.com/drone/go-scm/scm" @@ -70,6 +72,8 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo if hook != nil { hook.(*scm.IssueCommentHook).Action = scm.ActionDelete } + case "repo:commit_status_updated", "repo:commit_status_created": + hook, err = s.parsePipelineHook(data) } if err != nil { return nil, err @@ -138,6 +142,15 @@ func (s *webhookService) parsePullRequestHook(data []byte) (*scm.PullRequestHook } } +func (s *webhookService) parsePipelineHook(data []byte) (*scm.PipelineHook, error) { + dst := new(pipelineHook) + err := json.Unmarshal(data, dst) + if err != nil { + return nil, err + } + return convertBitbucketHook(dst), err +} + // // native data structures // @@ -598,6 +611,84 @@ type ( Repository prCommentHookRepo `json:"repository"` Actor prCommentHookUser `json:"actor"` } + + pipelineHook struct { + Repository webhookRepository `json:"repository"` + Actor actor `json:"actor"` + CommitStatus struct { + Key string `json:"key"` + Type string `json:"type"` + State string `json:"state"` + Name string `json:"name"` + RefName string `json:"refname"` + Commit struct { + Type string `json:"type"` + Hash string `json:"hash"` + Date time.Time `json:"date"` + Author author `json:"author"` + Message string `json:"message"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + } `json:"commit"` + URL string `json:"url"` + Repository info `json:"repository"` + Description string `json:"description"` + CreatedOn time.Time `json:"created_on"` + UpdatedOn time.Time `json:"updated_on"` + Links struct { + Self href `json:"self"` + Commit href `json:"commit"` + } `json:"links"` + } `json:"commit_status"` + } + + href struct { + Href string `json:"href"` + } + + actor struct { + DisplayName string `json:"display_name"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + UUID string `json:"uuid"` + Username string `json:"username"` + } + + author struct { + Type string `json:"type"` + Raw string `json:"raw"` + User struct { + DisplayName string `json:"display_name"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + Type string `json:"type"` + UUID string `json:"uuid"` + AccountID string `json:"account_id"` + Nickname string `json:"nickname"` + } `json:"user"` + } + + info struct { + Type string `json:"type"` + FullName string `json:"full_name"` + Links struct { + Self href `json:"self"` + HTML href `json:"html"` + Avatar href `json:"avatar"` + } `json:"links"` + Name string `json:"name"` + UUID string `json:"uuid"` + } ) // @@ -902,3 +993,61 @@ func convertPrCommentHook(src *prCommentHook) *scm.IssueCommentHook { } return &dst } + +func convertBitbucketHook(src *pipelineHook) *scm.PipelineHook { + if src.CommitStatus.Type == "" || src.CommitStatus.Type != "build" { + return nil + } + namespace, name := scm.Split(src.Repository.FullName) + + return &scm.PipelineHook{ + Repo: scm.Repository{ + ID: src.Repository.UUID, + Namespace: namespace, + Name: name, + Clone: src.Repository.Links.HTML.Href, // Assuming HTML link as Clone URL + Branch: src.CommitStatus.RefName, + Private: src.Repository.IsPrivate, + }, + Commit: scm.Commit{ + Sha: src.CommitStatus.Commit.Hash, + Message: src.CommitStatus.Commit.Message, + Author: scm.Signature{ + Name: src.CommitStatus.Commit.Author.User.DisplayName, + Email: extractEmail(src.CommitStatus.Commit.Author.Raw), + Avatar: src.CommitStatus.Commit.Author.User.Links.Avatar.Href, + }, + Committer: scm.Signature{ + Name: src.CommitStatus.Commit.Author.User.DisplayName, + Email: extractEmail(src.CommitStatus.Commit.Author.Raw), + Avatar: src.CommitStatus.Commit.Author.User.Links.Avatar.Href, + }, + Link: src.CommitStatus.Commit.Links.HTML.Href, + }, + Execution: scm.Execution{ + Number: extractExecutionId(src.CommitStatus.URL), + Status: scm.ConvertExecutionStatus(src.CommitStatus.State), + Created: src.CommitStatus.CreatedOn, + URL: src.CommitStatus.URL, + }, + Sender: scm.User{ + Login: src.Actor.Username, + Name: src.Actor.DisplayName, + Avatar: src.Actor.Links.Avatar.Href, + ID: src.Actor.UUID, + }, + PullRequest: scm.PullRequest{}, + } +} + +func extractExecutionId(url string) int { + re := regexp.MustCompile(`/results/(\d+)`) + match := re.FindStringSubmatch(url) + if len(match) > 1 { + id, err := strconv.Atoi(match[1]) + if err == nil { + return id + } + } + return -1 +} diff --git a/scm/driver/bitbucket/webhook_test.go b/scm/driver/bitbucket/webhook_test.go index e72e096ff..71f2b7e89 100644 --- a/scm/driver/bitbucket/webhook_test.go +++ b/scm/driver/bitbucket/webhook_test.go @@ -146,6 +146,20 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/pr_comment_deleted.json.golden", obj: new(scm.IssueCommentHook), }, + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "repo:commit_status_created", + before: "testdata/webhooks/pipeline_hook_created.json", + after: "testdata/webhooks/pipeline_hook_created.json.golden", + obj: new(scm.PipelineHook), + }, + { + sig: "71295b197fa25f4356d2fb9965df3f2379d903d7", + event: "repo:commit_status_updated", + before: "testdata/webhooks/pipeline_hook_update.json", + after: "testdata/webhooks/pipeline_hook_update.json.golden", + obj: new(scm.PipelineHook), + }, } for _, test := range tests { diff --git a/scm/driver/github/testdata/webhooks/pipeline_hook.json b/scm/driver/github/testdata/webhooks/pipeline_hook.json new file mode 100644 index 000000000..3a7fd0c92 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/pipeline_hook.json @@ -0,0 +1,389 @@ +{ + "action": "in_progress", + "workflow_run": { + "id": 14030131450, + "name": "CI", + "node_id": "WFR_kwLOE_pLVc8AAAADRELQ-g", + "head_branch": "shivamnegi94-patch-27", + "head_sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "path": ".github/workflows/blank.yml", + "display_title": "Update NewSre_v1.yaml", + "run_number": 2, + "event": "pull_request", + "status": "completed", + "conclusion": "success", + "workflow_id": 151617408, + "check_suite_id": 36111489428, + "check_suite_node_id": "CS_kwDOE_pLVc8AAAAIaGmZlA", + "url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450", + "html_url": "https://github.com/shivamnegi94/testrepo/actions/runs/14030131450", + "pull_requests": [ + { + "url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls/164", + "id": 2412967773, + "number": 164, + "head": { + "ref": "shivamnegi94-patch-27", + "sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "repo": { + "id": 335170389, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "name": "testrepo" + } + }, + "base": { + "ref": "main", + "sha": "ded75dda298abfbf9f1900092e92b43f23bdd6d2", + "repo": { + "id": 335170389, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "name": "testrepo" + } + } + } + ], + "created_at": "2025-03-24T08:03:42Z", + "updated_at": "2025-03-24T08:03:46Z", + "actor": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "run_attempt": 1, + "referenced_workflows": [ + + ], + "run_started_at": "2025-03-24T08:03:42Z", + "triggering_actor": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "jobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/jobs", + "logs_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/logs", + "check_suite_url": "https://api.github.com/repos/shivamnegi94/testrepo/check-suites/36111489428", + "artifacts_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/artifacts", + "cancel_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/cancel", + "rerun_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450/rerun", + "previous_attempt_url": null, + "workflow_url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/workflows/151617408", + "head_commit": { + "id": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "tree_id": "36698bb567243f3d104f398e3b6e1a339570d3dc", + "message": "Update NewSre_v1.yaml", + "timestamp": "2025-03-24T08:03:33Z", + "author": { + "name": "Shivam Negi", + "email": "shivam.negi@harness.io" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com" + } + }, + "repository": { + "id": 335170389, + "node_id": "MDEwOlJlcG9zaXRvcnkzMzUxNzAzODk=", + "name": "testrepo", + "full_name": "shivamnegi94/testrepo", + "private": false, + "owner": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/shivamnegi94/testrepo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "forks_url": "https://api.github.com/repos/shivamnegi94/testrepo/forks", + "keys_url": "https://api.github.com/repos/shivamnegi94/testrepo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/shivamnegi94/testrepo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/shivamnegi94/testrepo/teams", + "hooks_url": "https://api.github.com/repos/shivamnegi94/testrepo/hooks", + "issue_events_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/events{/number}", + "events_url": "https://api.github.com/repos/shivamnegi94/testrepo/events", + "assignees_url": "https://api.github.com/repos/shivamnegi94/testrepo/assignees{/user}", + "branches_url": "https://api.github.com/repos/shivamnegi94/testrepo/branches{/branch}", + "tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/tags", + "blobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/shivamnegi94/testrepo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/shivamnegi94/testrepo/languages", + "stargazers_url": "https://api.github.com/repos/shivamnegi94/testrepo/stargazers", + "contributors_url": "https://api.github.com/repos/shivamnegi94/testrepo/contributors", + "subscribers_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscribers", + "subscription_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscription", + "commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/shivamnegi94/testrepo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/shivamnegi94/testrepo/contents/{+path}", + "compare_url": "https://api.github.com/repos/shivamnegi94/testrepo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/shivamnegi94/testrepo/merges", + "archive_url": "https://api.github.com/repos/shivamnegi94/testrepo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/shivamnegi94/testrepo/downloads", + "issues_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues{/number}", + "pulls_url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/shivamnegi94/testrepo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/shivamnegi94/testrepo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/shivamnegi94/testrepo/labels{/name}", + "releases_url": "https://api.github.com/repos/shivamnegi94/testrepo/releases{/id}", + "deployments_url": "https://api.github.com/repos/shivamnegi94/testrepo/deployments" + }, + "head_repository": { + "id": 335170389, + "node_id": "MDEwOlJlcG9zaXRvcnkzMzUxNzAzODk=", + "name": "testrepo", + "full_name": "shivamnegi94/testrepo", + "private": false, + "owner": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/shivamnegi94/testrepo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "forks_url": "https://api.github.com/repos/shivamnegi94/testrepo/forks", + "keys_url": "https://api.github.com/repos/shivamnegi94/testrepo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/shivamnegi94/testrepo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/shivamnegi94/testrepo/teams", + "hooks_url": "https://api.github.com/repos/shivamnegi94/testrepo/hooks", + "issue_events_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/events{/number}", + "events_url": "https://api.github.com/repos/shivamnegi94/testrepo/events", + "assignees_url": "https://api.github.com/repos/shivamnegi94/testrepo/assignees{/user}", + "branches_url": "https://api.github.com/repos/shivamnegi94/testrepo/branches{/branch}", + "tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/tags", + "blobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/shivamnegi94/testrepo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/shivamnegi94/testrepo/languages", + "stargazers_url": "https://api.github.com/repos/shivamnegi94/testrepo/stargazers", + "contributors_url": "https://api.github.com/repos/shivamnegi94/testrepo/contributors", + "subscribers_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscribers", + "subscription_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscription", + "commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/shivamnegi94/testrepo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/shivamnegi94/testrepo/contents/{+path}", + "compare_url": "https://api.github.com/repos/shivamnegi94/testrepo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/shivamnegi94/testrepo/merges", + "archive_url": "https://api.github.com/repos/shivamnegi94/testrepo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/shivamnegi94/testrepo/downloads", + "issues_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues{/number}", + "pulls_url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/shivamnegi94/testrepo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/shivamnegi94/testrepo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/shivamnegi94/testrepo/labels{/name}", + "releases_url": "https://api.github.com/repos/shivamnegi94/testrepo/releases{/id}", + "deployments_url": "https://api.github.com/repos/shivamnegi94/testrepo/deployments" + } + }, + "workflow": { + "id": 151617408, + "node_id": "W_kwDOE_pLVc4JCX-A", + "name": "CI", + "path": ".github/workflows/blank.yml", + "state": "active", + "created_at": "2025-03-24T08:01:34.000Z", + "updated_at": "2025-03-24T08:01:34.000Z", + "url": "https://api.github.com/repos/shivamnegi94/testrepo/actions/workflows/151617408", + "html_url": "https://github.com/shivamnegi94/testrepo/blob/main/.github/workflows/blank.yml", + "badge_url": "https://github.com/shivamnegi94/testrepo/workflows/CI/badge.svg" + }, + "repository": { + "id": 335170389, + "node_id": "MDEwOlJlcG9zaXRvcnkzMzUxNzAzODk=", + "name": "testrepo", + "full_name": "shivamnegi94/testrepo", + "private": false, + "owner": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/shivamnegi94/testrepo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/shivamnegi94/testrepo", + "forks_url": "https://api.github.com/repos/shivamnegi94/testrepo/forks", + "keys_url": "https://api.github.com/repos/shivamnegi94/testrepo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/shivamnegi94/testrepo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/shivamnegi94/testrepo/teams", + "hooks_url": "https://api.github.com/repos/shivamnegi94/testrepo/hooks", + "issue_events_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/events{/number}", + "events_url": "https://api.github.com/repos/shivamnegi94/testrepo/events", + "assignees_url": "https://api.github.com/repos/shivamnegi94/testrepo/assignees{/user}", + "branches_url": "https://api.github.com/repos/shivamnegi94/testrepo/branches{/branch}", + "tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/tags", + "blobs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/shivamnegi94/testrepo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/shivamnegi94/testrepo/languages", + "stargazers_url": "https://api.github.com/repos/shivamnegi94/testrepo/stargazers", + "contributors_url": "https://api.github.com/repos/shivamnegi94/testrepo/contributors", + "subscribers_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscribers", + "subscription_url": "https://api.github.com/repos/shivamnegi94/testrepo/subscription", + "commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/shivamnegi94/testrepo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/shivamnegi94/testrepo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/shivamnegi94/testrepo/contents/{+path}", + "compare_url": "https://api.github.com/repos/shivamnegi94/testrepo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/shivamnegi94/testrepo/merges", + "archive_url": "https://api.github.com/repos/shivamnegi94/testrepo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/shivamnegi94/testrepo/downloads", + "issues_url": "https://api.github.com/repos/shivamnegi94/testrepo/issues{/number}", + "pulls_url": "https://api.github.com/repos/shivamnegi94/testrepo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/shivamnegi94/testrepo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/shivamnegi94/testrepo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/shivamnegi94/testrepo/labels{/name}", + "releases_url": "https://api.github.com/repos/shivamnegi94/testrepo/releases{/id}", + "deployments_url": "https://api.github.com/repos/shivamnegi94/testrepo/deployments", + "created_at": "2021-02-02T04:41:22Z", + "updated_at": "2025-03-24T08:01:37Z", + "pushed_at": "2025-03-24T08:03:33Z", + "git_url": "git://github.com/shivamnegi94/testrepo.git", + "ssh_url": "git@github.com:shivamnegi94/testrepo.git", + "clone_url": "https://github.com/shivamnegi94/testrepo.git", + "svn_url": "https://github.com/shivamnegi94/testrepo", + "homepage": null, + "size": 209, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 56, + "license": null, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "public", + "forks": 0, + "open_issues": 56, + "watchers": 0, + "default_branch": "main" + }, + "sender": { + "login": "shivamnegi94", + "id": 58415634, + "node_id": "MDQ6VXNlcjU4NDE1NjM0", + "avatar_url": "https://avatars.githubusercontent.com/u/58415634?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/shivamnegi94", + "html_url": "https://github.com/shivamnegi94", + "followers_url": "https://api.github.com/users/shivamnegi94/followers", + "following_url": "https://api.github.com/users/shivamnegi94/following{/other_user}", + "gists_url": "https://api.github.com/users/shivamnegi94/gists{/gist_id}", + "starred_url": "https://api.github.com/users/shivamnegi94/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/shivamnegi94/subscriptions", + "organizations_url": "https://api.github.com/users/shivamnegi94/orgs", + "repos_url": "https://api.github.com/users/shivamnegi94/repos", + "events_url": "https://api.github.com/users/shivamnegi94/events{/privacy}", + "received_events_url": "https://api.github.com/users/shivamnegi94/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + } +} \ No newline at end of file diff --git a/scm/driver/github/testdata/webhooks/pipeline_hook.json.golden b/scm/driver/github/testdata/webhooks/pipeline_hook.json.golden new file mode 100644 index 000000000..b56869de0 --- /dev/null +++ b/scm/driver/github/testdata/webhooks/pipeline_hook.json.golden @@ -0,0 +1,50 @@ +{ + "Repo": { + "ID": "335170389", + "Namespace": "shivamnegi94", + "Name": "testrepo", + "Clone": "https://github.com/shivamnegi94/testrepo.git", + "CloneSSH": "git@github.com:shivamnegi94/testrepo.git", + "Link": "https://github.com/shivamnegi94/testrepo", + "Branch": "main", + "Created": "2021-02-02T04:41:22Z", + "Updated": "2025-03-24T08:01:37Z", + "Private": false, + "Visibility": 1, + "Perm": {} + }, + "Commit": { + "Sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "Message": "Update NewSre_v1.yaml", + "Author": { + "Name": "Shivam Negi", + "Email": "shivam.negi@harness.io" + }, + "Committer": { + "Name": "GitHub", + "Email": "noreply@github.com" + } + }, + "Execution": { + "Number": 2, + "Status": "success", + "Created": "2025-03-24T08:03:42Z", + "URL": "https://api.github.com/repos/shivamnegi94/testrepo/actions/runs/14030131450" + }, + "Sender": { + "Login": "shivamnegi94", + "Avatar": "https://avatars.githubusercontent.com/u/58415634?v=4" + }, + "PullRequest": { + "Number": 164, + "Sha": "f4229db4b70a8dadeb687f5ccce5fd327c04461a", + "Ref": "shivamnegi94-patch-27", + "Source": "shivamnegi94-patch-27", + "Target": "main", + "Link": "https://api.github.com/repos/shivamnegi94/testrepo/pulls/164", + "Created": "2025-03-24T08:03:42Z", + "Draft": false, + "Closed": false, + "Merged": false + } +} diff --git a/scm/driver/github/webhook.go b/scm/driver/github/webhook.go index 2fbdae938..8f0b3571a 100644 --- a/scm/driver/github/webhook.go +++ b/scm/driver/github/webhook.go @@ -48,6 +48,8 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo hook, err = s.parseIssueCommentHook(data) case "release": hook, err = s.parseReleaseHook(data) + case "workflow_run": + hook, err = s.parsePipelineHook(data) default: return nil, scm.ErrUnknownEvent } @@ -182,6 +184,62 @@ func (s *webhookService) parsePullRequestHook(data []byte) (scm.Webhook, error) return dst, nil } +func (s *webhookService) parsePipelineHook(data []byte) (scm.Webhook, error) { + src := new(pipelineHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst, err := convertPipelineHook(src), nil + return dst, nil +} + +func convertPipelineHook(src *pipelineHook) *scm.PipelineHook { + pr := scm.PullRequest{} + if len(src.WorkflowRun.PullRequests) > 0 { + pr = scm.PullRequest{ + Number: src.WorkflowRun.PullRequests[0].Number, + Sha: src.WorkflowRun.PullRequests[0].Head.SHA, + Ref: src.WorkflowRun.PullRequests[0].Head.Ref, + Source: src.WorkflowRun.PullRequests[0].Head.Ref, + Target: src.WorkflowRun.PullRequests[0].Base.Ref, + Link: src.WorkflowRun.PullRequests[0].URL, + Created: src.WorkflowRun.CreatedAt, + } + } + + var execution_status string + if src.WorkflowRun.Status == "completed" { + execution_status = src.WorkflowRun.Conclusion.String + } else { + execution_status = src.WorkflowRun.Status + } + + return &scm.PipelineHook{ + Repo: *convertRepository(&src.Repository), + Commit: scm.Commit{ + Sha: src.WorkflowRun.HeadCommit.ID, + Message: src.WorkflowRun.HeadCommit.Message, + Author: scm.Signature{ + Name: src.WorkflowRun.HeadCommit.Author.Name, + Email: src.WorkflowRun.HeadCommit.Author.Email, + }, + Committer: scm.Signature{ + Name: src.WorkflowRun.HeadCommit.Committer.Name, + Email: src.WorkflowRun.HeadCommit.Committer.Email, + }, + }, + Execution: scm.Execution{ + Number: int(src.WorkflowRun.RunNumber), + Status: scm.ConvertExecutionStatus(execution_status), + Created: src.WorkflowRun.CreatedAt, + URL: src.WorkflowRun.URL, + }, + Sender: *convertUser(&src.Sender), + PullRequest: pr, + } +} + func (s *webhookService) parseReleaseHook(data []byte) (scm.Webhook, error) { src := new(releaseHook) err := json.Unmarshal(data, src) @@ -352,6 +410,80 @@ type ( Repository repository `json:"repository"` Sender user `json:"sender"` } + + pipelineHook struct { + Action string `json:"action"` + Sender user + WorkflowRun struct { + ID int64 `json:"id"` + Name string `json:"name"` + NodeID string `json:"node_id"` + HeadBranch string `json:"head_branch"` + HeadSHA string `json:"head_sha"` + Path string `json:"path"` + DisplayTitle string `json:"display_title"` + RunNumber int `json:"run_number"` + Event string `json:"event"` + Status string `json:"status"` + Conclusion null.String `json:"conclusion"` + WorkflowID int64 `json:"workflow_id"` + CheckSuiteID int64 `json:"check_suite_id"` + CheckSuiteNodeID string `json:"check_suite_node_id"` + URL string `json:"url"` + HtmlURL string `json:"html_url"` + PullRequests []struct { + URL string `json:"url"` + ID int64 `json:"id"` + Number int `json:"number"` + Head gitRef `json:"head"` + Base gitRef `json:"base"` + } `json:"pull_requests"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Actor owner `json:"actor"` + RunAttempt int `json:"run_attempt"` + RunStartedAt time.Time `json:"run_started_at"` + TriggeringActor owner `json:"triggering_actor"` + JobsURL string `json:"jobs_url"` + LogsURL string `json:"logs_url"` + CheckSuiteURL string `json:"check_suite_url"` + ArtifactsURL string `json:"artifacts_url"` + CancelURL string `json:"cancel_url"` + RerunURL string `json:"rerun_url"` + PreviousAttemptURL null.String `json:"previous_attempt_url"` + WorkflowURL string `json:"workflow_url"` + HeadCommit struct { + ID string `json:"id"` + TreeID string `json:"tree_id"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` + Author author `json:"author"` + Committer author `json:"committer"` + } `json:"head_commit"` + } `json:"workflow_run"` + Repository repository `json:"repository"` + } + + gitRef struct { + Ref string `json:"ref"` + SHA string `json:"sha"` + Repo repository `json:"repo"` + } + + owner struct { + Login string `json:"login"` + ID int64 `json:"id"` + NodeID string `json:"node_id"` + AvatarURL string `json:"avatar_url"` + HTMLURL string `json:"html_url"` + Type string `json:"type"` + SiteAdmin bool `json:"site_admin"` + } + + author struct { + Name string `json:"name"` + Email string `json:"email"` + } ) // diff --git a/scm/driver/github/webhook_test.go b/scm/driver/github/webhook_test.go index f7c63c3fd..f30804fa3 100644 --- a/scm/driver/github/webhook_test.go +++ b/scm/driver/github/webhook_test.go @@ -25,9 +25,8 @@ func TestWebhooks(t *testing.T) { after string obj interface{} }{ - // // push events - // + // push hooks { event: "push", @@ -236,6 +235,12 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/release_released.json.golden", obj: new(scm.ReleaseHook), }, + { + event: "workflow_run", + before: "testdata/webhooks/pipeline_hook.json", + after: "testdata/webhooks/pipeline_hook.json.golden", + obj: new(scm.PipelineHook), + }, } for _, test := range tests { diff --git a/scm/driver/gitlab/repo.go b/scm/driver/gitlab/repo.go index 9a44bc3bc..7a041a8fb 100644 --- a/scm/driver/gitlab/repo.go +++ b/scm/driver/gitlab/repo.go @@ -151,6 +151,9 @@ func (s *repositoryService) CreateHook(ctx context.Context, repo string, input * if input.Events.Tag { params.Set("tag_push_events", "true") } + if input.Events.Pipeline { + params.Set("pipeline_events", "true") + } path := fmt.Sprintf("api/v4/projects/%s/hooks?%s", encode(repo), params.Encode()) out := new(hook) diff --git a/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json new file mode 100644 index 000000000..6deec0b0e --- /dev/null +++ b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json @@ -0,0 +1,115 @@ +{ + "object_kind": "pipeline", + "object_attributes":{ + "id": 31, + "iid": 3, + "name": "Pipeline for branch: master", + "ref": "master", + "tag": false, + "sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "before_sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "source": "merge_request_event", + "status": "success", + "stages":[ + "build", + "test", + "deploy" + ], + "created_at": "2016-08-12 15:23:28 UTC", + "finished_at": "2016-08-12 15:26:29 UTC", + "duration": 63, + "variables": [ + { + "key": "NESTOR_PROD_ENVIRONMENT", + "value": "us-west-1" + } + ], + "url": "http://example.com/gitlab-org/gitlab-test/-/pipelines/31" + }, + "merge_request": { + "id": 371997275, + "iid": 15, + "title": "Edit test.txt", + "source_branch": "shivamnegi94-main-patch-62619", + "source_project_id": 27743392, + "target_branch": "main", + "target_project_id": 27743392, + "state": "opened", + "merge_status": "can_be_merged", + "detailed_merge_status": "mergeable", + "url": "https://gitlab.com/shivamnegi94/test/-/merge_requests/15" + }, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "user_email@gitlab.com" + }, + "project":{ + "id": 1, + "name": "Gitlab Test", + "description": "Atque in sunt eos similique dolores voluptatem.", + "web_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test", + "avatar_url": null, + "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", + "git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", + "namespace": "Gitlab Org", + "visibility_level": 20, + "path_with_namespace": "gitlab-org/gitlab-test", + "default_branch": "master" + }, + "commit":{ + "id": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "message": "test\n", + "timestamp": "2016-08-12T17:23:21+02:00", + "url": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "author":{ + "name": "User", + "email": "user@gitlab.com" + } + }, + "source_pipeline":{ + "project":{ + "id": 41, + "web_url": "https://gitlab.example.com/gitlab-org/upstream-project", + "path_with_namespace": "gitlab-org/upstream-project" + }, + "pipeline_id": 30, + "job_id": 3401 + }, + "builds":[ + { + "id": 380, + "stage": "deploy", + "name": "production", + "status": "skipped", + "created_at": "2016-08-12 15:23:28 UTC", + "started_at": null, + "finished_at": null, + "duration": null, + "queued_duration": null, + "failure_reason": null, + "when": "manual", + "manual": true, + "allow_failure": false, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "admin@example.com" + }, + "runner": null, + "artifacts_file":{ + "filename": null, + "size": null + }, + "environment": { + "name": "production", + "action": "start", + "deployment_tier": "production" + } + } + ] +} \ No newline at end of file diff --git a/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json.golden b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json.golden new file mode 100644 index 000000000..8e70f4b6b --- /dev/null +++ b/scm/driver/gitlab/testdata/webhooks/pipeline_hook.json.golden @@ -0,0 +1,50 @@ +{ + "repo": { + "id": "1", + "namespace": "gitlab-org", + "name": "gitlab-test", + "clone": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", + "cloneSSH": "git@192.168.64.1:gitlab-org/gitlab-test.git", + "link": "http://192.168.64.1:3005/gitlab-org/gitlab-test", + "branch": "master", + "private": false + }, + "commit": { + "sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "message": "test\n", + "author": { + "name": "User", + "email": "user@gitlab.com" + }, + "committer": { + "name": "User", + "email": "user@gitlab.com" + }, + "link": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2" + }, + "Execution": { + "Number": 31, + "status": "success", + "Created": "2016-08-12T15:23:28Z", + "URL": "http://example.com/gitlab-org/gitlab-test/-/pipelines/31" + }, + "sender": { + "login": "root", + "name": "Administrator", + "email": "user_email@gitlab.com", + "avatar": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80&d=identicon" + }, + "PullRequest": { + "Number": 371997275, + "Title": "Edit test.txt", + "Sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "Ref": "master", + "Source": "shivamnegi94-main-patch-62619", + "Target": "main", + "Link": "https://gitlab.com/shivamnegi94/test/-/merge_requests/15", + "Created": "2016-08-12T15:23:28Z", + "Draft": false, + "Closed": false, + "Merged": false + } +} diff --git a/scm/driver/gitlab/webhook.go b/scm/driver/gitlab/webhook.go index c70569471..c76f33f79 100644 --- a/scm/driver/gitlab/webhook.go +++ b/scm/driver/gitlab/webhook.go @@ -41,6 +41,8 @@ func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhoo hook, err = parseIssueCommentHook(data) case "System Hook": hook, err = parseSystemHook(data) + case "Pipeline Hook": + return parsePipelineHook(data) default: return nil, scm.ErrUnknownEvent } @@ -98,6 +100,16 @@ func parseIssueCommentHook(data []byte) (scm.Webhook, error) { return dst, nil } +func parsePipelineHook(data []byte) (scm.Webhook, error) { + src := new(pipelineHook) + err := json.Unmarshal(data, src) + if err != nil { + return nil, err + } + dst, err := convertPipelineHook(src), nil + return dst, nil +} + func parsePushHook(data []byte) (scm.Webhook, error) { src := new(pushHook) err := json.Unmarshal(data, src) @@ -385,8 +397,6 @@ func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook { Draft: src.ObjectAttributes.WorkInProgress, Closed: src.ObjectAttributes.State != "opened", Merged: src.ObjectAttributes.State == "merged", - // Created : src.ObjectAttributes.CreatedAt, - // Updated : src.ObjectAttributes.UpdatedAt, // 2017-12-10 17:01:11 UTC Author: scm.User{ Login: src.User.Username, Name: src.User.Name, @@ -420,6 +430,57 @@ func parseTimeString(timeString string) time.Time { return t } +func convertPipelineHook(src *pipelineHook) *scm.PipelineHook { + namespace, name := scm.Split(src.Project.PathWithNamespace) + return &scm.PipelineHook{ + Repo: scm.Repository{ + ID: strconv.Itoa(src.Project.ID), + Namespace: namespace, + Name: name, + Clone: src.Project.GitHTTPURL, + CloneSSH: src.Project.GitSSHURL, + Link: src.Project.WebURL, + Branch: src.Project.DefaultBranch, + Private: false, + }, + Commit: scm.Commit{ + Sha: src.ObjectAttributes.SHA, + Message: src.Commit.Message, + Author: scm.Signature{ + Name: src.Commit.Author.Name, + Email: src.Commit.Author.Email, + }, + Committer: scm.Signature{ + Name: src.Commit.Author.Name, + Email: src.Commit.Author.Email, + }, + Link: src.Commit.URL, + }, + Execution: scm.Execution{ + Number: src.ObjectAttributes.ID, + Status: scm.ConvertExecutionStatus(src.ObjectAttributes.Status), + Created: parseTimeString(src.ObjectAttributes.CreatedAt), + URL: src.ObjectAttributes.URL, + }, + Sender: scm.User{ + Login: src.User.Username, + Name: src.User.Name, + Email: src.User.Email, + Avatar: src.User.AvatarURL, + }, + PullRequest: scm.PullRequest{ + Number: src.MergeRequest.ID, + Title: src.MergeRequest.Title, + Sha: src.ObjectAttributes.SHA, + Ref: src.ObjectAttributes.Ref, + Source: src.MergeRequest.SourceBranch, + Target: src.MergeRequest.TargetBranch, + Link: src.MergeRequest.URL, + Created: parseTimeString(src.ObjectAttributes.CreatedAt), + }, + } +} + type ( // Generic struct to detect event type event struct { @@ -904,4 +965,131 @@ type ( Homepage string `json:"homepage"` } `json:"repository"` } + + pipelineHook struct { + ObjectKind string `json:"object_kind"` + ObjectAttributes struct { + ID int `json:"id"` + IID int `json:"iid"` + Name string `json:"name"` + Ref string `json:"ref"` + Tag bool `json:"tag"` + SHA string `json:"sha"` + BeforeSHA string `json:"before_sha"` + Source string `json:"source"` + Status string `json:"status"` + Stages []string `json:"stages"` + CreatedAt string `json:"created_at"` + FinishedAt string `json:"finished_at"` + Duration int `json:"duration"` + Variables []variable `json:"variables"` + URL string `json:"url"` + } `json:"object_attributes"` + MergeRequest struct { + ID int `json:"id"` + IID int `json:"iid"` + Title string `json:"title"` + SourceBranch string `json:"source_branch"` + SourceProjectID int `json:"source_project_id"` + TargetBranch string `json:"target_branch"` + TargetProjectID int `json:"target_project_id"` + State string `json:"state"` + MergeStatus string `json:"merge_status"` + DetailedMergeStatus string `json:"detailed_merge_status"` + URL string `json:"url"` + } `json:"merge_request"` + User struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + Email string `json:"email"` + } `json:"user"` + Project struct { + ID int `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + WebURL string `json:"web_url"` + AvatarURL null.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"` + } `json:"project"` + Commit struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp string `json:"timestamp"` + URL string `json:"url"` + Author author `json:"author"` + } `json:"commit"` + SourcePipeline struct { + Project struct { + ID int `json:"id"` + WebURL string `json:"web_url"` + PathWithNamespace string `json:"path_with_namespace"` + } `json:"project"` + PipelineID int `json:"pipeline_id"` + JobID int `json:"job_id"` + } `json:"source_pipeline"` + Builds []build `json:"builds"` + } + + variable struct { + Key string `json:"key"` + Value string `json:"value"` + } + + author struct { + Name string `json:"name"` + Email string `json:"email"` + } + + build struct { + ID int `json:"id"` + Stage string `json:"stage"` + Name string `json:"name"` + Status string `json:"status"` + CreatedAt string `json:"created_at"` + StartedAt null.String `json:"started_at"` + FinishedAt null.String `json:"finished_at"` + Duration float64 `json:"duration"` + QueuedDuration float64 `json:"queued_duration"` + FailureReason null.String `json:"failure_reason"` + When string `json:"when"` + Manual bool `json:"manual"` + AllowFailure bool `json:"allow_failure"` + User struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + Email string `json:"email"` + } `json:"user"` + Runner runner `json:"runner"` + ArtifactsFile artifacts `json:"artifacts_file"` + Environment environment `json:"environment"` + } + + runner struct { + ID int `json:"id"` + Description string `json:"description"` + Active bool `json:"active"` + RunnerType string `json:"runner_type"` + IsShared bool `json:"is_shared"` + Tags []string `json:"tags"` + } + + artifacts struct { + Filename null.String `json:"filename"` + Size null.Int `json:"size"` + } + + environment struct { + Name string `json:"name"` + Action string `json:"action"` + DeploymentTier string `json:"deployment_tier"` + } ) diff --git a/scm/driver/gitlab/webhook_test.go b/scm/driver/gitlab/webhook_test.go index 16041c67d..e238a615c 100644 --- a/scm/driver/gitlab/webhook_test.go +++ b/scm/driver/gitlab/webhook_test.go @@ -189,6 +189,12 @@ func TestWebhooks(t *testing.T) { after: "testdata/webhooks/merge_request_comment_create.json.golden", obj: new(scm.IssueCommentHook), }, + { + event: "Pipeline Hook", + before: "testdata/webhooks/pipeline_hook.json", + after: "testdata/webhooks/pipeline_hook.json.golden", + obj: new(scm.PipelineHook), + }, } for _, test := range tests { diff --git a/scm/git.go b/scm/git.go index 5f0d9892a..afcc9e1e9 100644 --- a/scm/git.go +++ b/scm/git.go @@ -56,6 +56,15 @@ type ( Avatar string } + // Pipeline Execution details + Execution struct { + Number int + Status ExecutionStatus + Created time.Time + Updated time.Time + URL string + } + // GitService provides access to git resources. GitService interface { // CreateBranch creates a git branch by name given a sha. diff --git a/scm/repo.go b/scm/repo.go index 8ec383c37..5fe699427 100644 --- a/scm/repo.go +++ b/scm/repo.go @@ -65,6 +65,7 @@ type ( Deployment bool Issue bool IssueComment bool + Pipeline bool PullRequest bool PullRequestComment bool Push bool diff --git a/scm/util.go b/scm/util.go index 6aa496834..4e72f524f 100644 --- a/scm/util.go +++ b/scm/util.go @@ -103,6 +103,23 @@ func ConvertVisibility(from string) Visibility { } } +func ConvertExecutionStatus(from string) ExecutionStatus { + switch from { + case "running", "in_progress", "INPROGRESS": + return StatusRunning + case "success", "completed", "SUCCESSFUL": + return StatusSuccess + case "Failed", "failure", "FAILED": + return StatusFailed + case "Canceled", "cancelled", "STOPPED": + return StatusCanceled + case "pending", "queued": + return StatusPending + default: + return StatusUnknown + } +} + func ConvertPrivate(from string) bool { switch from { case "public", "": diff --git a/scm/webhook.go b/scm/webhook.go index f6875f6f2..ffe4791cd 100644 --- a/scm/webhook.go +++ b/scm/webhook.go @@ -37,6 +37,15 @@ type ( Commits []Commit } + // PipelineHook + PipelineHook struct { + Commit Commit + Execution Execution + PullRequest PullRequest + Repo Repository + Sender User + } + // BranchHook represents a branch or tag event, // eg create and delete github event types. BranchHook struct { @@ -150,3 +159,4 @@ func (h *PullRequestHook) Repository() Repository { return h.Repo } func (h *PullRequestCommentHook) Repository() Repository { return h.Repo } func (h *ReviewCommentHook) Repository() Repository { return h.Repo } func (h *ReleaseHook) Repository() Repository { return h.Repo } +func (h *PipelineHook) Repository() Repository { return h.Repo }