puppet-library 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZDc4NjNkZDQyZTlhNWMzZWIwZDhmMTM1MzY1ZTg4NzUyNWQyYzY2OQ==
4
+ ZTgwMTJmOWUxMDllNDMyMjFjNTgyZmI2ZmQ2NDc0NmM0NDEwYjRlNQ==
5
5
  data.tar.gz: !binary |-
6
- MzA4N2JiOGU0MTkzMTBmZGUyYzhhOTFiNWQxZGViOGU0YTY5ODk3OA==
6
+ MmYzYzNiN2MxMTBhYTc1NzRlZGQ4OTExN2QyNzhmY2RhYjBlZDcyMw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NWUzMTQ5MDM2ZWEwOWY4MzcwYTI1NGRkNjJiNWI3ZDJiN2I0OTg5MGMwMWEz
10
- MmY0ZmRhNTQ4ZWI5YWQ2ZWUxMGUxNDQ0YjhjYzMzMmJmMTBjNWRmMTlkM2M3
11
- M2Y4YTU0NzQwOThjM2E0YTU2MzIzYWM2M2U4YmFmNDkyYzBkMDY=
9
+ Njk2ZmJmM2JmNDlhNzRmYzA3NDcyYWFmNjAwYTBmODQ2MzFmYmIxZmZmMGVh
10
+ MWFiNGRiOTM1NGYyMjQzY2NjNGFhMDdmOWUxNmM1YWVkOTRjMzhjNzVkMmE5
11
+ ZTA3ZWU0NDZiNTVlMjZjYzYzMjI5MDU2YzcxYmRmMzI5YmYwZDg=
12
12
  data.tar.gz: !binary |-
13
- MDBmNzBkZDYzZWZkZWU5YWE0ODhkZDNmMDQ5ZmRkODMxNjJjYTQ4Y2Q2M2U3
14
- Njc3M2E3Zjk1NGE4MGM2ZWJmMDllMThiM2IwMDE3M2EzYjAxNDg2OTNlOGM0
15
- ZGYyNGNhNjJlOWI5MTRlY2QzMjk0YzY5NmU1ZmFlNTNjNTg0ZDc=
13
+ ZWUzODAwZTRmOTNlY2U1MjRkZGI5NGY2YzAyOTJhMTFhNTc1N2U0MjJlMGUy
14
+ Yjc0MzQyN2FkNTRmOWY2ZTBlNmRmODhlY2ExMjk4MDIzYjJjNWFkMTJiZGI1
15
+ YWY1MTYxZTQ1ZmJhOWQ1NWZmOGU3YWVlZGM5MTJhNDUxODUxYjU=
data/.travis.yml CHANGED
@@ -25,7 +25,8 @@ rvm:
25
25
  - 2.1.0
26
26
  env:
27
27
  - RUBYGEMS_VERSION=2.1.11
28
- - RUBYGEMS_VERSION=1.8.24
28
+ #- RUBYGEMS_VERSION=1.8.5 # What Ubuntu 12.4 has
29
+ - RUBYGEMS_VERSION=1.8.28 # Earlier versions of Rubygems 1.8.x, when used with Ruby 2.0 fail to install nokogiri properly (Seen on R 2.0.0 / RG 1.8.24)
29
30
  #matrix:
30
31
  # allow_failures:
31
32
  # - rvm: 2.1.0
data/CHANGELOG.yml CHANGED
@@ -32,4 +32,9 @@
32
32
  changes:
33
33
  - Added module search
34
34
  - Improved performance of proxy
35
+ - tag: v0.4.0
36
+ changes:
37
+ - Added '--version' option to CLI
38
+ - Added option to daemonize server (with optional pidfile)
39
+ - Added web UI to browse modules
35
40
 
