libdolt 0.26.0 → 0.27.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -1
- data/Gemfile.lock +1 -1
- data/Readme.md +184 -75
- data/lib/libdolt/controller_actions.rb +191 -0
- data/lib/libdolt/version.rb +1 -1
- data/lib/libdolt.rb +1 -1
- data/test/libdolt/controller_actions_test.rb +475 -0
- data/test/test_helper.rb +127 -9
- metadata +4 -3
- data/lib/libdolt/gitorious_repo_resolver.rb +0 -29
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
@@ -1,102 +1,211 @@
|
|
1
|
-
#
|
1
|
+
# libdolt - Git repository browser internals
|
2
2
|
|
3
3
|
<a href="http://travis-ci.org/cjohansen/libdolt" class="travis">
|
4
4
|
<img src="https://secure.travis-ci.org/cjohansen/libdolt.png">
|
5
5
|
</a>
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
rendering, commit log and blame.
|
7
|
+
`libdolt` is all the reusable internal workings of the
|
8
|
+
[Dolt repository browser](https://gitorious.org/gitorious/dolt). It provides all
|
9
|
+
the mechanics for retrieving the data you need display Git trees, blobs, blame
|
10
|
+
and more, and also includes tools to render them in a web context.
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
templates outputting HTML.
|
12
|
+
`libdolt` does not depend on Sinatra, or any other web context, so it can easily
|
13
|
+
be embedded in other frameworks/apps. Most notably, `libdolt` is used as the
|
14
|
+
repository browser in [Gitorious 3](https://gitorious.org/gitorious/mainline),
|
15
|
+
and as a stand-alone repository browser in [Dolt](https://gitorious.org/gitorious/dolt).
|
18
16
|
|
19
|
-
|
20
|
-
[Gitorious](http://gitorious.org) software.
|
17
|
+
## Installing libdolt
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
To install `dolt` you need Ruby, RubyGems and Python development files. The
|
25
|
-
Python development files are required to support Pygments syntax highlighting.
|
26
|
-
|
27
|
-
Note: Dolt uses [libgit2](http://libgit2.github.com) and its Ruby bindings,
|
28
|
-
[Rugged](http://github.com/libgit2/rugged) for Git access where
|
29
|
-
feasible. Currently, ``Dolt`` relies on a version of `Rugged` that is not
|
30
|
-
yet released, so you have to build it yourself.
|
31
|
-
[See em-rugged instructions](http://github.com/cjohansen/em-rugged).
|
19
|
+
libdolt depends on two system packages to do its job.
|
32
20
|
|
33
21
|
### Systems using apt (Debian/Ubuntu, others)
|
34
22
|
|
35
|
-
# 1) Install
|
36
|
-
sudo apt-get install
|
23
|
+
# 1) Install Python development files
|
24
|
+
sudo apt-get install -y python-dev libicu-dev
|
37
25
|
|
38
|
-
# 2) Install
|
39
|
-
|
40
|
-
|
41
|
-
# 3) Install dolt. This may or may not require the use of sudo, depending on
|
42
|
-
# how you installed Ruby. This step assumes that you already built and
|
43
|
-
# installed em-rugged as explained above.
|
44
|
-
sudo gem install dolt
|
26
|
+
# 2) Install dolt. This may or may not require the use of sudo, depending on
|
27
|
+
# how you installed Ruby.
|
28
|
+
gem install libdolt
|
45
29
|
|
46
30
|
### Systems using yum (Fedora/CentOS/RedHat, others)
|
47
31
|
|
48
|
-
# 1) Install
|
49
|
-
sudo yum install
|
50
|
-
|
51
|
-
# 2) Install Python development files
|
52
|
-
sudo yum install python-devel
|
32
|
+
# 1) Install Python development files
|
33
|
+
sudo yum install -y python-devel libicu-devel
|
53
34
|
|
54
35
|
# 3) Install dolt. This may or may not require the use of sudo, depending on
|
55
|
-
# how you installed Ruby.
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
36
|
+
# how you installed Ruby.
|
37
|
+
gem install dolt
|
38
|
+
|
39
|
+
## API
|
40
|
+
|
41
|
+
`libdolt` provides two main abstractions you may be interested in:
|
42
|
+
|
43
|
+
* `Dolt::RepositoryLookup` provides an API that will fetch various bits of
|
44
|
+
information from your git repository, and returns a hash of data. This hash
|
45
|
+
can typically be used for rendering in a template of some sort.
|
46
|
+
* `Dolt::ControllerActions` provides a web front-end to the repository lookup.
|
47
|
+
It will use the lookup class to fetch the information it needs, and then it
|
48
|
+
will render them using [Tiltout](https://gitorious.org/gitorious/tiltout). If
|
49
|
+
you're looking to make a web-based repository browser, you can use this class
|
50
|
+
in a Sinatra, Rack or Rails application, provide you own templates etc.
|
51
|
+
|
52
|
+
## Repository lookups
|
53
|
+
|
54
|
+
The `Dolt::RepositoryLookup` class provides many methods that use
|
55
|
+
[libgit2/Rugged](https://github.com/libgit2/rugged) in conjunction with the
|
56
|
+
classes found in `lib/libdolt/git` to fetch, consolidate and prepare Git
|
57
|
+
repository data in a display-friendly way. All methods return a hash.
|
58
|
+
|
59
|
+
The repository lookup class depends on a "repository resolver". This is an
|
60
|
+
object that can take a string from the URL, such as `"gitorious/mainline"` and
|
61
|
+
return a usable repository object. The repository object is expected to conform
|
62
|
+
to the `Dolt::Git::Repository` interface. Typically you will want to instantiate
|
63
|
+
this object, but you can in theory provide your own implementation, so long as
|
64
|
+
you maintain the interface.
|
65
|
+
|
66
|
+
Repository resolvers are quite simple animals. Here's an example of how to make
|
67
|
+
Dolt work with Gitorious' Repository model objects:
|
68
|
+
|
69
|
+
```rb
|
70
|
+
module Gitorious
|
71
|
+
module Dolt
|
72
|
+
class RepositoryResolver
|
73
|
+
# How you initialize your objects is up to you - Dolt doesn't care, it
|
74
|
+
# only ever sees the instance, not the class itself.
|
75
|
+
def initialize(scope = ::Repository)
|
76
|
+
@scope = scope
|
77
|
+
end
|
78
|
+
|
79
|
+
def resolve(repo)
|
80
|
+
repository = @scope.find_by_path(repo)
|
81
|
+
raise ActiveRecord::RecordNotFound.new if repository.nil?
|
82
|
+
Gitorious::Dolt::Repository.new(repository)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
### Common data
|
90
|
+
|
91
|
+
All actions return a hash that include these keys:
|
92
|
+
|
93
|
+
* `path` - The repository-relative path
|
94
|
+
* `ref` - The ref or object id
|
95
|
+
|
96
|
+
### Example: Looking up a tree
|
97
|
+
|
98
|
+
```rb
|
99
|
+
resolver = Gitorious::Dolt::RepositoryResolver.new
|
100
|
+
lookup = Dolt::RepositoryLookup.new(resolver)
|
101
|
+
|
102
|
+
data = lookup.tree("gitorious/mainline", "master", "")
|
103
|
+
#=> {
|
104
|
+
# :path => "",
|
105
|
+
# :ref => "master",
|
106
|
+
# :tree => #<Rugged::Tree:16209820 {oid: 89cd7e9d4564928de6b803b36c6e3d081c8d9ca1}>
|
107
|
+
# <"README.org" b40c249db94476cac7fa91a9d6491c0faf21ec21>
|
108
|
+
# <"lib" 264c348a80906538018616fa16fc35d04bdf38b0>,
|
109
|
+
# :readme => { :blob => #<Rugged::Blob:0x00000002111460>, :path => "README.org" }
|
110
|
+
# }
|
111
|
+
```
|
112
|
+
|
113
|
+
Note that the `tree` lookup will include a readme blob if one is available, and
|
114
|
+
Dolt is able to render it.
|
115
|
+
|
116
|
+
## Controller actions
|
117
|
+
|
118
|
+
The controller actions that ship with libdolt are web framework agnostic. They
|
119
|
+
return arrays that can be passed directly to Rack, or can be picked apart for
|
120
|
+
further processing. The controller actions can be configured to redirect any
|
121
|
+
request for symbolic refs (e.g. a request for something on "master" will
|
122
|
+
redirect to the current tip of that branch), and it provides error handling,
|
123
|
+
renders blobs with syntax highlighting and more.
|
124
|
+
|
125
|
+
The controller actions have three dependencies: a router, a repository lookup
|
126
|
+
instance (see above) and a renderer.
|
127
|
+
|
128
|
+
The router is expected to respond to these messages:
|
129
|
+
|
130
|
+
* `tree_url(repo, ref, path)`
|
131
|
+
* `blob_url(repo, ref, path)`
|
132
|
+
* `tree_entry_url(repo, ref, path)`
|
133
|
+
* `blame_url(repo, ref, path)`
|
134
|
+
* `history_url(repo, ref, path)`
|
135
|
+
* `tree_history_url(repo, ref, path)`
|
136
|
+
* `raw_url(repo, ref, path)`
|
137
|
+
|
138
|
+
The renderer can be anything that understands this message:
|
139
|
+
|
140
|
+
```rb
|
141
|
+
renderer.render(template, data, template_options)
|
142
|
+
|
143
|
+
# e.g.
|
144
|
+
renderer.render("tree", {
|
145
|
+
:ref => "master",
|
146
|
+
:path => lib",
|
147
|
+
:tree => tree
|
148
|
+
}, { :layout => "dark_skin" })
|
149
|
+
```
|
150
|
+
|
151
|
+
[Tiltout](https://gitorious.org/gitorious/tiltout) is well suited for the task.
|
152
|
+
To just use the built-in templates in libdolt:
|
153
|
+
|
154
|
+
```rb
|
155
|
+
renderer = Tiltout.new(Dolt.template_dir, { :layout => "layout" })
|
156
|
+
renderer.helper(Dolt::View::Object)
|
157
|
+
renderer.helper(Dolt::View::Urls)
|
158
|
+
renderer.helper(Dolt::View::Blob)
|
159
|
+
renderer.helper(Dolt::View::Blame)
|
160
|
+
renderer.helper(Dolt::View::Breadcrumb)
|
161
|
+
renderer.helper(Dolt::View::Tree)
|
162
|
+
renderer.helper(Dolt::View::Commit)
|
163
|
+
renderer.helper(Dolt::View::Gravatar)
|
164
|
+
renderer.helper(Dolt::View::TabWidth)
|
165
|
+
renderer.helper(Dolt::View::BinaryBlobEmbedder)
|
166
|
+
renderer.helper(:tab_width => options[:tab_width], :maxdepth => 3)
|
167
|
+
|
168
|
+
actions = Dolt::ControllerActions.new(some_router, lookup, renderer)
|
169
|
+
response = actions.blob("gitorious/libdolt", "master", "Readme.md")
|
170
|
+
|
171
|
+
#=> [200, {
|
172
|
+
"Content-Type" => "text/html; charset=utf-8",
|
173
|
+
"X-UA-Compatible" => "IE=edge"
|
174
|
+
}, [html...]]
|
175
|
+
```
|
176
|
+
|
177
|
+
The controller actions also accept a last argument, which is a hash of
|
178
|
+
additional data to expose to the templates. This is useful if you are using
|
179
|
+
a custom layout and/or templates.
|
67
180
|
|
68
|
-
|
69
|
-
|
70
|
-
Then open a browser at [http://localhost:3000](http://localhost:3000). You will
|
71
|
-
be redirected to the root tree, and can browse the repository. To view trees and
|
72
|
-
blobs at specific refs, use the URL. A branch/tag selector will be added later.
|
73
|
-
|
74
|
-
## Browsing multiple repositories
|
75
|
-
|
76
|
-
The idea is that eventually, `dolt` should be able to serve up all Git
|
77
|
-
repositories managed by your Gitorious server. It does not yet do that, because
|
78
|
-
there currently is no "repository resolver" that understands the hashed paths
|
79
|
-
Gitorious uses.
|
181
|
+
## Markup rendering
|
80
182
|
|
81
|
-
|
82
|
-
|
183
|
+
Dolt uses the [``GitHub::Markup``](https://github.com/github/markup/) library
|
184
|
+
(through [Makeup](https://gitorious.org/gitorious/makeup)) to render certain
|
185
|
+
markup formats as HTML. Dolt does not have a hard dependency on any of the
|
186
|
+
required gems to actually render markups, so see the
|
187
|
+
[``GitHub::Markup`` docs](https://github.com/github/markup/) for information on
|
188
|
+
what and how to install support for various languages.
|
83
189
|
|
84
|
-
|
190
|
+
Various rendering techniques are implemented as modules that can be included in
|
191
|
+
you Tiltout views. Here's an excerpt from Dolt's `bin/dolt` script (which runs a
|
192
|
+
standalone repository browser locally on your box):
|
85
193
|
|
86
|
-
|
87
|
-
|
88
|
-
|
194
|
+
```rb
|
195
|
+
# Attempt to syntax highlight every blob
|
196
|
+
# renderer.helper(Dolt::View::SyntaxHighlight)
|
89
197
|
|
90
|
-
|
198
|
+
# Attempt to render every blob as markup
|
199
|
+
# renderer.helper(Dolt::View::Markup)
|
91
200
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
201
|
+
# Render supported formats as markup, syntax highlight the rest
|
202
|
+
# (if attempting to render some format as markup crashes, it will
|
203
|
+
# fall back to syntax highlighting)
|
204
|
+
renderer.helper(Dolt::View::SmartBlobRenderer)
|
205
|
+
```
|
97
206
|
|
98
207
|
# License
|
99
208
|
|
100
|
-
|
209
|
+
libdolt is free software licensed under the
|
101
210
|
[GNU Affero General Public License (AGPL)](http://www.gnu.org/licenses/agpl-3.0.html).
|
102
|
-
|
211
|
+
libdolt is developed as part of the Gitorious project.
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#--
|
3
|
+
# Copyright (C) 2012-2013 Gitorious AS
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#++
|
18
|
+
require "json"
|
19
|
+
require "time"
|
20
|
+
require "cgi"
|
21
|
+
|
22
|
+
module Dolt
|
23
|
+
class ControllerActions
|
24
|
+
def initialize(router, lookup, renderer)
|
25
|
+
@router = router
|
26
|
+
@lookup = lookup
|
27
|
+
@renderer = renderer
|
28
|
+
end
|
29
|
+
|
30
|
+
def redirect(url, status = 302)
|
31
|
+
body = "You are being <a href=\"#{url}\">redirected to #{url}</a>"
|
32
|
+
[status, { "Location" => url }, [body]]
|
33
|
+
end
|
34
|
+
|
35
|
+
def render_error(error, repo, ref, data = {})
|
36
|
+
$stderr.puts(error.message)
|
37
|
+
$stderr.puts(error.backtrace)
|
38
|
+
|
39
|
+
if error.class.to_s == "Rugged::ReferenceError" && ref == "HEAD"
|
40
|
+
return [200, headers, [renderer.render("empty", {
|
41
|
+
:repository => repo,
|
42
|
+
:ref => ref
|
43
|
+
}.merge(data))]]
|
44
|
+
end
|
45
|
+
|
46
|
+
[response, headers, [renderer.render(response.to_s.to_sym, {
|
47
|
+
:error => error,
|
48
|
+
:repository_slug => repo,
|
49
|
+
:ref => ref
|
50
|
+
}.merge(data))]]
|
51
|
+
rescue Exception => err
|
52
|
+
err_backtrace = err.backtrace.map { |s| "<li>#{s}</li>" }
|
53
|
+
error_backtrace = error.backtrace.map { |s| "<li>#{s}</li>" }
|
54
|
+
|
55
|
+
[500, headers, [<<-HTML]]
|
56
|
+
<h1>Fatal Dolt Error</h1>
|
57
|
+
<p>
|
58
|
+
Dolt encountered an exception, and additionally
|
59
|
+
triggered another exception trying to render the error.
|
60
|
+
</p>
|
61
|
+
<p>Tried to render the #{template} template with the following data:</p>
|
62
|
+
<dl>
|
63
|
+
<dt>Repository</dt>
|
64
|
+
<dd>#{repo}</dd>
|
65
|
+
<dt>Ref</dt>
|
66
|
+
<dd>#{ref}</dd>
|
67
|
+
</dl>
|
68
|
+
<h2>Error: #{err.class} #{err.message}</h2>
|
69
|
+
<ul>#{err_backtrace.join()}</ul>
|
70
|
+
<h2>Original error: #{error.class} #{error.message}</h2>
|
71
|
+
<ul>#{error_backtrace.join()}</ul>
|
72
|
+
HTML
|
73
|
+
end
|
74
|
+
|
75
|
+
def raw(repo, ref, path, custom_data = {})
|
76
|
+
if oid = lookup_ref_oid(repo, ref)
|
77
|
+
return redirect(router.raw_url(repo, oid, path), 307)
|
78
|
+
end
|
79
|
+
|
80
|
+
blob(repo, ref, path, custom_data, {
|
81
|
+
:template => :raw,
|
82
|
+
:content_type => "text/plain",
|
83
|
+
:template_options => { :layout => nil }
|
84
|
+
})
|
85
|
+
end
|
86
|
+
|
87
|
+
def blob(repo, ref, path, custom_data = {}, options = { :template => :blob })
|
88
|
+
if oid = lookup_ref_oid(repo, ref)
|
89
|
+
return redirect(router.blob_url(repo, oid, path), 307)
|
90
|
+
end
|
91
|
+
|
92
|
+
data = (custom_data || {}).merge(lookup.blob(repo, u(ref), path))
|
93
|
+
blob = data[:blob]
|
94
|
+
return redirect(router.tree_url(repo, ref, path)) if blob.class.to_s !~ /\bBlob/
|
95
|
+
|
96
|
+
tpl_options = options[:template_options] || {}
|
97
|
+
[200, headers(options.merge(:ref => ref)), [
|
98
|
+
renderer.render(options[:template], data, tpl_options)
|
99
|
+
]]
|
100
|
+
end
|
101
|
+
|
102
|
+
def tree(repo, ref, path, custom_data = {})
|
103
|
+
if oid = lookup_ref_oid(repo, ref)
|
104
|
+
return redirect(router.tree_url(repo, oid, path), 307)
|
105
|
+
end
|
106
|
+
|
107
|
+
data = (custom_data || {}).merge(lookup.tree(repo, u(ref), path))
|
108
|
+
tree = data[:tree]
|
109
|
+
return redirect(router.blob_url(repo, ref, path)) if tree.class.to_s !~ /\bTree/
|
110
|
+
[200, headers(:ref => ref), [renderer.render(:tree, data)]]
|
111
|
+
end
|
112
|
+
|
113
|
+
def tree_entry(repo, ref, path, custom_data = {})
|
114
|
+
if oid = lookup_ref_oid(repo, ref)
|
115
|
+
return redirect(router.tree_entry_url(repo, oid, path), 307)
|
116
|
+
end
|
117
|
+
|
118
|
+
data = (custom_data || {}).merge(lookup.tree_entry(repo, u(ref), path))
|
119
|
+
body = renderer.render(data.key?(:tree) ? :tree : :blob, data)
|
120
|
+
[200, headers(:ref => ref), [body]]
|
121
|
+
end
|
122
|
+
|
123
|
+
def blame(repo, ref, path, custom_data = {})
|
124
|
+
if oid = lookup_ref_oid(repo, ref)
|
125
|
+
return redirect(router.blame_url(repo, oid, path), 307)
|
126
|
+
end
|
127
|
+
|
128
|
+
data = (custom_data || {}).merge(lookup.blame(repo, u(ref), path))
|
129
|
+
[200, headers(:ref => ref), [renderer.render(:blame, data)]]
|
130
|
+
end
|
131
|
+
|
132
|
+
def history(repo, ref, path, count, custom_data = {})
|
133
|
+
if oid = lookup_ref_oid(repo, ref)
|
134
|
+
return redirect(router.history_url(repo, oid, path), 307)
|
135
|
+
end
|
136
|
+
|
137
|
+
data = (custom_data || {}).merge(lookup.history(repo, u(ref), path, count))
|
138
|
+
[200, headers(:ref => ref), [renderer.render(:commits, data)]]
|
139
|
+
end
|
140
|
+
|
141
|
+
def refs(repo, custom_data = {})
|
142
|
+
data = (custom_data || {}).merge(lookup.refs(repo))
|
143
|
+
[200, headers(:content_type => "application/json"), [
|
144
|
+
renderer.render(:refs, data, :layout => nil)
|
145
|
+
]]
|
146
|
+
end
|
147
|
+
|
148
|
+
def tree_history(repo, ref, path, count = 1, custom_data = {})
|
149
|
+
if oid = lookup_ref_oid(repo, ref)
|
150
|
+
return redirect(router.tree_history_url(repo, oid, path), 307)
|
151
|
+
end
|
152
|
+
|
153
|
+
data = (custom_data || {}).merge(lookup.tree_history(repo, u(ref), path, count))
|
154
|
+
[200, headers(:content_type => "application/json", :ref => ref), [
|
155
|
+
renderer.render(:tree_history, data, :layout => nil)
|
156
|
+
]]
|
157
|
+
end
|
158
|
+
|
159
|
+
def resolve_repository(repo)
|
160
|
+
@cache ||= {}
|
161
|
+
@cache[repo] ||= lookup.resolve_repository(repo)
|
162
|
+
end
|
163
|
+
|
164
|
+
def lookup_ref_oid(repo, ref)
|
165
|
+
return if !router.respond_to?(:redirect_refs?) || !router.redirect_refs? || ref.length == 40
|
166
|
+
lookup.rev_parse_oid(repo, ref)
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
attr_reader :router, :lookup, :renderer
|
171
|
+
|
172
|
+
def u(str)
|
173
|
+
# Temporarily swap the + out with a magic byte, so
|
174
|
+
# filenames/branches with +'s won't get unescaped to a space
|
175
|
+
CGI.unescape(str.gsub("+", "\001")).gsub("\001", '+')
|
176
|
+
end
|
177
|
+
|
178
|
+
def headers(options = {})
|
179
|
+
default_ct = "text/html; charset=utf-8"
|
180
|
+
year = 60*60*24*365
|
181
|
+
|
182
|
+
{
|
183
|
+
"Content-Type" => options[:content_type] || default_ct,
|
184
|
+
"X-UA-Compatible" => "IE=edge"
|
185
|
+
}.merge(!options[:ref] || options[:ref].length != 40 ? {} : {
|
186
|
+
"Cache-Control" => "max-age=315360000, public",
|
187
|
+
"Expires" => (Time.now + year).httpdate
|
188
|
+
})
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
data/lib/libdolt/version.rb
CHANGED
data/lib/libdolt.rb
CHANGED
@@ -0,0 +1,475 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#--
|
3
|
+
# Copyright (C) 2012-2013 Gitorious AS
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#++
|
18
|
+
require "test_helper"
|
19
|
+
require "libdolt/controller_actions"
|
20
|
+
|
21
|
+
describe Dolt::ControllerActions do
|
22
|
+
describe "#blob" do
|
23
|
+
it "delegates to lookup" do
|
24
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
25
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new)
|
26
|
+
|
27
|
+
dolt.blob("gitorious", "master", "app/models/repository.rb")
|
28
|
+
|
29
|
+
assert_equal "gitorious", lookup.repo
|
30
|
+
assert_equal "master", lookup.ref
|
31
|
+
assert_equal "app/models/repository.rb", lookup.path
|
32
|
+
end
|
33
|
+
|
34
|
+
it "renders the blob template as html" do
|
35
|
+
router = Test::Router.new
|
36
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Blob"))
|
37
|
+
|
38
|
+
response = dolt.blob("gitorious", "master", "app/models/repository.rb")
|
39
|
+
|
40
|
+
assert_equal "text/html; charset=utf-8", header(response, "Content-Type")
|
41
|
+
assert_equal "blob:Blob", body(response)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "renders the blob template with custom data" do
|
45
|
+
renderer = Test::Renderer.new("Blob")
|
46
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Blob.new), renderer)
|
47
|
+
|
48
|
+
dolt.blob("gitorious", "master", "app/models/repository.rb", { :who => 42 })
|
49
|
+
|
50
|
+
assert_equal 42, renderer.data[:who]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "redirects tree views to tree action" do
|
54
|
+
router = Test::Router.new
|
55
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
56
|
+
|
57
|
+
response = dolt.blob("gitorious", "master", "app/models")
|
58
|
+
|
59
|
+
assert_equal 302, status(response)
|
60
|
+
assert_equal "/gitorious/tree/master:app/models", header(response, "Location")
|
61
|
+
assert_match "You are being ", body(response)
|
62
|
+
assert_match "redirected", body(response)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "unescapes ref" do
|
66
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
67
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new("Blob"))
|
68
|
+
|
69
|
+
dolt.blob("gitorious", "issue-%23221", "app/my documents")
|
70
|
+
|
71
|
+
assert_equal "issue-#221", lookup.ref
|
72
|
+
end
|
73
|
+
|
74
|
+
it "does not redirect ref to oid by default" do
|
75
|
+
router = Test::Router.new
|
76
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Blob"))
|
77
|
+
|
78
|
+
response = dolt.blob("gitorious", "master", "lib/gitorious.rb")
|
79
|
+
|
80
|
+
location = header(response, "Location")
|
81
|
+
refute_equal 302, status(response)
|
82
|
+
refute_equal 307, status(response)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "redirects ref to oid if configured so" do
|
86
|
+
router = Test::RedirectingRouter.new
|
87
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Blob"))
|
88
|
+
|
89
|
+
response = dolt.blob("gitorious", "master", "lib/gitorious.rb")
|
90
|
+
|
91
|
+
location = header(response, "Location")
|
92
|
+
assert_equal 307, status(response)
|
93
|
+
assert_equal "/gitorious/blob/#{'a' * 40}:lib/gitorious.rb", location
|
94
|
+
assert_match "You are being", body(response)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#tree" do
|
99
|
+
it "delegates to actions" do
|
100
|
+
lookup = Test::Lookup.new(Stub::Tree.new)
|
101
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new)
|
102
|
+
|
103
|
+
dolt.tree("gitorious", "master", "app/models")
|
104
|
+
|
105
|
+
assert_equal "gitorious", lookup.repo
|
106
|
+
assert_equal "master", lookup.ref
|
107
|
+
assert_equal "app/models", lookup.path
|
108
|
+
end
|
109
|
+
|
110
|
+
it "renders the tree template as html" do
|
111
|
+
router = Test::Router.new
|
112
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
113
|
+
|
114
|
+
response = dolt.tree("gitorious", "master", "app/models")
|
115
|
+
|
116
|
+
assert_equal "text/html; charset=utf-8", header(response, "Content-Type")
|
117
|
+
assert_equal "tree:Tree", body(response)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "renders template with custom data" do
|
121
|
+
renderer = Test::Renderer.new("Tree")
|
122
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Tree.new), renderer)
|
123
|
+
|
124
|
+
dolt.tree("gitorious", "master", "app/models", { :who => 42 })
|
125
|
+
|
126
|
+
assert_equal 42, renderer.data[:who]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "redirects blob views to blob action" do
|
130
|
+
router = Test::Router.new
|
131
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Tree"))
|
132
|
+
|
133
|
+
response = dolt.tree("gitorious", "master", "app/models/repository.rb")
|
134
|
+
|
135
|
+
location = header(response, "Location")
|
136
|
+
assert_equal 302, status(response)
|
137
|
+
assert_equal "/gitorious/blob/master:app/models/repository.rb", location
|
138
|
+
assert_match "You are being", body(response)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "sets X-UA-Compatible header" do
|
142
|
+
router = Test::Router.new
|
143
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
144
|
+
|
145
|
+
response = dolt.tree("gitorious", "master", "app/models")
|
146
|
+
|
147
|
+
assert_equal "IE=edge", header(response, "X-UA-Compatible")
|
148
|
+
end
|
149
|
+
|
150
|
+
it "does not set cache-control header for head ref" do
|
151
|
+
router = Test::Router.new
|
152
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
153
|
+
|
154
|
+
response = dolt.tree("gitorious", "master", "app/models")
|
155
|
+
|
156
|
+
assert_nil header(response, "Cache-Control")
|
157
|
+
end
|
158
|
+
|
159
|
+
it "sets cache headers for full oid ref" do
|
160
|
+
router = Test::Router.new
|
161
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
162
|
+
|
163
|
+
response = dolt.tree("gitorious", "a" * 40, "app/models")
|
164
|
+
|
165
|
+
assert_equal "max-age=315360000, public", header(response, "Cache-Control")
|
166
|
+
refute_nil header(response, "Expires")
|
167
|
+
end
|
168
|
+
|
169
|
+
it "unescapes ref" do
|
170
|
+
lookup = Test::Lookup.new(Stub::Tree.new)
|
171
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new("Tree"))
|
172
|
+
|
173
|
+
dolt.tree("gitorious", "issue-%23221", "app")
|
174
|
+
|
175
|
+
assert_equal "issue-#221", lookup.ref
|
176
|
+
end
|
177
|
+
|
178
|
+
it "redirects ref to oid if configured so" do
|
179
|
+
router = Test::RedirectingRouter.new
|
180
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
181
|
+
|
182
|
+
response = dolt.tree("gitorious", "master", "lib")
|
183
|
+
|
184
|
+
assert_equal 307, status(response)
|
185
|
+
assert_equal "/gitorious/tree/#{'a' * 40}:lib", header(response, "Location")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "#tree_entry" do
|
190
|
+
it "renders trees with the tree template as html" do
|
191
|
+
router = Test::Router.new
|
192
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
193
|
+
|
194
|
+
response = dolt.tree_entry("gitorious", "master", "app/models")
|
195
|
+
|
196
|
+
assert_equal "text/html; charset=utf-8", header(response, "Content-Type")
|
197
|
+
assert_equal "tree:Tree", body(response)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "renders template with custom data" do
|
201
|
+
renderer = Test::Renderer.new("Tree")
|
202
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Tree.new), renderer)
|
203
|
+
|
204
|
+
dolt.tree_entry("gitorious", "master", "app/models", { :who => 42 })
|
205
|
+
|
206
|
+
assert_equal 42, renderer.data[:who]
|
207
|
+
end
|
208
|
+
|
209
|
+
it "renders trees with the tree template as html" do
|
210
|
+
router = Test::Router.new
|
211
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Blob"))
|
212
|
+
|
213
|
+
response = dolt.tree_entry("gitorious", "master", "app/models")
|
214
|
+
|
215
|
+
assert_equal "text/html; charset=utf-8", header(response, "Content-Type")
|
216
|
+
assert_equal "blob:Blob", body(response)
|
217
|
+
end
|
218
|
+
|
219
|
+
it "unescapes ref" do
|
220
|
+
lookup = Test::Lookup.new(Stub::Tree.new)
|
221
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new("Tree"))
|
222
|
+
|
223
|
+
dolt.tree_entry("gitorious", "issue-%23221", "app")
|
224
|
+
|
225
|
+
assert_equal "issue-#221", lookup.ref
|
226
|
+
end
|
227
|
+
|
228
|
+
it "redirects ref to oid if configured so" do
|
229
|
+
router = Test::RedirectingRouter.new
|
230
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
231
|
+
|
232
|
+
response = dolt.tree_entry("gitorious", "master", "lib")
|
233
|
+
|
234
|
+
assert_equal 307, status(response)
|
235
|
+
assert_equal "/gitorious/source/#{'a' * 40}:lib", header(response, "Location")
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
describe "#raw" do
|
240
|
+
it "delegates to lookup" do
|
241
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
242
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new)
|
243
|
+
|
244
|
+
dolt.raw("gitorious", "master", "app/models/repository.rb")
|
245
|
+
|
246
|
+
assert_equal "gitorious", lookup.repo
|
247
|
+
assert_equal "master", lookup.ref
|
248
|
+
assert_equal "app/models/repository.rb", lookup.path
|
249
|
+
end
|
250
|
+
|
251
|
+
it "renders the raw template as text" do
|
252
|
+
router = Test::Router.new
|
253
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Text"))
|
254
|
+
|
255
|
+
response = dolt.raw("gitorious", "master", "app/models/repository.rb")
|
256
|
+
|
257
|
+
assert_equal "text/plain", header(response, "Content-Type")
|
258
|
+
assert_equal "raw:Text", body(response)
|
259
|
+
end
|
260
|
+
|
261
|
+
it "renders template with custom data" do
|
262
|
+
renderer = Test::Renderer.new("Text")
|
263
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Blob.new), renderer)
|
264
|
+
|
265
|
+
dolt.raw("gitorious", "master", "app/models/repository.rb", { :who => 42 })
|
266
|
+
|
267
|
+
assert_equal 42, renderer.data[:who]
|
268
|
+
end
|
269
|
+
|
270
|
+
it "redirects tree views to tree action" do
|
271
|
+
router = Test::Router.new
|
272
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
273
|
+
|
274
|
+
response = dolt.raw("gitorious", "master", "app/models")
|
275
|
+
|
276
|
+
location = header(response, "Location")
|
277
|
+
assert_equal 302, status(response)
|
278
|
+
assert_equal "/gitorious/tree/master:app/models", location
|
279
|
+
assert_match "You are being", body(response)
|
280
|
+
end
|
281
|
+
|
282
|
+
it "unescapes ref" do
|
283
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
284
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new("Blob"))
|
285
|
+
|
286
|
+
dolt.raw("gitorious", "issue-%23221", "app/models/repository.rb")
|
287
|
+
|
288
|
+
assert_equal "issue-#221", lookup.ref
|
289
|
+
end
|
290
|
+
|
291
|
+
it "redirects ref to oid if configured so" do
|
292
|
+
router = Test::RedirectingRouter.new
|
293
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Blob"))
|
294
|
+
|
295
|
+
response = dolt.raw("gitorious", "master", "lib/gitorious.rb")
|
296
|
+
|
297
|
+
assert_equal 307, status(response)
|
298
|
+
assert_equal "/gitorious/raw/#{'a' * 40}:lib/gitorious.rb", header(response, "Location")
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe "#blame" do
|
303
|
+
it "delegates to lookup" do
|
304
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
305
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new)
|
306
|
+
|
307
|
+
dolt.blame("gitorious", "master", "app/models/repository.rb")
|
308
|
+
|
309
|
+
assert_equal "gitorious", lookup.repo
|
310
|
+
assert_equal "master", lookup.ref
|
311
|
+
assert_equal "app/models/repository.rb", lookup.path
|
312
|
+
end
|
313
|
+
|
314
|
+
it "renders the blame template as html" do
|
315
|
+
router = Test::Router.new
|
316
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Text"))
|
317
|
+
|
318
|
+
response = dolt.blame("gitorious", "master", "app/models/repository.rb")
|
319
|
+
|
320
|
+
assert_equal "text/html; charset=utf-8", header(response, "Content-Type")
|
321
|
+
assert_equal "blame:Text", body(response)
|
322
|
+
end
|
323
|
+
|
324
|
+
it "renders template with custom data" do
|
325
|
+
renderer = Test::Renderer.new("Text")
|
326
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Blob.new), renderer)
|
327
|
+
|
328
|
+
dolt.blame("gitorious", "master", "app/models/repository.rb", { :who => 42 })
|
329
|
+
|
330
|
+
assert_equal 42, renderer.data[:who]
|
331
|
+
end
|
332
|
+
|
333
|
+
it "unescapes ref" do
|
334
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
335
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new("Blob"))
|
336
|
+
|
337
|
+
dolt.blame("gitorious", "issue-%23221", "app/models/repository.rb")
|
338
|
+
|
339
|
+
assert_equal "issue-#221", lookup.ref
|
340
|
+
end
|
341
|
+
|
342
|
+
it "redirects ref to oid if configured so" do
|
343
|
+
router = Test::RedirectingRouter.new
|
344
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Blob"))
|
345
|
+
|
346
|
+
response = dolt.blame("gitorious", "master", "lib/gitorious.rb")
|
347
|
+
|
348
|
+
assert_equal 307, status(response)
|
349
|
+
assert_equal "/gitorious/blame/#{'a' * 40}:lib/gitorious.rb", header(response, "Location")
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
describe "#history" do
|
354
|
+
it "delegates to lookup" do
|
355
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
356
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new)
|
357
|
+
dolt.history("gitorious", "master", "app/models/repository.rb", 10)
|
358
|
+
|
359
|
+
assert_equal "gitorious", lookup.repo
|
360
|
+
assert_equal "master", lookup.ref
|
361
|
+
assert_equal "app/models/repository.rb", lookup.path
|
362
|
+
end
|
363
|
+
|
364
|
+
it "renders the commits template as html" do
|
365
|
+
router = Test::Router.new
|
366
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Text"))
|
367
|
+
|
368
|
+
response = dolt.history("gitorious", "master", "app/models/repository.rb", 10)
|
369
|
+
|
370
|
+
assert_equal "text/html; charset=utf-8", header(response, "Content-Type")
|
371
|
+
assert_equal "commits:Text", body(response)
|
372
|
+
end
|
373
|
+
|
374
|
+
it "renders template with custom data" do
|
375
|
+
renderer = Test::Renderer.new("Text")
|
376
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Blob.new), renderer)
|
377
|
+
|
378
|
+
dolt.history("gitorious", "master", "app/models/repository.rb", 10, { :who => 42 })
|
379
|
+
|
380
|
+
assert_equal 42, renderer.data[:who]
|
381
|
+
end
|
382
|
+
|
383
|
+
it "unescapes ref" do
|
384
|
+
lookup = Test::Lookup.new(Stub::Blob.new)
|
385
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new("Blob"))
|
386
|
+
|
387
|
+
dolt.history("gitorious", "issue-%23221", "lib/gitorious.rb", 10)
|
388
|
+
|
389
|
+
assert_equal "issue-#221", lookup.ref
|
390
|
+
end
|
391
|
+
|
392
|
+
it "redirects ref to oid if configured so" do
|
393
|
+
router = Test::RedirectingRouter.new
|
394
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("Blob"))
|
395
|
+
|
396
|
+
response = dolt.history("gitorious", "master", "lib/gitorious.rb", 10)
|
397
|
+
|
398
|
+
assert_equal 307, status(response)
|
399
|
+
assert_equal "/gitorious/history/#{'a' * 40}:lib/gitorious.rb", header(response, "Location")
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
describe "#refs" do
|
404
|
+
it "renders the refs template as json" do
|
405
|
+
router = Test::Router.new
|
406
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Blob.new), Test::Renderer.new("JSON"))
|
407
|
+
|
408
|
+
response = dolt.refs("gitorious")
|
409
|
+
|
410
|
+
assert_equal "application/json", header(response, "Content-Type")
|
411
|
+
assert_equal "refs:JSON", body(response)
|
412
|
+
end
|
413
|
+
|
414
|
+
it "renders template with custom data" do
|
415
|
+
renderer = Test::Renderer.new("Text")
|
416
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Blob.new), renderer)
|
417
|
+
|
418
|
+
dolt.refs("gitorious", { :who => 42 })
|
419
|
+
|
420
|
+
assert_equal 42, renderer.data[:who]
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe "#tree_history" do
|
425
|
+
it "renders the tree_history template as json" do
|
426
|
+
router = Test::Router.new
|
427
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("JSON"))
|
428
|
+
|
429
|
+
response = dolt.tree_history("gitorious", "master", "", 1)
|
430
|
+
|
431
|
+
assert_equal "application/json", header(response, "Content-Type")
|
432
|
+
assert_equal "tree_history:JSON", body(response)
|
433
|
+
end
|
434
|
+
|
435
|
+
it "renders template with custom data" do
|
436
|
+
renderer = Test::Renderer.new("Text")
|
437
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, Test::Lookup.new(Stub::Tree.new), renderer)
|
438
|
+
|
439
|
+
dolt.tree_history("gitorious", "master", "app/models", 1, { :who => 42 })
|
440
|
+
|
441
|
+
assert_equal 42, renderer.data[:who]
|
442
|
+
end
|
443
|
+
|
444
|
+
it "unescapes ref" do
|
445
|
+
lookup = Test::Lookup.new(Stub::Tree.new)
|
446
|
+
dolt = Dolt::ControllerActions.new(Test::Router.new, lookup, Test::Renderer.new("Tree"))
|
447
|
+
|
448
|
+
dolt.tree_history("gitorious", "issue-%23221", "app/models")
|
449
|
+
|
450
|
+
assert_equal "issue-#221", lookup.ref
|
451
|
+
end
|
452
|
+
|
453
|
+
it "redirects ref to oid if configured so" do
|
454
|
+
router = Test::RedirectingRouter.new
|
455
|
+
dolt = Dolt::ControllerActions.new(router, Test::Lookup.new(Stub::Tree.new), Test::Renderer.new("Tree"))
|
456
|
+
|
457
|
+
response = dolt.tree_history("gitorious", "master", "lib", 10)
|
458
|
+
|
459
|
+
assert_equal 307, status(response)
|
460
|
+
assert_equal "/gitorious/tree_history/#{'a' * 40}:lib", header(response, "Location")
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
def status(response)
|
465
|
+
response[0]
|
466
|
+
end
|
467
|
+
|
468
|
+
def header(response, name)
|
469
|
+
response[1][name]
|
470
|
+
end
|
471
|
+
|
472
|
+
def body(response)
|
473
|
+
response[2].join
|
474
|
+
end
|
475
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -46,15 +46,15 @@ module Dolt
|
|
46
46
|
root = File.join(File.dirname(__FILE__), "..", "views")
|
47
47
|
renderer = Tiltout.new(root, options)
|
48
48
|
renderer.helper(helpers || [Dolt::View::MultiRepository,
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
Dolt::View::Urls,
|
50
|
+
Dolt::View::Object,
|
51
|
+
Dolt::View::Blob,
|
52
|
+
Dolt::View::Tree,
|
53
|
+
Dolt::View::Blame,
|
54
|
+
Dolt::View::SyntaxHighlight,
|
55
|
+
Dolt::View::Commit,
|
56
|
+
Dolt::View::Gravatar,
|
57
|
+
Dolt::View::Breadcrumb])
|
58
58
|
renderer
|
59
59
|
end
|
60
60
|
end
|
@@ -80,3 +80,121 @@ module Dolt
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
83
|
+
|
84
|
+
module Stub
|
85
|
+
class Blob
|
86
|
+
def is_a?(type)
|
87
|
+
type == Rugged::Blob
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Tree
|
92
|
+
def is_a?(type)
|
93
|
+
type == Rugged::Tree
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
module Test
|
99
|
+
class Router
|
100
|
+
def tree_url(repo, ref, path)
|
101
|
+
"/#{repo}/tree/#{ref}:#{path}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def blob_url(repo, ref, path)
|
105
|
+
"/#{repo}/blob/#{ref}:#{path}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def tree_entry_url(repo, ref, path)
|
109
|
+
"/#{repo}/source/#{ref}:#{path}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def blame_url(repo, ref, path)
|
113
|
+
"/#{repo}/blame/#{ref}:#{path}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def history_url(repo, ref, path)
|
117
|
+
"/#{repo}/history/#{ref}:#{path}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def tree_history_url(repo, ref, path)
|
121
|
+
"/#{repo}/tree_history/#{ref}:#{path}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def raw_url(repo, ref, path)
|
125
|
+
"/#{repo}/raw/#{ref}:#{path}"
|
126
|
+
end
|
127
|
+
|
128
|
+
def method_missing(name, *args, &block)
|
129
|
+
@actions.send(name, *args, &block)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class RedirectingRouter < Router
|
134
|
+
def redirect_refs?; true; end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Renderer
|
138
|
+
attr_reader :data
|
139
|
+
def initialize(body = ""); @body = body; end
|
140
|
+
|
141
|
+
def render(action, data, options = {})
|
142
|
+
@action = action
|
143
|
+
@data = data
|
144
|
+
"#{action}:#@body"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class Lookup
|
149
|
+
attr_reader :repo, :ref, :path
|
150
|
+
|
151
|
+
def initialize(response)
|
152
|
+
@response = response
|
153
|
+
end
|
154
|
+
|
155
|
+
def blob(repo, ref, path)
|
156
|
+
respond(:blob, repo, ref, path)
|
157
|
+
end
|
158
|
+
|
159
|
+
def tree(repo, ref, path)
|
160
|
+
respond(:tree, repo, ref, path)
|
161
|
+
end
|
162
|
+
|
163
|
+
def tree_entry(repo, ref, path)
|
164
|
+
respond(:tree_entry, repo, ref, path)
|
165
|
+
end
|
166
|
+
|
167
|
+
def raw(repo, ref, path)
|
168
|
+
respond(:raw, repo, ref, path)
|
169
|
+
end
|
170
|
+
|
171
|
+
def blame(repo, ref, path)
|
172
|
+
respond(:blame, repo, ref, path)
|
173
|
+
end
|
174
|
+
|
175
|
+
def history(repo, ref, path, limit)
|
176
|
+
respond(:history, repo, ref, path)
|
177
|
+
end
|
178
|
+
|
179
|
+
def refs(repo)
|
180
|
+
respond(:refs, repo)
|
181
|
+
end
|
182
|
+
|
183
|
+
def tree_history(repo, ref, path, count)
|
184
|
+
respond(:tree_history, repo, ref, path)
|
185
|
+
end
|
186
|
+
|
187
|
+
def respond(type, repo, ref = nil, path = nil)
|
188
|
+
@repo = repo
|
189
|
+
@ref = ref
|
190
|
+
@path = path
|
191
|
+
data = { :ref => ref, :repository => repo }
|
192
|
+
data[type != :tree_entry ? type : (@response.class.to_s =~ /Tree/ ? :tree : :blob)] = @response
|
193
|
+
data
|
194
|
+
end
|
195
|
+
|
196
|
+
def rev_parse_oid(repo, ref)
|
197
|
+
"a" * 40
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libdolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.27.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rugged
|
@@ -201,6 +201,7 @@ files:
|
|
201
201
|
- Rakefile
|
202
202
|
- Readme.md
|
203
203
|
- lib/libdolt.rb
|
204
|
+
- lib/libdolt/controller_actions.rb
|
204
205
|
- lib/libdolt/disk_repo_resolver.rb
|
205
206
|
- lib/libdolt/git.rb
|
206
207
|
- lib/libdolt/git/archiver.rb
|
@@ -210,7 +211,6 @@ files:
|
|
210
211
|
- lib/libdolt/git/repository.rb
|
211
212
|
- lib/libdolt/git/submodule.rb
|
212
213
|
- lib/libdolt/git/tree.rb
|
213
|
-
- lib/libdolt/gitorious_repo_resolver.rb
|
214
214
|
- lib/libdolt/repository_lookup.rb
|
215
215
|
- lib/libdolt/version.rb
|
216
216
|
- lib/libdolt/view.rb
|
@@ -249,6 +249,7 @@ files:
|
|
249
249
|
- test/fixtures/dolt-test-repo.git/objects/fc/5f5fb50b435e183925b341909610aace90a413
|
250
250
|
- test/fixtures/dolt-test-repo.git/refs/heads/master
|
251
251
|
- test/fixtures/dolt-test-repo.git/refs/tags/testable-tag
|
252
|
+
- test/libdolt/controller_actions_test.rb
|
252
253
|
- test/libdolt/disk_repo_resolver_test.rb
|
253
254
|
- test/libdolt/git/archiver_test.rb
|
254
255
|
- test/libdolt/git/blame_test.rb
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#--
|
3
|
-
# Copyright (C) 2012 Gitorious AS
|
4
|
-
#
|
5
|
-
# This program is free software: you can redistribute it and/or modify
|
6
|
-
# it under the terms of the GNU Affero General Public License as published by
|
7
|
-
# the Free Software Foundation, either version 3 of the License, or
|
8
|
-
# (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This program is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
-
# GNU Affero General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Affero General Public License
|
16
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
-
#++
|
18
|
-
|
19
|
-
module Dolt
|
20
|
-
class GitoriousRepoResolver
|
21
|
-
def initialize(repository)
|
22
|
-
@repository = repository
|
23
|
-
end
|
24
|
-
|
25
|
-
def resolve(repo = nil)
|
26
|
-
Dolt::Git::Repository.new(@repository.full_repository_path)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|