tutter 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4192ecc489da04f7c71eb66580dca786823bce76
4
- data.tar.gz: f282b693463e39b6a25fb6656f08a84cc463acc1
3
+ metadata.gz: 2fd4ec7bd3451798835a4eda2b8840f7cc7c8f28
4
+ data.tar.gz: cbece5fa4f7c061acae900228c671c1e35a0ffa1
5
5
  SHA512:
6
- metadata.gz: a5341952596f313eeaac40969fec6e12203e8f99aaf3e521c6b8347b493454c4751adea57ea6e44e514ce001a3fd7a6961d8d48f95ba68e644d3dc39e122ae63
7
- data.tar.gz: b9decb7449728ff7873669e4311dfa95cb1f2bebc28ee072b2d2b77e7b3af2f80a7e9fc8cacff618660f1d8ae7a55c7fb015ac2a39d55b8e6f9adb74def8d112
6
+ metadata.gz: 5a3ba61909d5102036fa717f2e514780b9a07c2efb8f0759a14ec427a8c7442e8d560db3900d5e29def4a19a5f0936fab3b47ab409500fb916944681b78543a9
7
+ data.tar.gz: 49a1500844a2435bd1decb5aef68bec358c080cd8ac2836ada5462f0f2adba5d4ef5289100a8f53687ac0334287acd52a60073146e8a57cb9997bdbf5cc7db02
@@ -1,13 +1,11 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
3
  - 2.0.0
5
4
  deploy:
6
5
  provider: rubygems
7
6
  api_key:
8
7
  secure: n8Dxj8UpauHBzBF10yVOCndmXEfLUQNV9ye9fi+b3tCtZHPqfEAaOfltbgP0Z8UglbiN8zPlt+Ayq4AiYXMx+gWEWpin+euVSvcK2JnMLQP1U9WD9qpTpAUXzIXxdUsoIY0VDfDMWpC+PYVCbNYNviKslaMRvzCd7w5dCOfsI30=
9
8
  gem: tutter
10
- gemspec: .gemspec
11
9
  on:
12
10
  tags: true
13
11
  repo: jhaals/tutter
data/Gemfile CHANGED
@@ -1,7 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'octokit', '~> 3.2.0'
3
+ gem 'octokit', '~> 4.3.0'
4
4
  gem 'sinatra', '~> 1.4.4'
5
+ gem 'thin', '~> 1.7.0'
5
6
 
6
7
  group :development do
7
8
  gem 'sinatra-reloader'
@@ -11,7 +12,6 @@ group :test do
11
12
  gem 'sinatra-contrib'
12
13
  gem 'tutter', :path => '.'
13
14
  gem 'rake'
14
- gem 'rack'
15
15
  gem 'rspec'
16
16
  gem 'json'
17
17
  end
data/README.md CHANGED
@@ -1,43 +1,39 @@
1
1
  # Tutter - Plugin based Github robot