data/README.md CHANGED
@@ -89,6 +89,48 @@ Puppet Library currently supports:
89
89
  - dependency resolution and installation with [librarian-puppet](http://librarian-puppet.com)
90
90
  - installation with [r10k](https://github.com/adrienthebo/r10k)
91
91
 
92
+ Puppet Library is tested against Ruby versions:
93
+ - 1.8.7
94
+ - 1.9.3
95
+ - 2.0.0
96
+ - 2.1.0
97
+
98
+ ## Running with Phusion Passenger
99
+
100
+ To run Puppet Library with [Phusion Passenger](https://www.phusionpassenger.com):
101
+
102
+ ```sh
103
+ # Create a Passenger-compatible directory structure
104
+ mkdir -p /webapps/puppet-library/{public,tmp}
105
+
106
+ # Create a Rack config file to point Puppet Library to your modules
107
+ cat > /webapps/puppet-library/config.ru <<EOF
108
+ require "rubygems"
109
+ require "puppet_library"
110
+
111
+ server = PuppetLibrary::Server.set_up do |library|
112
+ # Serve our private modules
113
+ library.forge PuppetLibrary::Forge::Directory.new("/var/lib/modules")
114
+ # Download all other moduls from the Puppet Forge
115
+ library.forge PuppetLibrary::Forge::Proxy.new("http://forge.puppetlabs.com")
116
+ end
117
+
118
+ run server
119
+ EOF
120
+
121
+ # Create an Apache virtual host pointing at Puppet Library
122
+ cat > /etc/httpd/conf.d/puppetlibrary.conf <<EOF
123
+ <VirtualHost *:80>
124
+ ServerName privateforge.example.com
125
+ DocumentRoot /webapps/puppet-library/public
126
+ <Directory /webapps/puppet-library/public>
127
+ Allow from all
128
+ Options -MultiViews
129
+ </Directory>
130
+ </VirtualHost>
131
+ EOF
132
+ ```
133
+
92
134
  ## Contributing
93
135
 
94
136
  1. Fork it
data/Rakefile CHANGED
@@ -19,6 +19,12 @@ require 'bundler/gem_tasks'
19
19
  require 'rspec/core/rake_task'
20
20
  require 'coveralls/rake/task'
21
21
 
22
+ SUPPORTED_VERSIONS = %w[1.8 1.9 2.0 2.1]
23
+ # The integration test doesn't work on Ruby 1.8, and Puppet doesn't work on 2.1
24
+ INTEGRATION_TEST_INCOMPATIBLE_VERSIONS = %w[1.8 2.1]
25
+ # Capybara needs Nokogiri, which needs 1.9+
26
+ ACCEPTANCE_TEST_INCOMPATIBLE_VERSIONS = %w[1.8]
27
+
22
28
  class String
23
29
  def green
24
30
  "\e[32m#{self}\e[0m"
@@ -27,17 +33,22 @@ class String
27
33
  def red
28
34
  "\e[31m#{self}\e[0m"
29
35
  end
36
+
37
+ def yellow
38
+ "\e[33m#{self}\e[0m"
39
+ end
30
40
  end
31
41
 
32
42
  def ruby_version_supports_integration_test?(version = RUBY_VERSION)
33
- # The integration test doesn't work on Ruby 1.8, and Puppet doesn't work on 2.1
34
- ! /^(1\.8|2\.1)/.match(version)
43
+ ! INTEGRATION_TEST_INCOMPATIBLE_VERSIONS.find do |bad_version|
44
+ version.start_with? bad_version
45
+ end
35
46
  end
36
47
 
37
- if ruby_version_supports_integration_test?
38
- DEFAULT_TEST_TASK = :test
39
- else
40
- DEFAULT_TEST_TASK = :spec
48
+ def ruby_version_supports_acceptance_tests?(version = RUBY_VERSION)
49
+ ! ACCEPTANCE_TEST_INCOMPATIBLE_VERSIONS.find do |bad_version|
50
+ version.start_with? bad_version
51
+ end
41
52
  end
42
53
 
43
54
  Coveralls::RakeTask.new
@@ -45,17 +56,34 @@ Coveralls::RakeTask.new
45
56
  desc "Run the specs"
46
57
  RSpec::Core::RakeTask.new(:spec)
47
58
 
48
- desc "Run the integration tests"
49
- RSpec::Core::RakeTask.new(:integration_test) do |rspec|
50
- rspec.pattern = "test/**/*_integration_test.rb"
59
+ if ruby_version_supports_acceptance_tests?
60
+ require 'cucumber/rake/task'
61
+ Cucumber::Rake::Task.new(:features)
62
+ else
63
+ task :features do
64
+ puts "Skipping acceptance tests because this version of Ruby doesn't support them"
65
+ end
51
66
  end
52
67
 
53
- desc "Run all the tests"
54
- RSpec::Core::RakeTask.new(:test) do |rspec|
55
- rspec.pattern = "{spec,test}/**/*_{spec,integration_test}.rb"
68
+ if ruby_version_supports_integration_test?
69
+ desc "Run all the tests"
70
+ RSpec::Core::RakeTask.new(:test) do |rspec|
71
+ rspec.pattern = "{spec,test}/**/*_{spec,integration_test}.rb"
72
+ end
73
+ task :test => :features
74
+
75
+ desc "Run the integration tests"
76
+ RSpec::Core::RakeTask.new(:integration_test) do |rspec|
77
+ rspec.pattern = "test/**/*_integration_test.rb"
78
+ end
79
+ else
80
+ task :integration_test do
81
+ puts "Skipping integration tests because this version of Ruby doesn't support them"
82
+ end
83
+ task :test => [:features, :spec]
56
84
  end
57
85
 
58
- task :default => [DEFAULT_TEST_TASK, 'coveralls:push']
86
+ task :default => [:test, 'coveralls:push']
59
87
 
60
88
  desc "Check it works on all local rubies"
61
89
  task :verify do
@@ -72,18 +100,34 @@ task :verify do
72
100
  system "rvm #{ruby_version} do rake integration_test"
73
101
  end
74
102
 
103
+ puts "\nRunning Acceptance Tests".green
104
+ acceptance_test_results = versions.map do |ruby_version|
105
+ puts "\n- Ruby #{ruby_version}".green
106
+ system "rvm #{ruby_version} do rake features"
107
+ end
108
+
75
109
  puts "\nResults:\n".green
76
- results = spec_results.zip(integration_test_results)
77
- puts "+---------+-------+-------+"
78
- puts "| Version | Specs | Tests |"
79
- puts "+---------+-------+-------+"
80
- versions.zip(results).each do |(version, (spec_result, integration_test_result))|
110
+ results = [ spec_results, integration_test_results, acceptance_test_results ].transpose
111
+ puts "+---------+-------+-------+-------+"
112
+ puts "| Version | Specs | ITs | ATs |"
113
+ puts "+---------+-------+-------+-------+"
114
+ versions.zip(results).each do |(version, (spec_result, integration_test_result, acceptance_test_result))|
81
115
  v = version
82
116
  s = spec_result ? "pass".green : "fail".red
83
- i = integration_test_result ? "pass".green : "fail".red
84
- puts "| #{v} | #{s} | #{i} |"
117
+ if ruby_version_supports_integration_test? version
118
+ i = integration_test_result ? "pass".green : "fail".red
119
+ else
120
+ i = "skip".yellow
121
+ end
122
+
123
+ if ruby_version_supports_acceptance_tests? version
124
+ a = acceptance_test_result ? "pass".green : "fail".red
125
+ else
126
+ a = "skip".yellow
127
+ end
128
+ puts "| #{v} | #{s} | #{i} | #{a} |"
85
129
  end
86
- puts "+---------+-------+-------+"
130
+ puts "+---------+-------+-------+-------+"
87
131
 
88
132
  versions.zip(results).each do |(version, (spec_result, integration_test_result))|
89
133
  unless spec_result
data/TODO.yml CHANGED
@@ -1,3 +1,5 @@
1
+ bugs:
2
+ - Using captialised Author name to create full module name
1
3
  features:
2
4
  - Use config from a config file
3
5
  - Allow proxy to cache downloaded modules/API calls on disk
@@ -6,8 +8,7 @@ features:
6
8
  will need to embed the server or use a config file for more control)
7
9
  - Validate repo dirs (make sure they're readable)
8
10
  - Allow failover between module repositories
9
- - Document usage with Passenger
10
- - Web UI
11
+ - Web UI: asynchronous
11
12
  - Authentication
12
13
 
13
14
  dubious_features:
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2014 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU 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 General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Feature: Module list page
19
+ As a user
20
+ I want to see a list of available modules
21
+ So that I can quickly tell what's on the server
22
+
23
+ Scenario: Visit the module list page
24
+ When I visit the module list page
25
+ Then I should see "Modules"
26
+
27
+ Scenario: See module versions
28
+ Given the "puppetlabs/apache" module is available at version "1.0.0"
29
+ And the "puppetlabs/apache" module is available at version "1.1.0"
30
+ When I visit the module list page
31
+ Then I should see module "puppetlabs/apache" with versions 1.0.0 and 1.1.0
32
+
33
+ Scenario: Follow link to module page
34
+ Given the "puppetlabs/apache" module is available at version "1.0.0"
35
+ And the "puppetlabs/apache" module is available at version "1.1.0"
36
+ When I visit the module list page
37
+ And I click on "puppetlabs/apache"
38
+ Then I should be on the module page for "puppetlabs/apache"
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2014 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU 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 General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ Feature: Module page
19
+ As a user
20
+ I want to see a list of available modules
21
+ So that I can quickly tell what's on the server
22
+
23
+ Scenario: Visit the module page
24
+ Given the "puppetlabs/apache" module is available at version "1.0.0"
25
+ And the "puppetlabs/apache" module is available at version "1.1.0"
26
+ When I visit the module page for "puppetlabs/apache"
27
+ Then I should see "Author: puppetlabs"
28
+ Then I should see "Name: apache"
29
+ And I should see "1.0.0"
30
+ And I should see "1.1.0"
31
+ And I should see "puppetlabs/apache module, version 1.1.0"
32
+
33
+ Scenario: Visit a nonexistant module page
34
+ When I visit the module page for "nonexistant/nonexistant"
35
+ Then I should see 'Module "nonexistant/nonexistant" not found'
@@ -0,0 +1,82 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2014 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU 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 General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ spec_path = File.expand_path("../../spec", File.dirname(__FILE__))
19
+ $LOAD_PATH.unshift spec_path unless $LOAD_PATH.include? spec_path
20
+
21
+ require 'module_spec_helper'
22
+ require 'fileutils'
23
+
24
+ include FileUtils
25
+
26
+ def module_dir
27
+ unless @module_dir
28
+ file = Tempfile.new("module_dir")
29
+ @module_dir = file.path
30
+ file.delete
31
+ end
32
+ @module_dir
33
+ end
34
+
35
+ def module_writer
36
+ @module_writer ||= ModuleSpecHelper::ModuleWriter.new(module_dir)
37
+ end
38
+
39
+ Before do
40
+ mkdir_p module_dir
41
+ forge.add_forge PuppetLibrary::Forge::Directory.new(module_dir)
42
+ end
43
+
44
+ After do
45
+ rm_rf module_dir
46
+ end
47
+
48
+ Given /^the "(.*?)" module is available at version "(.*?)"$/ do |full_name, version|
49
+ author, name = full_name.split "/"
50
+ module_writer.write_module(author, name, version)
51
+ end
52
+
53
+ When /^I visit the module list page$/ do
54
+ visit "/"
55
+ end
56
+
57
+ When /^I visit the module page for "(.*?)"$/ do |module_name|
58
+ visit "/#{module_name}"
59
+ end
60
+
61
+ When /^I click on "(.*?)"$/ do |link_text|
62
+ click_link link_text
63
+ end
64
+
65
+ Then /^I should be on the module page for "(.*?)"$/ do |module_name|
66
+ expect(URI.parse(current_url).path).to eq "/#{module_name}"
67
+ end
68
+
69
+ Then /^I should see "(.*?)"$/ do |text|
70
+ expect(page).to have_content text
71
+ end
72
+
73
+ Then /^I should see '(.*?)'$/ do |text|
74
+ expect(page).to have_content text
75
+ end
76
+
77
+ Then /^I should see module "(.*?)" with versions? (.*)$/ do |full_name, versions|
78
+ versions = versions.split /\s*,\s*|\s*,?\s*and\s*/
79
+ versions.each do |version|
80
+ find(:xpath, "//li[contains(.,'#{full_name}')]").should have_content version
81
+ end
82
+ end
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2014 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU 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 General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'puppet_library'
19
+ require 'capybara/cucumber'
20
+
21
+ class ServerWorld
22
+ def server
23
+ @server ||= PuppetLibrary::Server.new(forge)
24
+ end
25
+
26
+ def forge
27
+ @forge ||= PuppetLibrary::Forge::Multi.new
28
+ end
29
+ end
30
+
31
+ world = ServerWorld.new
32
+ Capybara.app = world.server
33
+
34
+ World do
35
+ world
36
+ end
37
+
@@ -0,0 +1,26 @@
1
+ -# -*- encoding: utf-8 -*-
2
+ -# Puppet Library
3
+ -# Copyright (C) 2014 drrb
4
+ -#
5
+ -# This program is free software: you can redistribute it and/or modify
6
+ -# it under the terms of the GNU 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 General Public License for more details.
14
+ -#
15
+ -# You should have received a copy of the GNU General Public License
16
+ -# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ %h1 Modules
19
+ %ul
20
+ - modules.each do |mod|
21
+ %li
22
+ %b
23
+ %a{:href => mod["full_name"]}= mod["full_name"]
24
+ %ul
25
+ - mod["releases"].each do |release|
26
+ %li= release["version"]
@@ -0,0 +1,54 @@
1
+ -# -*- encoding: utf-8 -*-
2
+ -# Puppet Library
3
+ -# Copyright (C) 2014 drrb
4
+ -#
5
+ -# This program is free software: you can redistribute it and/or modify
6
+ -# it under the terms of the GNU 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 General Public License for more details.
14
+ -#
15
+ -# You should have received a copy of the GNU General Public License
16
+ -# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ !!!
18
+ %html
19
+ %head
20
+ %meta{ :charset => "utf-8" }
21
+ %title Puppet Library
22
+ %link{ :href => "https://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css", :type => "text/css", :rel => "stylesheet" }
23
+ /[if lt IE 9]
24
+ %script{:src => "https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"}
25
+ %script{:src => "https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"}
26
+ %style
27
+ :plain
28
+ body {
29
+ padding-top: 50px;
30
+ }
31
+ .starter-template {
32
+ padding: 40px 15px;
33
+ text-align: center;
34
+ }
35
+ %body
36
+ .navbar.navbar-inverse.navbar-fixed-top{ :role => "navigation" }
37
+ .container
38
+ .navbar-header
39
+ %button.navbar-toggle{ :type => "button", "data-toggle" => "collapse", "data-target" => ".navbar-collapse"}
40
+ %span.sr-only Toggle Navigation
41
+ %span.icon-bar
42
+ %span.icon-bar
43
+ %span.icon-bar
44
+ %a.navbar-brand{:href => '/'} Puppet Library
45
+ .collapse.navbar-collapse
46
+ %ul.nav.navbar-nav
47
+ %li.active
48
+ %a{:href => '/'} Modules
49
+ %li
50
+ %a{:href => 'https://github.com/drrb/puppet-library', :target => "puppet-library"} Help
51
+ .container
52
+ = yield
53
+ %script{ :src => "https://code.jquery.com/jquery-2.1.0.min.js" }
54
+ %script{ :src => "https://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js" }
@@ -0,0 +1,25 @@
1
+ -# -*- encoding: utf-8 -*-
2
+ -# Puppet Library
3
+ -# Copyright (C) 2014 drrb
4
+ -#
5
+ -# This program is free software: you can redistribute it and/or modify
6
+ -# it under the terms of the GNU 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 General Public License for more details.
14
+ -#
15
+ -# You should have received a copy of the GNU General Public License
16
+ -# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ %h1= "Module #{metadata["full_name"]}"
19
+ %div= "Author: #{metadata["author"]}"
20
+ %div= "Name: #{metadata["name"]}"
21
+ %div= "Description: #{metadata["desc"]}"
22
+ %div= "Versions:"
23
+ %ul
24
+ - metadata["releases"].each do |release|
25
+ %li= release["version"]
@@ -0,0 +1,19 @@
1
+ -# -*- encoding: utf-8 -*-
2
+ -# Puppet Library
3
+ -# Copyright (C) 2014 drrb
4
+ -#
5
+ -# This program is free software: you can redistribute it and/or modify
6
+ -# it under the terms of the GNU 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 General Public License for more details.
14
+ -#
15
+ -# You should have received a copy of the GNU General Public License
16
+ -# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ %h1 Not Found
19
+ %div= "Module \"#{author}/#{name}\" not found"
@@ -44,6 +44,7 @@ module PuppetLibrary::Forge
44
44
 
45
45
  raise ModuleNotFound if modules.empty?
46
46
 
47
+ modules = modules.version_sort_by { |m| m.version }
47
48
  module_infos = modules.map { |m| m.to_info }
48
49
  module_infos.deep_merge
49
50
  end
@@ -18,6 +18,7 @@
18
18
  require 'rack'
19
19
  require 'puppet_library/forge/directory'
20
20
  require 'puppet_library/forge/multi'
21
+ require 'puppet_library/version'
21
22
 
22
23
  module PuppetLibrary
23
24
  class PuppetLibrary
@@ -41,23 +42,34 @@ module PuppetLibrary
41
42
  option_parser = OptionParser.new do |opts|
42
43
  opts.banner = "Usage: #{File.basename $0} [options]"
43
44
 
44
- opts.on("-p", "--port [PORT]", "Port to listen on (defaults to whatever Rack wants to use)") do |port|
45
+ opts.on("-p", "--port PORT", "Port to listen on (defaults to whatever Rack wants to use)") do |port|
45
46
  options[:port] = port
46
47
  end
47
48
 
48
- opts.on("-s", "--server [SERVER]", "Server to use (defaults to whatever Rack wants to use)") do |server|
49
+ opts.on("-s", "--server SERVER", "Server to use (defaults to whatever Rack wants to use)") do |server|
49
50
  options[:server] = server
50
51
  end
51
52
 
52
- opts.on("-b", "--bind-host [HOSTNAME]", "Host name to bind to (defaults to whatever Rack wants to use)") do |hostname|
53
+ opts.on("-b", "--bind-host HOSTNAME", "Host name to bind to (defaults to whatever Rack wants to use)") do |hostname|
53
54
  options[:hostname] = hostname
54
55
  end
55
56
 
57
+ options[:daemonize] = false
58
+ opts.on("--daemonize", "Run the server in the background") do
59
+ options[:daemonize] = true
60
+ end
61
+
62
+ options[:pidfile] = nil
63
+ opts.on("--pidfile FILE", "Write a pidfile to this location after starting (implies --daemonize)") do |pidfile|
64
+ options[:daemonize] = true
65
+ options[:pidfile] = File.expand_path pidfile
66
+ end
67
+
56
68
  options[:forges] = []
57
- opts.on("-m", "--module-dir [DIR]", "Directory containing the modules (can be specified multiple times. Defaults to './modules')") do |module_dir|
69
+ opts.on("-m", "--module-dir DIR", "Directory containing the modules (can be specified multiple times)") do |module_dir|
58
70
  options[:forges] << [Forge::Directory, module_dir]
59
71
  end
60
- opts.on("-x", "--proxy [URL]", "Remote forge to proxy (can be specified multiple times)") do |url|
72
+ opts.on("-x", "--proxy URL", "Remote forge to proxy (can be specified multiple times)") do |url|
61
73
  options[:forges] << [Forge::Proxy, url]
62
74
  end
63
75
  end
@@ -86,9 +98,11 @@ module PuppetLibrary
86
98
  def announce_server_start(options)
87
99
  options = options.clone
88
100
  options.default = "default"
89
- @log.puts "Starting Puppet Library server:"
101
+ action = options[:daemonize] ? "Daemonizing" : "Starting"
102
+ @log.puts "#{action} Puppet Library server:"
90
103
  @log.puts " |- Port: #{options[:port]}"
91
104
  @log.puts " |- Host: #{options[:hostname]}"
105
+ @log.puts " |- Pidfile: #{options[:pidfile]}" if options[:pidfile]
92
106
  @log.puts " |- Server: #{options[:server]}"
93
107
  @log.puts " `- Forges:"
94
108
  options[:forges].each do |(forge_type, config)|
@@ -101,7 +115,9 @@ module PuppetLibrary
101
115
  :app => server,
102
116
  :Host => options[:hostname],
103
117
  :Port => options[:port],
104
- :server => options[:server]
118
+ :server => options[:server],
119
+ :daemonize => options[:daemonize],
120
+ :pid => options[:pidfile]
105
121
  )
106
122
  end
107
123
  end
@@ -16,6 +16,7 @@
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
18
  require 'sinatra/base'
19
+ require 'haml'
19
20
 
20
21
  require 'puppet_library/forge/multi'
21
22
 
@@ -44,6 +45,14 @@ module PuppetLibrary
44
45
 
45
46
  configure do
46
47
  enable :logging
48
+ set :haml, :format => :html5
49
+ set :root, File.expand_path("app", File.dirname(__FILE__))
50
+ end
51
+
52
+ get "/" do
53
+ modules = @forge.search_modules(nil)
54
+
55
+ haml :index, { :locals => { "modules" => modules } }
47
56
  end
48
57
 
49
58
  get "/modules.json" do
@@ -89,5 +98,18 @@ module PuppetLibrary
89
98
  status 404
90
99
  end
91
100
  end
101
+
102
+ get "/:author/:module" do
103
+ author = params[:author]
104
+ module_name = params[:module]
105
+
106
+ begin
107
+ metadata = @forge.get_module_metadata(author, module_name)
108
+ haml :module, { :locals => { "metadata" => metadata } }
109
+ rescue Forge::ModuleNotFound
110
+ status 404
111
+ haml :module_not_found, { :locals => { "author" => author, "name" => module_name } }
112
+ end
113
+ end
92
114
  end
93
115
  end
@@ -16,5 +16,5 @@
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
18
  module PuppetLibrary
19
- VERSION = "0.3.0"
19
+ VERSION = "0.4.0"
20
20
  end
@@ -38,9 +38,11 @@ Gem::Specification.new do |spec|
38
38
 
39
39
  spec.add_dependency "sinatra"
40
40
  spec.add_dependency "json"
41
+ spec.add_dependency "haml"
41
42
 
42
43
  spec.add_development_dependency "bundler", "~> 1.3"
43
44
  spec.add_development_dependency "coveralls"
45
+ spec.add_development_dependency "gitsu"
44
46
  spec.add_development_dependency "librarian-puppet"
45
47
  spec.add_development_dependency "mime-types", "< 2"
46
48
  spec.add_development_dependency "pry"
@@ -55,5 +57,10 @@ Gem::Specification.new do |spec|
55
57
  spec.add_development_dependency "guard"
56
58
  spec.add_development_dependency "guard-rspec"
57
59
  spec.add_development_dependency "terminal-notifier-guard"
60
+
61
+ # Capybara needs Nokogiri, which needs 1.9+
62
+ spec.add_development_dependency "capybara"
63
+ spec.add_development_dependency "nokogiri" # Rubygems 1.8 fails to resolve this on Ruby 2.0.0
64
+ spec.add_development_dependency "cucumber"
58
65
  end
59
66
  end
@@ -178,12 +178,12 @@ module PuppetLibrary::Forge
178
178
  "author" => "puppetlabs",
179
179
  "name" => "puppetlabs-apache",
180
180
  "description" => "Apache module",
181
- "version" => "1.0.0"
181
+ "version" => "1.1.0"
182
182
  }, {
183
183
  "author" => "puppetlabs",
184
184
  "name" => "puppetlabs-apache",
185
- "description" => "Apache module",
186
- "version" => "1.1.0"
185
+ "description" => "Old Apache module",
186
+ "version" => "1.0.0"
187
187
  } ]
