grudge 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.txt +2 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +108 -0
- data/Rakefile +18 -0
- data/TODO.markdown +27 -0
- data/bin/grudge +55 -0
- data/config.ru +13 -0
- data/config/grudge.yml +31 -0
- data/grudge.gemspec +64 -0
- data/lib/boot.rb +8 -0
- data/lib/grudge.rb +73 -0
- data/lib/grudge/base.rb +16 -0
- data/lib/grudge/config.rb +23 -0
- data/lib/grudge/database.rb +15 -0
- data/lib/grudge/extensions.rb +18 -0
- data/lib/grudge/helpers.rb +28 -0
- data/lib/grudge/repository.rb +47 -0
- data/lib/models/commit.rb +55 -0
- data/lib/models/vote.rb +16 -0
- data/lib/views/application.haml +26 -0
- data/lib/views/application.sass +110 -0
- data/lib/views/index.haml +28 -0
- data/lib/views/not_found.haml +1 -0
- data/lib/views/show.haml +25 -0
- data/test/commit_test.rb +226 -0
- data/test/config_test.rb +18 -0
- data/test/grudge_test.rb +193 -0
- data/test/model_factory.rb +30 -0
- data/test/repository_test.rb +118 -0
- data/test/test_helper.rb +46 -0
- data/test/vote_test.rb +65 -0
- metadata +165 -0
data/HISTORY.txt
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Justin Knowlden
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# Grudge
|
2
|
+
|
3
|
+
Grudge is a stand-alone system, which means you run it on your own, that watches the comments of some git repository and provides a web interface to allow people to rate the comments.
|
4
|
+
|
5
|
+
## Why would someone want to do this?
|
6
|
+
|
7
|
+
In my experience, code commit comments have been very funny; or at least very good reads. It's kind of an insight into some of the programmer's minds. At one point, I was scouring the commit comments and sending a daily email of the ones I thought were funny. The emails were well received, so I figured there must be something to this.
|
8
|
+
|
9
|
+
Thus, the goals are:
|
10
|
+
|
11
|
+
1. Make people laugh
|
12
|
+
2. Inform others - besides those in development - of the day-to-day
|
13
|
+
|
14
|
+
I also hope that something like this will make for better commit comments; since you know you are now being watched ... and judged.
|
15
|
+
|
16
|
+
## Why is it called Grudge?
|
17
|
+
|
18
|
+
Well, basically I typed 'rate' into Apple's thesaurus app and noticed the word 'judge'. I wanted to add a 'G' to the front of the app - since this is a git commit watcher - and so hit upon 'grudge'.
|
19
|
+
|
20
|
+
Alas, Grudge = Git Judge
|
21
|
+
|
22
|
+
## How does it work?
|
23
|
+
|
24
|
+
Once your system is bootstrapped, grudge will monitor for updates. For each commit, grudge will store the SHA hash of the commit-id (for referential reasons) and the date it was committed (for ordering reasons). Commit messages and other commit data (like author) stay in the git repository and are always retrieved from there; even at a possible speed reduction (though grudge seems pretty quick).
|
25
|
+
|
26
|
+
Each vote is recorded for a commit as either a +1 or a -1. Votes are themselves entities, which means you could get the voting history for any commit.
|
27
|
+
|
28
|
+
Commits have a net score, which is simply the sum of all of the votes. Popular commits are those with the highest net score. Unpopular are those with the lowest net score.
|
29
|
+
|
30
|
+
# Using Grudge
|
31
|
+
|
32
|
+
## Requirements
|
33
|
+
|
34
|
+
* [Sinatra](http://github.com/bmizerany/sinatra/tree/master)
|
35
|
+
* [Ruby Git](http://github.com/schacon/ruby-git/tree/master)
|
36
|
+
* [HAML](http://haml.hamptoncatlin.com/)
|
37
|
+
* [Sqlite3-ruby](http://github.com/jamis/sqlite3-ruby/tree/master)
|
38
|
+
|
39
|
+
* DataMapper - `sudo gem install data_mapper`
|
40
|
+
* DataObjects - `sudo gem install data_objects` ... *if not already installed*
|
41
|
+
* DataObject bindings for Sqlite - `sudo gem install do_sqlite3`
|
42
|
+
* JSON Pure - `sudo gem install json_pure` - annoyingly needed by data_mapper
|
43
|
+
|
44
|
+
## Setting up an app
|
45
|
+
|
46
|
+
### Install the gem
|
47
|
+
|
48
|
+
$ sudo gem install thumblemonks-grudge
|
49
|
+
|
50
|
+
### Setup an instance
|
51
|
+
|
52
|
+
$ mkdir foo && cd foo
|
53
|
+
$ grudge init
|
54
|
+
|
55
|
+
### Tell Grudge about your repository
|
56
|
+
|
57
|
+
Edit the file in your Grudge instance called `config/grudge.yml`. In it edit the git repository url that you want Grudge to watch. For now, do this for both development and production entries. You don't need to edit anything else, unless you just can't help yourself.
|
58
|
+
|
59
|
+
Example:
|
60
|
+
|
61
|
+
...
|
62
|
+
repository:
|
63
|
+
url: git://github.com/thumblemonks/grudge.git
|
64
|
+
...
|
65
|
+
|
66
|
+
### Run the app
|
67
|
+
|
68
|
+
When just playing around, you can run:
|
69
|
+
|
70
|
+
$ grudge start
|
71
|
+
|
72
|
+
This will first clone the remote repository you defined, bootstrap the commits in a local Sqlite database, then run the Sinatra web-app. As long as you don't remove `clone.git`, the cloning will only happen on the first run. Grudge will, however, grab new updates from the repo each time you start it.
|
73
|
+
|
74
|
+
Point your browser at `http://localhost:9292/` and you are done.
|
75
|
+
|
76
|
+
Oh yeah ... advertise it!
|
77
|
+
|
78
|
+
#### Phusion
|
79
|
+
|
80
|
+
It is suggested that you run grudge through Apache via [Phusion Passenger](http://www.modrails.com/). In order to do this, simply point a configured Phusion Virtual Host at the `public` directory wherever you ran `grudge init`.
|
81
|
+
|
82
|
+
### Getting automatic updates
|
83
|
+
|
84
|
+
As of this writing the way to tell Grudge to automatically look for updates is to setup a remote repository via a post-receive hook. This means your instance of Grudge will need to be routable by your git server.
|
85
|
+
|
86
|
+
If this is so, just setup a post-receive hook to hit the URL with a POST request:
|
87
|
+
|
88
|
+
http(s)://your-grudge-instance/repository/pull
|
89
|
+
|
90
|
+
#### Manual updates
|
91
|
+
|
92
|
+
You can update manually by either restarting the app or via the Grudge console like so:
|
93
|
+
|
94
|
+
$ grudge pull
|
95
|
+
|
96
|
+
You could also setup a bash alias like the following:
|
97
|
+
|
98
|
+
wget -q --post-data='\'''\'' --no-cookies --delete-after http://your-grudge-instance/repository/pull
|
99
|
+
|
100
|
+
Not that I did that ;)
|
101
|
+
|
102
|
+
# Acknowledgements
|
103
|
+
|
104
|
+
Someone for sure. I guess my [wife](http://lesfeministes.com) for giving me the Saturday to write this.
|
105
|
+
|
106
|
+
# Legal
|
107
|
+
|
108
|
+
Copyright © 2008 Justin Knowlden, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'lib/boot'
|
5
|
+
|
6
|
+
desc 'Default task: run all tests'
|
7
|
+
task :default => [:test]
|
8
|
+
|
9
|
+
desc 'Run all tests'
|
10
|
+
Rake::TestTask.new do |t|
|
11
|
+
t.test_files = FileList['test/*_test.rb']
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Open an irb session preloaded with this library"
|
16
|
+
task :console do
|
17
|
+
sh "irb -rubygems -r ./lib/boot.rb"
|
18
|
+
end
|
data/TODO.markdown
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Todo
|
2
|
+
|
3
|
+
## 0.1.0
|
4
|
+
|
5
|
+
* Get it started
|
6
|
+
* Make it a gem
|
7
|
+
* Command line options
|
8
|
+
* Make grudge start in production mode as a policy ;)
|
9
|
+
|
10
|
+
## Backlog
|
11
|
+
|
12
|
+
* Effective logging - not sure if logging git transactions is enough
|
13
|
+
* Paging: so we can see more commits
|
14
|
+
* Only allow one vote per person (maybe, honesty is often the best policy)
|
15
|
+
* [Dan Hodos](http://github.com/danhodos) proved to me that honesty just sucks
|
16
|
+
* Allow users to add tags
|
17
|
+
* Show results by tag
|
18
|
+
* Allow users to comment on commits
|
19
|
+
* Allow users to filter commits based on whether they were commented-on/rated
|
20
|
+
* RSS feeds
|
21
|
+
* Especially for tags
|
22
|
+
* UJS
|
23
|
+
* Ask for local/remote git repo URI on command line and pre-bootstrap
|
24
|
+
* Might name Suck to Boring
|
25
|
+
* Sparkline of voting history
|
26
|
+
* Handle branches
|
27
|
+
* Move away from DataMapper unless it gets better support?
|
data/bin/grudge
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
Signal.trap("INT") { puts "Exiting grudge"; exit } # If we need it
|
5
|
+
|
6
|
+
def usage
|
7
|
+
$stderr.puts "Usage: grudge [init|start|pull]"
|
8
|
+
end
|
9
|
+
|
10
|
+
def fire_up
|
11
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'boot')
|
12
|
+
Grudge::Config.fire_me_up(:production)
|
13
|
+
Grudge::Database.fire_me_up
|
14
|
+
Grudge::Repository.open_or_clone
|
15
|
+
end
|
16
|
+
|
17
|
+
def mkdir(dir)
|
18
|
+
if File.exists?(dir)
|
19
|
+
puts "- Existing directory #{dir} untouched"
|
20
|
+
else
|
21
|
+
puts "- Creating directory #{dir}"
|
22
|
+
FileUtils.mkdir(dir)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def cp_grudge_file(src, dest)
|
27
|
+
unless File.exists?(dest)
|
28
|
+
puts "- Copying grudge file #{src} to #{dest}"
|
29
|
+
FileUtils.cp(File.join(File.dirname(__FILE__), src), dest)
|
30
|
+
else
|
31
|
+
puts "- Existing file #{dest} untouched"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if ARGV.length == 1
|
36
|
+
case ARGV.shift
|
37
|
+
when 'start'
|
38
|
+
puts "Starting grudge ... but, why not just use Phusion with Rack?"
|
39
|
+
app = File.join(File.dirname(__FILE__), '..', 'lib', 'grudge.rb')
|
40
|
+
%x[rackup config.ru]
|
41
|
+
when 'pull'
|
42
|
+
puts "Pulling latest commits"
|
43
|
+
fire_up
|
44
|
+
Commit.download!
|
45
|
+
when 'init'
|
46
|
+
puts "Initializing grudge instance"
|
47
|
+
%w[public tmp config].each { |dir| mkdir("./#{dir}") }
|
48
|
+
cp_grudge_file('../config/grudge.yml', './config/grudge.yml')
|
49
|
+
cp_grudge_file('../config.ru', './config.ru')
|
50
|
+
else
|
51
|
+
usage
|
52
|
+
end
|
53
|
+
else
|
54
|
+
usage
|
55
|
+
end
|
data/config.ru
ADDED
data/config/grudge.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Database entries feed directly into DataMapper.setup
|
3
|
+
#
|
4
|
+
production:
|
5
|
+
log: 'grudge.log'
|
6
|
+
database:
|
7
|
+
adapter: 'sqlite3'
|
8
|
+
database: 'grudge.db'
|
9
|
+
repo:
|
10
|
+
master: 'clone.git'
|
11
|
+
#
|
12
|
+
# Hey you! You should change only this setting
|
13
|
+
origin: 'git://example.com/repository.git'
|
14
|
+
|
15
|
+
#
|
16
|
+
# You don't need to change anything below here
|
17
|
+
test:
|
18
|
+
log: '/dev/null'
|
19
|
+
database: 'sqlite3::memory:'
|
20
|
+
repo:
|
21
|
+
master: 'test/clone.git'
|
22
|
+
origin: 'test/origin.git'
|
23
|
+
|
24
|
+
development:
|
25
|
+
log: 'grudge_development.log'
|
26
|
+
database:
|
27
|
+
adapter: 'sqlite3'
|
28
|
+
database: 'grudge_development.db'
|
29
|
+
repo:
|
30
|
+
master: 'clone.git'
|
31
|
+
origin: 'git://example.com/repository.git'
|
data/grudge.gemspec
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "grudge"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.date = "2008-10-22"
|
5
|
+
s.summary = "Grudge is a git commit comment judging web-app"
|
6
|
+
s.email = "gus@gusg.us"
|
7
|
+
s.homepage = "http://github.com/thumblemonks/grudge"
|
8
|
+
s.description = "Grudge is a stand-alone system, which means you run it on your own, that watches the comments of some git repository and provides a web interface to allow people to rate the comments."
|
9
|
+
s.authors = ["Justin Knowlden"]
|
10
|
+
|
11
|
+
s.bindir = "bin"
|
12
|
+
s.executables = ["grudge"]
|
13
|
+
s.default_executable = "grudge"
|
14
|
+
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.rdoc_options = ["--main", "README.markdown"]
|
17
|
+
s.extra_rdoc_files = ["HISTORY.txt", "README.markdown"]
|
18
|
+
|
19
|
+
s.add_dependency("sinatra", [">= 0.3.1"])
|
20
|
+
s.add_dependency("git", [">= 1.0.5"])
|
21
|
+
s.add_dependency("haml", [">= 2.0.3"])
|
22
|
+
s.add_dependency("sqlite3-ruby", [">= 1.2.4"])
|
23
|
+
s.add_dependency("data_mapper", [">= 0.9.7"])
|
24
|
+
s.add_dependency("data_objects", [">= 0.9.7"])
|
25
|
+
s.add_dependency("do_sqlite3", [">= 0.9.7"])
|
26
|
+
s.add_dependency("json_pure", [">= 1.1.3"]) # datamapper! grrr
|
27
|
+
|
28
|
+
# run git ls-files to get an updated list
|
29
|
+
s.files = %w[
|
30
|
+
HISTORY.txt
|
31
|
+
MIT-LICENSE
|
32
|
+
README.markdown
|
33
|
+
Rakefile
|
34
|
+
TODO.markdown
|
35
|
+
bin/grudge
|
36
|
+
config.ru
|
37
|
+
config/grudge.yml
|
38
|
+
grudge.gemspec
|
39
|
+
lib/boot.rb
|
40
|
+
lib/grudge.rb
|
41
|
+
lib/grudge/base.rb
|
42
|
+
lib/grudge/config.rb
|
43
|
+
lib/grudge/database.rb
|
44
|
+
lib/grudge/extensions.rb
|
45
|
+
lib/grudge/helpers.rb
|
46
|
+
lib/grudge/repository.rb
|
47
|
+
lib/models/commit.rb
|
48
|
+
lib/models/vote.rb
|
49
|
+
lib/views/application.haml
|
50
|
+
lib/views/application.sass
|
51
|
+
lib/views/index.haml
|
52
|
+
lib/views/not_found.haml
|
53
|
+
lib/views/show.haml
|
54
|
+
]
|
55
|
+
s.test_files = %w[
|
56
|
+
test/commit_test.rb
|
57
|
+
test/config_test.rb
|
58
|
+
test/grudge_test.rb
|
59
|
+
test/model_factory.rb
|
60
|
+
test/repository_test.rb
|
61
|
+
test/test_helper.rb
|
62
|
+
test/vote_test.rb
|
63
|
+
]
|
64
|
+
end
|
data/lib/boot.rb
ADDED
data/lib/grudge.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
2
|
+
require 'sinatra'
|
3
|
+
|
4
|
+
# Configuration
|
5
|
+
|
6
|
+
configure(:development, :test) { require 'ruby-debug' }
|
7
|
+
|
8
|
+
configure do
|
9
|
+
set_option :views, File.join(File.dirname(__FILE__), 'views')
|
10
|
+
set_option :public, File.join(File.dirname(__FILE__), 'public')
|
11
|
+
Grudge::Config.fire_me_up(Sinatra.env)
|
12
|
+
Grudge::Database.fire_me_up
|
13
|
+
end
|
14
|
+
|
15
|
+
configure :development, :production do
|
16
|
+
Grudge::Repository.open_or_clone
|
17
|
+
Commit.download!
|
18
|
+
end
|
19
|
+
|
20
|
+
# Setup
|
21
|
+
|
22
|
+
include Grudge::Sinatra::Extensions
|
23
|
+
|
24
|
+
catch_all_css
|
25
|
+
template(:layout) {:application}
|
26
|
+
not_found {haml :not_found}
|
27
|
+
|
28
|
+
helpers do
|
29
|
+
include Grudge::Sinatra::Helpers
|
30
|
+
end
|
31
|
+
|
32
|
+
# Top-level actions
|
33
|
+
|
34
|
+
get("/") { redirect '/recent' }
|
35
|
+
|
36
|
+
%w[recent popular unpopular].each do |scope|
|
37
|
+
get "/#{scope}" do
|
38
|
+
set_title("#{scope.to_s.capitalize} commits")
|
39
|
+
@commits = Commit.send(scope)
|
40
|
+
haml :index
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
%w[awesome suck].each do |vote|
|
45
|
+
get "/:sha/#{vote}" do
|
46
|
+
commit = Commit.first(:sha => params[:sha])
|
47
|
+
raise Sinatra::NotFound unless commit
|
48
|
+
commit.send("#{vote}!")
|
49
|
+
redirect "/#{commit.sha}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
get '/:sha' do
|
54
|
+
show_commit(Commit.first(:sha => params[:sha]))
|
55
|
+
end
|
56
|
+
|
57
|
+
# TODO: search across all sorts of fields; not just commit id
|
58
|
+
post '/search' do
|
59
|
+
show_commit(Commit.search(params['query'].to_s))
|
60
|
+
end
|
61
|
+
|
62
|
+
post '/repository/pull' do
|
63
|
+
Commit.download!
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def show_commit(commit)
|
69
|
+
raise Sinatra::NotFound unless commit
|
70
|
+
@commit = commit
|
71
|
+
set_title(commit.sha)
|
72
|
+
haml :show
|
73
|
+
end
|
data/lib/grudge/base.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Grudge
|
2
|
+
VERSION = '0.1.0'
|
3
|
+
module Hash
|
4
|
+
def symbolize_keys
|
5
|
+
self.mash { |k,v| {k.to_sym => v} }
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end # Grudge
|
9
|
+
|
10
|
+
module Enumerable
|
11
|
+
def mash
|
12
|
+
self.inject({}) { |a,i| a.merge( yield(i) ) }
|
13
|
+
end
|
14
|
+
end # Enumerable
|
15
|
+
|
16
|
+
Hash.send(:include, Grudge::Hash)
|