{"action":"created","comment":{"url":"https://api.github.com/repos/instacart/blazer/pulls/comments/120466306","pull_request_review_id":42431678,"id":120466306,"diff_hunk":"@@ -0,0 +1,49 @@\n+require 'xxhash'\n+require 'faraday'\n+module Blazer\n+  class Webhook < ActiveRecord::Base\n+    belongs_to :creator, Blazer::BELONGS_TO_OPTIONAL.merge(class_name: Blazer.user_class.to_s) if Blazer.user_class\n+    belongs_to :check\n+    has_many :events, dependent: :destroy,\n+      foreign_key: \"webhook_id\",\n+      class_name: \"Blazer::WebhookEvent\"\n+\n+    validates :check_id, presence: true\n+    validates :uri, presence: true\n+    serialize :states, Array\n+\n+    def execute(current_state: \"failing\", results_set: {})\n+      last_event = events.first()\n+      current_check_sum = XXhash.xxh64(JSON.dump(results_set)).to_s\n+      unless last_event.state == current_state && \n+             last_event.check_sum == current_check_sum\n+        dt = DateTime.now\n+        code = request(hook_params(current_state, results_set))\n+        new_event = Blazer::WebhookEvent.new webhook: self, run_at: dt,\n+          state: current_state, return_code: code, check_sum: current_check_sum\n+        new_event.save!\n+      end\n+    end\n+\n+    def hook_params(current_state, result_set)\n+      {\n+        state: current_state,\n+        result_set: result_set,\n+        check_id: check_id\n+      }\n+    end\n+\n+    def request(params = {})\n+      conn = Faraday.new(uri)\n+      resp = conn.post do |req|","path":"app/models/blazer/webhook.rb","position":43,"original_position":38,"commit_id":"986fcd15914b1449bcb3668668cdd2f3a6920db2","original_commit_id":"2b838d45dc9a12b4ebdc9b6b35a6d56e65fe6380","user":{"login":"viktor-evdokimov","id":579795,"avatar_url":"https://avatars0.githubusercontent.com/u/579795?v=3","gravatar_id":"","url":"https://api.github.com/users/viktor-evdokimov","html_url":"https://github.com/viktor-evdokimov","followers_url":"https://api.github.com/users/viktor-evdokimov/followers","following_url":"https://api.github.com/users/viktor-evdokimov/following{/other_user}","gists_url":"https://api.github.com/users/viktor-evdokimov/gists{/gist_id}","starred_url":"https://api.github.com/users/viktor-evdokimov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/viktor-evdokimov/subscriptions","organizations_url":"https://api.github.com/users/viktor-evdokimov/orgs","repos_url":"https://api.github.com/users/viktor-evdokimov/repos","events_url":"https://api.github.com/users/viktor-evdokimov/events{/privacy}","received_events_url":"https://api.github.com/users/viktor-evdokimov/received_events","type":"User","site_admin":false},"body":"added rescue around `request` call.","created_at":"2017-06-06T20:04:47Z","updated_at":"2017-06-06T20:04:47Z","html_url":"https://github.com/instacart/blazer/pull/10#discussion_r120466306","pull_request_url":"https://api.github.com/repos/instacart/blazer/pulls/10","_links":{"self":{"href":"https://api.github.com/repos/instacart/blazer/pulls/comments/120466306"},"html":{"href":"https://github.com/instacart/blazer/pull/10#discussion_r120466306"},"pull_request":{"href":"https://api.github.com/repos/instacart/blazer/pulls/10"}}},"pull_request":{"url":"https://api.github.com/repos/instacart/blazer/pulls/10","id":124247389,"html_url":"https://github.com/instacart/blazer/pull/10","diff_url":"https://github.com/instacart/blazer/pull/10.diff","patch_url":"https://github.com/instacart/blazer/pull/10.patch","issue_url":"https://api.github.com/repos/instacart/blazer/issues/10","number":10,"state":"open","locked":false,"title":"Blazer webhook support","user":{"login":"viktor-evdokimov","id":579795,"avatar_url":"https://avatars0.githubusercontent.com/u/579795?v=3","gravatar_id":"","url":"https://api.github.com/users/viktor-evdokimov","html_url":"https://github.com/viktor-evdokimov","followers_url":"https://api.github.com/users/viktor-evdokimov/followers","following_url":"https://api.github.com/users/viktor-evdokimov/following{/other_user}","gists_url":"https://api.github.com/users/viktor-evdokimov/gists{/gist_id}","starred_url":"https://api.github.com/users/viktor-evdokimov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/viktor-evdokimov/subscriptions","organizations_url":"https://api.github.com/users/viktor-evdokimov/orgs","repos_url":"https://api.github.com/users/viktor-evdokimov/repos","events_url":"https://api.github.com/users/viktor-evdokimov/events{/privacy}","received_events_url":"https://api.github.com/users/viktor-evdokimov/received_events","type":"User","site_admin":false},"body":"Add support for webhooks. Related PR to carrot:  https://github.com/instacart/carrot/pull/15553\r\n\r\n - Every time check is run I check if there are webhooks with current_state present in the webhook states.\r\n- If there is I trigger webhook.execute and pass current result set from the underlying query and status.\r\n- If last webhook_event entry has different status or same status and different check_sum of payload (result set) I POST to the url of the webhook and save new webhook_event entry\r\n- You can add/edit/delete webhooks and see log (see screenshot)\r\n![screen shot 2017-06-06 at 10 49 36 am](https://user-images.githubusercontent.com/579795/26843684-ee923e4e-4aa5-11e7-837c-605cdc5cbba9.png)\r\n\r\nTBD:  \r\n[] toggle webhook\r\n[] better UI for webhook_events ( paging etc)\r\n[] scheduled cleanup of old webhook_events \r\n[] encrypt authentication parameters and authentication header values at rest\r\n","created_at":"2017-06-06T17:36:48Z","updated_at":"2017-06-06T20:04:47Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2bd652922115897935a2608333f8efc21ec0a268","assignee":null,"assignees":[],"requested_reviewers":[{"login":"righi","id":219317,"avatar_url":"https://avatars1.githubusercontent.com/u/219317?v=3","gravatar_id":"","url":"https://api.github.com/users/righi","html_url":"https://github.com/righi","followers_url":"https://api.github.com/users/righi/followers","following_url":"https://api.github.com/users/righi/following{/other_user}","gists_url":"https://api.github.com/users/righi/gists{/gist_id}","starred_url":"https://api.github.com/users/righi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/righi/subscriptions","organizations_url":"https://api.github.com/users/righi/orgs","repos_url":"https://api.github.com/users/righi/repos","events_url":"https://api.github.com/users/righi/events{/privacy}","received_events_url":"https://api.github.com/users/righi/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/instacart/blazer/pulls/10/commits","review_comments_url":"https://api.github.com/repos/instacart/blazer/pulls/10/comments","review_comment_url":"https://api.github.com/repos/instacart/blazer/pulls/comments{/number}","comments_url":"https://api.github.com/repos/instacart/blazer/issues/10/comments","statuses_url":"https://api.github.com/repos/instacart/blazer/statuses/986fcd15914b1449bcb3668668cdd2f3a6920db2","head":{"label":"instacart:viktor-evdokimov/blazer-webhook-support","ref":"viktor-evdokimov/blazer-webhook-support","sha":"986fcd15914b1449bcb3668668cdd2f3a6920db2","user":{"login":"instacart","id":3732412,"avatar_url":"https://avatars2.githubusercontent.com/u/3732412?v=3","gravatar_id":"","url":"https://api.github.com/users/instacart","html_url":"https://github.com/instacart","followers_url":"https://api.github.com/users/instacart/followers","following_url":"https://api.github.com/users/instacart/following{/other_user}","gists_url":"https://api.github.com/users/instacart/gists{/gist_id}","starred_url":"https://api.github.com/users/instacart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/instacart/subscriptions","organizations_url":"https://api.github.com/users/instacart/orgs","repos_url":"https://api.github.com/users/instacart/repos","events_url":"https://api.github.com/users/instacart/events{/privacy}","received_events_url":"https://api.github.com/users/instacart/received_events","type":"Organization","site_admin":false},"repo":{"id":49169747,"name":"blazer","full_name":"instacart/blazer","owner":{"login":"instacart","id":3732412,"avatar_url":"https://avatars2.githubusercontent.com/u/3732412?v=3","gravatar_id":"","url":"https://api.github.com/users/instacart","html_url":"https://github.com/instacart","followers_url":"https://api.github.com/users/instacart/followers","following_url":"https://api.github.com/users/instacart/following{/other_user}","gists_url":"https://api.github.com/users/instacart/gists{/gist_id}","starred_url":"https://api.github.com/users/instacart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/instacart/subscriptions","organizations_url":"https://api.github.com/users/instacart/orgs","repos_url":"https://api.github.com/users/instacart/repos","events_url":"https://api.github.com/users/instacart/events{/privacy}","received_events_url":"https://api.github.com/users/instacart/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/instacart/blazer","description":"Open source business intelligence","fork":true,"url":"https://api.github.com/repos/instacart/blazer","forks_url":"https://api.github.com/repos/instacart/blazer/forks","keys_url":"https://api.github.com/repos/instacart/blazer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/instacart/blazer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/instacart/blazer/teams","hooks_url":"https://api.github.com/repos/instacart/blazer/hooks","issue_events_url":"https://api.github.com/repos/instacart/blazer/issues/events{/number}","events_url":"https://api.github.com/repos/instacart/blazer/events","assignees_url":"https://api.github.com/repos/instacart/blazer/assignees{/user}","branches_url":"https://api.github.com/repos/instacart/blazer/branches{/branch}","tags_url":"https://api.github.com/repos/instacart/blazer/tags","blobs_url":"https://api.github.com/repos/instacart/blazer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/instacart/blazer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/instacart/blazer/git/refs{/sha}","trees_url":"https://api.github.com/repos/instacart/blazer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/instacart/blazer/statuses/{sha}","languages_url":"https://api.github.com/repos/instacart/blazer/languages","stargazers_url":"https://api.github.com/repos/instacart/blazer/stargazers","contributors_url":"https://api.github.com/repos/instacart/blazer/contributors","subscribers_url":"https://api.github.com/repos/instacart/blazer/subscribers","subscription_url":"https://api.github.com/repos/instacart/blazer/subscription","commits_url":"https://api.github.com/repos/instacart/blazer/commits{/sha}","git_commits_url":"https://api.github.com/repos/instacart/blazer/git/commits{/sha}","comments_url":"https://api.github.com/repos/instacart/blazer/comments{/number}","issue_comment_url":"https://api.github.com/repos/instacart/blazer/issues/comments{/number}","contents_url":"https://api.github.com/repos/instacart/blazer/contents/{+path}","compare_url":"https://api.github.com/repos/instacart/blazer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/instacart/blazer/merges","archive_url":"https://api.github.com/repos/instacart/blazer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/instacart/blazer/downloads","issues_url":"https://api.github.com/repos/instacart/blazer/issues{/number}","pulls_url":"https://api.github.com/repos/instacart/blazer/pulls{/number}","milestones_url":"https://api.github.com/repos/instacart/blazer/milestones{/number}","notifications_url":"https://api.github.com/repos/instacart/blazer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/instacart/blazer/labels{/name}","releases_url":"https://api.github.com/repos/instacart/blazer/releases{/id}","deployments_url":"https://api.github.com/repos/instacart/blazer/deployments","created_at":"2016-01-07T00:12:53Z","updated_at":"2017-01-04T18:51:40Z","pushed_at":"2017-06-06T20:03:51Z","git_url":"git://github.com/instacart/blazer.git","ssh_url":"git@github.com:instacart/blazer.git","clone_url":"https://github.com/instacart/blazer.git","svn_url":"https://github.com/instacart/blazer","homepage":"","size":1763,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":3,"forks":3,"open_issues":3,"watchers":1,"default_branch":"master"}},"base":{"label":"instacart:master","ref":"master","sha":"5c3bfa12c48d32a1317d19e00d6247a16c93e727","user":{"login":"instacart","id":3732412,"avatar_url":"https://avatars2.githubusercontent.com/u/3732412?v=3","gravatar_id":"","url":"https://api.github.com/users/instacart","html_url":"https://github.com/instacart","followers_url":"https://api.github.com/users/instacart/followers","following_url":"https://api.github.com/users/instacart/following{/other_user}","gists_url":"https://api.github.com/users/instacart/gists{/gist_id}","starred_url":"https://api.github.com/users/instacart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/instacart/subscriptions","organizations_url":"https://api.github.com/users/instacart/orgs","repos_url":"https://api.github.com/users/instacart/repos","events_url":"https://api.github.com/users/instacart/events{/privacy}","received_events_url":"https://api.github.com/users/instacart/received_events","type":"Organization","site_admin":false},"repo":{"id":49169747,"name":"blazer","full_name":"instacart/blazer","owner":{"login":"instacart","id":3732412,"avatar_url":"https://avatars2.githubusercontent.com/u/3732412?v=3","gravatar_id":"","url":"https://api.github.com/users/instacart","html_url":"https://github.com/instacart","followers_url":"https://api.github.com/users/instacart/followers","following_url":"https://api.github.com/users/instacart/following{/other_user}","gists_url":"https://api.github.com/users/instacart/gists{/gist_id}","starred_url":"https://api.github.com/users/instacart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/instacart/subscriptions","organizations_url":"https://api.github.com/users/instacart/orgs","repos_url":"https://api.github.com/users/instacart/repos","events_url":"https://api.github.com/users/instacart/events{/privacy}","received_events_url":"https://api.github.com/users/instacart/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/instacart/blazer","description":"Open source business intelligence","fork":true,"url":"https://api.github.com/repos/instacart/blazer","forks_url":"https://api.github.com/repos/instacart/blazer/forks","keys_url":"https://api.github.com/repos/instacart/blazer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/instacart/blazer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/instacart/blazer/teams","hooks_url":"https://api.github.com/repos/instacart/blazer/hooks","issue_events_url":"https://api.github.com/repos/instacart/blazer/issues/events{/number}","events_url":"https://api.github.com/repos/instacart/blazer/events","assignees_url":"https://api.github.com/repos/instacart/blazer/assignees{/user}","branches_url":"https://api.github.com/repos/instacart/blazer/branches{/branch}","tags_url":"https://api.github.com/repos/instacart/blazer/tags","blobs_url":"https://api.github.com/repos/instacart/blazer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/instacart/blazer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/instacart/blazer/git/refs{/sha}","trees_url":"https://api.github.com/repos/instacart/blazer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/instacart/blazer/statuses/{sha}","languages_url":"https://api.github.com/repos/instacart/blazer/languages","stargazers_url":"https://api.github.com/repos/instacart/blazer/stargazers","contributors_url":"https://api.github.com/repos/instacart/blazer/contributors","subscribers_url":"https://api.github.com/repos/instacart/blazer/subscribers","subscription_url":"https://api.github.com/repos/instacart/blazer/subscription","commits_url":"https://api.github.com/repos/instacart/blazer/commits{/sha}","git_commits_url":"https://api.github.com/repos/instacart/blazer/git/commits{/sha}","comments_url":"https://api.github.com/repos/instacart/blazer/comments{/number}","issue_comment_url":"https://api.github.com/repos/instacart/blazer/issues/comments{/number}","contents_url":"https://api.github.com/repos/instacart/blazer/contents/{+path}","compare_url":"https://api.github.com/repos/instacart/blazer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/instacart/blazer/merges","archive_url":"https://api.github.com/repos/instacart/blazer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/instacart/blazer/downloads","issues_url":"https://api.github.com/repos/instacart/blazer/issues{/number}","pulls_url":"https://api.github.com/repos/instacart/blazer/pulls{/number}","milestones_url":"https://api.github.com/repos/instacart/blazer/milestones{/number}","notifications_url":"https://api.github.com/repos/instacart/blazer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/instacart/blazer/labels{/name}","releases_url":"https://api.github.com/repos/instacart/blazer/releases{/id}","deployments_url":"https://api.github.com/repos/instacart/blazer/deployments","created_at":"2016-01-07T00:12:53Z","updated_at":"2017-01-04T18:51:40Z","pushed_at":"2017-06-06T20:03:51Z","git_url":"git://github.com/instacart/blazer.git","ssh_url":"git@github.com:instacart/blazer.git","clone_url":"https://github.com/instacart/blazer.git","svn_url":"https://github.com/instacart/blazer","homepage":"","size":1763,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":3,"forks":3,"open_issues":3,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/instacart/blazer/pulls/10"},"html":{"href":"https://github.com/instacart/blazer/pull/10"},"issue":{"href":"https://api.github.com/repos/instacart/blazer/issues/10"},"comments":{"href":"https://api.github.com/repos/instacart/blazer/issues/10/comments"},"review_comments":{"href":"https://api.github.com/repos/instacart/blazer/pulls/10/comments"},"review_comment":{"href":"https://api.github.com/repos/instacart/blazer/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/instacart/blazer/pulls/10/commits"},"statuses":{"href":"https://api.github.com/repos/instacart/blazer/statuses/986fcd15914b1449bcb3668668cdd2f3a6920db2"}}}}
{"actor":{"display_login":"viktor-evdokimov"}}