188
188
  expect(module_repo).to receive(:get_metadata).with("puppetlabs", "apache").and_return(metadata)
189
189
 
@@ -19,35 +19,47 @@ require 'zlib'
19
19
  require 'rubygems/package'
20
20
 
21
21
  module ModuleSpecHelper
22
- def write_tar_gzip(file_name)
23
- tar = StringIO.new
22
+ class ModuleWriter
23
+ def initialize(module_dir)
24
+ @module_dir = module_dir
25
+ end
26
+
27
+ def write_module(author, name, version)
28
+ full_name = "#{author}-#{name}"
29
+ fqn = "#{full_name}-#{version}"
30
+ module_file = File.join(@module_dir, "#{fqn}.tar.gz")
24
31
 
25
- Gem::Package::TarWriter.new(tar) do |writer|
26
- yield(writer)
32
+ write_tar_gzip(module_file) do |archive|
33
+ archive.add_file("#{fqn}/metadata.json", 0644) do |file|
34
+ content = {
35
+ "name" => full_name,
36
+ "version" => version,
37
+ "description" => "#{author}/#{name} module, version #{version}",
38
+ "dependencies" => []
39
+ }
40
+ yield(content) if block_given?
41
+ file.write content.to_json
42
+ end
43
+ end
27
44
  end
