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 +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
|
[![Build Status](https://travis-ci.org/jhaals/tutter.png?branch=master)](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
|
![img](http://f.cl.ly/items/1k111I3H1N0L3008301c/tutter.png)
|
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
|