puppet-library 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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