28
- tar.seek(0)
29
45
 
30
- gz = Zlib::GzipWriter.new(File.new(file_name, 'wb'))
31
- gz.write(tar.read)
32
- tar.close
33
- gz.close
34
- end
46
+ def write_tar_gzip(file_name)
47
+ tar = StringIO.new
35
48
 
36
- def add_module(author, name, version)
37
- full_name = "#{author}-#{name}"
38
- fqn = "#{full_name}-#{version}"
39
- module_file = File.join(module_dir, "#{fqn}.tar.gz")
40
-
41
- write_tar_gzip(module_file) do |archive|
42
- archive.add_file("#{fqn}/metadata.json", 0644) do |file|
43
- content = {
44
- "name" => full_name,
45
- "version" => version,
46
- "dependencies" => []
47
- }
48
- yield(content) if block_given?
49
- file.write content.to_json
49
+ Gem::Package::TarWriter.new(tar) do |writer|
50
+ yield(writer)
50
51
  end
52
+ tar.seek(0)
53
+
54
+ gz = Zlib::GzipWriter.new(File.new(file_name, 'wb'))
55
+ gz.write(tar.read)
56
+ tar.close
57
+ gz.close
51
58
  end
52
59
  end
60
+
61
+ def add_module(author, name, version, &block)
62
+ writer = ModuleWriter.new(module_dir)
63
+ writer.write_module(author, name, version, &block)
64
+ end
53
65
  end
