puppet_forge 1.0.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.
Files changed (51) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +13 -0
  4. data/README.md +172 -0
  5. data/Rakefile +2 -0
  6. data/lib/her/lazy_accessors.rb +140 -0
  7. data/lib/her/lazy_relations.rb +86 -0
  8. data/lib/puppet_forge.rb +19 -0
  9. data/lib/puppet_forge/middleware/json_for_her.rb +37 -0
  10. data/lib/puppet_forge/v3.rb +10 -0
  11. data/lib/puppet_forge/v3/base.rb +98 -0
  12. data/lib/puppet_forge/v3/base/paginated_collection.rb +73 -0
  13. data/lib/puppet_forge/v3/module.rb +15 -0
  14. data/lib/puppet_forge/v3/release.rb +35 -0
  15. data/lib/puppet_forge/v3/user.rb +21 -0
  16. data/lib/puppet_forge/version.rb +3 -0
  17. data/puppet_forge.gemspec +31 -0
  18. data/spec/fixtures/v3/files/puppetlabs-apache-0.0.1.tar.gz.headers +14 -0
  19. data/spec/fixtures/v3/files/puppetlabs-apache-0.0.1.tar.gz.json +0 -0
  20. data/spec/fixtures/v3/modules.headers +14 -0
  21. data/spec/fixtures/v3/modules.json +4197 -0
  22. data/spec/fixtures/v3/modules/puppetlabs-apache.headers +14 -0
  23. data/spec/fixtures/v3/modules/puppetlabs-apache.json +390 -0
  24. data/spec/fixtures/v3/modules?owner=puppetlabs.headers +14 -0
  25. data/spec/fixtures/v3/modules?owner=puppetlabs.json +4179 -0
  26. data/spec/fixtures/v3/modules?query=apache.headers +14 -0
  27. data/spec/fixtures/v3/modules?query=apache.json +3151 -0
  28. data/spec/fixtures/v3/releases.headers +14 -0
  29. data/spec/fixtures/v3/releases.json +3072 -0
  30. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.1.headers +14 -0
  31. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.1.json +93 -0
  32. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.2.headers +14 -0
  33. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.2.json +93 -0
  34. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.3.headers +14 -0
  35. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.3.json +93 -0
  36. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.4.headers +14 -0
  37. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.4.json +126 -0
  38. data/spec/fixtures/v3/releases/puppetlabs-apache-0.1.1.headers +14 -0
  39. data/spec/fixtures/v3/releases/puppetlabs-apache-0.1.1.json +140 -0
  40. data/spec/fixtures/v3/releases?module=puppetlabs-apache.headers +14 -0
  41. data/spec/fixtures/v3/releases?module=puppetlabs-apache.json +3287 -0
  42. data/spec/fixtures/v3/users/puppetlabs.headers +14 -0
  43. data/spec/fixtures/v3/users/puppetlabs.json +10 -0
  44. data/spec/spec_helper.rb +60 -0
  45. data/spec/unit/forge/v3/base/paginated_collection_spec.rb +88 -0
  46. data/spec/unit/forge/v3/module_spec.rb +118 -0
  47. data/spec/unit/forge/v3/release_spec.rb +112 -0
  48. data/spec/unit/forge/v3/user_spec.rb +50 -0
  49. data/spec/unit/her/lazy_accessors_spec.rb +142 -0
  50. data/spec/unit/her/lazy_relations_spec.rb +309 -0
  51. metadata +261 -0
