berkshelf 3.0.0.beta1 → 3.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -1
- data/CONTRIBUTING.md +2 -0
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/Thorfile +2 -2
- data/berkshelf.gemspec +3 -3
- data/features/install_command.feature +36 -8
- data/features/json_formatter.feature +93 -3
- data/features/licenses.feature +1 -1
- data/features/lockfile.feature +0 -12
- data/features/outdated_command.feature +124 -0
- data/features/show_command.feature +44 -25
- data/features/step_definitions/chef/config_steps.rb +2 -2
- data/features/step_definitions/chef_server_steps.rb +9 -1
- data/features/step_definitions/config_steps.rb +1 -1
- data/features/step_definitions/filesystem_steps.rb +7 -0
- data/features/support/env.rb +2 -1
- data/features/update_command.feature +11 -21
- data/features/upload_command.feature +45 -1
- data/features/vendor_command.feature +83 -0
- data/lib/berkshelf.rb +5 -4
- data/lib/berkshelf/api_client/remote_cookbook.rb +13 -0
- data/lib/berkshelf/berksfile.rb +155 -23
- data/lib/berkshelf/chef.rb +0 -1
- data/lib/berkshelf/cli.rb +40 -31
- data/lib/berkshelf/dependency.rb +14 -4
- data/lib/berkshelf/errors.rb +74 -3
- data/lib/berkshelf/formatters.rb +12 -1
- data/lib/berkshelf/formatters/human_readable.rb +44 -5
- data/lib/berkshelf/formatters/json.rb +50 -8
- data/lib/berkshelf/installer.rb +8 -8
- data/lib/berkshelf/location.rb +17 -0
- data/lib/berkshelf/locations/git_location.rb +7 -17
- data/lib/berkshelf/locations/mercurial_location.rb +112 -0
- data/lib/berkshelf/lockfile.rb +1 -1
- data/lib/berkshelf/mercurial.rb +146 -0
- data/lib/berkshelf/version.rb +1 -1
- data/spec/config/knife.rb +2 -4
- data/spec/fixtures/lockfiles/default.lock +0 -1
- data/spec/support/chef_api.rb +9 -2
- data/spec/support/mercurial.rb +122 -0
- data/spec/support/path_helpers.rb +2 -2
- data/spec/unit/berkshelf/berksfile_spec.rb +34 -8
- data/spec/unit/berkshelf/dependency_spec.rb +0 -7
- data/spec/unit/berkshelf/formatters/null_spec.rb +1 -1
- data/spec/unit/berkshelf/locations/mercurial_location_spec.rb +150 -0
- data/spec/unit/berkshelf/lockfile_spec.rb +0 -12
- data/spec/unit/berkshelf/mercurial_spec.rb +173 -0
- metadata +32 -110
- data/lib/berkshelf/chef/config.rb +0 -68
- data/lib/berkshelf/mixin/config.rb +0 -172
- data/spec/fixtures/cookbooks/example_metadata_name/metadata.rb +0 -2
- data/spec/fixtures/cookbooks/example_metadata_no_name/metadata.rb +0 -1
- data/spec/fixtures/cookbooks/example_no_metadata/recipes/default.rb +0 -1
- data/spec/fixtures/cookbooks/nginx-0.100.5/README.md +0 -77
- data/spec/fixtures/cookbooks/nginx-0.100.5/attributes/default.rb +0 -65
- data/spec/fixtures/cookbooks/nginx-0.100.5/definitions/nginx_site.rb +0 -35
- data/spec/fixtures/cookbooks/nginx-0.100.5/files/default/mime.types +0 -73
- data/spec/fixtures/cookbooks/nginx-0.100.5/files/ubuntu/mime.types +0 -73
- data/spec/fixtures/cookbooks/nginx-0.100.5/libraries/nginxlib.rb +0 -1
- data/spec/fixtures/cookbooks/nginx-0.100.5/metadata.rb +0 -91
- data/spec/fixtures/cookbooks/nginx-0.100.5/providers/defprovider.rb +0 -1
- data/spec/fixtures/cookbooks/nginx-0.100.5/recipes/default.rb +0 -59
- data/spec/fixtures/cookbooks/nginx-0.100.5/resources/defresource.rb +0 -1
- data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/nginx.pill.erb +0 -15
- data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/plugins/nginx.rb.erb +0 -66
- data/spec/fixtures/lockfile_spec/with_lock/Berksfile +0 -1
- data/spec/fixtures/lockfile_spec/without_lock/.gitkeep +0 -0
- data/spec/fixtures/reset.pem +0 -27
- data/spec/unit/chef/config_spec.rb +0 -81
@@ -12,6 +12,16 @@ Feature: Displaying information about a cookbook defined by a Berksfile
|
|
12
12
|
|
13
13
|
cookbook 'fake', '1.0.0'
|
14
14
|
"""
|
15
|
+
And I write to "Berksfile.lock" with:
|
16
|
+
"""
|
17
|
+
{
|
18
|
+
"dependencies": {
|
19
|
+
"fake": {
|
20
|
+
"locked_version": "1.0.0"
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
"""
|
15
25
|
When I successfully run `berks show fake`
|
16
26
|
Then the output should contain:
|
17
27
|
"""
|
@@ -23,43 +33,52 @@ Feature: Displaying information about a cookbook defined by a Berksfile
|
|
23
33
|
License: none
|
24
34
|
"""
|
25
35
|
|
26
|
-
Scenario: When
|
27
|
-
Given
|
28
|
-
|
36
|
+
Scenario: When the cookbook is not in the Berksfile
|
37
|
+
Given I write to "Berksfile" with:
|
38
|
+
"""
|
39
|
+
source "http://localhost:26210"
|
40
|
+
"""
|
41
|
+
When I run `berks show fake`
|
42
|
+
Then the output should contain:
|
43
|
+
"""
|
44
|
+
Could not find cookbook(s) 'fake' in any of the configured dependencies. Is it in your Berksfile?
|
45
|
+
"""
|
46
|
+
And the exit status should be "DependencyNotFound"
|
47
|
+
|
48
|
+
Scenario: When there is no lockfile present
|
29
49
|
And I write to "Berksfile" with:
|
30
50
|
"""
|
31
51
|
source "http://localhost:26210"
|
32
52
|
|
33
53
|
cookbook 'fake', '1.0.0'
|
34
54
|
"""
|
35
|
-
When I
|
55
|
+
When I run `berks show fake`
|
36
56
|
Then the output should contain:
|
37
57
|
"""
|
38
|
-
|
39
|
-
"cookbooks": [
|
40
|
-
{
|
41
|
-
"name": "fake",
|
42
|
-
"version": "1.0.0",
|
43
|
-
"description": "A fabulous new cookbook",
|
44
|
-
"author": "YOUR_COMPANY_NAME",
|
45
|
-
"email": "YOUR_EMAIL",
|
46
|
-
"license": "none"
|
47
|
-
}
|
48
|
-
],
|
49
|
-
"errors": [
|
50
|
-
|
51
|
-
],
|
52
|
-
"messages": [
|
53
|
-
"building universe..."
|
54
|
-
]
|
55
|
-
}
|
58
|
+
Could not find cookbook 'fake (>= 0.0.0)'. Try running `berks install` to download and install the missing dependencies.
|
56
59
|
"""
|
60
|
+
And the exit status should be "LockfileNotFound"
|
57
61
|
|
58
|
-
Scenario: When the cookbook is not
|
59
|
-
|
62
|
+
Scenario: When the cookbook is not installed
|
63
|
+
And I write to "Berksfile" with:
|
60
64
|
"""
|
61
65
|
source "http://localhost:26210"
|
66
|
+
|
67
|
+
cookbook 'fake', '1.0.0'
|
68
|
+
"""
|
69
|
+
And I write to "Berksfile.lock" with:
|
70
|
+
"""
|
71
|
+
{
|
72
|
+
"dependencies": {
|
73
|
+
"fake": {
|
74
|
+
"locked_version": "1.0.0"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
62
78
|
"""
|
63
79
|
When I run `berks show fake`
|
64
|
-
Then the output should contain
|
80
|
+
Then the output should contain:
|
81
|
+
"""
|
82
|
+
Could not find cookbook 'fake (= 1.0.0)'. Try running `berks install` to download and install the missing dependencies.
|
83
|
+
"""
|
65
84
|
And the exit status should be "CookbookNotFound"
|
@@ -4,8 +4,8 @@ end
|
|
4
4
|
|
5
5
|
Given /^I do not have a Chef config$/ do
|
6
6
|
path = tmp_path.join('knife.rb').to_s
|
7
|
-
Berkshelf.chef_config =
|
8
|
-
Berkshelf
|
7
|
+
Berkshelf.chef_config = Ridley::Chef::Config.new(path)
|
8
|
+
Berkshelf.chef_config.save
|
9
9
|
|
10
10
|
ENV['BERKSHELF_CHEF_CONFIG'] = path
|
11
11
|
set_env 'BERKSHELF_CHEF_CONFIG', path
|
@@ -8,10 +8,18 @@ Given /^the Chef Server has cookbooks:$/ do |cookbooks|
|
|
8
8
|
cookbooks.raw.each do |name, version|
|
9
9
|
purge_cookbook(name, version)
|
10
10
|
cb_path = generate_cookbook(tmp_path, name, version)
|
11
|
-
upload_cookbook(cb_path)
|
11
|
+
upload_cookbook(cb_path, freeze: false, force: true)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
Given /^the Chef Server has frozen cookbooks:$/ do |cookbooks|
|
16
|
+
cookbooks.raw.each do |name, version|
|
17
|
+
purge_cookbook(name, version)
|
18
|
+
cb_path = generate_cookbook(tmp_path, name, version)
|
19
|
+
upload_cookbook(cb_path, freeze: true, force: true)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
15
23
|
Then /^the Chef Server should have the cookbooks:$/ do |cookbooks|
|
16
24
|
cookbooks.raw.each do |name, version|
|
17
25
|
expect(server_has_cookbook?(name, version)).to be_true
|
@@ -34,7 +34,7 @@ end
|
|
34
34
|
Then /^a Berkshelf config file should exist at "(.+)" and contain:$/ do |path, table|
|
35
35
|
check_file_presence([path], true)
|
36
36
|
|
37
|
-
path
|
37
|
+
path = File.join(@dirs.first, path)
|
38
38
|
Berkshelf.config = Berkshelf::Config.from_file(path)
|
39
39
|
|
40
40
|
table.raw.each do |key, value|
|
@@ -250,3 +250,10 @@ Then /^the file "(.*?)" in the directory "(.*?)" should not contain:$/ do |file_
|
|
250
250
|
end
|
251
251
|
}
|
252
252
|
end
|
253
|
+
|
254
|
+
Then(/^the directory "(.*?)" should contain version "(.*?)" of the "(.*?)" cookbook$/) do |path, version, name|
|
255
|
+
cookbook_path = File.join(current_dir, path)
|
256
|
+
cookbook = Berkshelf::CachedCookbook.from_path(cookbook_path)
|
257
|
+
expect(cookbook.version).to eql(version)
|
258
|
+
expect(cookbook.cookbook_name).to eql(name)
|
259
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -29,6 +29,7 @@ Spork.prefork do
|
|
29
29
|
|
30
30
|
Aruba::InProcess.main_class = Berkshelf::Cli::Runner
|
31
31
|
Aruba.process = Aruba::InProcess
|
32
|
+
@dirs = ["spec/tmp/aruba"] # set aruba's temporary directory
|
32
33
|
|
33
34
|
stub_kitchen!
|
34
35
|
clean_tmp_path
|
@@ -42,7 +43,7 @@ Spork.prefork do
|
|
42
43
|
options: {
|
43
44
|
url: "http://localhost:#{CHEF_SERVER_PORT}",
|
44
45
|
client_name: "reset",
|
45
|
-
client_key:
|
46
|
+
client_key: File.expand_path("spec/config/berkshelf.pem")
|
46
47
|
}
|
47
48
|
}
|
48
49
|
]
|
@@ -23,8 +23,7 @@ Feature: Updating a cookbook defined by a Berksfile
|
|
23
23
|
{
|
24
24
|
"dependencies":{
|
25
25
|
"berkshelf-cookbook-fixture":{
|
26
|
-
"locked_version":"0.1.0"
|
27
|
-
"constraint":"~> 0.1"
|
26
|
+
"locked_version":"0.1.0"
|
28
27
|
}
|
29
28
|
}
|
30
29
|
}
|
@@ -47,12 +46,10 @@ Feature: Updating a cookbook defined by a Berksfile
|
|
47
46
|
{
|
48
47
|
"dependencies":{
|
49
48
|
"berkshelf-cookbook-fixture":{
|
50
|
-
"locked_version":"0.1.0"
|
51
|
-
"constraint":"~> 0.1"
|
49
|
+
"locked_version":"0.1.0"
|
52
50
|
},
|
53
51
|
"hostsfile":{
|
54
|
-
"locked_version":"1.0.1"
|
55
|
-
"constraint":"= 1.0.1"
|
52
|
+
"locked_version":"1.0.1"
|
56
53
|
}
|
57
54
|
}
|
58
55
|
}
|
@@ -63,12 +60,10 @@ Feature: Updating a cookbook defined by a Berksfile
|
|
63
60
|
{
|
64
61
|
"dependencies":{
|
65
62
|
"berkshelf-cookbook-fixture":{
|
66
|
-
"locked_version":"0.2.0"
|
67
|
-
"constraint":"~> 0.1"
|
63
|
+
"locked_version":"0.2.0"
|
68
64
|
},
|
69
65
|
"hostsfile":{
|
70
|
-
"locked_version":"1.0.1"
|
71
|
-
"constraint":"~> 1.0.0"
|
66
|
+
"locked_version":"1.0.1"
|
72
67
|
}
|
73
68
|
}
|
74
69
|
}
|
@@ -91,12 +86,10 @@ Feature: Updating a cookbook defined by a Berksfile
|
|
91
86
|
{
|
92
87
|
"dependencies":{
|
93
88
|
"berkshelf-cookbook-fixture":{
|
94
|
-
"locked_version":"0.1.0"
|
95
|
-
"constraint":"~> 0.1"
|
89
|
+
"locked_version":"0.1.0"
|
96
90
|
},
|
97
91
|
"hostsfile":{
|
98
|
-
"locked_version":"1.0.
|
99
|
-
"constraint":"~> 1.0.0"
|
92
|
+
"locked_version":"1.0.1"
|
100
93
|
}
|
101
94
|
}
|
102
95
|
}
|
@@ -107,12 +100,10 @@ Feature: Updating a cookbook defined by a Berksfile
|
|
107
100
|
{
|
108
101
|
"dependencies":{
|
109
102
|
"berkshelf-cookbook-fixture":{
|
110
|
-
"locked_version":"0.2.0"
|
111
|
-
"constraint":"~> 0.1"
|
103
|
+
"locked_version":"0.2.0"
|
112
104
|
},
|
113
105
|
"hostsfile":{
|
114
|
-
"locked_version":"1.0.
|
115
|
-
"constraint":"~> 1.0.0"
|
106
|
+
"locked_version":"1.0.1"
|
116
107
|
}
|
117
108
|
}
|
118
109
|
}
|
@@ -132,8 +123,7 @@ Feature: Updating a cookbook defined by a Berksfile
|
|
132
123
|
{
|
133
124
|
"dependencies":{
|
134
125
|
"berkshelf-cookbook-fixture":{
|
135
|
-
"locked_version":"0.1.0"
|
136
|
-
"constraint":"~> 0.1"
|
126
|
+
"locked_version":"0.1.0"
|
137
127
|
}
|
138
128
|
}
|
139
129
|
}
|
@@ -143,4 +133,4 @@ Feature: Updating a cookbook defined by a Berksfile
|
|
143
133
|
"""
|
144
134
|
Could not find cookbook(s) 'non-existent-cookbook' in any of the configured dependencies. Is it in your Berksfile?
|
145
135
|
"""
|
146
|
-
And the exit status should be "
|
136
|
+
And the exit status should be "DependencyNotFound"
|
@@ -100,7 +100,7 @@ Feature: Uploading cookbooks to a Chef Server
|
|
100
100
|
When I run `berks upload reset`
|
101
101
|
Then the output should contain:
|
102
102
|
"""
|
103
|
-
|
103
|
+
Could not find cookbook(s) 'reset' in any of the configured dependencies. Is it in your Berksfile?
|
104
104
|
"""
|
105
105
|
And the exit status should be "DependencyNotFound"
|
106
106
|
|
@@ -281,3 +281,47 @@ Feature: Uploading cookbooks to a Chef Server
|
|
281
281
|
"""
|
282
282
|
Uploading fake (0.0.0)
|
283
283
|
"""
|
284
|
+
|
285
|
+
Scenario: When the cookbook already exist
|
286
|
+
Given the cookbook store has the cookbooks:
|
287
|
+
| fake | 1.0.0 |
|
288
|
+
And the Chef Server has frozen cookbooks:
|
289
|
+
| fake | 1.0.0 |
|
290
|
+
And I write to "Berksfile" with:
|
291
|
+
"""
|
292
|
+
cookbook 'fake', '1.0.0'
|
293
|
+
"""
|
294
|
+
When I successfully run `berks upload`
|
295
|
+
Then the output should contain:
|
296
|
+
"""
|
297
|
+
Skipping fake (1.0.0) (already uploaded)
|
298
|
+
"""
|
299
|
+
And the output should contain:
|
300
|
+
"""
|
301
|
+
Skipped uploading some cookbooks because they already existed on the remote server. Re-run with the `--force` flag to force overwrite these cookbooks:
|
302
|
+
|
303
|
+
* fake (1.0.0)
|
304
|
+
"""
|
305
|
+
And the exit status should be 0
|
306
|
+
|
307
|
+
Scenario: When the cookbook already exist and is a metadata location
|
308
|
+
Given a cookbook named "fake"
|
309
|
+
And the cookbook "fake" has the file "Berksfile" with:
|
310
|
+
"""
|
311
|
+
metadata
|
312
|
+
"""
|
313
|
+
When I cd to "fake"
|
314
|
+
And the Chef Server has frozen cookbooks:
|
315
|
+
| fake | 0.0.0 |
|
316
|
+
When I run `berks upload`
|
317
|
+
Then the output should contain:
|
318
|
+
"""
|
319
|
+
building universe...
|
320
|
+
Using fake (0.0.0) path: '/home/travis/build/RiotGames/berkshelf/spec/tmp/aruba/fake'
|
321
|
+
Uploading fake (0.0.0) to: 'http://localhost:26310/'
|
322
|
+
Skipping fake (0.0.0) (already uploaded)
|
323
|
+
Skipped uploading some cookbooks because they already existed on the remote server. Re-run with the `--force` flag to force overwrite these cookbooks:
|
324
|
+
|
325
|
+
* fake (0.0.0)
|
326
|
+
"""
|
327
|
+
And the exit status should be 0
|
@@ -0,0 +1,83 @@
|
|
1
|
+
Feature: Vendoring cookbooks to a directory
|
2
|
+
As a CLI user
|
3
|
+
I want a command to vendor cookbooks into a directory
|
4
|
+
So they are structured similar to a Chef Repository
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given the Berkshelf API server's cache is empty
|
8
|
+
And the Chef Server is empty
|
9
|
+
|
10
|
+
Scenario: successfully vendoring a Berksfile with multiple cookbook demands
|
11
|
+
Given I write to "Berksfile" with:
|
12
|
+
"""
|
13
|
+
source "http://localhost:26210"
|
14
|
+
|
15
|
+
cookbook 'berkshelf'
|
16
|
+
cookbook 'elixir'
|
17
|
+
"""
|
18
|
+
And the Chef Server has cookbooks:
|
19
|
+
| berkshelf | 1.0.0 |
|
20
|
+
| elixir | 1.0.0 |
|
21
|
+
And the Berkshelf API server's cache is up to date
|
22
|
+
When I successfully run `berks vendor cukebooks`
|
23
|
+
Then the output should contain:
|
24
|
+
"""
|
25
|
+
Vendoring berkshelf (1.0.0) to
|
26
|
+
"""
|
27
|
+
And the output should contain:
|
28
|
+
"""
|
29
|
+
Vendoring elixir (1.0.0) to
|
30
|
+
"""
|
31
|
+
And a directory named "cukebooks/berkshelf" should exist
|
32
|
+
And a directory named "cukebooks/elixir" should exist
|
33
|
+
And the directory "cukebooks/berkshelf" should contain version "1.0.0" of the "berkshelf" cookbook
|
34
|
+
And the directory "cukebooks/elixir" should contain version "1.0.0" of the "elixir" cookbook
|
35
|
+
|
36
|
+
Scenario: attempting to vendor when no Berksfile is present
|
37
|
+
When I run `berks vendor cukebooks`
|
38
|
+
Then the exit status should be "BerksfileNotFound"
|
39
|
+
|
40
|
+
Scenario: vendoring a Berksfile with a metadata demand
|
41
|
+
Given a cookbook named "sparkle-motion"
|
42
|
+
And the cookbook "sparkle-motion" has the file "Berksfile" with:
|
43
|
+
"""
|
44
|
+
source "http://localhost:26210"
|
45
|
+
|
46
|
+
metadata
|
47
|
+
"""
|
48
|
+
When I cd to "sparkle-motion"
|
49
|
+
And I successfully run `berks vendor cukebooks`
|
50
|
+
Then the output should contain:
|
51
|
+
"""
|
52
|
+
Vendoring sparkle-motion (0.0.0) to
|
53
|
+
"""
|
54
|
+
And a directory named "cukebooks/sparkle-motion" should exist
|
55
|
+
And the directory "cukebooks/sparkle-motion" should contain version "0.0.0" of the "sparkle-motion" cookbook
|
56
|
+
|
57
|
+
Scenario: vendoring without an explicit path to vendor into
|
58
|
+
Given I write to "Berksfile" with:
|
59
|
+
"""
|
60
|
+
source "http://localhost:26210"
|
61
|
+
|
62
|
+
cookbook 'berkshelf'
|
63
|
+
"""
|
64
|
+
And the Chef Server has cookbooks:
|
65
|
+
| berkshelf | 1.0.0 |
|
66
|
+
And the Berkshelf API server's cache is up to date
|
67
|
+
When I successfully run `berks vendor`
|
68
|
+
And a directory named "berks-cookbooks/berkshelf" should exist
|
69
|
+
And the directory "berks-cookbooks/berkshelf" should contain version "1.0.0" of the "berkshelf" cookbook
|
70
|
+
|
71
|
+
Scenario: vendoring to a directory that already exists
|
72
|
+
Given I write to "Berksfile" with:
|
73
|
+
"""
|
74
|
+
source "http://localhost:26210"
|
75
|
+
|
76
|
+
cookbook 'berkshelf'
|
77
|
+
"""
|
78
|
+
And the Chef Server has cookbooks:
|
79
|
+
| berkshelf | 1.0.0 |
|
80
|
+
And the Berkshelf API server's cache is up to date
|
81
|
+
And a directory named "cukebooks"
|
82
|
+
When I run `berks vendor cukebooks`
|
83
|
+
And the exit status should be "VendorError"
|
data/lib/berkshelf.rb
CHANGED
@@ -67,14 +67,14 @@ module Berkshelf
|
|
67
67
|
|
68
68
|
# The Chef configuration file.
|
69
69
|
#
|
70
|
-
# @return [
|
70
|
+
# @return [Ridley::Chef::Config]
|
71
71
|
def chef_config
|
72
|
-
|
72
|
+
@chef_config ||= Ridley::Chef::Config.new(ENV['BERKSHELF_CHEF_CONFIG'])
|
73
73
|
end
|
74
74
|
|
75
|
-
# @param [
|
75
|
+
# @param [Ridley::Chef::Config]
|
76
76
|
def chef_config=(config)
|
77
|
-
|
77
|
+
@chef_config = config
|
78
78
|
end
|
79
79
|
|
80
80
|
# Initialize the filepath for the Berkshelf path..
|
@@ -153,6 +153,7 @@ require_relative 'berkshelf/dependency'
|
|
153
153
|
require_relative 'berkshelf/downloader'
|
154
154
|
require_relative 'berkshelf/formatters'
|
155
155
|
require_relative 'berkshelf/git'
|
156
|
+
require_relative 'berkshelf/mercurial'
|
156
157
|
require_relative 'berkshelf/init_generator'
|
157
158
|
require_relative 'berkshelf/installer'
|
158
159
|
require_relative 'berkshelf/location'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module Berkshelf
|
2
4
|
class APIClient
|
3
5
|
# A representation of cookbook metadata indexed by a Berkshelf API Server. Returned
|
@@ -37,6 +39,17 @@ module Berkshelf
|
|
37
39
|
def location_path
|
38
40
|
@attributes[:location_path]
|
39
41
|
end
|
42
|
+
|
43
|
+
def to_hash
|
44
|
+
{
|
45
|
+
name: name,
|
46
|
+
version: version
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_json(options = {})
|
51
|
+
::JSON.pretty_generate(to_hash, options)
|
52
|
+
end
|
40
53
|
end
|
41
54
|
end
|
42
55
|
end
|
data/lib/berkshelf/berksfile.rb
CHANGED
@@ -13,11 +13,13 @@ module Berkshelf
|
|
13
13
|
#
|
14
14
|
# @return [Berksfile]
|
15
15
|
def from_file(file)
|
16
|
-
new(file).
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
raise BerksfileNotFound.new(file) unless File.exist?(file)
|
17
|
+
|
18
|
+
begin
|
19
|
+
new(file).dsl_eval_file(file)
|
20
|
+
rescue => ex
|
21
|
+
raise BerksfileReadError.new(ex)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -365,6 +367,40 @@ module Berkshelf
|
|
365
367
|
self.install
|
366
368
|
end
|
367
369
|
|
370
|
+
# Retrieve information about a given cookbook that is installed by this Berksfile.
|
371
|
+
# Unlike {#find}, which returns a dependency, this method returns the corresponding
|
372
|
+
# CachedCookbook for the given name.
|
373
|
+
#
|
374
|
+
# @raise [LockfileNotFound]
|
375
|
+
# if there is no lockfile containing that cookbook
|
376
|
+
# @raise [CookbookNotFound]
|
377
|
+
# if there is a lockfile with a cookbook, but the cookbook is not downloaded
|
378
|
+
#
|
379
|
+
# @param [String] name
|
380
|
+
# the name of the cookbook to find
|
381
|
+
#
|
382
|
+
# @return [CachedCookbook]
|
383
|
+
# the CachedCookbook that corresponds to the given name parameter
|
384
|
+
def retrieve_locked(name)
|
385
|
+
validate_cookbook_names!(cookbooks: name)
|
386
|
+
|
387
|
+
locked = lockfile.find(name)
|
388
|
+
unless locked
|
389
|
+
raise LockfileNotFound, "Could not find cookbook '#{name} (>= 0.0.0)'."\
|
390
|
+
" Try running `berks install` to download and install the missing"\
|
391
|
+
" dependencies."
|
392
|
+
end
|
393
|
+
|
394
|
+
cookbook = locked.cached_cookbook
|
395
|
+
unless cookbook
|
396
|
+
raise CookbookNotFound, "Could not find cookbook '#{name} (= #{locked.locked_version})'."\
|
397
|
+
" Try running `berks install` to download and install the missing"\
|
398
|
+
" dependencies."
|
399
|
+
end
|
400
|
+
|
401
|
+
cookbook
|
402
|
+
end
|
403
|
+
|
368
404
|
# List of all the cookbooks which have a newer version found at a source that satisfies
|
369
405
|
# the constraints of your dependencies
|
370
406
|
#
|
@@ -386,7 +422,28 @@ module Berkshelf
|
|
386
422
|
# #<CachedCookbook name="artifact"> => "0.11.2"
|
387
423
|
# }
|
388
424
|
def outdated(options = {})
|
389
|
-
|
425
|
+
validate_cookbook_names!(options)
|
426
|
+
|
427
|
+
outdated = {}
|
428
|
+
dependencies(options).each do |dependency|
|
429
|
+
locked = retrieve_locked(dependency.name)
|
430
|
+
outdated[dependency.name] = {}
|
431
|
+
|
432
|
+
sources.each do |source|
|
433
|
+
cookbooks = source.versions(dependency.name)
|
434
|
+
|
435
|
+
latest = cookbooks.select do |cookbook|
|
436
|
+
dependency.version_constraint.satisfies?(cookbook.version) &&
|
437
|
+
cookbook.version != locked.version
|
438
|
+
end.sort_by { |cookbook| cookbook.version }.last
|
439
|
+
|
440
|
+
unless latest.nil?
|
441
|
+
outdated[dependency.name][source.uri.to_s] = latest
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
outdated.reject { |name, newer| newer.empty? }
|
390
447
|
end
|
391
448
|
|
392
449
|
# Upload the cookbooks installed by this Berksfile
|
@@ -417,16 +474,19 @@ module Berkshelf
|
|
417
474
|
# @raise [Berkshelf::DependencyNotFound]
|
418
475
|
# if one of the given cookbooks is not a dependency defined in the Berksfile
|
419
476
|
# @raise [Berkshelf::FrozenCookbook]
|
420
|
-
# if
|
421
|
-
#
|
477
|
+
# if the cookbook being uploaded is a {metadata} cookbook and is already
|
478
|
+
# frozen on the remote Chef Server; indirect dependencies or non-metadata
|
479
|
+
# dependencies are just skipped
|
422
480
|
def upload(options = {})
|
423
|
-
options =
|
481
|
+
options = {
|
482
|
+
force: false,
|
483
|
+
freeze: true,
|
484
|
+
halt_on_frozen: false,
|
485
|
+
skip_dependencies: false,
|
486
|
+
cookbooks: [],
|
487
|
+
}.merge(options)
|
424
488
|
|
425
|
-
options
|
426
|
-
unless dependency = find(cookbook)
|
427
|
-
raise DependencyNotFound, "Failed to upload cookbook '#{cookbook}'. Not defined in Berksfile."
|
428
|
-
end
|
429
|
-
end
|
489
|
+
validate_cookbook_names!(options)
|
430
490
|
|
431
491
|
cached_cookbooks = install(options)
|
432
492
|
cached_cookbooks = filter_to_upload(cached_cookbooks, options[:cookbooks]) if options[:cookbooks]
|
@@ -495,9 +555,12 @@ module Berkshelf
|
|
495
555
|
cached_cookbooks.each { |cookbook| validate_files!(cookbook) }
|
496
556
|
|
497
557
|
Dir.mktmpdir do |tmp|
|
558
|
+
cookbooks_dir = File.join(tmp, 'cookbooks')
|
559
|
+
FileUtils.mkdir_p(cookbooks_dir)
|
560
|
+
|
498
561
|
cached_cookbooks.each do |cookbook|
|
499
562
|
path = cookbook.path.to_s
|
500
|
-
destination = File.join(
|
563
|
+
destination = File.join(cookbooks_dir, cookbook.cookbook_name)
|
501
564
|
|
502
565
|
FileUtils.cp_r(path, destination)
|
503
566
|
|
@@ -522,6 +585,61 @@ module Berkshelf
|
|
522
585
|
output
|
523
586
|
end
|
524
587
|
|
588
|
+
# Install the Berksfile or Berksfile.lock and then copy the cached cookbooks into
|
589
|
+
# directories within the given destination matching their name.
|
590
|
+
#
|
591
|
+
# @param [String] destination
|
592
|
+
# filepath to vendor cookbooks to
|
593
|
+
#
|
594
|
+
# @option options [Symbol, Array] :except
|
595
|
+
# Group(s) to exclude which will cause any dependencies marked as a member of the
|
596
|
+
# group to not be installed
|
597
|
+
# @option options [Symbol, Array] :only
|
598
|
+
# Group(s) to include which will cause any dependencies marked as a member of the
|
599
|
+
# group to be installed and all others to be ignored
|
600
|
+
#
|
601
|
+
# @return [String, nil]
|
602
|
+
# the expanded path cookbooks were vendored to or nil if nothing was vendored
|
603
|
+
def vendor(destination, options = {})
|
604
|
+
destination = File.expand_path(destination)
|
605
|
+
|
606
|
+
if Dir.exist?(destination)
|
607
|
+
raise VendorError, "destination already exists #{destination}. Delete it and try again or use a " +
|
608
|
+
"different filepath."
|
609
|
+
end
|
610
|
+
|
611
|
+
scratch = Berkshelf.mktmpdir
|
612
|
+
chefignore = nil
|
613
|
+
cached_cookbooks = install(options.slice(:except, :only))
|
614
|
+
|
615
|
+
if cached_cookbooks.empty?
|
616
|
+
return nil
|
617
|
+
end
|
618
|
+
|
619
|
+
if ignore_file = Berkshelf::Chef::Cookbook::Chefignore.find_relative_to(Dir.pwd)
|
620
|
+
chefignore = Berkshelf::Chef::Cookbook::Chefignore.new(ignore_file)
|
621
|
+
end
|
622
|
+
|
623
|
+
cached_cookbooks.each do |cookbook|
|
624
|
+
Berkshelf.formatter.vendor(cookbook, destination)
|
625
|
+
cookbook_destination = File.join(scratch, cookbook.cookbook_name, '/')
|
626
|
+
FileUtils.mkdir_p(cookbook_destination)
|
627
|
+
|
628
|
+
# Dir.glob does not support backslash as a File separator
|
629
|
+
src = cookbook.path.to_s.gsub('\\', '/')
|
630
|
+
files = Dir.glob(File.join(src, '*'))
|
631
|
+
|
632
|
+
if chefignore
|
633
|
+
files = chefignore.remove_ignores_from(files)
|
634
|
+
end
|
635
|
+
|
636
|
+
FileUtils.cp_r(files, cookbook_destination)
|
637
|
+
end
|
638
|
+
|
639
|
+
FileUtils.mv(scratch, destination)
|
640
|
+
destination
|
641
|
+
end
|
642
|
+
|
525
643
|
# Get the lockfile corresponding to this Berksfile. This is necessary because
|
526
644
|
# the user can specify a different path to the Berksfile. So assuming the lockfile
|
527
645
|
# is named "Berksfile.lock" is a poor assumption.
|
@@ -536,22 +654,37 @@ module Berkshelf
|
|
536
654
|
private
|
537
655
|
|
538
656
|
def do_upload(cookbooks, options = {})
|
539
|
-
|
657
|
+
@skipped = []
|
540
658
|
|
541
659
|
ridley_connection(options) do |conn|
|
542
660
|
cookbooks.each do |cookbook|
|
543
|
-
Berkshelf.formatter.upload(cookbook
|
661
|
+
Berkshelf.formatter.upload(cookbook, conn)
|
544
662
|
validate_files!(cookbook)
|
545
663
|
|
546
664
|
begin
|
547
|
-
conn.cookbook.upload(cookbook.path,
|
665
|
+
conn.cookbook.upload(cookbook.path, {
|
666
|
+
force: options[:force],
|
667
|
+
freeze: options[:freeze],
|
668
|
+
name: cookbook.cookbook_name,
|
669
|
+
})
|
548
670
|
rescue Ridley::Errors::FrozenCookbook => ex
|
549
671
|
if options[:halt_on_frozen]
|
550
|
-
raise Berkshelf::FrozenCookbook
|
672
|
+
raise Berkshelf::FrozenCookbook.new(cookbook)
|
551
673
|
end
|
674
|
+
|
675
|
+
Berkshelf.formatter.skip(cookbook, conn)
|
676
|
+
@skipped << cookbook
|
552
677
|
end
|
553
678
|
end
|
554
679
|
end
|
680
|
+
|
681
|
+
unless @skipped.empty?
|
682
|
+
Berkshelf.formatter.msg "Skipped uploading some cookbooks because they" <<
|
683
|
+
" already existed on the remote server. Re-run with the `--force`" <<
|
684
|
+
" flag to force overwrite these cookbooks:" <<
|
685
|
+
"\n\n" <<
|
686
|
+
" * " << @skipped.map { |c| "#{c.cookbook_name} (#{c.version})" }.join("\n * ")
|
687
|
+
end
|
555
688
|
end
|
556
689
|
|
557
690
|
# Filter the cookbooks to upload based on a set of given names. The dependencies of a cookbook
|
@@ -608,14 +741,13 @@ module Berkshelf
|
|
608
741
|
# @option options [Array<String>] :cookbooks
|
609
742
|
# a list of strings of cookbook names
|
610
743
|
#
|
611
|
-
# @raise [Berkshelf::
|
744
|
+
# @raise [Berkshelf::DependencyNotFound]
|
612
745
|
# if a cookbook name is given that does not exist
|
613
746
|
def validate_cookbook_names!(options = {})
|
614
747
|
missing = (Array(options[:cookbooks]) - dependencies.map(&:name))
|
748
|
+
|
615
749
|
unless missing.empty?
|
616
|
-
raise Berkshelf::
|
617
|
-
"Could not find cookbook(s) #{missing.collect{ |c| "'#{c}'" }.join(', ')} " +
|
618
|
-
"in any of the configured dependencies. #{missing.size == 1 ? 'Is it' : 'Are they' } in your Berksfile?"
|
750
|
+
raise Berkshelf::DependencyNotFound.new(missing)
|
619
751
|
end
|
620
752
|
end
|
621
753
|
|