@@ -31,7 +31,8 @@ module PuppetLibrary
31
31
  end
32
32
  let(:log) { double('log').as_null_object }
33
33
  let(:library) { PuppetLibrary.new(log) }
34
- let(:default_options) {{ :app => server, :Host => nil, :Port => nil, :server => nil }}
34
+ let(:default_options) {{ :app => server, :Host => nil, :Port => nil, :server => nil, :daemonize => false, :pid => nil }}
35
+
35
36
  before do
36
37
  allow(Rack::Server).to receive(:start)
37
38
  end
@@ -85,6 +86,25 @@ module PuppetLibrary
85
86
  end
86
87
  end
87
88
 
89
+ context "when using --daemonize option" do
90
+ it "daemonizes the server" do
91
+ expect(Rack::Server).to receive(:start).with(default_options_with(:daemonize => true))
92
+ expect(log).to receive(:puts).with(/Daemonizing/)
93
+
94
+ library.go(["--daemonize"])
95
+ end
96
+ end
97
+
98
+ context "when using --pidfile option" do
99
+ it "daemonizes and writes a pidfile to the specified location" do
100
+ expect(Rack::Server).to receive(:start).with(default_options_with(:daemonize => true, :pid => "/var/run/puppet-library.pid"))
101
+ expect(log).to receive(:puts).with(/Daemonizing/)
102
+ expect(log).to receive(:puts).with(/Pidfile: \/var\/run\/puppet-library.pid/)
103
+
104
+ library.go(["--pidfile", "/var/run/puppet-library.pid"])
105
+ end
106
+ end
107
+
88
108
  context "when using --proxy option" do
