artifactory 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -16
  3. data/.travis.yml +8 -0
  4. data/CHANGELOG.md +9 -0
  5. data/Gemfile +6 -2
  6. data/LICENSE +202 -0
  7. data/README.md +216 -17
  8. data/Rakefile +6 -1
  9. data/artifactory.gemspec +15 -10
  10. data/lib/artifactory.rb +74 -2
  11. data/lib/artifactory/client.rb +222 -0
  12. data/lib/artifactory/collections/artifact.rb +12 -0
  13. data/lib/artifactory/collections/base.rb +49 -0
  14. data/lib/artifactory/configurable.rb +73 -0
  15. data/lib/artifactory/defaults.rb +67 -0
  16. data/lib/artifactory/errors.rb +22 -0
  17. data/lib/artifactory/resources/artifact.rb +481 -0
  18. data/lib/artifactory/resources/base.rb +145 -0
  19. data/lib/artifactory/resources/build.rb +27 -0
  20. data/lib/artifactory/resources/plugin.rb +22 -0
  21. data/lib/artifactory/resources/repository.rb +251 -0
  22. data/lib/artifactory/resources/system.rb +114 -0
  23. data/lib/artifactory/resources/user.rb +57 -0
  24. data/lib/artifactory/util.rb +93 -0
  25. data/lib/artifactory/version.rb +1 -1
  26. data/locales/en.yml +27 -0
  27. data/spec/integration/resources/artifact_spec.rb +73 -0
  28. data/spec/integration/resources/build_spec.rb +11 -0
  29. data/spec/integration/resources/repository_spec.rb +13 -0
  30. data/spec/integration/resources/system_spec.rb +59 -0
  31. data/spec/spec_helper.rb +40 -0
  32. data/spec/support/api_server.rb +41 -0
  33. data/spec/support/api_server/artifact_endpoints.rb +122 -0
  34. data/spec/support/api_server/build_endpoints.rb +22 -0
  35. data/spec/support/api_server/repository_endpoints.rb +75 -0
  36. data/spec/support/api_server/status_endpoints.rb +11 -0
  37. data/spec/support/api_server/system_endpoints.rb +44 -0
  38. data/spec/unit/artifactory_spec.rb +73 -0
  39. data/spec/unit/client_spec.rb +176 -0
  40. data/spec/unit/resources/artifact_spec.rb +377 -0
  41. data/spec/unit/resources/base_spec.rb +140 -0
  42. data/spec/unit/resources/build_spec.rb +34 -0
  43. data/spec/unit/resources/plugin_spec.rb +25 -0
  44. data/spec/unit/resources/repository_spec.rb +180 -0
  45. data/spec/unit/resources/system_spec.rb +88 -0
  46. metadata +106 -36
  47. data/LICENSE.txt +0 -22
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+
3
+ module Artifactory
4
+ describe Resource::Base do
5
+ describe '.attribute' do
6
+ before { described_class.attribute(:bacon) }
7
+
8
+ it 'defines an accessor method' do
9
+ expect(subject).to respond_to(:bacon)
10
+ end
11
+
12
+ it 'defines a setter method' do
13
+ expect(subject).to respond_to(:bacon=)
14
+ end
15
+
16
+ it 'defines a boolean method' do
17
+ expect(subject).to respond_to(:bacon?)
18
+ end
19
+ end
20
+
21
+ describe '.extract_client!' do
22
+ context 'when the :client key is present' do
23
+ let(:client) { double }
24
+ let(:options) { { client: client } }
25
+
26
+ it 'extracts the client' do
27
+ result = described_class.extract_client!(options)
28
+ expect(result).to be(client)
29
+ end
30
+
31
+ it 'removes the key from the hash' do
32
+ described_class.extract_client!(options)
33
+ expect(options).to_not have_key(:client)
34
+ end
35
+ end
36
+
37
+ context 'when the :client key is not present' do
38
+ let(:client) { double }
39
+ before { Artifactory.stub(:client).and_return(client) }
40
+
41
+ it 'uses Artifactory.client' do
42
+ expect(described_class.extract_client!({})).to be(client)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '.format_repos!' do
48
+ context 'when the :repos key is present' do
49
+ it 'joins an array' do
50
+ options = { repos: ['bacon', 'bits'] }
51
+ described_class.format_repos!(options)
52
+ expect(options[:repos]).to eq('bacon,bits')
53
+ end
54
+
55
+ it 'accepts a single repository' do
56
+ options = { repos: 'bacon' }
57
+ described_class.format_repos!(options)
58
+ expect(options[:repos]).to eq('bacon')
59
+ end
60
+ end
61
+
62
+ context 'when the :repos key is not present' do
63
+ it 'does not modify the hash' do
64
+ options = {}
65
+ described_class.format_repos!(options)
66
+ expect(options).to eq(options)
67
+ end
68
+ end
69
+
70
+ context 'when the :repos key is empty' do
71
+ it 'does not modify the hash' do
72
+ options = { repos: [] }
73
+ described_class.format_repos!(options)
74
+ expect(options).to eq(options)
75
+ end
76
+ end
77
+
78
+ describe '.url_safe' do
79
+ let(:string) { double(to_s: 'string') }
80
+
81
+ it 'delegates to URI.escape' do
82
+ expect(URI).to receive(:escape).once
83
+ described_class.url_safe(string)
84
+ end
85
+
86
+ it 'converts the value to a string' do
87
+ expect(string).to receive(:to_s).once
88
+ described_class.url_safe(string)
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#client' do
94
+ it 'defines a :client method' do
95
+ expect(subject).to respond_to(:client)
96
+ end
97
+
98
+ it 'defaults to the Artifactory.client' do
99
+ client = double
100
+ Artifactory.stub(:client).and_return(client)
101
+
102
+ expect(subject.client).to be(client)
103
+ end
104
+ end
105
+
106
+ describe '#extract_client!' do
107
+ it 'delegates to the class method' do
108
+ expect(described_class).to receive(:extract_client!).once
109
+ subject.extract_client!({})
110
+ end
111
+ end
112
+
113
+ describe '#format_repos!' do
114
+ it 'delegates to the class method' do
115
+ expect(described_class).to receive(:format_repos!).once
116
+ subject.format_repos!({})
117
+ end
118
+ end
119
+
120
+ describe '#url_safe' do
121
+ it 'delegates to the class method' do
122
+ expect(described_class).to receive(:url_safe).once
123
+ subject.url_safe('string')
124
+ end
125
+ end
126
+
127
+ describe '#to_s' do
128
+ it 'returns the name of the class' do
129
+ expect(subject.to_s).to eq('#<Artifactory::Resource::Base>')
130
+ end
131
+ end
132
+
133
+ describe '#inspect' do
134
+ it 'includes all the instance variables' do
135
+ subject.instance_variable_set(:@foo, 'bar')
136
+ expect(subject.inspect).to eq(%q|#<Artifactory::Resource::Base foo: "bar">|)
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ module Artifactory
4
+ describe Resource::Build do
5
+ let(:client) { double(:client) }
6
+
7
+ before(:each) do
8
+ Artifactory.stub(:client).and_return(client)
9
+ client.stub(:get).and_return(response) if defined?(response)
10
+ end
11
+
12
+ describe '.all' do
13
+ let(:response) { ['a', 'b', 'c'] }
14
+
15
+ it 'gets /api/build' do
16
+ expect(client).to receive(:get).with('/api/build').once
17
+ described_class.all
18
+ end
19
+
20
+ context 'when there are builds' do
21
+ it 'returns the builds' do
22
+ expect(described_class.all).to eq(['a', 'b', 'c'])
23
+ end
24
+ end
25
+
26
+ context 'when the system has no builds' do
27
+ it 'returns an empty array' do
28
+ client.stub(:get).and_raise(Error::NotFound)
29
+ expect(described_class.all).to be_empty
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ module Artifactory
4
+ describe Resource::Plugin do
5
+ let(:client) { double(:client) }
6
+
7
+ before(:each) do
8
+ Artifactory.stub(:client).and_return(client)
9
+ client.stub(:get).and_return(response) if defined?(response)
10
+ end
11
+
12
+ describe '.all' do
13
+ let(:response) { ['a', 'b', 'c'] }
14
+
15
+ it 'gets /api/plugins' do
16
+ expect(client).to receive(:get).with('/api/plugins').once
17
+ described_class.all
18
+ end
19
+
20
+ it 'returns the plugins' do
21
+ expect(described_class.all).to eq(['a', 'b', 'c'])
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ module Artifactory
4
+ describe Resource::Repository do
5
+ let(:client) { double(:client) }
6
+
7
+ before(:each) do
8
+ Artifactory.stub(:client).and_return(client)
9
+ client.stub(:get).and_return(response) if defined?(response)
10
+ end
11
+
12
+ describe '.all' do
13
+ let(:response) do
14
+ [
15
+ { 'key' => 'a' },
16
+ { 'key' => 'b' },
17
+ { 'key' => 'c' },
18
+ ]
19
+ end
20
+ before do
21
+ described_class.stub(:find).with(name: 'a', client: client).and_return('a')
22
+ described_class.stub(:find).with(name: 'b', client: client).and_return('b')
23
+ described_class.stub(:find).with(name: 'c', client: client).and_return('c')
24
+ end
25
+
26
+ it 'gets /api/repositories' do
27
+ expect(client).to receive(:get).with('/api/repositories').once
28
+ described_class.all
29
+ end
30
+
31
+ it 'returns the repositories' do
32
+ expect(described_class.all).to eq(['a', 'b', 'c'])
33
+ end
34
+ end
35
+
36
+ describe '.find' do
37
+ let(:response) { {} }
38
+
39
+ it 'gets /api/repositories/#{name}' do
40
+ expect(client).to receive(:get).with('/api/repositories/libs-release-local').once
41
+ described_class.find(name: 'libs-release-local')
42
+ end
43
+ end
44
+
45
+ describe '.from_hash' do
46
+ let(:hash) do
47
+ {
48
+ 'key' => 'libs-release-local',
49
+ 'description' => 'Local repository for in-house libraries',
50
+ 'notes' => '',
51
+ 'includesPattern' => '**/*',
52
+ 'excludesPattern' => '',
53
+ 'repoLayoutRef' => 'maven-2-default',
54
+ 'enableNuGetSupport' => false,
55
+ 'enableGemsSupport' => false,
56
+ 'checksumPolicyType' => 'client-checksums',
57
+ 'handleReleases' => true,
58
+ 'handleSnapshots' => false,
59
+ 'maxUniqueSnapshots' => 0,
60
+ 'snapshotVersionBehavior' => 'unique',
61
+ 'suppressPomConsistencyChecks' => false,
62
+ 'blackedOut' => false,
63
+ 'propertySets' => ['artifactory'],
64
+ 'archiveBrowsingEnabled' => false,
65
+ 'calculateYumMetadata' => false,
66
+ 'yumRootDepth' => 0,
67
+ 'rclass' => 'local',
68
+ }
69
+ end
70
+
71
+ it 'creates a new instnace' do
72
+ instance = described_class.from_hash(hash)
73
+ expect(instance.blacked_out).to be_false
74
+ expect(instance.description).to eq('Local repository for in-house libraries')
75
+ expect(instance.checksum_policy).to eq('client-checksums')
76
+ expect(instance.excludes_pattern).to eq('')
77
+ expect(instance.handle_releases).to be_true
78
+ expect(instance.handle_snapshots).to be_false
79
+ expect(instance.includes_pattern).to eq('**/*')
80
+ expect(instance.key).to eq('libs-release-local')
81
+ expect(instance.maximum_unique_snapshots).to eq(0)
82
+ expect(instance.notes).to eq('')
83
+ expect(instance.property_sets).to eq(['artifactory'])
84
+ expect(instance.snapshot_version_behavior).to eq('unique')
85
+ expect(instance.suppress_pom_checks).to be_false
86
+ expect(instance.type).to eq('local')
87
+ end
88
+ end
89
+
90
+ describe '#upload' do
91
+ let(:client) { double }
92
+ before do
93
+ subject.client = client
94
+ subject.key = 'libs-release-local'
95
+ end
96
+
97
+ context 'when the artifact is a File' do
98
+ it 'PUTs the file to the server' do
99
+ file = double(:file, is_a?: true)
100
+ expect(client).to receive(:put).with('libs-release-local/remote/path', { file: file }, {})
101
+
102
+ subject.upload(file, '/remote/path')
103
+ end
104
+ end
105
+
106
+ context 'when the artifact is a file path' do
107
+ it 'PUTs the file at the path to the server' do
108
+ file = double(:file)
109
+ path = '/fake/path'
110
+ File.stub(:new).with('/fake/path').and_return(file)
111
+ expect(client).to receive(:put).with('libs-release-local/remote/path', { file: file }, {})
112
+
113
+ subject.upload(path, '/remote/path')
114
+ end
115
+ end
116
+
117
+ context 'when matrix properties are given' do
118
+ it 'converts the hash into matrix properties' do
119
+ file = double(:file, is_a?: true)
120
+ expect(client).to receive(:put).with('libs-release-local;branch=master;user=Seth%20Vargo/remote/path', { file: file }, {})
121
+
122
+ subject.upload(file, '/remote/path',
123
+ branch: 'master',
124
+ user: 'Seth Vargo',
125
+ )
126
+ end
127
+ end
128
+
129
+ context 'when custom headers are given' do
130
+ it 'passes the headers to the client' do
131
+ headers = { 'Content-Type' => 'text/plain' }
132
+ file = double(:file, is_a?: true)
133
+ expect(client).to receive(:put).with('libs-release-local/remote/path', { file: file }, headers)
134
+
135
+ subject.upload(file, '/remote/path', {}, headers)
136
+ end
137
+ end
138
+ end
139
+
140
+ describe '#upload_with_checksum' do
141
+ it 'delegates to #upload' do
142
+ expect(subject).to receive(:upload).with(
143
+ '/local/file',
144
+ '/remote/path',
145
+ { branch: 'master' },
146
+ {
147
+ 'X-Checksum-Deploy' => true,
148
+ 'X-Checksum-Sha1' => 'ABCD1234',
149
+ },
150
+ )
151
+ subject.upload_with_checksum('/local/file', '/remote/path',
152
+ 'ABCD1234',
153
+ { branch: 'master' },
154
+ )
155
+ end
156
+ end
157
+
158
+ describe '#upload_from_archive' do
159
+ it 'delegates to #upload' do
160
+ expect(subject).to receive(:upload).with(
161
+ '/local/file',
162
+ '/remote/path',
163
+ {},
164
+ {
165
+ 'X-Explode-Archive' => true,
166
+ },
167
+ )
168
+ subject.upload_from_archive('/local/file', '/remote/path')
169
+ end
170
+ end
171
+
172
+ describe '#artifacts' do
173
+ before { subject.key = 'libs-release-local' }
174
+
175
+ it 'returns an artifact collection' do
176
+ expect(subject.artifacts).to be_a(Collection::Artifact)
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ module Artifactory
4
+ describe Resource::System do
5
+ let(:client) { double(:client) }
6
+
7
+ before(:each) do
8
+ Artifactory.stub(:client).and_return(client)
9
+ client.stub(:get).and_return(response) if defined?(response)
10
+ end
11
+
12
+ describe '.info' do
13
+ let(:response) { 'This is the response...' }
14
+
15
+ it 'calls /api/system' do
16
+ expect(client).to receive(:get).with('/api/system').once
17
+ described_class.info
18
+ end
19
+
20
+ it 'returns the plan-text body' do
21
+ expect(described_class.info).to eq(response)
22
+ end
23
+ end
24
+
25
+ describe '.ping' do
26
+ let(:response) { '' }
27
+
28
+ it 'gets /api/system/ping' do
29
+ expect(client).to receive(:get).with('/api/system/ping').once
30
+ described_class.ping
31
+ end
32
+
33
+ context 'when the system is ok' do
34
+ it 'returns true' do
35
+ expect(described_class.ping).to be_true
36
+ end
37
+ end
38
+
39
+ context 'when the system is not running' do
40
+ it 'returns false' do
41
+ client.stub(:get).and_raise(Error::ConnectionError)
42
+ expect(described_class.ping).to be_false
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '.configuration' do
48
+ let(:response) { '<config></config>' }
49
+
50
+ it 'gets /api/system/configuration' do
51
+ expect(client).to receive(:get).with('/api/system/configuration').once
52
+ described_class.configuration
53
+ end
54
+
55
+ it 'returns the xml' do
56
+ expect(described_class.configuration).to be_a(REXML::Document)
57
+ end
58
+ end
59
+
60
+ describe '.update_configuration' do
61
+ let(:xml) { double(:xml) }
62
+ let(:response) { double(body: '...') }
63
+ before { client.stub(:post).and_return(response) }
64
+
65
+ it 'posts /api/system/configuration' do
66
+ expect(client).to receive(:post).with('/api/system/configuration', xml).once
67
+ described_class.update_configuration(xml)
68
+ end
69
+
70
+ it 'returns the body of the response' do
71
+ expect(described_class.update_configuration(xml)).to eq(response)
72
+ end
73
+ end
74
+
75
+ describe '.version' do
76
+ let(:response) { double(json: { 'foo' => 'bar' }) }
77
+
78
+ it 'gets /api/system/version' do
79
+ expect(client).to receive(:get).with('/api/system/version').once
80
+ described_class.version
81
+ end
82
+
83
+ it 'returns the parsed JSON of the response' do
84
+ expect(described_class.version).to eq(response)
85
+ end
86
+ end
87
+ end
88
+ end