From 44552b6b1ecbe153969e9da47726b30b377b3ba7 Mon Sep 17 00:00:00 2001 From: Hugo Thiessard Date: Fri, 22 Apr 2016 08:09:02 +0200 Subject: [PATCH] Add S-needs-code-changes if travis build fails --- eventhandler.py | 9 +- handlers/status_update/__init__.py | 5 + .../status_update/tests/build_status.json | 212 ++++++++++++++++++ newpr.py | 10 +- travisciapiprovider.py | 17 ++ 5 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 handlers/status_update/tests/build_status.json create mode 100644 travisciapiprovider.py diff --git a/eventhandler.py b/eventhandler.py index 3ec77a9..d8dbd57 100644 --- a/eventhandler.py +++ b/eventhandler.py @@ -10,7 +10,8 @@ 'synchronize': 'on_pr_updated', 'created': 'on_new_comment', 'closed': 'on_pr_closed', - 'labeled': 'on_issue_labeled' + 'labeled': 'on_issue_labeled', + 'status': 'on_build_status' } @@ -30,10 +31,14 @@ def on_pr_closed(self, api, payload): def on_issue_labeled(self, api, payload): pass + def on_build_status(self, api, payload): + pass + def handle_payload(self, api, payload): def callback(action): getattr(self, _payload_actions[action])(api, payload) - payload_action = payload['action'] + payload_action = 'status' if 'context' in payload \ + else payload['action'] linear_search(_payload_actions, payload_action, callback) def warn(self, msg): diff --git a/handlers/status_update/__init__.py b/handlers/status_update/__init__.py index 31f504d..b872fdf 100644 --- a/handlers/status_update/__init__.py +++ b/handlers/status_update/__init__.py @@ -45,4 +45,9 @@ def on_pr_closed(self, api, payload): if payload['pull_request']['merged']: api.remove_label("S-awaiting-merge") + def on_build_status(self, api, payload): + if payload['context'] == 'continuous-integration/travis-ci/pr': + if payload['state'] == 'failure' or payload['state'] == 'error': + api.add_label("S-needs-code-changes") + handler_interface = StatusUpdateHandler diff --git a/handlers/status_update/tests/build_status.json b/handlers/status_update/tests/build_status.json new file mode 100644 index 0000000..a1b6268 --- /dev/null +++ b/handlers/status_update/tests/build_status.json @@ -0,0 +1,212 @@ +{ + "initial": { + "labels": [] + }, + "expected": { + "labels": ["S-needs-code-changes"] + }, + "payload": { + "id": 510996575, + "sha": "650aae0ca9be912021c0d21e30e4cedf67135a78", + "name": "servo/servo", + "target_url": "https://travis-ci.org/servo/servo/builds/120670455", + "context": "continuous-integration/travis-ci/pr", + "description": "The Travis CI build failed", + "state": "failure", + "commit": { + "sha": "650aae0ca9be912021c0d21e30e4cedf67135a78", + "commit": { + "author": { + "name": "Alan Jeffrey", + "email": "ajeffrey@mozilla.com", + "date": "2016-04-04T16:47:29Z" + }, + "committer": { + "name": "Alan Jeffrey", + "email": "ajeffrey@mozilla.com", + "date": "2016-04-04T16:47:29Z" + }, + "message": "Responding to reviewer comments.", + "tree": { + "sha": "c74649f3b0d52b932a19cfb3ce47415fb6439680", + "url": "https://api.github.com/repos/servo/servo/git/trees/c74649f3b0d52b932a19cfb3ce47415fb6439680" + }, + "url": "https://api.github.com/repos/servo/servo/git/commits/650aae0ca9be912021c0d21e30e4cedf67135a78", + "comment_count": 0 + }, + "url": "https://api.github.com/repos/servo/servo/commits/650aae0ca9be912021c0d21e30e4cedf67135a78", + "html_url": "https://github.com/servo/servo/commit/650aae0ca9be912021c0d21e30e4cedf67135a78", + "comments_url": "https://api.github.com/repos/servo/servo/commits/650aae0ca9be912021c0d21e30e4cedf67135a78/comments", + "author": { + "login": "asajeffrey", + "id": 403333, + "avatar_url": "https://avatars.githubusercontent.com/u/403333?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/asajeffrey", + "html_url": "https://github.com/asajeffrey", + "followers_url": "https://api.github.com/users/asajeffrey/followers", + "following_url": "https://api.github.com/users/asajeffrey/following{/other_user}", + "gists_url": "https://api.github.com/users/asajeffrey/gists{/gist_id}", + "starred_url": "https://api.github.com/users/asajeffrey/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/asajeffrey/subscriptions", + "organizations_url": "https://api.github.com/users/asajeffrey/orgs", + "repos_url": "https://api.github.com/users/asajeffrey/repos", + "events_url": "https://api.github.com/users/asajeffrey/events{/privacy}", + "received_events_url": "https://api.github.com/users/asajeffrey/received_events", + "type": "User", + "site_admin": false + }, + "committer": { + "login": "asajeffrey", + "id": 403333, + "avatar_url": "https://avatars.githubusercontent.com/u/403333?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/asajeffrey", + "html_url": "https://github.com/asajeffrey", + "followers_url": "https://api.github.com/users/asajeffrey/followers", + "following_url": "https://api.github.com/users/asajeffrey/following{/other_user}", + "gists_url": "https://api.github.com/users/asajeffrey/gists{/gist_id}", + "starred_url": "https://api.github.com/users/asajeffrey/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/asajeffrey/subscriptions", + "organizations_url": "https://api.github.com/users/asajeffrey/orgs", + "repos_url": "https://api.github.com/users/asajeffrey/repos", + "events_url": "https://api.github.com/users/asajeffrey/events{/privacy}", + "received_events_url": "https://api.github.com/users/asajeffrey/received_events", + "type": "User", + "site_admin": false + }, + "parents": [ + { + "sha": "7f6cc24145dda4f056f70add7154fd3a416bb0d6", + "url": "https://api.github.com/repos/servo/servo/commits/7f6cc24145dda4f056f70add7154fd3a416bb0d6", + "html_url": "https://github.com/servo/servo/commit/7f6cc24145dda4f056f70add7154fd3a416bb0d6" + } + ] + }, + "branches": [ + + ], + "created_at": "2016-04-04T17:06:05Z", + "updated_at": "2016-04-04T17:06:05Z", + "repository": { + "id": 3390243, + "name": "servo", + "full_name": "servo/servo", + "owner": { + "login": "servo", + "id": 2566135, + "avatar_url": "https://avatars.githubusercontent.com/u/2566135?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/servo", + "html_url": "https://github.com/servo", + "followers_url": "https://api.github.com/users/servo/followers", + "following_url": "https://api.github.com/users/servo/following{/other_user}", + "gists_url": "https://api.github.com/users/servo/gists{/gist_id}", + "starred_url": "https://api.github.com/users/servo/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/servo/subscriptions", + "organizations_url": "https://api.github.com/users/servo/orgs", + "repos_url": "https://api.github.com/users/servo/repos", + "events_url": "https://api.github.com/users/servo/events{/privacy}", + "received_events_url": "https://api.github.com/users/servo/received_events", + "type": "Organization", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/servo/servo", + "description": "The Servo Browser Engine", + "fork": false, + "url": "https://api.github.com/repos/servo/servo", + "forks_url": "https://api.github.com/repos/servo/servo/forks", + "keys_url": "https://api.github.com/repos/servo/servo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/servo/servo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/servo/servo/teams", + "hooks_url": "https://api.github.com/repos/servo/servo/hooks", + "issue_events_url": "https://api.github.com/repos/servo/servo/issues/events{/number}", + "events_url": "https://api.github.com/repos/servo/servo/events", + "assignees_url": "https://api.github.com/repos/servo/servo/assignees{/user}", + "branches_url": "https://api.github.com/repos/servo/servo/branches{/branch}", + "tags_url": "https://api.github.com/repos/servo/servo/tags", + "blobs_url": "https://api.github.com/repos/servo/servo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/servo/servo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/servo/servo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/servo/servo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/servo/servo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/servo/servo/languages", + "stargazers_url": "https://api.github.com/repos/servo/servo/stargazers", + "contributors_url": "https://api.github.com/repos/servo/servo/contributors", + "subscribers_url": "https://api.github.com/repos/servo/servo/subscribers", + "subscription_url": "https://api.github.com/repos/servo/servo/subscription", + "commits_url": "https://api.github.com/repos/servo/servo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/servo/servo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/servo/servo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/servo/servo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/servo/servo/contents/{+path}", + "compare_url": "https://api.github.com/repos/servo/servo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/servo/servo/merges", + "archive_url": "https://api.github.com/repos/servo/servo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/servo/servo/downloads", + "issues_url": "https://api.github.com/repos/servo/servo/issues{/number}", + "pulls_url": "https://api.github.com/repos/servo/servo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/servo/servo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/servo/servo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/servo/servo/labels{/name}", + "releases_url": "https://api.github.com/repos/servo/servo/releases{/id}", + "deployments_url": "https://api.github.com/repos/servo/servo/deployments", + "created_at": "2012-02-08T19:07:25Z", + "updated_at": "2016-04-04T15:48:28Z", + "pushed_at": "2016-04-04T17:04:27Z", + "git_url": "git://github.com/servo/servo.git", + "ssh_url": "git@github.com:servo/servo.git", + "clone_url": "https://github.com/servo/servo.git", + "svn_url": "https://github.com/servo/servo", + "homepage": "https://servo.org/", + "size": 214000, + "stargazers_count": 6429, + "watchers_count": 6429, + "language": null, + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 1055, + "mirror_url": null, + "open_issues_count": 1417, + "forks": 1055, + "open_issues": 1417, + "watchers": 6429, + "default_branch": "master" + }, + "organization": { + "login": "servo", + "id": 2566135, + "url": "https://api.github.com/orgs/servo", + "repos_url": "https://api.github.com/orgs/servo/repos", + "events_url": "https://api.github.com/orgs/servo/events", + "hooks_url": "https://api.github.com/orgs/servo/hooks", + "issues_url": "https://api.github.com/orgs/servo/issues", + "members_url": "https://api.github.com/orgs/servo/members{/member}", + "public_members_url": "https://api.github.com/orgs/servo/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/2566135?v=3", + "description": null + }, + "sender": { + "login": "asajeffrey", + "id": 403333, + "avatar_url": "https://avatars.githubusercontent.com/u/403333?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/asajeffrey", + "html_url": "https://github.com/asajeffrey", + "followers_url": "https://api.github.com/users/asajeffrey/followers", + "following_url": "https://api.github.com/users/asajeffrey/following{/other_user}", + "gists_url": "https://api.github.com/users/asajeffrey/gists{/gist_id}", + "starred_url": "https://api.github.com/users/asajeffrey/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/asajeffrey/subscriptions", + "organizations_url": "https://api.github.com/users/asajeffrey/orgs", + "repos_url": "https://api.github.com/users/asajeffrey/repos", + "events_url": "https://api.github.com/users/asajeffrey/events{/privacy}", + "received_events_url": "https://api.github.com/users/asajeffrey/received_events", + "type": "User", + "site_admin": false + } + } +} diff --git a/newpr.py b/newpr.py index b0224b1..9bfd391 100755 --- a/newpr.py +++ b/newpr.py @@ -15,6 +15,7 @@ from StringIO import StringIO import urllib2 +from travisciapiprovider import TravisCiApiProvider import eventhandler @@ -215,7 +216,14 @@ def get_page_content(self, url): def extract_globals_from_payload(payload): - if payload["action"] == "created" or payload["action"] == "labeled": + if 'context' in payload: + owner = payload['repository']['owner']['login'] + repo = payload['repository']['name'] + travisCiApiProvider = TravisCiApiProvider() + build_number = payload['target_url'].split('/')[-1] + build = travisCiApiProvider.get_build(build_number) + issue = travisCiApiProvider.get_pull_request_number(build) + elif payload['action'] == 'created' or payload['action'] == 'labeled': owner = payload['repository']['owner']['login'] repo = payload['repository']['name'] issue = str(payload['issue']['number']) diff --git a/travisciapiprovider.py b/travisciapiprovider.py new file mode 100644 index 0000000..573f9cd --- /dev/null +++ b/travisciapiprovider.py @@ -0,0 +1,17 @@ +import urllib +import json + + +# If more functionality is needed from this class, it might be a +# better decision to use travispy +class TravisCiApiProvider(): + host_url = 'https://api.travis-ci.org' + build_url = host_url + '/builds/{build_id}' + log_url = host_url + '/jobs/{job_id}/log' + + def get_build(self, build_id): + url = self.build_url.format(build_id=build_id) + return json.loads(urllib.urlopen(url).read()) + + def get_pull_request_number(self, build_data): + return int(build_data['compare_url'].split('/')[-1])