artifactory 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,5 +15,5 @@
15
15
  #
16
16
 
17
17
  module Artifactory
18
- VERSION = '2.2.1'
18
+ VERSION = '2.3.0'
19
19
  end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ module Artifactory
4
+ describe Resource::BuildComponent, :integration do
5
+ let(:build_component) { described_class.find('wicket') }
6
+
7
+ describe '.all' do
8
+ it 'returns an array of build component objects' do
9
+ results = described_class.all
10
+ expect(results).to be_a(Array)
11
+ expect(results.first).to be_a(described_class)
12
+ end
13
+ end
14
+
15
+ describe '.find' do
16
+ it 'finds a build component by name' do
17
+ expect(build_component).to be_a(described_class)
18
+ expect(build_component.name).to eq('wicket')
19
+ expect(build_component.last_started).to eq(Time.parse('2015-06-19T20:13:20.222Z'))
20
+ end
21
+ end
22
+
23
+ describe '#delete' do
24
+ let(:build_numbers) { %w( 51 52 )}
25
+ let(:delete_all) { false }
26
+
27
+ it 'deletes the specified builds from the component' do
28
+
29
+ expect(build_component.delete(
30
+ build_numbers: build_numbers,
31
+ delete_all: delete_all
32
+ )).to be_truthy
33
+ end
34
+
35
+ context 'no build numbers provided' do
36
+ let(:build_numbers) { nil }
37
+
38
+ it 'deletes no builds' do
39
+
40
+ expect(build_component.delete(
41
+ delete_all: delete_all
42
+ )).to be_falsey
43
+ end
44
+
45
+ context 'the delete_all flag is true' do
46
+ let(:delete_all) { true }
47
+
48
+ it 'deletes the component and all builds' do
49
+ expect(build_component.delete(
50
+ delete_all: delete_all
51
+ )).to be_truthy
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#rename' do
58
+ it 'renames the build component on the server' do
59
+
60
+ expect(build_component.rename('fricket')).to be_truthy
61
+ end
62
+ end
63
+ end
64
+ end
@@ -3,7 +3,35 @@ require 'spec_helper'
3
3
  module Artifactory
4
4
  describe Resource::Build, :integration do
5
5
  describe '.all' do
6
- it 'returns an array of build objects'
6
+ it 'returns an array of build objects' do
7
+ results = described_class.all('wicket')
8
+ expect(results).to be_a(Array)
9
+ expect(results.first).to be_a(described_class)
10
+ end
11
+ end
12
+
13
+ describe '.find' do
14
+ it 'finds a build by component and number' do
15
+ build = described_class.find('wicket', 51)
16
+
17
+ expect(build).to be_a(described_class)
18
+ expect(build.name).to eq('wicket')
19
+ expect(build.number).to eq('51')
20
+ expect(build.started).to eq(Time.parse('2014-09-30T12:00:19.893+0300'))
21
+ end
22
+ end
23
+
24
+ describe '#save' do
25
+ it 'saves the build data to the server' do
26
+ build = described_class.new(
27
+ name: 'fricket',
28
+ number: '1',
29
+ properties: {
30
+ 'buildInfo.env.JAVA_HOME' => '/usr/jdk/latest'
31
+ })
32
+
33
+ expect(build.save).to be_truthy
34
+ end
7
35
  end
8
36
  end
9
37
  end
@@ -25,9 +25,10 @@ RSpec.configure do |config|
25
25
  config.before(:each) { Artifactory.reset! }
26
26
  config.after(:each) { Artifactory.reset! }
27
27
 
28
- #
29
28
  config.before(:each, :integration) do
30
29
  Artifactory.endpoint = 'http://localhost:8889'
