gitgo 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History +44 -0
- data/License.txt +22 -0
- data/README +45 -0
- data/bin/gitgo +4 -0
- data/lib/gitgo.rb +1 -0
- data/lib/gitgo/app.rb +63 -0
- data/lib/gitgo/controller.rb +89 -0
- data/lib/gitgo/controllers/code.rb +198 -0
- data/lib/gitgo/controllers/issue.rb +76 -0
- data/lib/gitgo/controllers/repo.rb +186 -0
- data/lib/gitgo/controllers/wiki.rb +19 -0
- data/lib/gitgo/document.rb +680 -0
- data/lib/gitgo/document/invalid_document_error.rb +34 -0
- data/lib/gitgo/documents/comment.rb +20 -0
- data/lib/gitgo/documents/issue.rb +56 -0
- data/lib/gitgo/git.rb +941 -0
- data/lib/gitgo/git/tree.rb +315 -0
- data/lib/gitgo/git/utils.rb +59 -0
- data/lib/gitgo/helper.rb +3 -0
- data/lib/gitgo/helper/doc.rb +28 -0
- data/lib/gitgo/helper/form.rb +88 -0
- data/lib/gitgo/helper/format.rb +200 -0
- data/lib/gitgo/helper/html.rb +19 -0
- data/lib/gitgo/helper/utils.rb +85 -0
- data/lib/gitgo/index.rb +421 -0
- data/lib/gitgo/index/idx_file.rb +119 -0
- data/lib/gitgo/index/sha_file.rb +135 -0
- data/lib/gitgo/patches/grit.rb +47 -0
- data/lib/gitgo/repo.rb +626 -0
- data/lib/gitgo/repo/graph.rb +333 -0
- data/lib/gitgo/repo/node.rb +122 -0
- data/lib/gitgo/rest.rb +87 -0
- data/lib/gitgo/server.rb +114 -0
- data/lib/gitgo/version.rb +8 -0
- data/public/css/gitgo.css +24 -0
- data/public/javascript/gitgo.js +148 -0
- data/public/javascript/jquery-1.4.2.min.js +154 -0
- data/views/app/index.erb +4 -0
- data/views/app/timeline.erb +27 -0
- data/views/app/welcome.erb +13 -0
- data/views/code/_comment.erb +10 -0
- data/views/code/_comment_form.erb +14 -0
- data/views/code/_comments.erb +5 -0
- data/views/code/_commit.erb +25 -0
- data/views/code/_grepnav.erb +5 -0
- data/views/code/_treenav.erb +3 -0
- data/views/code/blob.erb +6 -0
- data/views/code/commit_grep.erb +35 -0
- data/views/code/commits.erb +11 -0
- data/views/code/diff.erb +10 -0
- data/views/code/grep.erb +32 -0
- data/views/code/index.erb +17 -0
- data/views/code/obj/blob.erb +4 -0
- data/views/code/obj/commit.erb +25 -0
- data/views/code/obj/tag.erb +25 -0
- data/views/code/obj/tree.erb +9 -0
- data/views/code/tree.erb +9 -0
- data/views/error.erb +19 -0
- data/views/issue/_issue.erb +15 -0
- data/views/issue/_issue_form.erb +39 -0
- data/views/issue/edit.erb +11 -0
- data/views/issue/index.erb +28 -0
- data/views/issue/new.erb +5 -0
- data/views/issue/show.erb +27 -0
- data/views/layout.erb +34 -0
- data/views/not_found.erb +1 -0
- data/views/repo/fsck.erb +29 -0
- data/views/repo/help.textile +5 -0
- data/views/repo/help/faq.textile +19 -0
- data/views/repo/help/howto.textile +31 -0
- data/views/repo/help/trouble.textile +28 -0
- data/views/repo/idx.erb +29 -0
- data/views/repo/index.erb +72 -0
- data/views/repo/status.erb +16 -0
- data/views/wiki/index.erb +3 -0
- metadata +253 -0
data/History
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
== 0.3.3 2010-04-28
|
2
|
+
|
3
|
+
Fixed (hopefully) usage in repos with no user name/email set.
|
4
|
+
|
5
|
+
== 0.3.2 2010-04-27
|
6
|
+
|
7
|
+
Fixed (hopefully) the cause of zero-padded file modes warning.
|
8
|
+
|
9
|
+
== 0.3.1 2010-04-26
|
10
|
+
|
11
|
+
Improvements to repo lifecycle.
|
12
|
+
|
13
|
+
== 0.3.0 2010-04-26
|
14
|
+
|
15
|
+
Updated internal data store to (more or less) halve the overhead of each new
|
16
|
+
document by storing document information inline with associations. Index now
|
17
|
+
assigns shas an integer index for faster comparisons and smaller index files.
|
18
|
+
Continued overhaul of internals. General updates to the interface.
|
19
|
+
|
20
|
+
== 0.2.0 2010-03-29
|
21
|
+
|
22
|
+
This release significantly changes the internals of Gitgo. Old gitgo branches
|
23
|
+
will not be compatible. To migrate a gitgo-0.1.* branch to the new storage
|
24
|
+
format:
|
25
|
+
|
26
|
+
% git clone git://github.com/bahuvrihi/gitgo.git
|
27
|
+
% cd gitgo
|
28
|
+
% git checkout migrate-0.2.0
|
29
|
+
% ruby script/migrate-0.2.0.rb PATH_TO_REPO SOURCE_BRANCH TARGET_BRANCH
|
30
|
+
|
31
|
+
Then rename the target branch as necessary. You will also have to remove the
|
32
|
+
old gitgo files:
|
33
|
+
|
34
|
+
% cd <path_to_repo>
|
35
|
+
% rm -rf .git/gitgo
|
36
|
+
|
37
|
+
Major changes:
|
38
|
+
|
39
|
+
* changed document serialization format to JSON
|
40
|
+
* complete overhaul of internal classes
|
41
|
+
* implemented a more robust system for calculating
|
42
|
+
(and drawing) a document graph
|
43
|
+
* temporary removal of comments
|
44
|
+
* improvements to indexing system
|
data/License.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2010 Pinnacol Assurance
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software. Except as contained in this
|
12
|
+
notice, the name(s) of the above copyright holders shall not be used in
|
13
|
+
advertising or otherwise to promote the sale, use or other dealings in this
|
14
|
+
Software without prior written authorization.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= Gitgo
|
2
|
+
|
3
|
+
Gitgo -- git-driven issues, comments, and a wiki... to go.
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
Gitgo is an issue tracker that stores issue information in a git repository.
|
8
|
+
|
9
|
+
At present gitgo is in a developmental state. While the backend and data model
|
10
|
+
both work and appear to be robust, the front-end is highly lacking. Usage will
|
11
|
+
be difficult without insider knowledge.
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
|
15
|
+
In the working directory for a git repository:
|
16
|
+
|
17
|
+
% gitgo
|
18
|
+
|
19
|
+
Then visit http://localhost:8080 in a web browser.
|
20
|
+
|
21
|
+
== Installation
|
22
|
+
|
23
|
+
Gitgo is not available as a gem yet. To clone the project and build your own:
|
24
|
+
|
25
|
+
% git clone git://github.com/pinnacol/gitgo.git
|
26
|
+
% cd gitgo
|
27
|
+
% rake gem
|
28
|
+
% gem install pkg/gitgo-...
|
29
|
+
|
30
|
+
== Development
|
31
|
+
|
32
|
+
Gitgo is open-source and welcomes help from the community! To get started:
|
33
|
+
|
34
|
+
% git clone git://github.com/pinnacol/gitgo.git
|
35
|
+
% cd gitgo
|
36
|
+
% rake test
|
37
|
+
|
38
|
+
To see bugs tracked in the gitgo repo:
|
39
|
+
|
40
|
+
% bin/gitgo
|
41
|
+
|
42
|
+
== Info
|
43
|
+
|
44
|
+
Developer:: {Simon Chiang}[http://bahuvrihi.wordpress.com]
|
45
|
+
License:: {MIT-Style}[link:files/License_txt.html]
|
data/bin/gitgo
ADDED
data/lib/gitgo.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'gitgo/server'
|
data/lib/gitgo/app.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'gitgo/controller'
|
2
|
+
require 'gitgo/controllers/code'
|
3
|
+
require 'gitgo/controllers/issue'
|
4
|
+
require 'gitgo/controllers/repo'
|
5
|
+
require 'gitgo/controllers/wiki'
|
6
|
+
|
7
|
+
module Gitgo
|
8
|
+
class App < Controller
|
9
|
+
set :views, File.expand_path("views/app", ROOT)
|
10
|
+
set :static, true
|
11
|
+
|
12
|
+
get('/') { repo.head ? index : welcome }
|
13
|
+
get('/timeline') { timeline }
|
14
|
+
|
15
|
+
use Controllers::Code
|
16
|
+
use Controllers::Issue
|
17
|
+
use Controllers::Wiki
|
18
|
+
use Controllers::Repo
|
19
|
+
|
20
|
+
def index
|
21
|
+
erb :index
|
22
|
+
end
|
23
|
+
|
24
|
+
def welcome
|
25
|
+
erb :welcome, :locals => {
|
26
|
+
:branch => repo.branch,
|
27
|
+
:remotes => repo.refs
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def timeline
|
32
|
+
Document.update_index
|
33
|
+
|
34
|
+
page = (request[:page] || 0).to_i
|
35
|
+
per_page = (request[:per_page] || 5).to_i
|
36
|
+
|
37
|
+
author = request[:author]
|
38
|
+
author = '' if author == 'unknown'
|
39
|
+
|
40
|
+
docs = repo.timeline(:n => per_page, :offset => page * per_page) do |sha|
|
41
|
+
author.nil? || repo[sha]['author'].include?("<#{author}>")
|
42
|
+
end.collect do |sha|
|
43
|
+
Document.cast(repo[sha], sha)
|
44
|
+
end.sort_by do |doc|
|
45
|
+
doc.date
|
46
|
+
end
|
47
|
+
|
48
|
+
erb :timeline, :locals => {
|
49
|
+
:page => page,
|
50
|
+
:per_page => per_page,
|
51
|
+
:docs => docs,
|
52
|
+
:author => author,
|
53
|
+
:authors => repo.index.values('email'),
|
54
|
+
:active_sha => session_head
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def build_query(params)
|
59
|
+
params.delete_if {|key, value| value.nil? }
|
60
|
+
super(params)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'gitgo/helper'
|
4
|
+
require 'gitgo/document'
|
5
|
+
require 'gitgo/rest'
|
6
|
+
|
7
|
+
module Gitgo
|
8
|
+
class Controller < Sinatra::Base
|
9
|
+
ROOT = File.expand_path(File.dirname(__FILE__) + "/../..")
|
10
|
+
HEAD = 'gitgo.head'
|
11
|
+
MOUNT = 'gitgo.mount'
|
12
|
+
|
13
|
+
set :root, ROOT
|
14
|
+
set :raise_errors, Proc.new { test? }
|
15
|
+
set :dump_errors, true
|
16
|
+
|
17
|
+
template(:layout) do
|
18
|
+
File.read(File.join(ROOT, "views/layout.erb"))
|
19
|
+
end
|
20
|
+
|
21
|
+
not_found do
|
22
|
+
erb :not_found, :views => path("views")
|
23
|
+
end
|
24
|
+
|
25
|
+
error Exception do
|
26
|
+
err = env['sinatra.error']
|
27
|
+
resetable = err.kind_of?(Errno::ENOENT) && err.message =~ /No such file or directory - .*idx/
|
28
|
+
|
29
|
+
erb :error, :views => path("views"), :locals => {:err => err, :resetable => resetable}
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(app=nil, repo=nil)
|
33
|
+
super(app)
|
34
|
+
@repo = repo
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the path expanded relative to the Gitgo::ROOT directory. Paths
|
38
|
+
# often need to be expanded like this so that they will be correct when
|
39
|
+
# Gitgo is running as a gem.
|
40
|
+
def path(path)
|
41
|
+
File.expand_path(path, ROOT)
|
42
|
+
end
|
43
|
+
|
44
|
+
def repo
|
45
|
+
@repo ||= Repo.current
|
46
|
+
end
|
47
|
+
|
48
|
+
def call(env)
|
49
|
+
env[Repo::REPO] ||= @repo
|
50
|
+
Repo.with_env(env) { super(env) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def session_head
|
54
|
+
# grit.head will be nil if not on a local branch
|
55
|
+
@session_head ||= begin
|
56
|
+
if session.has_key?(HEAD)
|
57
|
+
session[HEAD]
|
58
|
+
else
|
59
|
+
grit = repo.git.grit
|
60
|
+
session[HEAD] = grit.head ? grit.head.name : nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def session_head=(input)
|
66
|
+
@session_head = session[HEAD] = input
|
67
|
+
end
|
68
|
+
|
69
|
+
def mount_point
|
70
|
+
@mount_point ||= (env[MOUNT] || '/')
|
71
|
+
end
|
72
|
+
|
73
|
+
def url(paths)
|
74
|
+
File.join(mount_point, *paths)
|
75
|
+
end
|
76
|
+
|
77
|
+
def format
|
78
|
+
@format ||= Helper::Format.new(self)
|
79
|
+
end
|
80
|
+
|
81
|
+
def form
|
82
|
+
@form ||= Helper::Form.new(self)
|
83
|
+
end
|
84
|
+
|
85
|
+
def html
|
86
|
+
Helper::Html
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'gitgo/controller'
|
2
|
+
require 'gitgo/documents/comment'
|
3
|
+
|
4
|
+
module Gitgo
|
5
|
+
module Controllers
|
6
|
+
class Code < Controller
|
7
|
+
include Rest
|
8
|
+
|
9
|
+
set :views, File.expand_path("views/code", ROOT)
|
10
|
+
|
11
|
+
get('/code') { index }
|
12
|
+
get('/blob') { blob_grep }
|
13
|
+
get('/tree') { tree_grep }
|
14
|
+
get('/commit') { commit_grep }
|
15
|
+
|
16
|
+
get('/blob/:treeish/*') {|treeish, path| show_blob(treeish, path) }
|
17
|
+
get('/tree/:treeish') {|treeish| show_tree(treeish, '') }
|
18
|
+
get('/tree/:treeish/*') {|treeish, path| show_tree(treeish, path) }
|
19
|
+
get('/commit/:treeish') {|treeish| show_commit(treeish) }
|
20
|
+
get('/commits/:treeish') {|treeish| show_commits(treeish) }
|
21
|
+
get('/obj/:sha') {|sha| show_object(sha) }
|
22
|
+
|
23
|
+
get('/comment/:sha') {|sha| read(sha) }
|
24
|
+
post('/comment') { create }
|
25
|
+
post('/comment/:sha') do |sha|
|
26
|
+
_method = request[:_method]
|
27
|
+
case _method
|
28
|
+
when /\Aupdate\z/i then update(obj)
|
29
|
+
when /\Adelete\z/i then destroy(obj)
|
30
|
+
else raise("unknown post method: #{_method}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
put('/comment/:sha') {|sha| update(sha) }
|
34
|
+
delete('/comment/:sha') {|sha| destroy(sha) }
|
35
|
+
|
36
|
+
Comment = Documents::Comment
|
37
|
+
|
38
|
+
def git
|
39
|
+
@git ||= repo.git
|
40
|
+
end
|
41
|
+
|
42
|
+
def grit
|
43
|
+
@grit ||= git.grit
|
44
|
+
end
|
45
|
+
|
46
|
+
def model
|
47
|
+
Comment
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# actions
|
52
|
+
#
|
53
|
+
|
54
|
+
def index
|
55
|
+
erb :index, :locals => {
|
56
|
+
:branches => grit.branches,
|
57
|
+
:tags => grit.tags
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def treeish
|
62
|
+
request['at'] || grit.head.commit
|
63
|
+
end
|
64
|
+
|
65
|
+
def grep_opts(overrides={})
|
66
|
+
{
|
67
|
+
:ignore_case => request['ignore_case'] == 'true',
|
68
|
+
:invert_match => request['invert_match'] == 'true',
|
69
|
+
:fixed_strings => request['fixed_strings'] == 'true',
|
70
|
+
}.merge!(overrides)
|
71
|
+
end
|
72
|
+
|
73
|
+
def blob_grep
|
74
|
+
options = grep_opts(:e => request['pattern'])
|
75
|
+
|
76
|
+
selected = []
|
77
|
+
git.grep(options, treeish) do |path, blob|
|
78
|
+
selected << [path, blob.id]
|
79
|
+
end
|
80
|
+
|
81
|
+
erb :grep, :locals => options.merge!(
|
82
|
+
:type => 'blob',
|
83
|
+
:at => treeish,
|
84
|
+
:selected => selected,
|
85
|
+
:refs => grit.refs
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
def tree_grep
|
90
|
+
options = grep_opts(:e => request['pattern'])
|
91
|
+
|
92
|
+
selected = []
|
93
|
+
git.tree_grep(options, treeish) do |path, blob|
|
94
|
+
selected << [path, blob.id]
|
95
|
+
end
|
96
|
+
|
97
|
+
erb :grep, :locals => options.merge!(
|
98
|
+
:type => 'tree',
|
99
|
+
:at => treeish,
|
100
|
+
:selected => selected,
|
101
|
+
:refs => grit.refs
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def commit_grep
|
106
|
+
options = grep_opts(
|
107
|
+
:author => request['author'],
|
108
|
+
:committer => request['committer'],
|
109
|
+
:grep => request['grep'],
|
110
|
+
:regexp_ignore_case => request['regexp_ignore_case'] == 'true',
|
111
|
+
:fixed_strings => request['fixed_strings'] == 'true',
|
112
|
+
:all_match => request['all_match'] == 'true',
|
113
|
+
:max_count => request['max_count'] || '10'
|
114
|
+
)
|
115
|
+
|
116
|
+
selected = []
|
117
|
+
git.commit_grep(options, treeish) {|sha| selected << sha }
|
118
|
+
|
119
|
+
erb :commit_grep, :locals => options.merge!(
|
120
|
+
:selected => selected
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
def show_blob(treeish, path)
|
125
|
+
commit = grit.commit(treeish) || not_found
|
126
|
+
blob = commit.tree / path || not_found
|
127
|
+
|
128
|
+
erb :blob, :locals => {
|
129
|
+
:commit => commit,
|
130
|
+
:treeish => treeish,
|
131
|
+
:blob => blob,
|
132
|
+
:path => path
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def show_tree(treeish, path)
|
137
|
+
commit = grit.commit(treeish) || not_found
|
138
|
+
tree = path.split("/").inject(commit.tree) do |obj, name|
|
139
|
+
not_found if obj.nil?
|
140
|
+
obj.trees.find {|obj| obj.name == name }
|
141
|
+
end
|
142
|
+
|
143
|
+
erb :tree, :locals => {
|
144
|
+
:commit => commit,
|
145
|
+
:treeish => treeish,
|
146
|
+
:tree => tree,
|
147
|
+
:path => path
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
def show_commit(treeish)
|
152
|
+
commit = grit.commit(treeish) || not_found
|
153
|
+
erb :diff, :locals => {
|
154
|
+
:commit => commit,
|
155
|
+
:treeish => treeish
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
def show_commits(treeish)
|
160
|
+
commit = grit.commit(treeish)
|
161
|
+
page = (request[:page] || 0).to_i
|
162
|
+
per_page = (request[:per_page] || 10).to_i
|
163
|
+
|
164
|
+
erb :commits, :locals => {
|
165
|
+
:treeish => treeish,
|
166
|
+
:page => page,
|
167
|
+
:per_page => per_page,
|
168
|
+
:commits => grit.commits(commit.sha, per_page, page * per_page)
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
def show_object(sha)
|
173
|
+
sha = git.resolve(sha)
|
174
|
+
|
175
|
+
case
|
176
|
+
when request['content'] == 'true'
|
177
|
+
response['Content-Type'] = 'text/plain'
|
178
|
+
grit.git.cat_file({:p => true}, sha)
|
179
|
+
|
180
|
+
when request['download'] == 'true'
|
181
|
+
response['Content-Type'] = 'text/plain'
|
182
|
+
response['Content-Disposition'] = "attachment; filename=#{sha};"
|
183
|
+
raw_object = grit.git.ruby_git.get_raw_object_by_sha1(sha)
|
184
|
+
"%s %d\0" % [raw_object.type, raw_object.content.length] + raw_object.content
|
185
|
+
|
186
|
+
else
|
187
|
+
type = git.type(sha).to_sym
|
188
|
+
obj = git.get(type, sha) or not_found
|
189
|
+
|
190
|
+
erb type, :locals => {
|
191
|
+
:sha => sha,
|
192
|
+
:obj => obj
|
193
|
+
}, :views => path('views/code/obj')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|