@@ -0,0 +1,14 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx
3
+ Date: Mon, 06 Jan 2014 22:42:07 GMT
4
+ Content-Type: application/json;charset=utf-8
5
+ Content-Length: 285
6
+ Connection: keep-alive
7
+ Status: 200 OK
8
+ X-Frame-Options: sameorigin
9
+ X-XSS-Protection: 1; mode=block
10
+ Cache-Control: public, must-revalidate
11
+ Last-Modified: Mon, 12 Nov 2012 14:51:00 GMT
12
+ X-Node: forgeapi02
13
+ X-Revision: 49f66e061b0021c081fb58e754898cd928f61494
14
+
@@ -0,0 +1,10 @@
1
+ {
2
+ "uri": "/v3/users/puppetlabs",
3
+ "gravatar_id": "fdd009b7c1ec96e088b389f773e87aec",
4
+ "username": "puppetlabs",
5
+ "display_name": "Puppet Labs",
6
+ "release_count": 422,
7
+ "module_count": 81,
8
+ "created_at": "2010-05-19 05:46:26 -0700",
9
+ "updated_at": "2012-11-12 06:51:00 -0800"
10
+ }
@@ -0,0 +1,60 @@
1
+ PROJECT_ROOT = File.join(File.dirname(__FILE__), '..')
2
+
3
+ if ENV['COVERAGE']
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_filter "/spec/"
7
+ end
8
+
9
+ end
10
+
11
+ require 'puppet_forge'
12
+
13
+ module StubbingHer
14
+ def stub_api_for(klass)
15
+ klass.use_api begin
16
+ Her::API.new :url => "http://api.example.com" do |c|
17
+ c.use PuppetForge::Middleware::JSONForHer
18
+ c.adapter(:test) { |s| yield(s) }
19
+ end
20
+ end
21
+ end
22
+
23
+ def stub_fixture(api, method, path)
24
+ api.send(method, path) do |env|
25
+ load_fixture([ env[:url].path, env[:url].query ].compact.join('?'))
26
+ end
27
+ end
28
+
29
+ def load_fixture(path)
30
+ [ 404 ].tap do |response|
31
+ local = File.join(PROJECT_ROOT, 'spec', 'fixtures', path.to_s)
32
+
33
+ if File.exists?("#{local}.headers") && File.exists?("#{local}.json")
34
+ File.open("#{local}.headers") do |file|
35
+ response[0] = file.readline[/\d{3}/].to_i
36
+ response[1] = headers = {}
37
+ file.read.scan(/^([^:]+?):(.*)/) do |key, val|
38
+ headers[key] = val.strip
39
+ end
40
+ end
41
+
42
+ response << File.read("#{local}.json")
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ RSpec.configure do |config|
49
+ config.treat_symbols_as_metadata_keys_with_true_values = true
50
+ config.run_all_when_everything_filtered = true
51
+ config.filter_run :focus
52
+
53
+ config.include StubbingHer
54
+
55
+ # Run specs in random order to surface order dependencies. If you find an
56
+ # order dependency and want to debug it, you can fix the order by providing
57
+ # the seed, which is printed after each run.
58
+ # --seed 1234
59
+ config.order = 'random'
60
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetForge::V3::Base::PaginatedCollection do
4
+ let(:klass) do
5
+ Class.new do
6
+ def self.get_collection(url)
7
+ data = {
8
+ '/v3/collection' => [ :A, :B, :C ],
9
+ '/v3/collection?page=2' => [ :D, :E, :F ],
10
+ '/v3/collection?page=3' => [ :G, :H ],
11
+ }
12
+
13
+ meta = {
14
+ '/v3/collection' => {
15
+ :limit => 3,
16
+ :offset => 0,
17
+ :first => '/v3/collection',
18
+ :previous => nil,
19
+ :current => '/v3/collection',
20
+ :next => '/v3/collection?page=2',
21
+ :total => 8,
22
+ },
23
+ '/v3/collection?page=2' => {
24
+ :limit => 3,
25
+ :offset => 0,
26
+ :first => '/v3/collection',
27
+ :previous => '/v3/collection',
28
+ :current => '/v3/collection?page=2',
29
+ :next => '/v3/collection?page=3',
30
+ :total => 8,
31
+ },
32
+ '/v3/collection?page=3' => {
33
+ :limit => 3,
34
+ :offset => 0,
35
+ :first => '/v3/collection',
36
+ :previous => '/v3/collection?page=2',
37
+ :current => '/v3/collection?page=3',
38
+ :next => nil,
39
+ :total => 8,
40
+ },
41
+ }
42
+
43
+ PuppetForge::V3::Base::PaginatedCollection.new(self, data[url], meta[url], {})
44
+ end
45
+ end
46
+ end
47
+
48
+ subject { klass.get_collection('/v3/collection') }
49
+
50
+ it 'maps to a single page of the collection' do
51
+ expect(subject.to_a).to eql([ :A, :B, :C ])
52
+ end
53
+
54
+ it 'knows the size of the entire collection' do
55
+ expect(subject.total).to be 8
56
+ end
57
+
58
+ it 'contains only a subset of the entire collection' do
59
+ expect(subject.size).to be 3
60
+ end
61
+
62
+ it 'enables page navigation' do
63
+ expect(subject.next).to_not be_empty
64
+ expect(subject.next.to_a).to_not eql(subject.to_a)
65
+ expect(subject.next.previous.to_a).to eql(subject.to_a)
66
+ end
67
+
68
+ it 'exposes the pagination metadata' do
69
+ expect(subject.metadata[:limit]).to be subject.size
70
+ end
71
+
72
+ it 'exposes previous_url and next_url' do
73
+ expected = subject.next_url
74
+ expect(subject.next.next.previous_url).to eql(expected)
75
+ end
76
+
77
+ describe '#unpaginated' do
78
+ it 'provides an iterator over the entire collection' do
79
+ expected = [ :A, :B, :C, :D, :E, :F, :G, :H ]
80
+ expect(subject.unpaginated.to_a).to eql(expected)
81
+ end
82
+
83
+ it "provides a full iterator regardless of which page it's started on" do
84
+ expected = [ :A, :B, :C, :D, :E, :F, :G, :H ]
85
+ expect(subject.next.next.unpaginated.to_a).to eql(expected)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetForge::V3::Module do
4
+ before do
5
+ stub_api_for(PuppetForge::V3::Module) do |api|
6
+ stub_fixture(api, :get, '/v3/modules/puppetlabs-apache')
7
+ stub_fixture(api, :get, '/v3/modules/absent-apache')
8
+ end
9
+ end
10
+
11
+ describe '::find' do
12
+ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') }
13
+ let(:missing_mod) { PuppetForge::V3::Module.find('absent-apache') }
14
+
15
+ it 'can find modules that exist' do
16
+ mod.name.should == 'apache'
17
+ end
18
+
19
+ it 'returns nil for non-existent modules' do
20
+ missing_mod.should be_nil
21
+ end
22
+ end
23
+
24
+ describe '#owner' do
25
+ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') }
26
+
27
+ before do
28
+ stub_api_for(PuppetForge::V3::User) do |api|
29
+ stub_fixture(api, :get, '/v3/users/puppetlabs')
30
+ end
31
+ end
32
+
33
+ it 'exposes the related module as a property' do
34
+ expect(mod.owner).to_not be nil
35
+ end
36
+
37
+ it 'grants access to module attributes without an API call' do
38
+ PuppetForge::V3::User.should_not_receive(:request)
39
+ expect(mod.owner.username).to eql('puppetlabs')
40
+ end
41
+
42
+ it 'transparently makes API calls for other attributes' do
43
+ PuppetForge::V3::User.should_receive(:request).once.and_call_original
44
+ expect(mod.owner.created_at).to_not be nil
45
+ end
46
+ end
47
+
48
+ describe '#current_release' do
49
+ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') }
50
+
51
+ it 'exposes the current_release as a property' do
52
+ expect(mod.current_release).to_not be nil
53
+ end
54
+
55
+ it 'grants access to release attributes without an API call' do
56
+ PuppetForge::V3::Release.should_not_receive(:request)
57
+ expect(mod.current_release.version).to_not be nil
58
+ end
59
+
60
+ it 'transparently makes API calls for other attributes' do
61
+ stub_api_for(PuppetForge::V3::Release) do |api|
62
+ api.get(mod.current_release.uri) do
63
+ load_fixture('/v3/releases/puppetlabs-apache-0.0.1')
64
+ end
65
+ end
66
+
67
+ mod.attributes[:current_release].delete :created_at
68
+ expect(mod.current_release.created_at).to_not be nil
69
+ end
70
+ end
71
+
72
+ describe '#releases' do
73
+ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') }
74
+
75
+ before do
76
+ stub_api_for(PuppetForge::V3::Release) do |api|
77
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.0.1')
78
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.0.2')
79
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.0.3')
80
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.0.4')
81
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.1.1')
82
+ stub_fixture(api, :get, '/v3/releases?module=puppetlabs-apache')
83
+ end
84
+ end
85
+
86
+ it 'exposes the related releases as a property' do
87
+ expect(mod.releases).to be_an Array
88
+ end
89
+
90
+ it 'knows the size of the collection' do
91
+ expect(mod.releases).to_not be_empty
92
+ end
93
+
94
+ it 'grants access to release attributes without an API call' do
95
+ PuppetForge::V3::Release.should_not_receive(:request)
96
+ expect(mod.releases.map(&:version)).to_not include nil
97
+ end
98
+
99
+ it 'transparently makes API calls for other attributes' do
100
+ versions = %w[ 0.0.1 0.0.2 0.0.3 0.0.4 0.1.1 ]
101
+ releases = mod.releases.select { |x| versions.include? x.version }
102
+
103
+ PuppetForge::V3::Release.should_receive(:request) \
104
+ .exactly(5).times \
105
+ .and_call_original
106
+
107
+ expect(releases.map(&:created_at)).to_not include nil
108
+ end
109
+ end
110
+
111
+ describe 'instance properies' do
112
+ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') }
113
+
114
+ example 'are easily accessible' do
115
+ expect(mod.created_at).to_not be nil
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ describe PuppetForge::V3::Release do
5
+ before do
6
+ stub_api_for(PuppetForge::V3::Release) do |api|
7
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.0.1')
8
+ stub_fixture(api, :get, '/v3/releases/absent-apache-0.0.1')
9
+ end
10
+ end
11
+
12
+ describe '::find' do
13
+ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') }
14
+ let(:missing_release) { PuppetForge::V3::Release.find('absent-apache-0.0.1') }
15
+
16
+ it 'can find releases that exist' do
17
+ expect(release.version).to eql('0.0.1')
18
+ end
19
+
20
+ it 'returns nil for non-existent releases' do
21
+ expect(missing_release).to be nil
22
+ end
23
+ end
24
+
25
+ describe '#module' do
26
+ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') }
27
+
28
+ before do
29
+ stub_api_for(PuppetForge::V3::Module) do |api|
30
+ stub_fixture(api, :get, '/v3/modules/puppetlabs-apache')
31
+ end
32
+ end
33
+
34
+ it 'exposes the related module as a property' do
35
+ expect(release.module).to_not be nil
36
+ end
37
+
38
+ it 'grants access to module attributes without an API call' do
39
+ PuppetForge::V3::Module.should_not_receive(:request)
40
+ expect(release.module.name).to eql('apache')
41
+ end
42
+
43
+ it 'transparently makes API calls for other attributes' do
44
+ PuppetForge::V3::Module.should_receive(:request).once.and_call_original
45
+ expect(release.module.created_at).to_not be nil
46
+ end
47
+ end
48
+
49
+ describe '#download_url' do
50
+ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') }
51
+
52
+ before do
53
+ stub_api_for(PuppetForge::V3::Release) do |api|
54
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.0.1')
55
+ end
56
+ end
57
+
58
+ it 'handles an API response that does not include a scheme and host' do
59
+ release.file_uri = '/v3/files/puppetlabs-apache-0.0.1.tar.gz'
60
+ expect(release.download_url).to eql(PuppetForge.host + '/v3/files/puppetlabs-apache-0.0.1.tar.gz')
61
+ end
62
+
63
+ it 'handles an API response that includes a scheme and host' do
64
+ release.file_uri = 'https://example.com/v3/files/puppetlabs-apache-0.0.1.tar.gz'
65
+ expect(release.download_url).to eql('https://example.com/v3/files/puppetlabs-apache-0.0.1.tar.gz')
66
+ end
67
+ end
68
+
69
+ describe '#download' do
70
+ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') }
71
+ let(:tarball) { "#{PROJECT_ROOT}/spec/tmp/module.tgz" }
72
+
73
+ before { FileUtils.rm tarball rescue nil }
74
+ after { FileUtils.rm tarball rescue nil }
75
+ before do
76
+ stub_api_for(PuppetForge::V3::Release) do |api|
77
+ stub_fixture(api, :get, '/v3/releases/puppetlabs-apache-0.0.1')
78
+ stub_fixture(api, :get, '/v3/files/puppetlabs-apache-0.0.1.tar.gz')
79
+ end
80
+ end
81
+
82
+ it 'downloads the file to the specified location' do
83
+ expect(File.exist?(tarball)).to be false
84
+ release.download(tarball)
85
+ expect(File.exist?(tarball)).to be true
86
+ end
87
+ end
88
+
89
+ describe '#metadata' do
90
+ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') }
91
+
92
+ before do
93
+ stub_api_for(PuppetForge::V3::Module) do |api|
94
+ stub_fixture(api, :get, '/v3/modules/puppetlabs-apache')
95
+ end
96
+ end
97
+
98
+ it 'is lazy and repeatable' do
99
+ 3.times do
100
+ expect(release.module.releases.last.metadata).to_not be_nil
101
+ end
102
+ end
103
+ end
104
+
105
+ describe 'instance properies' do
106
+ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') }
107
+
108
+ example 'are easily accessible' do
109
+ expect(release.created_at).to_not be nil
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetForge::V3::User do
4
+ before do
5
+ stub_api_for(PuppetForge::V3::User) do |api|
6
+ stub_fixture(api, :get, '/v3/users/puppetlabs')
7
+ stub_fixture(api, :get, '/v3/users/absent')
8
+ end
9
+ end
10
+
11
+ describe '::find' do
12
+ let(:user) { PuppetForge::V3::User.find('puppetlabs') }
13
+ let(:missing_user) { PuppetForge::V3::User.find('absent') }
14
+
15
+ it 'can find users that exist' do
16
+ user.username.should == 'puppetlabs'
17
+ end
18
+
19
+ it 'returns nil for non-existent users' do
20
+ missing_user.should be_nil
21
+ end
22
+ end
23
+
24
+ describe '#modules' do
25
+ before do
26
+ stub_api_for(PuppetForge::V3::Module) do |api|
27
+ stub_fixture(api, :get, '/v3/modules?owner=puppetlabs')
28
+ end
29
+ end
30
+
31
+ let(:user) { PuppetForge::V3::User.find('puppetlabs') }
32
+
33
+ it 'should return a PaginatedCollection' do
34
+ expect(user.modules).to be_a PuppetForge::V3::Base::PaginatedCollection
35
+ end
36
+
37
+ it 'should only return modules for the current user' do
38
+ module_owners = user.modules.map(&:owner)
39
+ expect(module_owners.group_by(&:username).keys).to eql(['puppetlabs'])
40
+ end
41
+ end
42
+
43
+ describe 'instance properies' do
44
+ let(:user) { PuppetForge::V3::User.find('puppetlabs') }
45
+
46
+ example 'are easily accessible' do
47
+ expect(user.created_at).to_not be nil
48
+ end
49
+ end
50
+ end