berkshelf 3.0.0.beta1 → 3.0.0.beta2
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.
- 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
|
|