89
109
  it "adds a proxy module forge for each option specified" do
90
110
  proxy1 = double('proxy1')
data/spec/server_spec.rb CHANGED
@@ -28,6 +28,31 @@ module PuppetLibrary
28
28
  Server.new(forge)
29
29
  end
30
30
 
31
+ describe "GET /" do
32
+ it "lists all the modules" do
33
+ modules = [
34
+ {
35
+ "author" => "puppetlabs",
36
+ "name" => "apache",
37
+ "tag_list" => ["apache", "httpd"],
38
+ "releases" => [{"version"=>"0.0.1"}, {"version"=>"0.0.2"}],
39
+ "full_name" => "puppetlabs/apache",
40
+ "version" => "0.0.2",
41
+ "project_url" => "http://github.com/puppetlabs/puppetlabs-apache",
42
+ "desc" => "Puppet module for Apache"
43
+ }
44
+ ]
45
+ expect(forge).to receive(:search_modules).with(nil).and_return(modules)
46
+
47
+ get "/"
48
+
49
+ expect(last_response.body).to include "Modules"
50
+ expect(last_response.body).to include "puppetlabs/apache"
51
+ expect(last_response.body).to include "0.0.1"
52
+ expect(last_response.body).to include "0.0.2"
53
+ end
54
+ end
55
+
31
56
  describe "GET /modules.json" do