2
2
  [![Build Status](https://travis-ci.org/jhaals/tutter.png?branch=master)](https://travis-ci.org/JHaals/tutter)
3
3
 
4
- Tutter is a web app that trigger actions based on Github events(push, pull_reqeust, release, issue, ...)
4
+ Tutter is a robot that can trigger customizable actions based on Github [events]((https://developer.github.com/v3/activity/events/types/)(push, pull_request, release, issue, ..)
5
5
 
6
- # Features
7
- * Pluggable with custom actions
8
- * Supports multiple projects
9
6
 
10
7
  # Installation
11
8
 
12
9
  gem install tutter
13
10
 
14
- put a configuration file in `/etc/tutter.yaml`
15
- an example can be found under `conf/tutter.yaml`
16
-
17
- Let's install the `thanks` action that thank anyone that creates an issue in your project.
11
+ Place configuration file in `/etc/tutter.yaml`, example can be found in the conf/ directory.
18
12
 
19
13
  ### tutter.yaml settings
20
14
 
21
- * `name` - username/projectname
22
- * `access_token` - github access token (can be generated [here](https://github.com/settings/applications))
15
+ * `name` - username/project_name
16
+ * `access_token` - Github access token (can be generated [here](https://github.com/settings/applications))
23
17
  * `github_site` - github website
24
- * `github_api_enpoint` - github api endpint
18
+ * `github_api_endpoint` - github api endpoint
19
+ * `hook_secret` - (Optional) validate hook data based on known secret([more](https://developer.github.com/webhooks/securing/)).
25
20
  * `action` - action you wish to use for the project
26
21
  * `action_settings` - whatever settings your action require
27
22
 
28
- ### Create the Github webhook
29
- Hooks can be configured just to send the event that you're interested in. The important part is that `Payload URL` points to the webserver running tutter
23
+ ### Configure Tutter action
24
+ Hooks can be configured just to send the event that you're interested in. The important part is that `Payload URL` points to the webserver running Tutter
30
25
 
31
26
  https://github.com/ORG/PROJECT/settings/hooks/new
32
27
 
33
- Example of how the `thanks` demo-action look like. Tutter listen for issue events and posts back with a greeting.
28
+ Example on how the `thanks` action looks like. Tutter listens for `issue` events and posts back with a greeting.
34
29
  ![img](http://f.cl.ly/items/1k111I3H1N0L3008301c/tutter.png)
35
30
 
36
31
  ## Build custom action
37
32
 
38
- See [thanks action](https://github.com/jhaals/tutter/blob/master/lib/tutter/action/thanks.rb)
33
+ A simple action for getting started is the built in [thanks](https://github.com/jhaals/tutter/blob/master/lib/tutter/action/thanks.rb) action.
34
+ More advanced usage can be seen in the [tutter-sppuppet](https://github.com/jhaals/tutter-sppuppet) action that allows non-collaborators to merge pull requests
39
35
 
40
- #####Required methods and their arguments
36
+ ##### Required methods and their arguments
41
37
 
42
38
  `initialize`
43
39
 
@@ -52,7 +48,4 @@ See [thanks action](https://github.com/jhaals/tutter/blob/master/lib/tutter/acti
52
48
  Tutter uses [octokit.rb](https://github.com/octokit/octokit.rb) to communicate with the Github [API](http://developer.github.com/v3/)
53
49
 
54
50
  ### Features to implement
55
- * Support multiple actions per project
56
51
  * Authenticate as a Github application
57
- * Features your're missing (please contribute)
58
- * Tests!
@@ -3,9 +3,14 @@ projects:
3
3
  access_token: ''
4
4
  github_site: 'https://github.com'
5
5
  github_api_endpoint: 'https://api.github.com'
6
+ github_api_auto_paginate: true
6
7
 
7
- action: 'thanks'
8
+ actions:
9
+ issue:
10
+ - thanks
11
+ - sassy
12
+ issue_comment:
13
+ - sassy
8
14
  action_settings:
9
15
  whatever_action_specific_setting: 'foo'
10
16
  another_setting: false
11
-
@@ -1,14 +1,16 @@
1
- require 'rubygems'
1
+ require 'json'
2
2
  require 'octokit'
3
- require 'yaml'
4
3
  require 'sinatra'
4
+ require 'thin'
5
5
  require 'tutter/action'
6
- require 'json'
6
+ require 'yaml'
7
7
 
8
+ # Modular sinatra app Tutter
8
9
  class Tutter < Sinatra::Base
10
+ enable :logging
9
11
 
10
12
  configure do
11
- set :config_path, ENV['TUTTER_CONFIG_PATH'] || "conf/tutter.yaml"
13
+ set :config_path, ENV['TUTTER_CONFIG_PATH'] || 'conf/tutter.yaml'
12
14
  set :config, YAML.load_file(settings.config_path)
13
15
  end
14
16
 
@@ -22,78 +24,91 @@ class Tutter < Sinatra::Base
22
24
  set :bind, '0.0.0.0'
23
25
  end
24
26
 
27
+ def verify_signature(payload_body, secret_token)
28
+ signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), secret_token, payload_body)
29
+ return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE'])
30
+ end
31
+
25
32
  # Return project settings from config
26
- def get_project_settings project
33
+ def project_settings(project)
27
34
  settings.config['projects'].each do |p|
28
35
  return p if p['name'] == project
29
36
  end
30
- false
37
+ error(404, 'Project does not exist in tutter.conf')
31
38
  end
32
39
 
33
- def try_action event, data
34
- project = data['repository']['full_name'] || error(400, 'Bad request')
35
-
36
- conf = get_project_settings(project) || error(404, 'Project does not exist in tutter.conf')
40
+ # Return actions for event from config
41
+ def actions_for_event(event, config)
42
+ config['actions'][event] || error(404,
43
+ "No Actions for #{event} in tutter.conf"
44
+ )
45
+ end
37
46
 
38
- # Setup octokit endpoints
47
+ def octokit_client(config)
39
48
  Octokit.configure do |c|
40
- c.api_endpoint = conf['github_api_endpoint']
41
- c.web_endpoint = conf['github_site']
49
+ c.api_endpoint = config['github_api_endpoint']
50
+ c.web_endpoint = config['github_site']
51
+ c.auto_paginate = config['github_api_auto_paginate'] or false
42
52
  end
43
53
 
44
- if conf['access_token_env_var']
45
- access_token = ENV[conf['access_token_env_var']] || ''
54
+ if config['access_token_env_var']
55
+ access_token = ENV[config['access_token_env_var']] || ''
46
56
  else
47
- access_token = conf['access_token'] || ''
57
+ access_token = config['access_token'] || ''
48
58
  end
49
59
 
50
- client = Octokit::Client.new :access_token => access_token
51
-
52
- # Load action
53
- action = Action.create(conf['action'],
54
- conf['action_settings'],
55
- client,
56
- project,
57
- event,
58
- data)
60
+ Octokit::Client.new access_token: access_token
61
+ end
59
62
 
60
- status_code, message = action.run
63
+ def prepare_actions(project, event, data, config)
64
+ client = octokit_client(config)
65
+ actions_for_event(event, config).each do |a|
66
+ yield Action.create(a,
67
+ config['action_settings'],
68
+ client,
69
+ project,
70
+ event,
71
+ data), a
72
+ end
73
+ end
61
74
 
62
- return status_code, message
75
+ def try_actions(event, data, project, config)
76
+ responses = { event: event, responses: {} }
77
+ prepare_actions(project, event, data, config) do |action, name|
78
+ status_code, message = action.run
79
+ responses[:responses][name] = { status_code: status_code,
80
+ message: message
81
+ }
82
+ break if status_code != 200
83
+ end
84
+ [responses[:responses].values.last[:status_code], responses.to_json]
63
85
  end
64
86
 
65
87
  post '/' do
66
- event = env['HTTP_X_GITHUB_EVENT']
67
-
68
- unless event
69
- error(500, "Invalid request")
70
- end
88
+ event = env['HTTP_X_GITHUB_EVENT'] || error(500, 'Invalid request')
71
89
 
72
90
  # Get a 200 OK message in the Github webhook history
73
91
  # Previously this showed an error.
74
- if event == "ping"
75
- return 200, "Tutter likes this hook!"
76
- end
92
+ return 200, 'Tutter likes this hook!' if event == 'ping'
77
93
 
78
94
  # Github send data in JSON format, parse it!
95
+ request_body = request.body.read
79
96
  begin
80
- data = JSON.parse request.body.read
97
+ data = JSON.parse request_body
81
98
  rescue JSON::ParserError
82
99
  error(400, 'POST data is not JSON')
83
100
  end
84
101
 
85
- # Check actions with repo
86
-
87
- if data['repository']
88
- return try_action(event, data)
89
- end
102
+ project = data['repository']['full_name'] || error(400, 'Bad request')
103
+ config = project_settings(project)
104
+ verify_signature(request_body, config['hook_secret']) if config['hook_secret']
90
105
 
91
- error(400, "Unsupported request: #{event}")
106
+ return try_actions(event, data, project, config) if data['repository']
92
107
  end
93
108
 
94
109
  get '/' do
95
110
  'Source code and documentation at https://github.com/jhaals/tutter'
96
111
  end
97
112
 
98
- run! if app_file == $0
113
+ run! if app_file == $PROGRAM_NAME
99
114
  end
@@ -0,0 +1,36 @@
1
+ # Example action
2
+ # Thank the person who submit an issue
3
+ # The comment text is configurabe using the 'comment' setting.
4
+
5
+ class Sassy
6
+ def initialize(settings, client, project, data, event)
7
+ @settings = settings # action specific settings
8
+ @client = client # Octokit client
9
+ @project = project # project name
10
+ @event = event # Github event
11
+ @data = data
12
+ end
13
+
14
+ def run
15
+ # Only trigger if a new issue is created
16
+ unless @data['action'] == 'created'
17
+ return 200, "Web hook from GitHub for #{@project} does not have status created. Dont know what to do."
18
+ end
19
+ issue = @data['issue']['number']
20
+ submitter = @data['issue']['user']['login']
21
+ comment = @settings['sassy_comment'] || "@#{submitter} Oh! big man eh? knowlage and shit"
22
+
23
+ begin
24
+ @client.add_comment(@project, issue, comment)
25
+ return 200, "Commented!"
26
+ rescue Octokit::NotFound
27
+ return 404, "Octokit returned 404, this could be an issue with your access token"
28
+ rescue Octokit::Unauthorized
29
+ return 401, "Authorization to #{@project} failed, please verify your access token"
30
+ rescue Octokit::TooManyLoginAttempts
31
+ return 429, "Account for #{@project} has been temporary locked down due to to many failed login attempts"
32
+ end
33
+ # TODO - Verify return data from @client.add_comment
34
+ end
35
+
36
+ end
@@ -0,0 +1,154 @@
1
+ {
2
+ "action": "closed",
3
+ "issue": {
4
+ "url": "https://api.github.com/repos/JHaals/testing/issues/9",
5
+ "labels_url": "https://api.github.com/repos/JHaals/testing/issues/9/labels{/name}",
6
+ "comments_url": "https://api.github.com/repos/JHaals/testing/issues/9/comments",
7
+ "events_url": "https://api.github.com/repos/JHaals/testing/issues/9/events",
8
+ "html_url": "https://github.com/JHaals/testing/issues/9",
9
+ "id": 28705860,
10
+ "number": 9,
11
+ "title": "the internet is broken",
12
+ "user": {
13
+ "login": "JHaals",
14
+ "id": 68980,
15
+ "avatar_url": "https://avatars.githubusercontent.com/u/68980",
16
+ "gravatar_id": "4e51de553ebfe258f038e040c8b25892",
17
+ "url": "https://api.github.com/users/JHaals",
18
+ "html_url": "https://github.com/JHaals",
19
+ "followers_url": "https://api.github.com/users/JHaals/followers",
20
+ "following_url": "https://api.github.com/users/JHaals/following{/other_user}",
21
+ "gists_url": "https://api.github.com/users/JHaals/gists{/gist_id}",
22
+ "starred_url": "https://api.github.com/users/JHaals/starred{/owner}{/repo}",
23
+ "subscriptions_url": "https://api.github.com/users/JHaals/subscriptions",
24
+ "organizations_url": "https://api.github.com/users/JHaals/orgs",
25
+ "repos_url": "https://api.github.com/users/JHaals/repos",
26
+ "events_url": "https://api.github.com/users/JHaals/events{/privacy}",
27
+ "received_events_url": "https://api.github.com/users/JHaals/received_events",
28
+ "type": "User",
29
+ "site_admin": false
30
+ },
31
+ "labels": [
32
+
33
+ ],
34
+ "state": "closed",
35
+ "assignee": null,
36
+ "milestone": null,
37
+ "comments": 0,
38
+ "created_at": "2014-03-04T13:46:06Z",
39
+ "updated_at": "2014-03-04T13:46:06Z",
40
+ "closed_at": null,
41
+ "pull_request": {
42
+ "html_url": null,
43
+ "diff_url": null,
44
+ "patch_url": null
45
+ },
46
+ "body": "what to do?"
47
+ },
48
+ "repository": {
49
+ "id": 16474769,
50
+ "name": "testing",
51
+ "full_name": "JHaals\/testing",
52
+ "owner": {
53
+ "login": "JHaals",
54
+ "id": 68980,
55
+ "avatar_url": "https://avatars.githubusercontent.com/u/68980",
56
+ "gravatar_id": "4e51de553ebfe258f038e040c8b25892",
57
+ "url": "https://api.github.com/users/JHaals",
58
+ "html_url": "https://github.com/JHaals",
59
+ "followers_url": "https://api.github.com/users/JHaals/followers",
60
+ "following_url": "https://api.github.com/users/JHaals/following{/other_user}",
61
+ "gists_url": "https://api.github.com/users/JHaals/gists{/gist_id}",
62
+ "starred_url": "https://api.github.com/users/JHaals/starred{/owner}{/repo}",
63
+ "subscriptions_url": "https://api.github.com/users/JHaals/subscriptions",
64
+ "organizations_url": "https://api.github.com/users/JHaals/orgs",
65
+ "repos_url": "https://api.github.com/users/JHaals/repos",
66
+ "events_url": "https://api.github.com/users/JHaals/events{/privacy}",
67
+ "received_events_url": "https://api.github.com/users/JHaals/received_events",
68
+ "type": "User",
69
+ "site_admin": false
70
+ },
71
+ "private": false,
72
+ "html_url": "https://github.com/JHaals/testing",
73
+ "description": "this is just for personal tests",
74
+ "fork": false,
75
+ "url": "https://api.github.com/repos/JHaals/testing",
76
+ "forks_url": "https://api.github.com/repos/JHaals/testing/forks",
77
+ "keys_url": "https://api.github.com/repos/JHaals/testing/keys{/key_id}",
78
+ "collaborators_url": "https://api.github.com/repos/JHaals/testing/collaborators{/collaborator}",
79
+ "teams_url": "https://api.github.com/repos/JHaals/testing/teams",
80
+ "hooks_url": "https://api.github.com/repos/JHaals/testing/hooks",
81
+ "issue_events_url": "https://api.github.com/repos/JHaals/testing/issues/events{/number}",
82
+ "events_url": "https://api.github.com/repos/JHaals/testing/events",
83
+ "assignees_url": "https://api.github.com/repos/JHaals/testing/assignees{/user}",
84
+ "branches_url": "https://api.github.com/repos/JHaals/testing/branches{/branch}",
85
+ "tags_url": "https://api.github.com/repos/JHaals/testing/tags",
86
+ "blobs_url": "https://api.github.com/repos/JHaals/testing/git/blobs{/sha}",
87
+ "git_tags_url": "https://api.github.com/repos/JHaals/testing/git/tags{/sha}",
88
+ "git_refs_url": "https://api.github.com/repos/JHaals/testing/git/refs{/sha}",
89
+ "trees_url": "https://api.github.com/repos/JHaals/testing/git/trees{/sha}",
90
+ "statuses_url": "https://api.github.com/repos/JHaals/testing/statuses/{sha}",
91
+ "languages_url": "https://api.github.com/repos/JHaals/testing/languages",
92
+ "stargazers_url": "https://api.github.com/repos/JHaals/testing/stargazers",
93
+ "contributors_url": "https://api.github.com/repos/JHaals/testing/contributors",
94
+ "subscribers_url": "https://api.github.com/repos/JHaals/testing/subscribers",
95
+ "subscription_url": "https://api.github.com/repos/JHaals/testing/subscription",
96
+ "commits_url": "https://api.github.com/repos/JHaals/testing/commits{/sha}",
97
+ "git_commits_url": "https://api.github.com/repos/JHaals/testing/git/commits{/sha}",
98
+ "comments_url": "https://api.github.com/repos/JHaals/testing/comments{/number}",
99
+ "issue_comment_url": "https://api.github.com/repos/JHaals/testing/issues/comments/{number}",
100
+ "contents_url": "https://api.github.com/repos/JHaals/testing/contents/{+path}",
101
+ "compare_url": "https://api.github.com/repos/JHaals/testing/compare/{base}...{head}",
102
+ "merges_url": "https://api.github.com/repos/JHaals/testing/merges",
103
+ "archive_url": "https://api.github.com/repos/JHaals/testing/{archive_format}{/ref}",
104
+ "downloads_url": "https://api.github.com/repos/JHaals/testing/downloads",
105
+ "issues_url": "https://api.github.com/repos/JHaals/testing/issues{/number}",
106
+ "pulls_url": "https://api.github.com/repos/JHaals/testing/pulls{/number}",
107
+ "milestones_url": "https://api.github.com/repos/JHaals/testing/milestones{/number}",
108
+ "notifications_url": "https://api.github.com/repos/JHaals/testing/notifications{?since,all,participating}",
109
+ "labels_url": "https://api.github.com/repos/JHaals/testing/labels{/name}",
110
+ "releases_url": "https://api.github.com/repos/JHaals/testing/releases{/id}",
111
+ "created_at": "2014-02-03T09:25:47Z",
112
+ "updated_at": "2014-02-16T20:25:07Z",
113
+ "pushed_at": "2014-02-16T20:25:06Z",
114
+ "git_url": "git://github.com/JHaals/testing.git",
115
+ "ssh_url": "git@github.com:JHaals/testing.git",
116
+ "clone_url": "https://github.com/JHaals/testing.git",
117
+ "svn_url": "https://github.com/JHaals/testing",
118
+ "homepage": null,
119
+ "size": 312,
120
+ "stargazers_count": 0,
121
+ "watchers_count": 0,
122
+ "language": null,
123
+ "has_issues": true,
124
+ "has_downloads": true,
125
+ "has_wiki": true,
126
+ "forks_count": 0,
127
+ "mirror_url": null,
128
+ "open_issues_count": 5,
129
+ "forks": 0,
130
+ "open_issues": 5,
131
+ "watchers": 0,
132
+ "default_branch": "master",
133
+ "master_branch": "master"
134
+ },
135
+ "sender": {
136
+ "login": "JHaals",
137
+ "id": 68980,
138
+ "avatar_url": "https://avatars.githubusercontent.com/u/68980",
139
+ "gravatar_id": "4e51de553ebfe258f038e040c8b25892",
140
+ "url": "https://api.github.com/users/JHaals",
141
+ "html_url": "https://github.com/JHaals",
142
+ "followers_url": "https://api.github.com/users/JHaals/followers",
143
+ "following_url": "https://api.github.com/users/JHaals/following{/other_user}",
144
+ "gists_url": "https://api.github.com/users/JHaals/gists{/gist_id}",
145
+ "starred_url": "https://api.github.com/users/JHaals/starred{/owner}{/repo}",
146
+ "subscriptions_url": "https://api.github.com/users/JHaals/subscriptions",
147
+ "organizations_url": "https://api.github.com/users/JHaals/orgs",
148
+ "repos_url": "https://api.github.com/users/JHaals/repos",
149
+ "events_url": "https://api.github.com/users/JHaals/events{/privacy}",
150
+ "received_events_url": "https://api.github.com/users/JHaals/received_events",
151
+ "type": "User",
152
+ "site_admin": false
153
+ }
154
+ }
@@ -0,0 +1,184 @@
1
+ {
2
+ "action": "created",
3
+ "issue": {
4
+ "url": "https://api.github.com/repos/JHaals/testing/issues/1",
5
+ "labels_url": "https://api.github.com/repos/JHaals/testing/issues/1/labels{/name}",
6
+ "comments_url": "https://api.github.com/repos/JHaals/testing/issues/1/comments",
7
+ "events_url": "https://api.github.com/repos/JHaals/testing/issues/1/events",
8
+ "html_url": "https://github.com/JHaals/testing/pull/1",
9
+ "id": 73231160,
10
+ "number": 1,
11
+ "title": "Added new fixture",
12
+ "user": {
13
+ "login": "JHaals",
14
+ "id": 568619,
15
+ "avatar_url": "https://avatars.githubusercontent.com/u/568619?v=3",
16
+ "gravatar_id": "",
17
+ "url": "https://api.github.com/users/JHaals",
18
+ "html_url": "https://github.com/JHaals",
19
+ "followers_url": "https://api.github.com/users/JHaals/followers",
20
+ "following_url": "https://api.github.com/users/JHaals/following{/other_user}",
21
+ "gists_url": "https://api.github.com/users/JHaals/gists{/gist_id}",
22
+ "starred_url": "https://api.github.com/users/JHaals/starred{/owner}{/repo}",
23
+ "subscriptions_url": "https://api.github.com/users/JHaals/subscriptions",
24
+ "organizations_url": "https://api.github.com/users/JHaals/orgs",
25
+ "repos_url": "https://api.github.com/users/JHaals/repos",
26
+ "events_url": "https://api.github.com/users/JHaals/events{/privacy}",
27
+ "received_events_url": "https://api.github.com/users/JHaals/received_events",
28
+ "type": "User",
29
+ "site_admin": false
30
+ },
31
+ "labels": [
32
+
33
+ ],
34
+ "state": "open",
35
+ "locked": false,
36
+ "assignee": null,
37
+ "milestone": null,
38
+ "comments": 2,
39
+ "created_at": "2015-05-05T07:06:01Z",
40
+ "updated_at": "2015-05-07T16:51:41Z",
41
+ "closed_at": null,
42
+ "pull_request": {
43
+ "url": "https://api.github.com/repos/JHaals/testing/pulls/1",
44
+ "html_url": "https://github.com/JHaals/testing/pull/1",
45
+ "diff_url": "https://github.com/JHaals/testing/pull/1.diff",
46
+ "patch_url": "https://github.com/JHaals/testing/pull/1.patch"
47
+ },
48
+ "body": ""
49
+ },
50
+ "comment": {
51
+ "url": "https://api.github.com/repos/JHaals/testing/issues/comments/99936656",
52
+ "html_url": "https://github.com/JHaals/testing/pull/1#issuecomment-99936656",
53
+ "issue_url": "https://api.github.com/repos/JHaals/testing/issues/1",
54
+ "id": 99936656,
55
+ "user": {
56
+ "login": "JHaals",
57
+ "id": 568619,
58
+ "avatar_url": "https://avatars.githubusercontent.com/u/568619?v=3",
59
+ "gravatar_id": "",
60
+ "url": "https://api.github.com/users/JHaals",
61
+ "html_url": "https://github.com/JHaals",
62
+ "followers_url": "https://api.github.com/users/JHaals/followers",
63
+ "following_url": "https://api.github.com/users/JHaals/following{/other_user}",
64
+ "gists_url": "https://api.github.com/users/JHaals/gists{/gist_id}",
65
+ "starred_url": "https://api.github.com/users/JHaals/starred{/owner}{/repo}",
66
+ "subscriptions_url": "https://api.github.com/users/JHaals/subscriptions",
67
+ "organizations_url": "https://api.github.com/users/JHaals/orgs",
68
+ "repos_url": "https://api.github.com/users/JHaals/repos",
69
+ "events_url": "https://api.github.com/users/JHaals/events{/privacy}",
70
+ "received_events_url": "https://api.github.com/users/JHaals/received_events",
71
+ "type": "User",
72
+ "site_admin": false
73
+ },
74
+ "created_at": "2015-05-07T16:51:41Z",
75
+ "updated_at": "2015-05-07T16:51:41Z",
76
+ "body": "nonsense!"
77
+ },
78
+ "repository": {
79
+ "id": 35081222,
80
+ "name": "tutter-sppuppet",
81
+ "full_name": "JHaals/testing",
82
+ "owner": {
83
+ "login": "JHaals",
84
+ "id": 568619,
85
+ "avatar_url": "https://avatars.githubusercontent.com/u/568619?v=3",
86
+ "gravatar_id": "",
87
+ "url": "https://api.github.com/users/JHaals",
88
+ "html_url": "https://github.com/JHaals",
89
+ "followers_url": "https://api.github.com/users/JHaals/followers",
90
+ "following_url": "https://api.github.com/users/JHaals/following{/other_user}",
91
+ "gists_url": "https://api.github.com/users/JHaals/gists{/gist_id}",
92
+ "starred_url": "https://api.github.com/users/JHaals/starred{/owner}{/repo}",
93
+ "subscriptions_url": "https://api.github.com/users/JHaals/subscriptions",
94
+ "organizations_url": "https://api.github.com/users/JHaals/orgs",
95
+ "repos_url": "https://api.github.com/users/JHaals/repos",
96
+ "events_url": "https://api.github.com/users/JHaals/events{/privacy}",
97
+ "received_events_url": "https://api.github.com/users/JHaals/received_events",
98
+ "type": "User",
99
+ "site_admin": false
100
+ },
101
+ "private": false,
102
+ "html_url": "https://github.com/JHaals/testing",
103
+ "description": "tutter action - code review without collaborator access",
104
+ "fork": true,
105
+ "url": "https://api.github.com/repos/JHaals/testing",
106
+ "forks_url": "https://api.github.com/repos/JHaals/testing/forks",
107
+ "keys_url": "https://api.github.com/repos/JHaals/testing/keys{/key_id}",
108
+ "collaborators_url": "https://api.github.com/repos/JHaals/testing/collaborators{/collaborator}",
109
+ "teams_url": "https://api.github.com/repos/JHaals/testing/teams",
110
+ "hooks_url": "https://api.github.com/repos/JHaals/testing/hooks",
111
+ "issue_events_url": "https://api.github.com/repos/JHaals/testing/issues/events{/number}",
112
+ "events_url": "https://api.github.com/repos/JHaals/testing/events",
113
+ "assignees_url": "https://api.github.com/repos/JHaals/testing/assignees{/user}",
114
+ "branches_url": "https://api.github.com/repos/JHaals/testing/branches{/branch}",
115
+ "tags_url": "https://api.github.com/repos/JHaals/testing/tags",
116
+ "blobs_url": "https://api.github.com/repos/JHaals/testing/git/blobs{/sha}",
117
+ "git_tags_url": "https://api.github.com/repos/JHaals/testing/git/tags{/sha}",
118
+ "git_refs_url": "https://api.github.com/repos/JHaals/testing/git/refs{/sha}",
119
+ "trees_url": "https://api.github.com/repos/JHaals/testing/git/trees{/sha}",
120
+ "statuses_url": "https://api.github.com/repos/JHaals/testing/statuses/{sha}",
121
+ "languages_url": "https://api.github.com/repos/JHaals/testing/languages",
122
+ "stargazers_url": "https://api.github.com/repos/JHaals/testing/stargazers",
123
+ "contributors_url": "https://api.github.com/repos/JHaals/testing/contributors",
124
+ "subscribers_url": "https://api.github.com/repos/JHaals/testing/subscribers",
125
+ "subscription_url": "https://api.github.com/repos/JHaals/testing/subscription",
126
+ "commits_url": "https://api.github.com/repos/JHaals/testing/commits{/sha}",
127
+ "git_commits_url": "https://api.github.com/repos/JHaals/testing/git/commits{/sha}",
128
+ "comments_url": "https://api.github.com/repos/JHaals/testing/comments{/number}",
129
+ "issue_comment_url": "https://api.github.com/repos/JHaals/testing/issues/comments{/number}",
130
+ "contents_url": "https://api.github.com/repos/JHaals/testing/contents/{+path}",
131
+ "compare_url": "https://api.github.com/repos/JHaals/testing/compare/{base}...{head}",
132
+ "merges_url": "https://api.github.com/repos/JHaals/testing/merges",
133
+ "archive_url": "https://api.github.com/repos/JHaals/testing/{archive_format}{/ref}",
134
+ "downloads_url": "https://api.github.com/repos/JHaals/testing/downloads",
135
+ "issues_url": "https://api.github.com/repos/JHaals/testing/issues{/number}",
136
+ "pulls_url": "https://api.github.com/repos/JHaals/testing/pulls{/number}",
137
+ "milestones_url": "https://api.github.com/repos/JHaals/testing/milestones{/number}",
138
+ "notifications_url": "https://api.github.com/repos/JHaals/testing/notifications{?since,all,participating}",
139
+ "labels_url": "https://api.github.com/repos/JHaals/testing/labels{/name}",
140
+ "releases_url": "https://api.github.com/repos/JHaals/testing/releases{/id}",
141
+ "created_at": "2015-05-05T06:08:56Z",
142
+ "updated_at": "2015-05-05T06:08:57Z",
143
+ "pushed_at": "2015-05-05T07:06:01Z",
144
+ "git_url": "git://github.com/JHaals/testing.git",
145
+ "ssh_url": "git@github.com:JHaals/testing.git",
146
+ "clone_url": "https://github.com/JHaals/testing.git",
147
+ "svn_url": "https://github.com/JHaals/testing",
148
+ "homepage": null,
149
+ "size": 181,
150
+ "stargazers_count": 0,
151
+ "watchers_count": 0,
152
+ "language": "Ruby",
153
+ "has_issues": false,
154
+ "has_downloads": true,
155
+ "has_wiki": true,
156
+ "has_pages": false,
157
+ "forks_count": 0,
158
+ "mirror_url": null,
159
+ "open_issues_count": 1,
160
+ "forks": 0,
161
+ "open_issues": 1,
162
+ "watchers": 0,
163
+ "default_branch": "master"
164
+ },
165
+ "sender": {
166
+ "login": "JHaals",
167
+ "id": 568619,
168
+ "avatar_url": "https://avatars.githubusercontent.com/u/568619?v=3",
169
+ "gravatar_id": "",
170
+ "url": "https://api.github.com/users/JHaals",
171
+ "html_url": "https://github.com/JHaals",
172
+ "followers_url": "https://api.github.com/users/JHaals/followers",
173
+ "following_url": "https://api.github.com/users/JHaals/following{/other_user}",
174
+ "gists_url": "https://api.github.com/users/JHaals/gists{/gist_id}",
175
+ "starred_url": "https://api.github.com/users/JHaals/starred{/owner}{/repo}",
176
+ "subscriptions_url": "https://api.github.com/users/JHaals/subscriptions",
177
+ "organizations_url": "https://api.github.com/users/JHaals/orgs",
178
+ "repos_url": "https://api.github.com/users/JHaals/repos",
179
+ "events_url": "https://api.github.com/users/JHaals/events{/privacy}",
180
+ "received_events_url": "https://api.github.com/users/JHaals/received_events",
181
+ "type": "User",
182
+ "site_admin": false
183
+ }
184
+ }
@@ -48,7 +48,7 @@
48
48
  "repository": {
49
49
  "id": 16474769,
50
50
  "name": "testing",
51
- "full_name": "JHaals/testing",
51
+ "full_name": "JHaals\/testing",
52
52
  "owner": {
53
53
  "login": "JHaals",
54
54
  "id": 68980,
@@ -151,4 +151,4 @@
151
151
  "type": "User",
152
152
  "site_admin": false
153
153
  }
154
- }
154
+ }
@@ -1,32 +1,88 @@
1
1
  require 'spec_helper'
2
2
  require 'json'
3
3
 
4
- describe 'tutter' do
4
+ describe 'Tutter' do
5
+ it 'Complains about missing Github header' do
6
+ post '/', JSON.generate(repository: { full_name: '404' })
7
+ expect(last_response.body).to match(/Invalid request/)
8
+ expect(last_response.status).to be 500
9
+ end
10
+
11
+ it 'Complains about missing project in settings' do
12
+ post '/', JSON.generate(repository: { full_name: '404' }), 'HTTP_X_GITHUB_EVENT' => 'fake'
13
+ expect(last_response.body).to match(/Project does not exist in tutter.conf/)
14
+ expect(last_response.status).to be 404
15
+ end
16
+
17
+ it 'Complains about missing repository name in json payload' do
18
+ post '/', JSON.generate(repository: {}), 'HTTP_X_GITHUB_EVENT' => 'issue_comment'
19
+ expect(last_response.body).to match(/Bad request/)
20
+ expect(last_response.status).to be 400
21
+ end
22
+
23
+ it 'Complains about event not configured for project' do
24
+ post '/', JSON.generate(repository: { full_name: 'JHaals/testing' }), 'HTTP_X_GITHUB_EVENT' => 'fake'
25
+ expect(last_response.body).to match(/No Actions for fake in tutter.conf/)
26
+ expect(last_response.status).to be 404
27
+ end
5
28
 
6
- it 'expect complain about missing project in settings' do
7
- post '/', params=JSON.generate({'repository' => {'full_name' => '404'}}), {'HTTP_X_GITHUB_EVENT' => 'fake'}
8
- expect { last_response.body match /Project does not exist in tutter.conf/ }
9
- expect { last_response.status == 404 }
29
+ it 'Complains about POST data not being JSON' do
30
+ post '/', { broken: 'data' }, 'HTTP_X_GITHUB_EVENT' => 'fake'
31
+ expect(last_response.body).to match(/POST data is not JSON/)
32
+ expect(last_response.status).to be 400
10
33
  end
11
34
 
12
- it 'expect complain about POST data not being JSON' do
13
- post '/', params={'broken' => 'data'}, {'HTTP_X_GITHUB_EVENT' => 'fake'}
14
- expect { last_response.body match /POST data is not JSON/ }
15
- expect { last_response.status == 400 }
35
+ it 'Responds to Github ping event' do
36
+ post '/', JSON.generate({}), 'HTTP_X_GITHUB_EVENT' => 'ping'
37
+ expect(last_response.body).to match(/Tutter likes this hook!/)
38
+ expect(last_response.status).to be 200
16
39
  end
17
40
 
18
- it 'expect return documentation URL' do
41
+ it 'Returns documentation URL' do
19
42
  get '/'
20
- expect { last_response.body match /Source code and documentation/ }
43
+ expect(last_response.body).to match(/Source code and documentation/)
21
44
  end
22
45
 
46
+ it 'Retruns only one response in repsonses due to first action failiure' do
47
+ data = IO.read('spec/fixtures/new_issue.json')
48
+ post '/', data, 'HTTP_X_GITHUB_EVENT' => 'issue'
49
+ body = JSON.parse(last_response.body)
50
+ expect(body["responses"]["thanks"]["message"]).to match(/Authorization to JHaals\/testing failed, please verify your access token/)
51
+ expect(body["responses"].length).to be(1)
52
+ expect(last_response.status).to be 401
53
+ end
23
54
  end
24
55
 
25
- describe 'tutter Hello action' do
26
- it 'expect complain about invalid credentials' do
56
+ describe 'Tutter Thanks action' do
57
+ it 'Complains about invalid credentials' do
27
58
  data = IO.read('spec/fixtures/new_issue.json')
28
- post '/', params=data, {'HTTP_X_GITHUB_EVENT' => 'fake'}
29
- expect { last_response.body match /Authorization to JHaals\/testing failed, please verify your access token/ }
30
- expect { last_response.status == 401 }
59
+ post '/', data, 'HTTP_X_GITHUB_EVENT' => 'issue'
60
+ body = JSON.parse(last_response.body)
61
+ expect(body["responses"]["thanks"]["message"]).to match(/Authorization to JHaals\/testing failed, please verify your access token/)
62
+ expect(last_response.status).to be 401
63
+ end
64
+ it 'Will not thank user for anything else that opening an issue' do
65
+ data = IO.read('spec/fixtures/closed_issue.json')
66
+ post '/', data, 'HTTP_X_GITHUB_EVENT' => 'issue'
67
+ body = JSON.parse(last_response.body)
68
+ expect(body["responses"]["thanks"]["message"]).to match(/Web hook from GitHub for JHaals\/testing does not have status opened. We don't thank people for closing issues/)
69
+ expect(last_response.status).to be 200
31
70
  end
32
- end
71
+ end
72
+
73
+ describe 'Tutter Sassy action' do
74
+ it 'Complains about invalid credentials' do
75
+ data = IO.read('spec/fixtures/issue_comment.json')
76
+ post '/', data, 'HTTP_X_GITHUB_EVENT' => 'issue_comment'
77
+ body = JSON.parse(last_response.body)
78
+ expect(body["responses"]["sassy"]["message"]).to match(/Authorization to JHaals\/testing failed, please verify your access token/)
79
+ expect(last_response.status).to be 401
80
+ end
81
+ it 'Fails gracefully when it dosent know what to do' do
82
+ data = IO.read('spec/fixtures/closed_issue.json')
83
+ post '/', data, 'HTTP_X_GITHUB_EVENT' => 'issue_comment'
84
+ body = JSON.parse(last_response.body)
85
+ expect(body["responses"]["sassy"]["message"]).to match(/Web hook from GitHub for JHaals\/testing does not have status created. Dont know what to do./)
86
+ expect(last_response.status).to be 200
87
+ end
88
+ end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = 'tutter'
4
- s.version = '0.0.5'
4
+ s.version = '0.0.6'
5
5
  s.author = 'Johan Haals'
6
6
  s.email = ['johan.haals@gmail.com']
7
7
  s.homepage = 'https://github.com/jhaals/tutter'
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.required_ruby_version = '>= 1.8.7'
17
17
  s.add_runtime_dependency 'sinatra', '~> 1.4'
18
- s.add_runtime_dependency 'octokit', '~> 3.2'
18
+ s.add_runtime_dependency 'octokit', '~> 4.3'
19
19
 
20
20
  s.add_development_dependency 'sinatra-contrib', '~> 1.4'
21
21
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tutter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johan Haals
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-30 00:00:00.000000000 Z
11
+ date: 2017-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.2'
33
+ version: '4.3'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.2'
40
+ version: '4.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sinatra-contrib
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -60,7 +60,6 @@ executables: []
60
60
  extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
- - ".gemspec"
64
63
  - ".gitignore"
65
64
  - ".travis.yml"
66
65
  - Gemfile
@@ -69,10 +68,14 @@ files:
69
68
  - conf/tutter.yaml
70
69
  - lib/tutter.rb
71
70
  - lib/tutter/action.rb
71
+ - lib/tutter/action/sassy.rb
72
72
  - lib/tutter/action/thanks.rb
73
+ - spec/fixtures/closed_issue.json
74
+ - spec/fixtures/issue_comment.json
73
75
  - spec/fixtures/new_issue.json
74
76
  - spec/spec_helper.rb
75
77
  - spec/tutter_spec.rb
78
+ - tutter.gemspec
76
79
  homepage: https://github.com/jhaals/tutter
77
80
  licenses:
78
81
  - Apache 2.0
@@ -94,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
97
  version: '0'
95
98
  requirements: []
96
99
  rubyforge_project:
97
- rubygems_version: 2.2.2
100
+ rubygems_version: 2.6.11
98
101
  signing_key:
99
102
  specification_version: 4
100
103
  summary: Plugin based Github robot