tutter 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gemspec +2 -2
- data/.travis.yml +4 -0
- data/Gemfile +10 -2
- data/README.md +11 -12
- data/Rakefile +4 -0
- data/lib/tutter.rb +51 -20
- data/lib/tutter/action.rb +2 -2
- data/lib/tutter/action/thanks.rb +16 -5
- data/spec/fixtures/new_issue.json +154 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/tutter_spec.rb +32 -0
- metadata +19 -16
- data/bin/tutter +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 088744f1c591bb26d27a3185ff95e5005c79c6b9
|
4
|
+
data.tar.gz: fa5ceaf606dda9364f705f6559a0b4d7d54ef416
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75e9f1d02da92ca932ccab2a97698aa6f77fada6aff141154afe8ad7872fbccd43e35fb21cfb6aeb9778fd3f439f4304202bf14d2bf7d6b47dfdf5768a58b6ff
|
7
|
+
data.tar.gz: 43064843cd32e3542d7ce6d48d842e57d474aa80cc78b5f676b0a4f7781cc48d903fe95c2fc19932e51be8f5a94c8e4846cf01cf7cabf66b2dd24c7746627ca8
|
data/.gemspec
CHANGED
@@ -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.2'
|
5
5
|
s.author = 'Johan Haals'
|
6
6
|
s.email = ['johan.haals@gmail.com']
|
7
7
|
s.homepage = 'https://github.com/jhaals/tutter'
|
@@ -15,6 +15,6 @@ 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.4'
|
18
|
-
s.add_runtime_dependency 'octokit', '~> 2.
|
18
|
+
s.add_runtime_dependency 'octokit', '~> 3.2.0'
|
19
19
|
end
|
20
20
|
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,9 +1,17 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gem 'octokit', '~> 2.
|
3
|
+
gem 'octokit', '~> 3.2.0'
|
4
4
|
gem 'sinatra', '~> 1.4.4'
|
5
5
|
|
6
|
-
group :
|
6
|
+
group :development do
|
7
|
+
gem 'sinatra-reloader'
|
8
|
+
end
|
9
|
+
|
10
|
+
group :test do
|
7
11
|
gem 'sinatra-contrib'
|
8
12
|
gem 'tutter', :path => '.'
|
13
|
+
gem 'rake'
|
14
|
+
gem 'rack'
|
15
|
+
gem 'rspec'
|
16
|
+
gem 'json'
|
9
17
|
end
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# Tutter - Plugin based Github robot
|
2
|
+
[![Build Status](https://travis-ci.org/JHaals/tutter.png?branch=master)](https://travis-ci.org/JHaals/tutter)
|
3
|
+
|
2
4
|
Tutter is a web app that trigger actions based on Github events(push, pull_reqeust, release, issue, ...)
|
3
5
|
|
4
6
|
# Features
|
@@ -23,21 +25,17 @@ Let's install the `thanks` action that thank anyone that creates an issue in you
|
|
23
25
|
* `action` - action you wish to use for the project
|
24
26
|
* `action_settings` - whatever settings your action require
|
25
27
|
|
26
|
-
### Create the Github
|
27
|
-
|
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
|
28
30
|
|
29
|
-
|
31
|
+
https://github.com/ORG/PROJECT/settings/hooks/new
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
--access-token <github_api_token> \
|
34
|
-
--github-web-url https://github.com \
|
35
|
-
--github-api-endpoint https://api.github.com \
|
36
|
-
--events issues
|
33
|
+
Example of how the `thanks` demo-action look like. Tutter listen for issue events and posts back with a greeting.
|
34
|
+
![img](http://f.cl.ly/items/1k111I3H1N0L3008301c/tutter.png)
|
37
35
|
|
38
36
|
## Build custom action
|
39
37
|
|
40
|
-
|
38
|
+
See [thanks action](https://github.com/jhaals/tutter/blob/master/lib/tutter/action/thanks.rb)
|
41
39
|
|
42
40
|
#####Required methods and their arguments
|
43
41
|
|
@@ -46,6 +44,7 @@ Another example action [github.com/jhaals/tutter-sppuppet](https://github.com/jh
|
|
46
44
|
settings - contains a hash of action specific settings
|
47
45
|
client - Used to access the github api, all authentication is already done by tutter
|
48
46
|
project - Project name, eg jhaals/tutter
|
47
|
+
event - Event type
|
49
48
|
data - POST data that github send when a hook is triggered
|
50
49
|
|
51
50
|
`run` - Run action
|
@@ -53,7 +52,7 @@ Another example action [github.com/jhaals/tutter-sppuppet](https://github.com/jh
|
|
53
52
|
Tutter uses [octokit.rb](https://github.com/octokit/octokit.rb) to communicate with the Github [API](http://developer.github.com/v3/)
|
54
53
|
|
55
54
|
### Features to implement
|
56
|
-
* Add web hooks in Github automatically
|
57
55
|
* Support multiple actions per project
|
58
56
|
* Authenticate as a Github application
|
59
|
-
* Features your're missing (please contribute)
|
57
|
+
* Features your're missing (please contribute)
|
58
|
+
* Tests!
|
data/Rakefile
ADDED
data/lib/tutter.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'rubygems'
|
1
2
|
require 'octokit'
|
2
3
|
require 'yaml'
|
3
4
|
require 'sinatra'
|
@@ -5,15 +6,20 @@ require 'tutter/action'
|
|
5
6
|
require 'json'
|
6
7
|
|
7
8
|
class Tutter < Sinatra::Base
|
9
|
+
|
10
|
+
configure do
|
11
|
+
set :config_path, ENV['TUTTER_CONFIG_PATH'] || "conf/tutter.yaml"
|
12
|
+
set :config, YAML.load_file(settings.config_path)
|
13
|
+
end
|
14
|
+
|
8
15
|
configure :development do
|
9
16
|
require 'sinatra/reloader'
|
10
17
|
register Sinatra::Reloader
|
11
|
-
set :config, YAML.load_file('conf/tutter.yaml')
|
12
18
|
set :bind, '0.0.0.0'
|
13
19
|
end
|
14
20
|
|
15
|
-
configure :
|
16
|
-
set :
|
21
|
+
configure :test do
|
22
|
+
set :bind, '0.0.0.0'
|
17
23
|
end
|
18
24
|
|
19
25
|
# Return project settings from config
|
@@ -24,13 +30,10 @@ class Tutter < Sinatra::Base
|
|
24
30
|
false
|
25
31
|
end
|
26
32
|
|
27
|
-
|
28
|
-
|
29
|
-
data = JSON.parse request.body.read
|
30
|
-
project = data['repository']['full_name']
|
33
|
+
def try_action event, data
|
34
|
+
project = data['repository']['full_name'] || error(400, 'Bad request')
|
31
35
|
|
32
|
-
conf = get_project_settings(project)
|
33
|
-
return 'Project does not exist in tutter.conf' unless conf
|
36
|
+
conf = get_project_settings(project) || error(404, 'Project does not exist in tutter.conf')
|
34
37
|
|
35
38
|
# Setup octokit endpoints
|
36
39
|
Octokit.configure do |c|
|
@@ -38,26 +41,54 @@ class Tutter < Sinatra::Base
|
|
38
41
|
c.web_endpoint = conf['github_site']
|
39
42
|
end
|
40
43
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
return "Authorization to #{project} failed, please verify your access token"
|
46
|
-
rescue Octokit::TooManyLoginAttempts
|
47
|
-
return "Account for #{project} has been temporary locked down due to to many failed login attempts"
|
44
|
+
if conf['access_token_env_var']
|
45
|
+
access_token = ENV[conf['access_token_env_var']] || ''
|
46
|
+
else
|
47
|
+
access_token = conf['access_token'] || ''
|
48
48
|
end
|
49
49
|
|
50
|
+
client = Octokit::Client.new :access_token => access_token
|
51
|
+
|
50
52
|
# Load action
|
51
53
|
action = Action.create(conf['action'],
|
52
54
|
conf['action_settings'],
|
53
55
|
client,
|
54
56
|
project,
|
57
|
+
event,
|
55
58
|
data)
|
56
59
|
|
57
|
-
action.run
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
status_code, message = action.run
|
61
|
+
|
62
|
+
return status_code, message
|
63
|
+
end
|
64
|
+
|
65
|
+
post '/' do
|
66
|
+
event = env['HTTP_X_GITHUB_EVENT']
|
67
|
+
|
68
|
+
unless event
|
69
|
+
error(500, "Invalid request")
|
70
|
+
end
|
71
|
+
|
72
|
+
# Get a 200 OK message in the Github webhook history
|
73
|
+
# Previously this showed an error.
|
74
|
+
if event == "ping"
|
75
|
+
return 200, "Tutter likes this hook!"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Github send data in JSON format, parse it!
|
79
|
+
begin
|
80
|
+
data = JSON.parse request.body.read
|
81
|
+
rescue JSON::ParserError
|
82
|
+
error(400, 'POST data is not JSON')
|
83
|
+
end
|
84
|
+
|
85
|
+
# Check actions with repo
|
86
|
+
|
87
|
+
if data['repository']
|
88
|
+
return try_action(event, data)
|
89
|
+
end
|
90
|
+
|
91
|
+
error(400, "Unsupported request: #{event}")
|
61
92
|
end
|
62
93
|
|
63
94
|
get '/' do
|
data/lib/tutter/action.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
class Action
|
2
|
-
def self.create(action, settings, client, project, data)
|
2
|
+
def self.create(action, settings, client, project, event, data)
|
3
3
|
begin
|
4
4
|
require "tutter/action/#{action.downcase}"
|
5
5
|
rescue LoadError => e
|
6
6
|
raise "Unsupported action #{action}: #{e}"
|
7
7
|
end
|
8
8
|
class_name = action.split("_").map {|v| v.capitalize }.join
|
9
|
-
const_get(class_name).new settings, client, project, data
|
9
|
+
const_get(class_name).new settings, client, project, data, event
|
10
10
|
end
|
11
11
|
end
|
data/lib/tutter/action/thanks.rb
CHANGED
@@ -2,23 +2,34 @@
|
|
2
2
|
# Thank the person who submit an issue
|
3
3
|
|
4
4
|
class Thanks
|
5
|
-
def initialize(settings, client, project, data)
|
5
|
+
def initialize(settings, client, project, data, event)
|
6
6
|
@settings = settings # action specific settings
|
7
7
|
@client = client # Octokit client
|
8
8
|
@project = project # project name
|
9
|
+
@event = event # Github event
|
9
10
|
@data = data
|
10
11
|
end
|
11
12
|
|
12
13
|
def run
|
13
14
|
# Only trigger if a new issue is created
|
14
|
-
|
15
|
-
|
15
|
+
unless @data['action'] == 'opened'
|
16
|
+
return 200, "Web hook from GitHub for #{@project} does not have status opened. We don't thank people for closing issues"
|
17
|
+
end
|
16
18
|
issue = @data['issue']['number']
|
17
19
|
submitter = @data['issue']['user']['login']
|
18
20
|
comment = "@#{submitter} thanks for submitting this issue!"
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
+
begin
|
23
|
+
@client.add_comment(@project, issue, comment)
|
24
|
+
return 200, "Commented!"
|
25
|
+
rescue Octokit::NotFound
|
26
|
+
return 404, "Octokit returned 404, this could be an issue with your access token"
|
27
|
+
rescue Octokit::Unauthorized
|
28
|
+
return 401, "Authorization to #{@project} failed, please verify your access token"
|
29
|
+
rescue Octokit::TooManyLoginAttempts
|
30
|
+
return 429, "Account for #{@project} has been temporary locked down due to to many failed login attempts"
|
31
|
+
end
|
32
|
+
# TODO - Verify return data from @client.add_comment
|
22
33
|
end
|
23
34
|
|
24
35
|
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
{
|
2
|
+
"action": "opened",
|
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": "open",
|
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
|
+
}
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../lib/tutter.rb')
|
2
|
+
|
3
|
+
require 'sinatra'
|
4
|
+
require 'rack/test'
|
5
|
+
Tutter.environment = :development
|
6
|
+
set :run, false
|
7
|
+
set :raise_errors, true
|
8
|
+
set :logging, true
|
9
|
+
|
10
|
+
def app
|
11
|
+
Tutter
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.include Rack::Test::Methods
|
16
|
+
end
|
data/spec/tutter_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
describe 'tutter' do
|
5
|
+
|
6
|
+
it 'should complain about missing project in settings' do
|
7
|
+
post '/', params=JSON.generate({'repository' => {'full_name' => '404'}}), {'HTTP_X_GITHUB_EVENT' => 'fake'}
|
8
|
+
last_response.body.should match /Project does not exist in tutter.conf/
|
9
|
+
last_response.status.should == 404
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should complain about POST data not being JSON' do
|
13
|
+
post '/', params={'broken' => 'data'}, {'HTTP_X_GITHUB_EVENT' => 'fake'}
|
14
|
+
last_response.body.should match /POST data is not JSON/
|
15
|
+
last_response.status.should == 400
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return documentation URL' do
|
19
|
+
get '/'
|
20
|
+
last_response.body.should match /Source code and documentation/
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'tutter Hello action' do
|
26
|
+
it 'should complain about invalid credentials' do
|
27
|
+
data = IO.read('spec/fixtures/new_issue.json')
|
28
|
+
post '/', params=data, {'HTTP_X_GITHUB_EVENT' => 'fake'}
|
29
|
+
last_response.body.should match /Authorization to JHaals\/testing failed, please verify your access token/
|
30
|
+
last_response.status.should == 401
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -1,61 +1,64 @@
|
|
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.2
|
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: 2015-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.4.4
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.4.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: octokit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 3.2.0
|
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: 2.
|
40
|
+
version: 3.2.0
|
41
41
|
description: Tutter is a web app that trigger actions based on Github events(push,
|
42
42
|
pull_reqeust, release, issue, ...)
|
43
43
|
email:
|
44
44
|
- johan.haals@gmail.com
|
45
|
-
executables:
|
46
|
-
- tutter
|
45
|
+
executables: []
|
47
46
|
extensions: []
|
48
47
|
extra_rdoc_files: []
|
49
48
|
files:
|
50
|
-
- .gemspec
|
51
|
-
- .gitignore
|
49
|
+
- ".gemspec"
|
50
|
+
- ".gitignore"
|
51
|
+
- ".travis.yml"
|
52
52
|
- Gemfile
|
53
53
|
- README.md
|
54
|
-
-
|
54
|
+
- Rakefile
|
55
55
|
- conf/tutter.yaml
|
56
56
|
- lib/tutter.rb
|
57
57
|
- lib/tutter/action.rb
|
58
58
|
- lib/tutter/action/thanks.rb
|
59
|
+
- spec/fixtures/new_issue.json
|
60
|
+
- spec/spec_helper.rb
|
61
|
+
- spec/tutter_spec.rb
|
59
62
|
homepage: https://github.com/jhaals/tutter
|
60
63
|
licenses:
|
61
64
|
- Apache 2.0
|
@@ -67,17 +70,17 @@ require_paths:
|
|
67
70
|
- conf
|
68
71
|
required_ruby_version: !ruby/object:Gem::Requirement
|
69
72
|
requirements:
|
70
|
-
- -
|
73
|
+
- - ">="
|
71
74
|
- !ruby/object:Gem::Version
|
72
75
|
version: 1.8.7
|
73
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
77
|
requirements:
|
75
|
-
- -
|
78
|
+
- - ">="
|
76
79
|
- !ruby/object:Gem::Version
|
77
80
|
version: '0'
|
78
81
|
requirements: []
|
79
82
|
rubyforge_project:
|
80
|
-
rubygems_version: 2.
|
83
|
+
rubygems_version: 2.2.2
|
81
84
|
signing_key:
|
82
85
|
specification_version: 4
|
83
86
|
summary: Plugin based Github robot
|
data/bin/tutter
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'optparse'
|
3
|
-
require 'octokit'
|
4
|
-
|
5
|
-
options = {}
|
6
|
-
|
7
|
-
OptionParser.new do |opts|
|
8
|
-
opts.banner = "Usage: tutter --project [project] [options]"
|
9
|
-
opts.on("-p", "--project [PROJECT]", "Github project name (jhaals/tutter)") do |p|
|
10
|
-
options[:project] = p
|
11
|
-
end
|
12
|
-
opts.on("-e", "--events [EVENTS]", "Github events that will trigger tutter") do |e|
|
13
|
-
options[:events] = e
|
14
|
-
end
|
15
|
-
opts.on("-u", "--url [URL]", "URL to the tutter service") do |u|
|
16
|
-
options[:url] = u
|
17
|
-
end
|
18
|
-
opts.on("-t", "--access-token [TOKEN]", "Github access token") do |t|
|
19
|
-
options[:access_token] = t
|
20
|
-
end
|
21
|
-
opts.on("--github-api-endpoint [api-endpoint]", "Github API endpoint") do |t|
|
22
|
-
options[:api_endpoint] = t
|
23
|
-
end
|
24
|
-
opts.on("--github-web-url [GITHUBWEBSITE]", "Github website url") do |t|
|
25
|
-
options[:base_url] = t
|
26
|
-
end
|
27
|
-
end.parse!
|
28
|
-
|
29
|
-
if options[:project].nil?
|
30
|
-
puts '--project required'
|
31
|
-
exit 1
|
32
|
-
end
|
33
|
-
|
34
|
-
if options[:url].nil?
|
35
|
-
puts '--url required'
|
36
|
-
exit 1
|
37
|
-
end
|
38
|
-
|
39
|
-
if options[:access_token].nil?
|
40
|
-
puts '--access-token required'
|
41
|
-
exit 1
|
42
|
-
end
|
43
|
-
|
44
|
-
if options[:base_url].nil?
|
45
|
-
puts '--github-web-url required'
|
46
|
-
exit 1
|
47
|
-
end
|
48
|
-
|
49
|
-
if options[:api_endpoint].nil?
|
50
|
-
puts '--github-api-endpoint required'
|
51
|
-
exit 1
|
52
|
-
end
|
53
|
-
|
54
|
-
Octokit.configure do |c|
|
55
|
-
c.api_endpoint = options[:api_endpoint]
|
56
|
-
c.web_endpoint = options[:base_url]
|
57
|
-
end
|
58
|
-
|
59
|
-
client = Octokit::Client.new :access_token => options[:access_token]
|
60
|
-
client.login
|
61
|
-
|
62
|
-
p client.create_hook(
|
63
|
-
options[:project],
|
64
|
-
'web',
|
65
|
-
{
|
66
|
-
:url => options[:url],
|
67
|
-
:content_type => 'json'
|
68
|
-
},
|
69
|
-
{
|
70
|
-
:events => options[:events].split(','),
|
71
|
-
:active => true
|
72
|
-
}
|
73
|
-
)
|
74
|
-
|
75
|
-
|