30
+ Artifactory.username = nil
31
+ Artifactory.password = nil
31
32
  stub_request(:any, /#{Artifactory.endpoint}/).to_rack(Artifactory::APIServer)
32
33
  end
33
34
 
@@ -7,6 +7,7 @@ module Artifactory
7
7
  #
8
8
  class APIServer < Sinatra::Base
9
9
  require_relative 'api_server/artifact_endpoints'
10
+ require_relative 'api_server/build_component_endpoints'
10
11
  require_relative 'api_server/build_endpoints'
11
12
  require_relative 'api_server/group_endpoints'
12
13
  require_relative 'api_server/repository_endpoints'
@@ -16,6 +17,7 @@ module Artifactory
16
17
  require_relative 'api_server/user_endpoints'
17
18
 
18
19
  register APIServer::ArtifactEndpoints
20
+ register APIServer::BuildComponentEndpoints
19
21
  register APIServer::BuildEndpoints
20
22
  register APIServer::GroupEndpoints
21
23
  register APIServer::PermissionTargetEndpoints
@@ -0,0 +1,44 @@
1
+ module Artifactory
2
+ module APIServer::BuildComponentEndpoints
3
+ def self.registered(app)
4
+ app.get('/api/build') do
5
+ content_type 'application/vnd.org.jfrog.build.Builds+json'
6
+ JSON.fast_generate(
7
+ 'uri' => server_url.join('/api/build'),
8
+ 'builds' => [
9
+ {
10
+ 'uri' => '/wicket',
11
+ 'lastStarted' => '2015-06-19T20:13:20.222Z',
12
+ },
13
+ {
14
+ 'uri' => '/jackrabbit',
15
+ 'lastStarted' => '2015-06-20T20:13:20.333Z',
16
+ }
17
+ ]
18
+ )
19
+ end
20
+
21
+ app.post('/api/build/rename/:name') do
22
+ content_type 'text/plain'
23
+ body "Build renaming of '#{params['name']}' to '#{params['to']}' was successfully started."
24
+ end
25
+
26
+ app.delete('/api/build/:name') do
27
+ content_type 'text/plain'
28
+
29
+ if params['deleteAll']
30
+ body "All '#{params['name']}' builds have been deleted successfully."
31
+ elsif params['buildNumbers'].nil?
32
+ status 400
33
+ body 'Please provide at least one build number to delete.'
34
+ else
35
+ message = params['buildNumbers'].split(',').map do |n|
36
+ "#{params['name']}##{n}"
37
+ end.join(', ')
38
+
39
+ body "The following builds has been deleted successfully: #{message}."
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,18 +1,227 @@
1
1
  module Artifactory
2
2
  module APIServer::BuildEndpoints
3
3
  def self.registered(app)
4
- app.get('/api/build') do
5
- content_type 'application/vnd.org.jfrog.build.Builds+json'
4
+ app.get('/api/build/wicket') do
5
+ content_type 'application/vnd.org.jfrog.build.BuildsByName+json'
6
6
  JSON.fast_generate(
7
- 'uri' => server_url.join('/api/build'),
8
- 'builds' => [
7
+ 'uri' => server_url.join('/api/build/wicket'),
8
+ 'buildsNumbers' => [
9
9
  {
10
- 'uri' => '/wicket',
11
- 'lastStarted' => '2014-01-01 12:00:00',
10
+ 'uri' => "/51",
11
+ 'started' => '2014-09-30T12:00:19.893+0300',
12
+ }
13
+ ]
14
+ )
15
+ end
16
+
17
+ app.get('/api/build/wicket/51') do
18
+ content_type 'application/vnd.org.jfrog.build.BuildInfo+json'
19
+ JSON.fast_generate(
20
+ 'uri' => server_url.join('/api/build/wicket/51'),
21
+ 'buildInfo' => {
22
+ "properties" => {
23
+ "buildInfo.env.JAVA_HOME" => "/usr/jdk/latest",
24
+ },
25
+ "version" => "1.0.1",
26
+ "name" => "wicket",
27
+ "number" => "51",
28
+ "type" => "MAVEN",
29
+ "buildAgent" => {
30
+ "name" => "Maven",
31
+ "version" => "3.0.5"
32
+ },
33
+ "agent" => {
34
+ "name" => "Jenkins",
35
+ "version" => "1.565.2"
12
36
  },
37
+ "started" => '2014-09-30T12:00:19.893+0300',
38
+ "durationMillis" => 8926,
39
+ "artifactoryPrincipal" => "admin",
40
+ "url" => "http://localhost:8080/job/Maven2-3/9/",
41
+ "vcsRevision" => "83049487ecc61bef3dce798838e7a9457e174a5a",
42
+ "vcsUrl" => "https://github.com/aseftel/project-examples",
43
+ "licenseControl" => {
44
+ "runChecks" => false,
45
+ "includePublishedArtifacts" => false,
46
+ "autoDiscover" => true,
47
+ "scopesList" => "",
48
+ "licenseViolationsRecipientsList" => ""
49
+ },
50
+ "buildRetention" => {
51
+ "count" => -1,
52
+ "deleteBuildArtifacts" => true,
53
+ "buildNumbersNotToBeDiscarded" => []
54
+ },
55
+ "modules" => [
56
+ {
57
+ "properties" => {
58
+ "project.build.sourceEncoding" => "UTF-8"
59
+ },
60
+ "id" => "org.jfrog.test:multi:2.19-SNAPSHOT",
61
+ "artifacts" => [
62
+ {
63
+ "type" => "pom",
64
+ "sha1" => "045b66ebbf8504002b626f592d087612aca36582",
65
+ "md5" => "c25542a353dab1089cd186465dc47a68",
66
+ "name" => "multi-2.19-SNAPSHOT.pom"
67
+ }
68
+ ]
69
+ },
70
+ {
71
+ "properties" => {
72
+ "project.build.sourceEncoding" => "UTF-8"
73
+ },
74
+ "id" => "org.jfrog.test:multi1:2.19-SNAPSHOT",
75
+ "artifacts"=> [
76
+ {
77
+ "type" => "jar",
78
+ "sha1" => "f4c5c9cb3091011ec2a895b3dedd7f10d847361c",
79
+ "md5" => "d1fd850a3582efba41092c624e0b46b8",
80
+ "name" => "multi1-2.19-SNAPSHOT.jar"
81
+ },
82
+ {
83
+ "type" => "pom",
84
+ "sha1" => "2ddbf9824676f548d637726d3bcbb494ba823090",
85
+ "md5" => "a64aa7f305f63a85e63a0155ff0fb404",
86
+ "name" => "multi1-2.19-SNAPSHOT.pom"
87
+ },
88
+ {
89
+ "type" => "jar",
90
+ "sha1" => "6fdd143a44cea3a2636660c5c266c95c27e50abc",
91
+ "md5" => "12a1e438f4bef8c4b740fe848a1704a4",
92
+ "id" => "org.slf4j:slf4j-simple:1.4.3",
93
+ "scopes" => [ "compile" ]
94
+ },
95
+ {
96
+ "type" => "jar",
97
+ "sha1" => "496e91f7df8a0417e00cecdba840cdf0e5f2472c",
98
+ "md5" => "76a412a37c9d18659d2dacccdb1c24ff",
99
+ "id" => "org.jenkins-ci.lib:dry-run-lib:0.1",
100
+ "scopes" => [ "compile" ]
101
+ }
102
+ ]
103
+ },
104
+ {
105
+ "properties" => {
106
+ "daversion" => "2.19-SNAPSHOT",
107
+ "project.build.sourceEncoding"=>"UTF-8"
108
+ },
109
+ "id" => "org.jfrog.test:multi2:2.19-SNAPSHOT",
110
+ "artifacts" => [
111
+ {
112
+ "type" => "txt",
113
+ "name" => "multi2-2.19-SNAPSHOT.txt"
114
+ },
115
+ {
116
+ "type" => "java-source-jar",
117
+ "sha1" => "49108b0c7db5fdb4efe3c29a5a9f54e806aecb62",
118
+ "md5" => "0e2c5473cf2a9b694afb4a2e8da34b53",
119
+ "name" => "multi2-2.19-SNAPSHOT-sources.jar"},
120
+ {
121
+ "type" => "jar",
122
+ "sha1" => "476e89d290ae36dabb38ff22f75f264ae019d542",
123
+ "md5" => "fa9b3df58ac040fffcff9310f261be80",
124
+ "name" => "multi2-2.19-SNAPSHOT.jar"
125
+ },
126
+ {
127
+ "type" => "pom",
128
+ "sha1" => "b719b90364e5ae38cda358072f61f821bdae5d5d",
129
+ "md5" => "8d5060005235d75907baca4490cf60bf",
130
+ "name" => "multi2-2.19-SNAPSHOT.pom"
131
+ }
132
+ ],
133
+ "dependencies"=> [
134
+ {
135
+ "type" => "jar",
136
+ "sha1" => "19d4e90b43059058f6e056f794f0ea4030d60b86",
137
+ "md5" => "dcd95bcb84b09897b2b66d4684c040da",
138
+ "id" => "xpp3:xpp3_min:1.1.4c",
139
+ "scopes" => [ "provided" ]
140
+ },
141
+ {
142
+ "type" => "jar",
143
+ "sha1" => "e2d866af5518e81282838301b49a1bd2452619d3",
144
+ "md5" => "e9e4b59c69305ba3698dd61c5dfc4fc8",
145
+ "id" => "org.jvnet.hudson.plugins:perforce:1.3.7",
146
+ "scopes" => [ "compile" ]
147
+ },
148
+ {
149
+ "type" => "jar",
150
+ "sha1" => "6fdd143a44cea3a2636660c5c266c95c27e50abc",
151
+ "md5" => "12a1e438f4bef8c4b740fe848a1704a4",
152
+ "id" => "org.slf4j:slf4j-simple:1.4.3",
153
+ "scopes" => [ "compile" ]
154
+ },
155
+ {
156
+ "type" => "jar",
157
+ "sha1" => "496e91f7df8a0417e00cecdba840cdf0e5f2472c",
158
+ "md5" => "76a412a37c9d18659d2dacccdb1c24ff",
159
+ "id" => "org.jenkins-ci.lib:dry-run-lib:0.1",
160
+ "scopes" => [ "compile" ]
161
+ }
162
+ ]
163
+ },
164
+ {
165
+ "properties" => {
166
+ "project.build.sourceEncoding" => "UTF-8"
167
+ },
168
+ "id" => "org.jfrog.test:multi3:2.19-SNAPSHOT",
169
+ "artifacts" => [
170
+ {
171
+ "type" => "java-source-jar",
172
+ "sha1" => "3cd104785167ac37ef999431f308ffef10810348",
173
+ "md5" => "c683276f8dda97078ae8eb5e26bb3ee5",
174
+ "name" => "multi3-2.19-SNAPSHOT-sources.jar"
175
+ },
176
+ {
177
+ "type" => "war",
178
+ "sha1" => "34aeebeb805b23922d9d05507404533518cf81e4",
179
+ "md5" => "55af06a2175cfb23cc6dc3931475b57c",
180
+ "name" => "multi3-2.19-SNAPSHOT.war"
181
+ },
182
+ {
183
+ "type" => "jar",
184
+ "sha1" => "496e91f7df8a0417e00cecdba840cdf0e5f2472c",
185
+ "md5" => "76a412a37c9d18659d2dacccdb1c24ff",
186
+ "id" => "org.jenkins-ci.lib:dry-run-lib:0.1",
187
+ "scopes" => [ "compile" ]
188
+ },
189
+ {
190
+ "type" => "jar",
191
+ "sha1" => "7e9978fdb754bce5fcd5161133e7734ecb683036",
192
+ "md5" => "7df83e09e41d742cc5fb20d16b80729c",
193
+ "id" => "hsqldb:hsqldb:1.8.0.10",
194
+ "scopes" => [ "runtime" ]
195
+ }
196
+ ]
197
+ }
198
+ ],
199
+ "governance" => {
200
+ "blackDuckProperties" => {
201
+ "runChecks" => false,
202
+ "includePublishedArtifacts" => false,
203
+ "autoCreateMissingComponentRequests" => false,
204
+ "autoDiscardStaleComponentRequests" => false
205
+ }
206
+ }
207
+ }
208
+ )
209
+ end
210
+
211
+ app.put('/api/build') do
212
+ status 204
213
+ body ''
214
+ end
215
+
216
+ app.post('/api/build/promote/wicket/51') do
217
+ content_type 'application/vnd.org.jfrog.artifactory.build.PromotionResult+json'
218
+
219
+ JSON.fast_generate(
220
+ 'uri' => server_url.join('/api/build/wicket'),
221
+ 'buildsNumbers' => [
13
222
  {
14
- 'uri' => '/jackrabbit',
15
- 'lastStarted' => '2014-02-11 10:00:00',
223
+ 'uri' => "/51",
224
+ 'started' => '2014-09-30T12:00:19.893+0300',
16
225
  }
17
226
  ]
18
227
  )
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ module Artifactory
4
+ describe Resource::BuildComponent do
5
+ let(:client) { double(:client) }
6
+
7
+ before(:each) do
8
+ allow(Artifactory).to receive(:client).and_return(client)
9
+ allow(client).to receive(:get).and_return(response) if defined?(response)
10
+ subject.name = 'wicket'
11
+ end
12
+
13
+ describe '.all' do
14
+ let(:response) do
15
+ {
16
+ 'uri' => "#{Artifactory.endpoint}/api/build",
17
+ 'builds' => [
18
+ {
19
+ 'uri' => "/wicket",
20
+ 'lastStarted' => '2015-06-19T20:13:20.222Z',
21
+ },
22
+ {
23
+ 'uri' => "/jackrabbit",
24
+ 'lastStarted' => '2015-06-20T20:13:20.333Z',
25
+ },
26
+ ]
27
+ }
28
+ end
29
+
30
+ before do
31
+ allow(described_class).to receive(:from_hash).with(hash_including('uri' => '/wicket'), client: client).and_return('wicket')
32
+ allow(described_class).to receive(:from_hash).with(hash_including('uri' => '/jackrabbit'), client: client).and_return('jackrabbit')
33
+ end
34
+
35
+ it 'GETS /api/build' do
36
+ expect(client).to receive(:get).with('/api/build').once
37
+ described_class.all
38
+ end
39
+
40
+ context 'when there are components with builds' do
41
+ it 'returns the components' do
42
+ expect(described_class.all).to eq(%w( wicket jackrabbit ))
43
+ end
44
+ end
45
+
46
+ context 'when the system has no components with builds' do
47
+ it 'returns an empty array' do
48
+ allow(client).to receive(:get).and_raise(Error::HTTPError.new('status' => 404))
49
+ expect(described_class.all).to be_empty
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '.find' do
55
+ before do
56
+ allow(described_class).to receive(:all).and_return([
57
+ described_class.new(name: 'wicket'),
58
+ described_class.new(name: 'jackrabbit')
59
+ ])
60
+ end
61
+
62
+ it 'filters the full build component list by name' do
63
+ expect(described_class.find('wicket')).to_not be_nil
64
+ end
65
+
66
+ context 'when the build component does not exist' do
67
+ it 'returns nil' do
68
+ expect(described_class.find('fricket')).to be_nil
69
+ end
70
+ end
71
+ end
72
+
73
+ describe '.from_hash' do
74
+ let(:time) { Time.now.utc.round }
75
+ let(:hash) do
76
+ {
77
+ 'uri' => '/wicket',
78
+ 'lastStarted' => time.iso8601(3),
79
+ }
80
+ end
81
+
82
+ it 'creates a new instance' do
83
+ instance = described_class.from_hash(hash)
84
+ expect(instance.uri).to eq('/wicket')
85
+ expect(instance.name).to eq('wicket')
86
+ expect(instance.last_started).to eq(time)
87
+ end
88
+ end
89
+
90
+ describe '#builds' do
91
+
92
+ it 'returns a build collection' do
93
+ expect(subject.builds).to be_a(Collection::Build)
94
+ end
95
+ end
96
+
97
+ describe '#delete' do
98
+
99
+ it 'sends DELETE to the client' do
100
+ expect(client).to receive(:delete)
101
+ subject.delete
102
+ end
103
+
104
+ it 'adds the correct parameters to the request' do
105
+ expect(client).to receive(:delete).with('/api/build/wicket?buildNumbers=51,52,55&artifacts=1&deleteAll=1', {})
106
+ subject.delete(build_numbers: %w( 51 52 55 ), artifacts: true, delete_all: true)
107
+ end
108
+ end
109
+
110
+ describe '#rename' do
111
+
112
+ it 'sends POST to the client with the correct param' do
113
+ expect(client).to receive(:post).with('/api/build/rename/wicket?to=fricket', {})
114
+ subject.rename('fricket')
115
+ end
116
+ end
117
+ end
118
+ end