{"action":"created","comment":{"url":"https://api.github.com/repos/tsuru/tsuru/pulls/comments/186427610","pull_request_review_id":117996497,"id":186427610,"diff_hunk":"@@ -0,0 +1,259 @@\n+// Copyright 2018 tsuru authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n+package webhook\n+\n+import (\n+\t\"bytes\"\n+\t\"context\"\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"io/ioutil\"\n+\t\"net/http\"\n+\t\"net/url\"\n+\t\"strings\"\n+\t\"time\"\n+\n+\t\"github.com/pkg/errors\"\n+\t\"github.com/prometheus/client_golang/prometheus\"\n+\t\"github.com/tsuru/tsuru/api/shutdown\"\n+\ttsuruErrors \"github.com/tsuru/tsuru/errors\"\n+\t\"github.com/tsuru/tsuru/event\"\n+\t\"github.com/tsuru/tsuru/log\"\n+\ttsuruNet \"github.com/tsuru/tsuru/net\"\n+\t\"github.com/tsuru/tsuru/storage\"\n+\teventTypes \"github.com/tsuru/tsuru/types/event\"\n+\t\"github.com/tsuru/tsuru/validation\"\n+)\n+\n+var (\n+\t_ eventTypes.WebHookService = &webHookService{}\n+\n+\tchanBufferSize   = 1000\n+\tdefaultUserAgent = \"tsuru-webhook-client/1.0\"\n+\n+\twebhooksLatency = prometheus.NewHistogram(prometheus.HistogramOpts{\n+\t\tName: \"tsuru_webhooks_latency_seconds\",\n+\t\tHelp: \"The latency for webhooks requests in seconds\",\n+\t})\n+\n+\twebhooksQueue = prometheus.NewGauge(prometheus.GaugeOpts{\n+\t\tName: \"tsuru_webhooks_event_queue_current\",\n+\t\tHelp: \"The current number of queued events waiting for webhooks processing\",\n+\t})\n+\n+\twebhooksTotal = prometheus.NewCounter(prometheus.CounterOpts{\n+\t\tName: \"tsuru_webhooks_calls_total\",\n+\t\tHelp: \"The total number of webhooks calls\",\n+\t})\n+\n+\twebhooksError = prometheus.NewCounter(prometheus.CounterOpts{\n+\t\tName: \"tsuru_webhooks_calls_error\",\n+\t\tHelp: \"The total number of webhooks calls with error\",\n+\t})\n+)\n+\n+func init() {\n+\tprometheus.MustRegister(webhooksLatency, webhooksQueue, webhooksTotal, webhooksError)\n+}\n+\n+func WebHookService() (eventTypes.WebHookService, error) {\n+\tdbDriver, err := storage.GetCurrentDbDriver()\n+\tif err != nil {\n+\t\tdbDriver, err = storage.GetDefaultDbDriver()\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t}\n+\ts := &webHookService{\n+\t\tstorage: dbDriver.WebHookStorage,\n+\t\tevtCh:   make(chan string, chanBufferSize),\n+\t\tquitCh:  make(chan struct{}),\n+\t\tdoneCh:  make(chan struct{}),\n+\t}\n+\tgo s.run()\n+\tshutdown.Register(s)\n+\treturn s, nil\n+}\n+\n+type webHookService struct {\n+\tstorage eventTypes.WebHookStorage\n+\tevtCh   chan string\n+\tquitCh  chan struct{}\n+\tdoneCh  chan struct{}\n+}\n+\n+func (s *webHookService) Shutdown(ctx context.Context) error {\n+\tdoneCtx := ctx.Done()","path":"event/webhook/webhook.go","position":89,"original_position":89,"commit_id":"d1fc696a2946bac91d21818df536bc3f1b57536e","original_commit_id":"ca540d9e31345d82e315b526c8501c39b9e33578","user":{"login":"andrestc","id":2944739,"avatar_url":"https://avatars3.githubusercontent.com/u/2944739?v=4","gravatar_id":"","url":"https://api.github.com/users/andrestc","html_url":"https://github.com/andrestc","followers_url":"https://api.github.com/users/andrestc/followers","following_url":"https://api.github.com/users/andrestc/following{/other_user}","gists_url":"https://api.github.com/users/andrestc/gists{/gist_id}","starred_url":"https://api.github.com/users/andrestc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/andrestc/subscriptions","organizations_url":"https://api.github.com/users/andrestc/orgs","repos_url":"https://api.github.com/users/andrestc/repos","events_url":"https://api.github.com/users/andrestc/events{/privacy}","received_events_url":"https://api.github.com/users/andrestc/received_events","type":"User","site_admin":false},"body":"Just curious: any specific reason for this, instead of calling <-ctx.Done() from within the select statement?","created_at":"2018-05-07T13:48:01Z","updated_at":"2018-05-07T13:58:56Z","html_url":"https://github.com/tsuru/tsuru/pull/2018#discussion_r186427610","pull_request_url":"https://api.github.com/repos/tsuru/tsuru/pulls/2018","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/tsuru/tsuru/pulls/comments/186427610"},"html":{"href":"https://github.com/tsuru/tsuru/pull/2018#discussion_r186427610"},"pull_request":{"href":"https://api.github.com/repos/tsuru/tsuru/pulls/2018"}}},"pull_request":{"url":"https://api.github.com/repos/tsuru/tsuru/pulls/2018","id":183138492,"html_url":"https://github.com/tsuru/tsuru/pull/2018","diff_url":"https://github.com/tsuru/tsuru/pull/2018.diff","patch_url":"https://github.com/tsuru/tsuru/pull/2018.patch","issue_url":"https://api.github.com/repos/tsuru/tsuru/issues/2018","number":2018,"state":"open","locked":false,"title":"Add support for webhooks triggered on events","user":{"login":"cezarsa","id":11041,"avatar_url":"https://avatars1.githubusercontent.com/u/11041?v=4","gravatar_id":"","url":"https://api.github.com/users/cezarsa","html_url":"https://github.com/cezarsa","followers_url":"https://api.github.com/users/cezarsa/followers","following_url":"https://api.github.com/users/cezarsa/following{/other_user}","gists_url":"https://api.github.com/users/cezarsa/gists{/gist_id}","starred_url":"https://api.github.com/users/cezarsa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cezarsa/subscriptions","organizations_url":"https://api.github.com/users/cezarsa/orgs","repos_url":"https://api.github.com/users/cezarsa/repos","events_url":"https://api.github.com/users/cezarsa/events{/privacy}","received_events_url":"https://api.github.com/users/cezarsa/received_events","type":"User","site_admin":false},"body":"WebHooks can now be registered in the tsuru API to be triggered whenever an event matches the webhook specification.\r\n\r\nThe two main parts for this PR are:\r\n1 - Routes for WebHooks CRUD and corresponding service and storage methods.\r\n2 - Each time an event is finished (`evt.Done()` call), tsuru will send to event to a channel where a dedicated goroutine will pick the event and search for all webhooks matching it. After listing all webhooks that must be called tsuru will proceed to call them sequentially.\r\n\r\nBy default the webhook request is a POST containing in its body the event that triggered it serialized as JSON, but this behavior can be overridden by setting a custom method and body in the event.\r\n","created_at":"2018-04-20T18:32:59Z","updated_at":"2018-05-07T13:58:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ec590c2b5d8a1aefb28a6950d9c9da2d3a7b5469","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/tsuru/tsuru/pulls/2018/commits","review_comments_url":"https://api.github.com/repos/tsuru/tsuru/pulls/2018/comments","review_comment_url":"https://api.github.com/repos/tsuru/tsuru/pulls/comments{/number}","comments_url":"https://api.github.com/repos/tsuru/tsuru/issues/2018/comments","statuses_url":"https://api.github.com/repos/tsuru/tsuru/statuses/d1fc696a2946bac91d21818df536bc3f1b57536e","head":{"label":"cezarsa:webhooks","ref":"webhooks","sha":"d1fc696a2946bac91d21818df536bc3f1b57536e","user":{"login":"cezarsa","id":11041,"avatar_url":"https://avatars1.githubusercontent.com/u/11041?v=4","gravatar_id":"","url":"https://api.github.com/users/cezarsa","html_url":"https://github.com/cezarsa","followers_url":"https://api.github.com/users/cezarsa/followers","following_url":"https://api.github.com/users/cezarsa/following{/other_user}","gists_url":"https://api.github.com/users/cezarsa/gists{/gist_id}","starred_url":"https://api.github.com/users/cezarsa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cezarsa/subscriptions","organizations_url":"https://api.github.com/users/cezarsa/orgs","repos_url":"https://api.github.com/users/cezarsa/repos","events_url":"https://api.github.com/users/cezarsa/events{/privacy}","received_events_url":"https://api.github.com/users/cezarsa/received_events","type":"User","site_admin":false},"repo":{"id":12112183,"name":"tsuru","full_name":"cezarsa/tsuru","owner":{"login":"cezarsa","id":11041,"avatar_url":"https://avatars1.githubusercontent.com/u/11041?v=4","gravatar_id":"","url":"https://api.github.com/users/cezarsa","html_url":"https://github.com/cezarsa","followers_url":"https://api.github.com/users/cezarsa/followers","following_url":"https://api.github.com/users/cezarsa/following{/other_user}","gists_url":"https://api.github.com/users/cezarsa/gists{/gist_id}","starred_url":"https://api.github.com/users/cezarsa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cezarsa/subscriptions","organizations_url":"https://api.github.com/users/cezarsa/orgs","repos_url":"https://api.github.com/users/cezarsa/repos","events_url":"https://api.github.com/users/cezarsa/events{/privacy}","received_events_url":"https://api.github.com/users/cezarsa/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/cezarsa/tsuru","description":"Open source Platform as a Service.","fork":true,"url":"https://api.github.com/repos/cezarsa/tsuru","forks_url":"https://api.github.com/repos/cezarsa/tsuru/forks","keys_url":"https://api.github.com/repos/cezarsa/tsuru/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cezarsa/tsuru/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cezarsa/tsuru/teams","hooks_url":"https://api.github.com/repos/cezarsa/tsuru/hooks","issue_events_url":"https://api.github.com/repos/cezarsa/tsuru/issues/events{/number}","events_url":"https://api.github.com/repos/cezarsa/tsuru/events","assignees_url":"https://api.github.com/repos/cezarsa/tsuru/assignees{/user}","branches_url":"https://api.github.com/repos/cezarsa/tsuru/branches{/branch}","tags_url":"https://api.github.com/repos/cezarsa/tsuru/tags","blobs_url":"https://api.github.com/repos/cezarsa/tsuru/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cezarsa/tsuru/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cezarsa/tsuru/git/refs{/sha}","trees_url":"https://api.github.com/repos/cezarsa/tsuru/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cezarsa/tsuru/statuses/{sha}","languages_url":"https://api.github.com/repos/cezarsa/tsuru/languages","stargazers_url":"https://api.github.com/repos/cezarsa/tsuru/stargazers","contributors_url":"https://api.github.com/repos/cezarsa/tsuru/contributors","subscribers_url":"https://api.github.com/repos/cezarsa/tsuru/subscribers","subscription_url":"https://api.github.com/repos/cezarsa/tsuru/subscription","commits_url":"https://api.github.com/repos/cezarsa/tsuru/commits{/sha}","git_commits_url":"https://api.github.com/repos/cezarsa/tsuru/git/commits{/sha}","comments_url":"https://api.github.com/repos/cezarsa/tsuru/comments{/number}","issue_comment_url":"https://api.github.com/repos/cezarsa/tsuru/issues/comments{/number}","contents_url":"https://api.github.com/repos/cezarsa/tsuru/contents/{+path}","compare_url":"https://api.github.com/repos/cezarsa/tsuru/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cezarsa/tsuru/merges","archive_url":"https://api.github.com/repos/cezarsa/tsuru/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cezarsa/tsuru/downloads","issues_url":"https://api.github.com/repos/cezarsa/tsuru/issues{/number}","pulls_url":"https://api.github.com/repos/cezarsa/tsuru/pulls{/number}","milestones_url":"https://api.github.com/repos/cezarsa/tsuru/milestones{/number}","notifications_url":"https://api.github.com/repos/cezarsa/tsuru/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cezarsa/tsuru/labels{/name}","releases_url":"https://api.github.com/repos/cezarsa/tsuru/releases{/id}","deployments_url":"https://api.github.com/repos/cezarsa/tsuru/deployments","created_at":"2013-08-14T15:24:00Z","updated_at":"2015-01-08T16:08:55Z","pushed_at":"2018-05-07T13:58:32Z","git_url":"git://github.com/cezarsa/tsuru.git","ssh_url":"git@github.com:cezarsa/tsuru.git","clone_url":"https://github.com/cezarsa/tsuru.git","svn_url":"https://github.com/cezarsa/tsuru","homepage":"http://tsuru.io","size":56582,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause"},"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"tsuru:master","ref":"master","sha":"50afeecae9721eb8cb61b5a371c8b0311c621f69","user":{"login":"tsuru","id":6999787,"avatar_url":"https://avatars1.githubusercontent.com/u/6999787?v=4","gravatar_id":"","url":"https://api.github.com/users/tsuru","html_url":"https://github.com/tsuru","followers_url":"https://api.github.com/users/tsuru/followers","following_url":"https://api.github.com/users/tsuru/following{/other_user}","gists_url":"https://api.github.com/users/tsuru/gists{/gist_id}","starred_url":"https://api.github.com/users/tsuru/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tsuru/subscriptions","organizations_url":"https://api.github.com/users/tsuru/orgs","repos_url":"https://api.github.com/users/tsuru/repos","events_url":"https://api.github.com/users/tsuru/events{/privacy}","received_events_url":"https://api.github.com/users/tsuru/received_events","type":"Organization","site_admin":false},"repo":{"id":3631697,"name":"tsuru","full_name":"tsuru/tsuru","owner":{"login":"tsuru","id":6999787,"avatar_url":"https://avatars1.githubusercontent.com/u/6999787?v=4","gravatar_id":"","url":"https://api.github.com/users/tsuru","html_url":"https://github.com/tsuru","followers_url":"https://api.github.com/users/tsuru/followers","following_url":"https://api.github.com/users/tsuru/following{/other_user}","gists_url":"https://api.github.com/users/tsuru/gists{/gist_id}","starred_url":"https://api.github.com/users/tsuru/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tsuru/subscriptions","organizations_url":"https://api.github.com/users/tsuru/orgs","repos_url":"https://api.github.com/users/tsuru/repos","events_url":"https://api.github.com/users/tsuru/events{/privacy}","received_events_url":"https://api.github.com/users/tsuru/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/tsuru/tsuru","description":"Open source, extensible and Docker-based Platform as a Service (PaaS).","fork":false,"url":"https://api.github.com/repos/tsuru/tsuru","forks_url":"https://api.github.com/repos/tsuru/tsuru/forks","keys_url":"https://api.github.com/repos/tsuru/tsuru/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tsuru/tsuru/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tsuru/tsuru/teams","hooks_url":"https://api.github.com/repos/tsuru/tsuru/hooks","issue_events_url":"https://api.github.com/repos/tsuru/tsuru/issues/events{/number}","events_url":"https://api.github.com/repos/tsuru/tsuru/events","assignees_url":"https://api.github.com/repos/tsuru/tsuru/assignees{/user}","branches_url":"https://api.github.com/repos/tsuru/tsuru/branches{/branch}","tags_url":"https://api.github.com/repos/tsuru/tsuru/tags","blobs_url":"https://api.github.com/repos/tsuru/tsuru/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tsuru/tsuru/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tsuru/tsuru/git/refs{/sha}","trees_url":"https://api.github.com/repos/tsuru/tsuru/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tsuru/tsuru/statuses/{sha}","languages_url":"https://api.github.com/repos/tsuru/tsuru/languages","stargazers_url":"https://api.github.com/repos/tsuru/tsuru/stargazers","contributors_url":"https://api.github.com/repos/tsuru/tsuru/contributors","subscribers_url":"https://api.github.com/repos/tsuru/tsuru/subscribers","subscription_url":"https://api.github.com/repos/tsuru/tsuru/subscription","commits_url":"https://api.github.com/repos/tsuru/tsuru/commits{/sha}","git_commits_url":"https://api.github.com/repos/tsuru/tsuru/git/commits{/sha}","comments_url":"https://api.github.com/repos/tsuru/tsuru/comments{/number}","issue_comment_url":"https://api.github.com/repos/tsuru/tsuru/issues/comments{/number}","contents_url":"https://api.github.com/repos/tsuru/tsuru/contents/{+path}","compare_url":"https://api.github.com/repos/tsuru/tsuru/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tsuru/tsuru/merges","archive_url":"https://api.github.com/repos/tsuru/tsuru/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tsuru/tsuru/downloads","issues_url":"https://api.github.com/repos/tsuru/tsuru/issues{/number}","pulls_url":"https://api.github.com/repos/tsuru/tsuru/pulls{/number}","milestones_url":"https://api.github.com/repos/tsuru/tsuru/milestones{/number}","notifications_url":"https://api.github.com/repos/tsuru/tsuru/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tsuru/tsuru/labels{/name}","releases_url":"https://api.github.com/repos/tsuru/tsuru/releases{/id}","deployments_url":"https://api.github.com/repos/tsuru/tsuru/deployments","created_at":"2012-03-05T21:41:08Z","updated_at":"2018-05-07T13:41:57Z","pushed_at":"2018-05-07T13:58:34Z","git_url":"git://github.com/tsuru/tsuru.git","ssh_url":"git@github.com:tsuru/tsuru.git","clone_url":"https://github.com/tsuru/tsuru.git","svn_url":"https://github.com/tsuru/tsuru","homepage":"https://tsuru.io","size":56751,"stargazers_count":2756,"watchers_count":2756,"language":"Go","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":360,"mirror_url":null,"archived":false,"open_issues_count":174,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause"},"forks":360,"open_issues":174,"watchers":2756,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/tsuru/tsuru/pulls/2018"},"html":{"href":"https://github.com/tsuru/tsuru/pull/2018"},"issue":{"href":"https://api.github.com/repos/tsuru/tsuru/issues/2018"},"comments":{"href":"https://api.github.com/repos/tsuru/tsuru/issues/2018/comments"},"review_comments":{"href":"https://api.github.com/repos/tsuru/tsuru/pulls/2018/comments"},"review_comment":{"href":"https://api.github.com/repos/tsuru/tsuru/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/tsuru/tsuru/pulls/2018/commits"},"statuses":{"href":"https://api.github.com/repos/tsuru/tsuru/statuses/d1fc696a2946bac91d21818df536bc3f1b57536e"}},"author_association":"OWNER"}}
{"actor":{"display_login":"andrestc"}}