Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support v3 API #23

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c1f4e92
Add rspec examples for queries done by puppet module commands
javiplx Feb 28, 2015
11dc0f8
Add methods to serve client V3 queries
javiplx Feb 28, 2015
0a34ead
Add specific methods to respond to V3 queries
javiplx Feb 28, 2015
017f62b
Implement V3 searches along all Forge subclasses
javiplx Feb 28, 2015
86ef5a2
Add basic test for /modules output
javiplx Feb 28, 2015
0609e7b
Adapt module names to some newer puppet standards
javiplx Feb 28, 2015
738139f
Add pagination to abstract get_modules method
javiplx Feb 28, 2015
649d8bd
Disable integration tests
javiplx Feb 28, 2015
951b25b
First draft for V3 modules aggregator
javiplx Feb 28, 2015
fc620a5
Improve tests for V3 get_modules
javiplx Feb 28, 2015
1767e8e
Fix /modules V3 query
javiplx Feb 28, 2015
25e9474
Add rspec tests for V3 get_releases
javiplx Mar 6, 2015
5167259
Full implementation of get_releases
javiplx Mar 6, 2015
4329ca2
Implement V3 module download
javiplx Mar 7, 2015
4be35cc
Change to SSL and forgeapi.puppetlabs.com
javiplx Mar 7, 2015
fec1195
BUGFIX : add schema elements required for package install
javiplx Mar 9, 2015
047d70d
Implement MD5 calculation for directory forges
javiplx Mar 9, 2015
53260a4
Implement md5 sums for source forges
javiplx Mar 9, 2015
6f5fc04
Add workaround to compensate forgeapi-forge translation from libraria…
javiplx Mar 10, 2015
3cf2523
Partial rspec fix of v1 to v3 api traslation
Mar 11, 2015
b8a34a7
Fix v1-v3 translation for module query
javiplx Mar 11, 2015
ca67dc7
Implement md5sum for modules hosted at git repositories
javiplx Mar 11, 2015
e3268f1
Fix acceptance tests
Mar 11, 2015
9538d90
Fix return json for get_modules
Mar 13, 2015
867502a
BUGFIX : return all found releases
Mar 13, 2015
5bb926b
Fix return payload for /releases
Mar 13, 2015
54e487d
Iterate to full download remote forges
javiplx Apr 4, 2015
1a6e3d2
Turn browsing to use V3 metadata
javiplx Apr 5, 2015
5eb0ce7
Get nearly perfect match on v3 to v1 translations
javiplx Apr 5, 2015
6517de5
Fix or skip broken examples
javiplx Apr 5, 2015
8ce432b
BUGFIX: allow donwload of modules with labeled versions
Apr 6, 2015
f1a4e68
BUGFIX: module download broken
javiplx Apr 12, 2015
4599428
BUGFIX: tilde shorthand not supported by puppet semantic versioning
javiplx Apr 12, 2015
bd80b05
BUGFIX: set right v1 url on forgeapi
Apr 13, 2015
0a99a20
Mark really broken integration tests
Apr 13, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A private Puppet Forge. Compatible with [librarian-puppet](http://librarian-pupp
[![Gem Version](https://badge.fury.io/rb/puppet-library.svg)](http://badge.fury.io/rb/puppet-library)
[![Dependency Status](https://gemnasium.com/drrb/puppet-library.svg)](https://gemnasium.com/drrb/puppet-library)

Puppet Library serves Puppet modules in the same format as [the Puppet Forge](http://forge.puppetlabs.com). This allows you to create a private Puppet Forge and manage all the modules you use completely within your infrastructure.
Puppet Library serves Puppet modules in the same format as [the Puppet Forge](https://forge.puppetlabs.com). This allows you to create a private Puppet Forge and manage all the modules you use completely within your infrastructure.

Plugins can be created to serve modules from arbitrary sources. Puppet Library contains built-in support for:
- serving packaged (`.tar.gz`) modules from a directory (or directories) of your choosing
Expand Down Expand Up @@ -71,11 +71,11 @@ Serve modules from a specific directory

Serve modules from a remote forge as a proxy

$ puppet-library --proxy http://forge.puppetlabs.com
$ puppet-library --proxy https://forgeapi.puppetlabs.com

Proxy a remote forge, caching downloaded modules on disk

$ puppet-library --proxy http://forge.puppetlabs.com --cache-basedir
$ puppet-library --proxy https://forgeapi.puppetlabs.com --cache-basedir

Serve a module from source

Expand Down Expand Up @@ -145,7 +145,7 @@ forges:
- Directory: /var/lib/modules
- Directory: /var/lib/other-modules
- Source: /var/code/puppetlabs-apache
- Proxy: http://forge.puppetlabs.com
- Proxy: https://forgeapi.puppetlabs.com
```

## Running with Phusion Passenger (EXPERIMENTAL)
Expand All @@ -170,7 +170,7 @@ require "puppet_library"
server = PuppetLibrary::Server.configure do
# Proxy the Puppet Forge
forge :proxy do
url "http://forge.puppetlabs.com"
url "https://forgeapi.puppetlabs.com"
end
end

Expand Down Expand Up @@ -214,7 +214,7 @@ server = PuppetLibrary::Server.configure do

# Proxy a remote forge, caching modules to disk
forge :cache do
url "http://forge.puppetlabs.com"
url "https://forgeapi.puppetlabs.com"
path "/var/puppet/modules/cache"
end
end
Expand Down
51 changes: 16 additions & 35 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ require 'yaml'
require 'net/http'

SUPPORTED_RUBY_VERSIONS = %w[1.8 1.9 2.0 2.1 system]
# Puppet doesn't work on 2.1
INTEGRATION_TEST_INCOMPATIBLE_RUBY_VERSIONS = %w[2.1]
# Capybara needs Nokogiri, which needs 1.9+
ACCEPTANCE_TEST_INCOMPATIBLE_RUBY_VERSIONS = %w[1.8]

Expand All @@ -41,20 +39,14 @@ class String
end
end

def ruby_version_supports_integration_test?(version = RUBY_VERSION)
! INTEGRATION_TEST_INCOMPATIBLE_RUBY_VERSIONS.find do |bad_version|
version.start_with? bad_version
end
end

def ruby_version_supports_acceptance_tests?(version = RUBY_VERSION)
! ACCEPTANCE_TEST_INCOMPATIBLE_RUBY_VERSIONS.find do |bad_version|
version.start_with? bad_version
end
end

def offline?
Net::HTTP.get_response(URI.parse("http://forge.puppetlabs.com"))
Net::HTTP.get_response(URI.parse("https://forgeapi.puppetlabs.com"))
return false
rescue
return true
Expand Down Expand Up @@ -83,28 +75,21 @@ else
end
end

if ruby_version_supports_integration_test?
desc "Run all the tests"
RSpec::Core::RakeTask.new(:test) do |rspec|
rspec.pattern = "{spec,test}/**/*_{spec,integration_test}.rb"
end
task :test => :features

desc "Run the integration tests"
RSpec::Core::RakeTask.new(:integration_test) do |rspec|
rspec.pattern = "test/**/*_integration_test.rb"
tags = []
tags << "~online" if offline?
tags << "~no_1_8" if RUBY_VERSION.start_with? "1.8"
unless tags.empty?
rspec.rspec_opts = tags.map { |tag| "--tag #{tag}" }.join(" ")
end
end
else
task :integration_test do
puts "Skipping integration tests because this version of Ruby doesn't support them"
desc "Run all the tests"
RSpec::Core::RakeTask.new(:test) do |rspec|
rspec.pattern = "{spec,test}/**/*_{spec,integration_test}.rb"
end
task :test => :features

desc "Run the integration tests"
RSpec::Core::RakeTask.new(:integration_test) do |rspec|
rspec.pattern = "test/**/*_integration_test.rb"
tags = []
tags << "~online" if offline?
tags << "~no_1_8" if RUBY_VERSION.start_with? "1.8"
unless tags.empty?
rspec.rspec_opts = tags.map { |tag| "--tag #{tag}" }.join(" ")
end
task :test => [:features, :spec]
end

task :default => [:test, 'coveralls:push']
Expand Down Expand Up @@ -143,11 +128,7 @@ task :verify => [ 'check-license', 'test-imports' ] do
v = version.ljust(7)
g = gem_version.ljust(8)
s = spec_result ? "pass".green : "fail".red
if ruby_version_supports_integration_test? version
i = integration_test_result ? "pass".green : "fail".red
else
i = "skip".yellow
end
i = integration_test_result ? "pass".green : "fail".red

if ruby_version_supports_acceptance_tests? version
a = acceptance_test_result ? "pass".green : "fail".red
Expand Down
2 changes: 1 addition & 1 deletion config.ru
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ server = PuppetLibrary::Server.configure do

# Everything from The Forge
forge :proxy do
url "http://forge.puppetlabs.com"
url "https://forgeapi.puppetlabs.com"
end
end

Expand Down
14 changes: 7 additions & 7 deletions features/module_list.feature
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ Feature: Module list page
Then I should see "Modules"

Scenario: See module versions
Given the "puppetlabs/apache" module is available at version "1.0.0"
And the "puppetlabs/apache" module is available at version "1.1.0"
Given the "puppetlabs-apache" module is available at version "1.0.0"
And the "puppetlabs-apache" module is available at version "1.1.0"
When I visit the module list page
Then I should see module "puppetlabs/apache" with versions 1.0.0 and 1.1.0
Then I should see module "puppetlabs-apache" with versions 1.0.0 and 1.1.0

Scenario: Follow link to module page
Given the "puppetlabs/apache" module is available at version "1.0.0"
And the "puppetlabs/apache" module is available at version "1.1.0"
Given the "puppetlabs-apache" module is available at version "1.0.0"
And the "puppetlabs-apache" module is available at version "1.1.0"
When I visit the module list page
And I click on "puppetlabs/apache"
Then I should be on the module page for "puppetlabs/apache"
And I click on "puppetlabs-apache"
Then I should be on the module page for "puppetlabs-apache"
12 changes: 6 additions & 6 deletions features/module_page.feature
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ Feature: Module page
So that I can tell exactly what's on the server

Scenario: Visit the module page
Given the "puppetlabs/apache" module is available at version "1.0.0"
And the "puppetlabs/apache" module is available at version "1.1.0"
When I visit the module page for "puppetlabs/apache"
Given the "puppetlabs-apache" module is available at version "1.0.0"
And the "puppetlabs-apache" module is available at version "1.1.0"
When I visit the module page for "puppetlabs-apache"
Then I should see "Author: puppetlabs"
Then I should see "Name: apache"
And I should see "1.0.0"
And I should see "1.1.0"
And I should see "puppetlabs/apache module, version 1.1.0"
And I should see "puppetlabs-apache module, version 1.1.0"

Scenario: Visit a nonexistant module page
When I visit the module page for "nonexistant/nonexistant"
Then I should see 'Module "nonexistant/nonexistant" not found'
When I visit the module page for "nonexistant-nonexistant"
Then I should see 'Module "nonexistant-nonexistant" not found'
8 changes: 4 additions & 4 deletions features/module_search.feature
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ Feature: Module search
So that I can find details about specific modules

Scenario: Visit the module list page
Given the "puppetlabs/apache" module is available at version "1.0.0"
And the "puppetlabs/stdlib" module is available at version "1.0.0"
Given the "puppetlabs-apache" module is available at version "1.0.0"
And the "puppetlabs-stdlib" module is available at version "1.0.0"
When I visit the module list page
And I search for "apache"
Then I should see "puppetlabs/apache"
And I should not see "puppetlabs/stdlib"
Then I should see "puppetlabs-apache"
And I should not see "puppetlabs-stdlib"
2 changes: 1 addition & 1 deletion features/step_definitions/sinatra_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def module_writer
end

Given /^the "(.*?)" module is available at version "(.*?)"$/ do |full_name, version|
author, name = full_name.split "/"
author, name = full_name.split "-"
module_writer.write_module(author, name, version)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/puppet_library/app/views/module.haml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
%h1= "Module #{metadata["full_name"]}"
%div= "Author: #{metadata["author"]}"
%div= "Name: #{metadata["name"]}"
%div= "Description: #{metadata["desc"]}"
%div= "Description: #{metadata["summary"]}"
%div= "Versions:"
%ul
- metadata["releases"].each do |release|
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet_library/app/views/module_not_found.haml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
-# along with this program. If not, see <http://www.gnu.org/licenses/>.

%h1 Not Found
%div= "Module \"#{author}/#{name}\" not found"
%div= "Module \"#{author}-#{name}\" not found"
100 changes: 87 additions & 13 deletions lib/puppet_library/forge/abstract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,55 @@ def get_module_metadata_with_dependencies(author, name, version)
return versions
end

def get_modules(query)
search = Search.new(query)

search_results = retrieve_all_metadata.select do |result|
search.matches? result
end.map do |result|
result.to_search_result
end.group_by do |result|
result["name"]
end

search_results.values.map do |module_results|
current = module_results.sort do |a,b|
Gem::Version.new(a['version']) <=> Gem::Version.new(b['version'])
end.last
{
'uri' => '/v3/modules/' + current['full_name'],
'name' => current['name'],
'owner' => {
'username' => current['author']
},
'current_release' => {
'uri' => "/v3/releases/#{current['full_name']}-#{current['version']}" ,
'module' => {
'uri' => '/v3/modules/' + current['full_name'],
'name' => current['name'],
'owner' => {
'username' => current['author']
},
},
'version' => current['version'],
'metadata' => current,
'tags' => current['tag_list']
},
'releases' => module_results.collect{ |h| { "version" => h["version"] , "uri" => "/v3/releases/#{current['full_name']}-#{current['version']}" } }
}
end
end

def get_releases(module_name)
author, name = module_name.split "-"
retrieve_metadata(author, name).map{ |m| m.to_release }
end

def get_module_v3(module_name, version)
author, name = module_name.split "-"
@repo.get_module(author, name, version) or raise ModuleNotFound
end

def collect_dependencies_versions(module_full_name, metadata = {})
author, module_name = module_full_name.split "/"
module_versions = retrieve_metadata(author, module_name)
Expand All @@ -87,16 +136,20 @@ def collect_dependencies_versions(module_full_name, metadata = {})
return metadata
end

def get_md5(author, name, version)
"00000000000000000000000000000000"
end

def get_module_buffer(author, name, version)
@repo.get_module(author, name, version) or raise ModuleNotFound
end

def retrieve_metadata(author, module_name)
@repo.get_metadata(author, module_name).map {|metadata| ModuleMetadata.new(metadata)}
@repo.get_metadata(author, module_name).map {|metadata| ModuleMetadata.new(metadata, @repo)}
end

def retrieve_all_metadata
@repo.get_all_metadata.map {|metadata| ModuleMetadata.new(metadata)}
@repo.get_all_metadata.map {|metadata| ModuleMetadata.new(metadata, @repo)}
end
end

Expand All @@ -114,20 +167,27 @@ def matches?(metadata)
end

class ModuleMetadata
def initialize(metadata)
attr_reader :md5

def initialize(metadata, repo)
@metadata = metadata
@md5 = repo.get_md5(author, name, version)
end

def author
@metadata["name"][/^[^-]+/]
@metadata["author"]
end

def name
@metadata["name"].sub(/^[^-]+-/, "")
end

def full_name
@metadata["name"].sub("-", "/")
@metadata["name"].sub("/", "-")
end

def classname
name.sub(/^[^-]+-/, "")
end

def version
Expand All @@ -142,10 +202,6 @@ def summary
@metadata["summary"]
end

def description
@metadata["description"]
end

def project_page
@metadata["project_page"]
end
Expand All @@ -159,14 +215,14 @@ def to_info
"author" => author,
"full_name" => full_name,
"name" => name,
"desc" => description,
"summary" => summary,
"releases" => [ { "version" => version } ]
}
end

def to_version
{
"file" => "/modules/#{author}-#{name}-#{version}.tar.gz",
"file" => "/modules/#{full_name}-#{version}.tar.gz",
"version" => version,
"dependencies" => dependencies.map do |dependency|
[ dependency["name"], dependency["version_requirement"] ]
Expand All @@ -179,12 +235,30 @@ def to_search_result
"author" => author,
"full_name" => full_name,
"name" => name,
"desc" => summary,
"project_url" => project_page,
"summary" => summary,
"project_page" => project_page,
"releases" => [{ "version" => version}],
"version" => version,
"tag_list" => [author, name]
}
end

def to_release
{
"uri" => "/v3/releases/#{full_name}-#{version}" ,
"module" => {
"uri" => "/v3/modules/#{full_name}",
"name" => name,
"owner" => {
"username" => author
},
},
"version" => version,
"metadata" => @metadata,
"file_md5" => md5,
"file_uri" => "/modules/#{full_name}-#{version}.tar.gz"
}
end

end
end
Loading