puppet-forge-server 1.8.0 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/lib/puppet_forge_server.rb +4 -0
- data/lib/puppet_forge_server/api/v1/modules.rb +7 -3
- data/lib/puppet_forge_server/api/v3/modules.rb +7 -2
- data/lib/puppet_forge_server/api/v3/releases.rb +9 -4
- data/lib/puppet_forge_server/app/frontend.rb +19 -0
- data/lib/puppet_forge_server/app/public/css/puppetlabs.css +236 -0
- data/lib/puppet_forge_server/app/views/layout.haml +1 -1
- data/lib/puppet_forge_server/app/views/module.haml +71 -0
- data/lib/puppet_forge_server/app/views/modules.haml +1 -1
- data/lib/puppet_forge_server/backends/directory.rb +12 -5
- data/lib/puppet_forge_server/backends/proxy.rb +29 -4
- data/lib/puppet_forge_server/backends/proxy_v3.rb +20 -6
- data/lib/puppet_forge_server/http/http_client.rb +29 -2
- data/lib/puppet_forge_server/logger.rb +9 -2
- data/lib/puppet_forge_server/models/builder.rb +6 -1
- data/lib/puppet_forge_server/models/metadata.rb +1 -1
- data/lib/puppet_forge_server/models/module.rb +2 -2
- data/lib/puppet_forge_server/server.rb +2 -0
- data/lib/puppet_forge_server/utils/archiver.rb +3 -1
- data/lib/puppet_forge_server/utils/cache_provider.rb +42 -0
- data/lib/puppet_forge_server/utils/encoding.rb +46 -0
- data/lib/puppet_forge_server/utils/filtering_inspecter.rb +30 -0
- data/lib/puppet_forge_server/utils/md_renderer.rb +54 -0
- data/lib/puppet_forge_server/utils/option_parser.rb +23 -1
- data/lib/puppet_forge_server/version.rb +1 -1
- data/puppet-forge-server.gemspec +8 -0
- data/spec/spec_helper.rb +41 -1
- data/spec/unit/http/http_client_spec.rb +93 -0
- data/spec/unit/utils/encoding_spec.rb +35 -0
- metadata +110 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 08f079588ee75d93139153846fb0021ffd6e856a
|
4
|
+
data.tar.gz: 985dd8259b92e2a616e2ea00dcb4ac906572fb69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bb6e219dd02e6484fab928c5c5047bf51329facd1fc1d2acd4613c79f4e22bc1fce66f4709302c0b57d24137417b23a8cd1b37c64b149e7f6e48cbc5186a438
|
7
|
+
data.tar.gz: 4abba59d6b0cc3c16a65534940a37187286207ba273936dcf0c0b6d859c7a851cb055a549aecdaaf551797817cd08f3ab711341cc67223aac54fa175543bb8d6
|
data/.rspec
ADDED
data/.travis.yml
CHANGED
data/lib/puppet_forge_server.rb
CHANGED
@@ -56,10 +56,14 @@ module PuppetForgeServer
|
|
56
56
|
end
|
57
57
|
|
58
58
|
module Utils
|
59
|
+
autoload :CacheProvider, 'puppet_forge_server/utils/cache_provider'
|
60
|
+
autoload :FilteringInspecter, 'puppet_forge_server/utils/filtering_inspecter'
|
59
61
|
autoload :Archiver, 'puppet_forge_server/utils/archiver'
|
60
62
|
autoload :OptionParser, 'puppet_forge_server/utils/option_parser'
|
61
63
|
autoload :Buffer, 'puppet_forge_server/utils/buffer'
|
62
64
|
autoload :Http, 'puppet_forge_server/utils/http'
|
65
|
+
autoload :MarkdownRenderer, 'puppet_forge_server/utils/md_renderer'
|
66
|
+
autoload :Encoding, 'puppet_forge_server/utils/encoding'
|
63
67
|
end
|
64
68
|
|
65
69
|
module Http
|
@@ -29,16 +29,20 @@ module PuppetForgeServer::Api::V1
|
|
29
29
|
modules[element.metadata.name][:releases] = (modules[element.metadata.name][:releases] + releases_version(element.metadata)).uniq.sort_by { |r| Gem::Version.new(r[:version]) }.reverse
|
30
30
|
modules[element.metadata.name][:tag_list] = (modules[element.metadata.name][:tag_list] + element.tags).uniq.compact
|
31
31
|
else
|
32
|
-
name = element.metadata.name.
|
32
|
+
author, name = element.metadata.name.split('-')
|
33
|
+
unless name
|
34
|
+
name = author
|
35
|
+
author = element.metadata.author
|
36
|
+
end
|
33
37
|
modules[element.metadata.name] = {
|
34
|
-
:author =>
|
38
|
+
:author => author,
|
35
39
|
:full_name => element.metadata.name.sub('-', '/'),
|
36
40
|
:name => name,
|
37
41
|
:desc => element.metadata.description,
|
38
42
|
:version => element.metadata.version,
|
39
43
|
:project_url => element.metadata.project_page,
|
40
44
|
:releases => releases_version(element.metadata),
|
41
|
-
:tag_list => element.tags ? element.tags : [
|
45
|
+
:tag_list => element.tags ? element.tags : [author, name],
|
42
46
|
:private => element.private
|
43
47
|
}
|
44
48
|
end
|
@@ -30,14 +30,19 @@ module PuppetForgeServer::Api::V3
|
|
30
30
|
end
|
31
31
|
modules[element.metadata.name][:releases] = (modules[element.metadata.name][:releases] + releases_version(element.metadata)).uniq.sort_by { |r| Gem::Version.new(r[:version]) }.reverse
|
32
32
|
else
|
33
|
+
author, name = element.metadata.name.split('-')
|
34
|
+
unless name
|
35
|
+
name = author
|
36
|
+
author = element.metadata.author
|
37
|
+
end
|
33
38
|
modules[element.metadata.name] = {
|
34
39
|
:uri => "/v3/modules/#{element.metadata.name}",
|
35
|
-
:name =>
|
40
|
+
:name => name,
|
36
41
|
:homepage_url => element.metadata.project_page,
|
37
42
|
:issues_url => element.metadata.issues_url,
|
38
43
|
:releases => releases_version(element.metadata),
|
39
44
|
:current_release => get_releases([element]).first,
|
40
|
-
:owner => {:username =>
|
45
|
+
:owner => {:username => author, :uri => "/v3/users/#{author}"},
|
41
46
|
:private => element.private
|
42
47
|
}
|
43
48
|
end
|
@@ -16,10 +16,14 @@
|
|
16
16
|
|
17
17
|
module PuppetForgeServer::Api::V3
|
18
18
|
module Releases
|
19
|
+
include PuppetForgeServer::Utils::Encoding
|
19
20
|
def get_releases(metadata)
|
20
21
|
metadata.map do |element|
|
21
|
-
name = element.metadata.name.
|
22
|
-
|
22
|
+
author, name = element.metadata.name.split('-')
|
23
|
+
unless name
|
24
|
+
name = author
|
25
|
+
author = element.metadata.author
|
26
|
+
end
|
23
27
|
{
|
24
28
|
:uri => "/v3/releases/#{element.metadata.name}-#{element.metadata.version}",
|
25
29
|
:module => {
|
@@ -29,10 +33,11 @@ module PuppetForgeServer::Api::V3
|
|
29
33
|
},
|
30
34
|
:metadata => element.metadata.to_hash,
|
31
35
|
:version => element.metadata.version,
|
32
|
-
:tags => element.tags ? element.tags : [
|
36
|
+
:tags => element.tags ? element.tags : [author, name],
|
33
37
|
:file_uri => "/v3/files#{element.path}",
|
34
38
|
:file_md5 => element.checksum,
|
35
|
-
:deleted_at => element.deleted_at
|
39
|
+
:deleted_at => element.deleted_at,
|
40
|
+
:readme => to_utf8(element.readme)
|
36
41
|
}
|
37
42
|
end.uniq{|r| r[:version]}.sort_by { |r| Gem::Version.new(r[:version]) }
|
38
43
|
end
|
@@ -17,9 +17,11 @@
|
|
17
17
|
require 'sinatra/base'
|
18
18
|
require 'haml'
|
19
19
|
require 'json'
|
20
|
+
require 'tilt/haml'
|
20
21
|
|
21
22
|
module PuppetForgeServer::App
|
22
23
|
class Frontend < Sinatra::Base
|
24
|
+
include PuppetForgeServer::Utils::MarkdownRenderer
|
23
25
|
|
24
26
|
configure do
|
25
27
|
set :haml, :format => :html5
|
@@ -47,6 +49,23 @@ module PuppetForgeServer::App
|
|
47
49
|
haml :modules, :locals => {:query => query, :modules => modules}
|
48
50
|
end
|
49
51
|
|
52
|
+
get '/module' do
|
53
|
+
module_v3_name = params[:name].gsub(/\//, '-')
|
54
|
+
releases = get("#{request.base_url}/v3/modules/#{module_v3_name}")['releases']
|
55
|
+
if params.has_key? 'version'
|
56
|
+
module_uri = releases.find {|r| r['version'] == params['version']}['uri']
|
57
|
+
module_metadata = get("#{request.base_url}#{module_uri}")
|
58
|
+
else
|
59
|
+
module_metadata = get("#{request.base_url}#{releases[0]['uri']}")
|
60
|
+
end
|
61
|
+
begin
|
62
|
+
readme_markdown = markdown(module_metadata['readme'])
|
63
|
+
rescue
|
64
|
+
readme_markdown = ''
|
65
|
+
end
|
66
|
+
haml :module, :locals => { :module_metadata => module_metadata, :base_url => request.base_url, :readme_markdown => readme_markdown, :releases => releases }
|
67
|
+
end
|
68
|
+
|
50
69
|
get '/upload' do
|
51
70
|
haml :upload, :locals => {:upload_status => ''}
|
52
71
|
end
|
@@ -16,6 +16,7 @@
|
|
16
16
|
* limitations under the License.
|
17
17
|
*/
|
18
18
|
|
19
|
+
@import url(https://fonts.googleapis.com/css?family=PT+Sans&subset=latin,latin-ext);
|
19
20
|
body {
|
20
21
|
background: #fff;
|
21
22
|
color: #5d5e59;
|
@@ -215,6 +216,214 @@ h3.search-results-title {
|
|
215
216
|
margin: 0;
|
216
217
|
border-bottom: solid 1px #cccccc;
|
217
218
|
}
|
219
|
+
.module-header {
|
220
|
+
position: relative;
|
221
|
+
float: left;
|
222
|
+
width: 90%;
|
223
|
+
min-height: 77px;
|
224
|
+
padding: 1em;
|
225
|
+
background-color: #f4f4f4;
|
226
|
+
}
|
227
|
+
.module-header.supported {
|
228
|
+
background-image: url("/assets/41dfc34/images/supported-tag-upper-right.png");
|
229
|
+
background-repeat: no-repeat;
|
230
|
+
background-position: top right;
|
231
|
+
}
|
232
|
+
.module-header.approved {
|
233
|
+
background-image: url("/assets/41dfc34/images/approved-tag-upper-right.png");
|
234
|
+
background-repeat: no-repeat;
|
235
|
+
background-position: top right;
|
236
|
+
}
|
237
|
+
.module-header .author,
|
238
|
+
.module-header .tag-section {
|
239
|
+
padding-top: 0.25em;
|
240
|
+
}
|
241
|
+
.module-header .popular {
|
242
|
+
display: inline;
|
243
|
+
margin-left: 0;
|
244
|
+
}
|
245
|
+
.module-header .tags {
|
246
|
+
display: inline;
|
247
|
+
margin-left: 0;
|
248
|
+
}
|
249
|
+
.module-header .endorsement-trigger {
|
250
|
+
position: absolute;
|
251
|
+
top: 0;
|
252
|
+
right: 0;
|
253
|
+
width: 77px;
|
254
|
+
height: 77px;
|
255
|
+
}
|
256
|
+
.module-header .details {
|
257
|
+
font-size: 0.95em;
|
258
|
+
}
|
259
|
+
.module-header .details table {
|
260
|
+
width: 100%;
|
261
|
+
position: relative;
|
262
|
+
}
|
263
|
+
.module-header .details .gravatar {
|
264
|
+
float: left;
|
265
|
+
width: 77px;
|
266
|
+
}
|
267
|
+
.module-header .details .gravatar .avatar {
|
268
|
+
margin: 0;
|
269
|
+
padding: 0;
|
270
|
+
}
|
271
|
+
.module-header .details .module-info-basic {
|
272
|
+
margin-left: 93px;
|
273
|
+
/* width of gravatar (77) + 1em (16) */
|
274
|
+
}
|
275
|
+
.module-header .details .module-info-basic .module-info-header {
|
276
|
+
margin: 0;
|
277
|
+
padding-right: 45px;
|
278
|
+
}
|
279
|
+
.module-header .details .module-info-basic .module-info-header a:hover {
|
280
|
+
text-decoration: underline;
|
281
|
+
}
|
282
|
+
.module-header .details .module-info-basic .module-info-header h2 {
|
283
|
+
display: inline-block;
|
284
|
+
margin: 0 10px 0 0;
|
285
|
+
line-height: 1.1rem;
|
286
|
+
}
|
287
|
+
@media (max-width: 1150px) {
|
288
|
+
.module-header .details .module-info-basic .module-info-header h2 .namespace {
|
289
|
+
display: none;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
.module-header .details .module-info-basic .module-info-header .module-info-author {
|
293
|
+
display: inline-block;
|
294
|
+
margin-right: 15px;
|
295
|
+
font-size: 12px;
|
296
|
+
white-space: nowrap;
|
297
|
+
}
|
298
|
+
.module-header .details .module-info-basic .module-info-header .module-links {
|
299
|
+
display: inline-block;
|
300
|
+
font-size: 12px;
|
301
|
+
}
|
302
|
+
.module-header .details .module-info-basic .module-info-header .module-links li {
|
303
|
+
display: inline-block;
|
304
|
+
margin-bottom: 0;
|
305
|
+
margin-right: 15px;
|
306
|
+
}
|
307
|
+
.module-header .details .module-info-basic > div {
|
308
|
+
padding-bottom: 0.35em;
|
309
|
+
}
|
310
|
+
.module-header .details .module-info-basic ul {
|
311
|
+
margin: 0;
|
312
|
+
list-style-type: none;
|
313
|
+
}
|
314
|
+
.module-header .details .module-info-basic ul.release-os-compat li {
|
315
|
+
display: inline;
|
316
|
+
margin-right: 5px;
|
317
|
+
}
|
318
|
+
.module-header .details .module-info-basic ul.release-os-compat span[data-releases] {
|
319
|
+
border-bottom: 1px dotted;
|
320
|
+
cursor: default;
|
321
|
+
}
|
322
|
+
.module-header .details .module-info-basic .module-info-summary {
|
323
|
+
margin-bottom: 1em;
|
324
|
+
}
|
325
|
+
.module-header .details .module-info-basic .module-info-tags {
|
326
|
+
font-size: 0.85em;
|
327
|
+
margin-top: 1.75em;
|
328
|
+
width: 85%;
|
329
|
+
}
|
330
|
+
.module-header .details .module-info-basic .compatibility {
|
331
|
+
background-color: #ffffff;
|
332
|
+
padding: 0.5em;
|
333
|
+
margin-top: 0.25em;
|
334
|
+
}
|
335
|
+
.module-header .details .module-info-basic .compatibility ul.bullets {
|
336
|
+
list-style-type: disc;
|
337
|
+
margin-left: 1.5em;
|
338
|
+
}
|
339
|
+
.module-header .details .module-info-basic .compatibility ul.bullets li {
|
340
|
+
margin-bottom: 0;
|
341
|
+
padding-bottom: 0;
|
342
|
+
}
|
343
|
+
.module-header .download-info {
|
344
|
+
padding-top: 1em;
|
345
|
+
margin-top: 1em;
|
346
|
+
border-top: 1px #ccc solid;
|
347
|
+
}
|
348
|
+
.module-header .download-info > div {
|
349
|
+
-moz-box-sizing: border-box;
|
350
|
+
box-sizing: border-box;
|
351
|
+
}
|
352
|
+
.module-header .download-info .installation {
|
353
|
+
float: left;
|
354
|
+
width: 75%;
|
355
|
+
}
|
356
|
+
.module-header .download-info .installation small {
|
357
|
+
display: block;
|
358
|
+
float: left;
|
359
|
+
width: 50%;
|
360
|
+
font-size: 11px;
|
361
|
+
}
|
362
|
+
.module-header .download-info .installation small.download-link {
|
363
|
+
text-align: right;
|
364
|
+
font-weight: bold;
|
365
|
+
}
|
366
|
+
.module-header .download-info .download-counts {
|
367
|
+
float: left;
|
368
|
+
width: 25%;
|
369
|
+
padding-top: 36px;
|
370
|
+
padding-right: 5%;
|
371
|
+
text-align: right;
|
372
|
+
font-size: 1.1em;
|
373
|
+
line-height: 1em;
|
374
|
+
font-weight: bold;
|
375
|
+
}
|
376
|
+
.module-header .download-info .download-counts small {
|
377
|
+
font-size: 11px;
|
378
|
+
font-weight: normal;
|
379
|
+
color: #6c6d6d;
|
380
|
+
}
|
381
|
+
.module-header .download-info .pe-only {
|
382
|
+
padding-left: 93px;
|
383
|
+
}
|
384
|
+
.module-header .download-info .pe-only input[type=text] {
|
385
|
+
box-sizing: border-box;
|
386
|
+
max-width: none;
|
387
|
+
width: 100%;
|
388
|
+
}
|
389
|
+
.module-header .download-info .pe-only p {
|
390
|
+
margin-bottom: 0.5em;
|
391
|
+
}
|
392
|
+
.module-header-sidebar {
|
393
|
+
float: right;
|
394
|
+
width: 22%;
|
395
|
+
}
|
396
|
+
.module-meta-info ul.release-dependencies {
|
397
|
+
margin-top: 1.25em;
|
398
|
+
}
|
399
|
+
#module-release-header {
|
400
|
+
overflow: auto;
|
401
|
+
margin-top: 20px;
|
402
|
+
margin-bottom: 10px;
|
403
|
+
}
|
404
|
+
#module-release-header #module-release-title {
|
405
|
+
float: left;
|
406
|
+
font-size: 1.2em;
|
407
|
+
}
|
408
|
+
#module-release-header #module-release-switcher {
|
409
|
+
float: right;
|
410
|
+
padding-top: 3px;
|
411
|
+
text-align: right;
|
412
|
+
font-size: 13px;
|
413
|
+
}
|
414
|
+
#module-release-header #module-release-switcher label {
|
415
|
+
display: inline-block;
|
416
|
+
font-weight: normal;
|
417
|
+
}
|
418
|
+
#module-release-header #module-release-switcher a {
|
419
|
+
display: inline-block;
|
420
|
+
margin-left: 6px;
|
421
|
+
padding: 3px 9px;
|
422
|
+
min-width: 60px;
|
423
|
+
border-radius: 4px;
|
424
|
+
background-color: #f4f4f4;
|
425
|
+
text-align: center;
|
426
|
+
}
|
218
427
|
ul, ol, dl {
|
219
428
|
margin-bottom: 1.5em;
|
220
429
|
margin-left: 0;
|
@@ -249,6 +458,11 @@ li.private {
|
|
249
458
|
background-repeat: no-repeat;
|
250
459
|
background-position: right top;
|
251
460
|
}
|
461
|
+
section.private {
|
462
|
+
background-image: url("/img/endorsement-private.png");
|
463
|
+
background-repeat: no-repeat;
|
464
|
+
background-position: right top;
|
465
|
+
}
|
252
466
|
p {
|
253
467
|
margin: 0;
|
254
468
|
}
|
@@ -277,3 +491,25 @@ a.module-link {
|
|
277
491
|
color: #0095dd;
|
278
492
|
font-size: 0.9em;
|
279
493
|
}
|
494
|
+
.installation input.paste-code {
|
495
|
+
display: block;
|
496
|
+
-moz-box-sizing: border-box;
|
497
|
+
box-sizing: border-box;
|
498
|
+
margin-top: 0.5em;
|
499
|
+
margin-bottom: 3px;
|
500
|
+
width: 100%;
|
501
|
+
max-width: none;
|
502
|
+
padding: 0.75em;
|
503
|
+
border: 0;
|
504
|
+
background: #e5e5e5;
|
505
|
+
color: #5d5e59;
|
506
|
+
font-family: Monaco, "Liberation Mono", Courier, monospace;
|
507
|
+
}
|
508
|
+
pre {
|
509
|
+
border-radius: .25em;
|
510
|
+
background: #f5f2f0;
|
511
|
+
border: 1px solid #DDD;
|
512
|
+
padding: .5em 1em;
|
513
|
+
overflow: auto;
|
514
|
+
display: block;
|
515
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
-# -*- encoding: utf-8 -*-
|
2
|
+
-#
|
3
|
+
-# Copyright 2015 North Development AB
|
4
|
+
-#
|
5
|
+
-# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
-# you may not use this file except in compliance with the License.
|
7
|
+
-# You may obtain a copy of the License at
|
8
|
+
-#
|
9
|
+
-# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
-#
|
11
|
+
-# Unless required by applicable law or agreed to in writing, software
|
12
|
+
-# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
-# See the License for the specific language governing permissions and
|
15
|
+
-# limitations under the License.
|
16
|
+
|
17
|
+
- if !module_metadata.has_key? 'metadata'
|
18
|
+
%section{:id => 'content'}
|
19
|
+
%div{:class => 'site-width clearfix'}
|
20
|
+
%section{:id => 'body', :class => ' '}
|
21
|
+
No such module
|
22
|
+
- else
|
23
|
+
%section{:id => 'content'}
|
24
|
+
%div{:class => 'site-width clearfix'}
|
25
|
+
%section{:id => 'body', :class => ' '}
|
26
|
+
%div{:class => 'module-header-container clearfix'}
|
27
|
+
%section{:class => module_metadata['private'] ? 'module-header private' : 'module-header'}
|
28
|
+
%section{:class => 'details clearfix'}
|
29
|
+
%div{:class => 'module-info-basic'}
|
30
|
+
%div{:class => 'module-info-header'}
|
31
|
+
%h2
|
32
|
+
%span{:class => 'namespace'}= module_metadata['metadata']['name']
|
33
|
+
%div{:class => 'module-info-author'}= "by: #{module_metadata['metadata']['author']}"
|
34
|
+
%ul{:class => 'module-links'}
|
35
|
+
%li
|
36
|
+
%a{:href => module_metadata['metadata']['project_page']}= 'Project URL'
|
37
|
+
%li
|
38
|
+
%a{:href => module_metadata['metadata']['issues_url']}= 'Report issues'
|
39
|
+
%div{:class => 'module-info-summary'}= module_metadata['metadata']['summary']
|
40
|
+
%div{:class => 'download-info clearfix'}
|
41
|
+
%div{:class => 'installation'}
|
42
|
+
%div{:class => 'pmt-option clearfix'}
|
43
|
+
%strong= 'Use this command to install the latest compatible version:'
|
44
|
+
%input{:type => 'text', :class => 'paste-code', :value => "puppet module install --module_repository=#{base_url} #{module_metadata['metadata']['name']}", :onclick => 'this.select()'}
|
45
|
+
%div{:class => 'module-meta-info clearfix'}
|
46
|
+
%h3= 'Module dependencies'
|
47
|
+
%ul.release-dependencies
|
48
|
+
- module_metadata['metadata']['dependencies'].each do |dep|
|
49
|
+
%li
|
50
|
+
%a{:href => "/module?name=#{dep['name']}"}= dep['name']
|
51
|
+
- if dep['version_requirement']
|
52
|
+
= "(#{dep['version_requirement']})"
|
53
|
+
%section{:id => 'module-release-info'}
|
54
|
+
%div
|
55
|
+
%div{:id => 'module-release-header'}
|
56
|
+
%div{:id => 'module-release-title'}
|
57
|
+
Version
|
58
|
+
%strong= module_metadata['metadata']['version']
|
59
|
+
%div{:id => 'module-release-switcher'}
|
60
|
+
%label= 'Select another release: '
|
61
|
+
%select{:id => 'module-release-selector', :onchange => "location = this.options[this.selectedIndex].value;"}
|
62
|
+
- releases.each do |release|
|
63
|
+
%option{:value => "/module?name=#{module_metadata['metadata']['name']}&version=#{release['version']}", :selected => module_metadata['metadata']['version'] == release['version']}= release['version']
|
64
|
+
%a{:class => 'module-release-download', :href => module_metadata['file_uri'], :title => 'Download module'}= 'Download'
|
65
|
+
%div{:id => 'release-info-tabs', :class => 'module-meta-info'}
|
66
|
+
%div{:class => 'tabbed content'}
|
67
|
+
%div
|
68
|
+
%div
|
69
|
+
%section{:class => 'markdown'}
|
70
|
+
:preserve
|
71
|
+
#{readme_markdown}
|