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 +4 -4
- data/.travis.yml +0 -2
- data/Gemfile +2 -2
- data/README.md +12 -19
- data/conf/tutter.yaml +7 -2
- data/lib/tutter.rb +58 -43
- data/lib/tutter/action/sassy.rb +36 -0
- data/spec/fixtures/closed_issue.json +154 -0
- data/spec/fixtures/issue_comment.json +184 -0
- data/spec/fixtures/new_issue.json +2 -2
- data/spec/tutter_spec.rb +73 -17
- data/{.gemspec → tutter.gemspec} +2 -2
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2fd4ec7bd3451798835a4eda2b8840f7cc7c8f28
|
4
|
+
data.tar.gz: cbece5fa4f7c061acae900228c671c1e35a0ffa1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a3ba61909d5102036fa717f2e514780b9a07c2efb8f0759a14ec427a8c7442e8d560db3900d5e29def4a19a5f0936fab3b47ab409500fb916944681b78543a9
|
7
|
+
data.tar.gz: 49a1500844a2435bd1decb5aef68bec358c080cd8ac2836ada5462f0f2adba5d4ef5289100a8f53687ac0334287acd52a60073146e8a57cb9997bdbf5cc7db02
|
data/.travis.yml
CHANGED
@@ -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.
|
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
|
[](https://travis-ci.org/JHaals/tutter)
|
3
3
|
|
4
|
-
Tutter is a
|
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
|
-
|
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/
|
22
|
-
* `access_token` -
|
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
|
-
* `
|
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
|
-
###
|
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
|
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
|
28
|
+
Example on how the `thanks` action looks like. Tutter listens for `issue` events and posts back with a greeting.
|
34
29
|

|
35
30
|
|
36
31
|
## Build custom action
|
37
32
|
|
38
|
-
|
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!
|
data/conf/tutter.yaml
CHANGED
@@ -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
|
-
|
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
|
-
|
data/lib/tutter.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
require '
|
1
|
+
require 'json'
|
2
2
|
require 'octokit'
|
3
|
-
require 'yaml'
|
4
3
|
require 'sinatra'
|
4
|
+
require 'thin'
|
5
5
|
require 'tutter/action'
|
6
|
-
require '
|
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'] ||
|
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
|
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
|
-
|
37
|
+
error(404, 'Project does not exist in tutter.conf')
|
31
38
|
end
|
32
39
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
47
|
+
def octokit_client(config)
|
39
48
|
Octokit.configure do |c|
|
40
|
-
c.api_endpoint =
|
41
|
-
c.web_endpoint =
|
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
|
45
|
-
access_token = ENV[
|
54
|
+
if config['access_token_env_var']
|
55
|
+
access_token = ENV[config['access_token_env_var']] || ''
|
46
56
|
else
|
47
|
-
access_token =
|
57
|
+
access_token = config['access_token'] || ''
|
48
58
|
end
|
49
59
|
|
50
|
-
|
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
|
-
|
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
|
-
|
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 ==
|
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
|
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
|
-
|
86
|
-
|
87
|
-
if
|
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
|
-
|
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 == $
|
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
|
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
|
+
}
|
data/spec/tutter_spec.rb
CHANGED
@@ -1,32 +1,88 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'json'
|
3
3
|
|
4
|
-
describe '
|
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 '
|
7
|
-
post '/',
|
8
|
-
expect
|
9
|
-
expect
|
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 '
|
13
|
-
post '/',
|
14
|
-
expect
|
15
|
-
expect
|
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 '
|
41
|
+
it 'Returns documentation URL' do
|
19
42
|
get '/'
|
20
|
-
expect
|
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 '
|
26
|
-
it '
|
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 '/',
|
29
|
-
|
30
|
-
expect
|
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
|
data/{.gemspec → tutter.gemspec}
RENAMED
@@ -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.
|
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
|
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.
|
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:
|
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
|
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
|
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.
|
100
|
+
rubygems_version: 2.6.11
|
98
101
|
signing_key:
|
99
102
|
specification_version: 4
|
100
103
|
summary: Plugin based Github robot
|