32
57
  it "renders the search result as JSON" do
33
58
  search_results = [
@@ -78,6 +103,41 @@ module PuppetLibrary
78
103
  end
79
104
  end
80
105
 
106
+ describe "GET /<author>/<module>" do
107
+ it "displays module metadata" do
108
+ metadata = {
109
+ "author" => "puppetlabs",
110
+ "full_name" => "puppetlabs/apache",
111
+ "name" => "apache",
112
+ "desc" => "Puppet module for Apache",
113
+ "releases" => [
114
+ { "version" => "0.10.0" },
115
+ { "version" => "0.9.0" },
116
+ ]
117
+ }
118
+ expect(forge).to receive(:get_module_metadata).with("puppetlabs", "apache").and_return(metadata)
119
+
120
+ get "/puppetlabs/apache"
121
+
122
+ expect(last_response.body).to include "Author: puppetlabs"
123
+ expect(last_response.body).to include "Name: apache"
124
+ expect(last_response.body).to include "0.10.0"
125
+ expect(last_response.body).to include "0.9.0"
126
+ expect(last_response).to be_ok
127
+ end
128
+
129
+ context "when no modules found" do
130
+ it "returns an error" do
131
+ expect(forge).to receive(:get_module_metadata).with("nonexistant", "nonexistant").and_raise(Forge::ModuleNotFound)
132
+
133
+ get "/nonexistant/nonexistant"
134
+
135
+ expect(last_response.body).to include 'Module "nonexistant/nonexistant" not found'
136
+ expect(last_response.status).to eq(404)
137
+ end
138
+ end
139
+ end
140
+
81
141
  describe "GET /<author>/<module>.json" do
82
142
  it "gets module metadata for all versions" do
83
143
  metadata = {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-library
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - drrb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-25 00:00:00.000000000 Z
11
+ date: 2014-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ! '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: haml
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - ! '>='
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: gitsu
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: librarian-puppet
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +248,48 @@ dependencies:
220
248
  - - ! '>='
221
249
  - !ruby/object:Gem::Version
222
250
  version: '0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: capybara
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ! '>='
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ! '>='
263
+ - !ruby/object:Gem::Version
264
+ version: '0'
265
+ - !ruby/object:Gem::Dependency
266
+ name: nokogiri
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ! '>='
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ! '>='
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: cucumber
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ! '>='
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ! '>='
291
+ - !ruby/object:Gem::Version
292
+ version: '0'
223
293
  description: A Puppet module server
224
294
  email:
225
295
  - drrrrrrrrrrrb@gmail.com
@@ -241,7 +311,15 @@ files:
241
311
  - TODO.yml
242
312
  - bin/puppet-library
243
313
  - config.ru
314
+ - features/module_list.feature
315
+ - features/module_page.feature
316
+ - features/step_definitions/sinatra_steps.rb
317
+ - features/support/env.rb
244
318
  - lib/puppet_library.rb
319
+ - lib/puppet_library/app/views/index.haml
320
+ - lib/puppet_library/app/views/layout.haml
321
+ - lib/puppet_library/app/views/module.haml
322
+ - lib/puppet_library/app/views/module_not_found.haml
245
323
  - lib/puppet_library/forge.rb
246
324
  - lib/puppet_library/forge/abstract.rb
247
325
  - lib/puppet_library/forge/directory.rb
@@ -298,6 +376,10 @@ signing_key:
298
376
  specification_version: 4
299
377
  summary: Puppet Library is a private Puppet module server that's compatible with librarian-puppet.
300
378
  test_files:
379
+ - features/module_list.feature
380
+ - features/module_page.feature
381
+ - features/step_definitions/sinatra_steps.rb
382
+ - features/support/env.rb
301
383
  - spec/forge/abstract_spec.rb
302
384
  - spec/forge/directory_spec.rb
303
385
  - spec/forge/multi_spec.rb