tutter 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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