berkshelf 3.0.0.beta3 → 3.0.0.beta4
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 +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +12 -2
- data/CONTRIBUTING.md +53 -53
- data/Gemfile +1 -1
- data/Guardfile +12 -6
- data/PLUGINS.md +2 -2
- data/README.md +7 -11
- data/berkshelf.gemspec +1 -1
- data/features/commands/apply.feature +15 -4
- data/features/commands/cookbook.feature +1 -1
- data/features/commands/install.feature +85 -15
- data/features/commands/list.feature +35 -2
- data/features/commands/outdated.feature +3 -3
- data/features/commands/package.feature +1 -0
- data/features/commands/show.feature +3 -3
- data/features/commands/update.feature +1 -0
- data/features/commands/upload.feature +28 -4
- data/features/json_formatter.feature +2 -0
- data/features/lockfile.feature +1 -0
- data/features/support/env.rb +8 -4
- data/generator_files/Gemfile.erb +9 -0
- data/generator_files/README.md.erb +15 -33
- data/generator_files/Vagrantfile.erb +6 -3
- data/lib/berkshelf.rb +32 -2
- data/lib/berkshelf/berksfile.rb +59 -83
- data/lib/berkshelf/cli.rb +15 -67
- data/lib/berkshelf/community_rest.rb +18 -2
- data/lib/berkshelf/dependency.rb +6 -4
- data/lib/berkshelf/downloader.rb +3 -0
- data/lib/berkshelf/errors.rb +15 -0
- data/lib/berkshelf/formatters.rb +1 -0
- data/lib/berkshelf/formatters/human_readable.rb +27 -4
- data/lib/berkshelf/formatters/json.rb +21 -5
- data/lib/berkshelf/git.rb +4 -0
- data/lib/berkshelf/installer.rb +3 -1
- data/lib/berkshelf/locations/git_location.rb +22 -10
- data/lib/berkshelf/locations/github_location.rb +3 -7
- data/lib/berkshelf/locations/path_location.rb +0 -19
- data/lib/berkshelf/lockfile.rb +66 -4
- data/lib/berkshelf/mixin/logging.rb +1 -1
- data/lib/berkshelf/version.rb +1 -1
- data/spec/spec_helper.rb +8 -4
- data/spec/support/git.rb +9 -9
- data/spec/support/mercurial.rb +9 -9
- data/spec/unit/berkshelf/api_client_spec.rb +1 -1
- data/spec/unit/berkshelf/berksfile_spec.rb +36 -59
- data/spec/unit/berkshelf/cli_spec.rb +16 -0
- data/spec/unit/berkshelf/config_spec.rb +1 -1
- data/spec/unit/berkshelf/cookbook_generator_spec.rb +4 -6
- data/spec/unit/berkshelf/locations/git_location_spec.rb +1 -1
- data/spec/unit/berkshelf/lockfile_spec.rb +81 -2
- data/spec/unit/berkshelf/resolver/graph_spec.rb +1 -1
- data/spec/unit/berkshelf/ui_spec.rb +4 -4
- metadata +7 -7
- data/features/commands/configure.feature +0 -89
@@ -1,24 +1,5 @@
|
|
1
1
|
module Berkshelf
|
2
2
|
class PathLocation < Location::Base
|
3
|
-
class << self
|
4
|
-
# Expand and return a string representation of the given path if it is
|
5
|
-
# absolute or a path in the users home directory.
|
6
|
-
#
|
7
|
-
# Returns the given relative path otherwise.
|
8
|
-
#
|
9
|
-
# @param [#to_s] path
|
10
|
-
#
|
11
|
-
# @return [String]
|
12
|
-
def normalize_path(path)
|
13
|
-
path = path.to_s
|
14
|
-
if (path[0] == '~') || Pathname.new(path).absolute?
|
15
|
-
File.expand_path(path)
|
16
|
-
else
|
17
|
-
path
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
3
|
set_location_key :path
|
23
4
|
set_valid_options :path, :metadata
|
24
5
|
|
data/lib/berkshelf/lockfile.rb
CHANGED
@@ -5,6 +5,29 @@ module Berkshelf
|
|
5
5
|
# when working in teams where the same cookbook versions are desired across
|
6
6
|
# multiple workstations.
|
7
7
|
class Lockfile
|
8
|
+
class << self
|
9
|
+
# Initialize a Lockfile from the given filepath
|
10
|
+
#
|
11
|
+
# @param [String] filepath
|
12
|
+
# filepath to the lockfile
|
13
|
+
def from_file(filepath)
|
14
|
+
new(filepath: filepath)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Initialize a Lockfile from the given Berksfile
|
18
|
+
#
|
19
|
+
# @param [Berkshelf::Berksfile] berksfile
|
20
|
+
# the Berksfile associated with the Lockfile
|
21
|
+
def from_berksfile(berksfile)
|
22
|
+
filepath = File.join(File.dirname(File.expand_path(berksfile.filepath)), Lockfile::DEFAULT_FILENAME)
|
23
|
+
new(berksfile: berksfile, filepath: filepath)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
DEFAULT_FILENAME = "Berksfile.lock"
|
28
|
+
|
29
|
+
include Berkshelf::Mixin::Logging
|
30
|
+
|
8
31
|
# @return [Pathname]
|
9
32
|
# the path to this Lockfile
|
10
33
|
attr_reader :filepath
|
@@ -17,16 +40,55 @@ module Berkshelf
|
|
17
40
|
# Lockfile exists, it is automatically loaded. Otherwise, an empty instance is
|
18
41
|
# created and ready for use.
|
19
42
|
#
|
20
|
-
# @
|
43
|
+
# @option options [String] :filepath
|
44
|
+
# filepath to the lockfile
|
45
|
+
# @option options [Berkshelf::Berksfile] :berksfile
|
21
46
|
# the Berksfile associated with this Lockfile
|
22
|
-
def initialize(
|
23
|
-
@
|
24
|
-
@
|
47
|
+
def initialize(options = {})
|
48
|
+
@filepath = options[:filepath].to_s
|
49
|
+
@berksfile = options[:berksfile]
|
25
50
|
@dependencies = {}
|
26
51
|
|
27
52
|
load! if File.exists?(@filepath)
|
28
53
|
end
|
29
54
|
|
55
|
+
# Resolve this Berksfile and apply the locks found in the generated Berksfile.lock to the
|
56
|
+
# target Chef environment
|
57
|
+
#
|
58
|
+
# @param [String] environment_name
|
59
|
+
#
|
60
|
+
# @option options [Hash] :ssl_verify (true)
|
61
|
+
# Disable/Enable SSL verification during uploads
|
62
|
+
#
|
63
|
+
# @raise [EnvironmentNotFound]
|
64
|
+
# if the target environment was not found
|
65
|
+
# @raise [ChefConnectionError]
|
66
|
+
# if you are locking cookbooks with an invalid or not-specified client configuration
|
67
|
+
def apply(environment_name, options = {})
|
68
|
+
Berkshelf.ridley_connection(options) do |conn|
|
69
|
+
unless environment = conn.environment.find(environment_name)
|
70
|
+
raise EnvironmentNotFound.new(environment_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
environment.cookbook_versions = {}.tap do |cookbook_versions|
|
74
|
+
dependencies.each do |dependency|
|
75
|
+
if dependency.locked_version.nil?
|
76
|
+
# A locked version must be present for each entry. Older versions of the lockfile
|
77
|
+
# may have contained dependencies with a special type of location that would attempt
|
78
|
+
# to dynamically determine the locked version. This is incorrect and the Lockfile
|
79
|
+
# should be regenerated if that is the case.
|
80
|
+
raise InvalidLockFile, "Your lockfile contains a dependency without a locked version. This " +
|
81
|
+
"may be because you have an old lockfile. Regenerate your lockfile and try again."
|
82
|
+
end
|
83
|
+
|
84
|
+
cookbook_versions[dependency.name] = "= #{dependency.locked_version.to_s}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
environment.save
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
30
92
|
# Load the lockfile from file system.
|
31
93
|
def load!
|
32
94
|
contents = File.read(filepath).strip
|
data/lib/berkshelf/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
require 'spork'
|
2
2
|
|
3
|
+
def windows?
|
4
|
+
!!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
|
5
|
+
end
|
6
|
+
|
3
7
|
Spork.prefork do
|
4
8
|
require 'rspec'
|
5
9
|
require 'webmock/rspec'
|
6
|
-
require 'berkshelf/api/rspec'
|
10
|
+
require 'berkshelf/api/rspec' unless windows?
|
7
11
|
|
8
12
|
Dir['spec/support/**/*.rb'].each { |f| require File.expand_path(f) }
|
9
13
|
|
@@ -13,7 +17,7 @@ Spork.prefork do
|
|
13
17
|
config.include Berkshelf::RSpec::ChefServer
|
14
18
|
config.include Berkshelf::RSpec::Git
|
15
19
|
config.include Berkshelf::RSpec::PathHelpers
|
16
|
-
config.include Berkshelf::API::RSpec
|
20
|
+
config.include Berkshelf::API::RSpec unless windows?
|
17
21
|
|
18
22
|
config.expect_with :rspec do |c|
|
19
23
|
c.syntax = :expect
|
@@ -27,7 +31,7 @@ Spork.prefork do
|
|
27
31
|
config.before(:suite) do
|
28
32
|
WebMock.disable_net_connect!(allow_localhost: true, net_http_connect_on_start: true)
|
29
33
|
Berkshelf::RSpec::ChefServer.start
|
30
|
-
Berkshelf::API::RSpec::Server.start
|
34
|
+
Berkshelf::API::RSpec::Server.start unless windows?
|
31
35
|
Berkshelf.set_format(:null)
|
32
36
|
Berkshelf.ui.mute!
|
33
37
|
end
|
@@ -41,7 +45,7 @@ Spork.prefork do
|
|
41
45
|
end
|
42
46
|
|
43
47
|
config.before(:each) do
|
44
|
-
Berkshelf::API::RSpec::Server.clear_cache
|
48
|
+
Berkshelf::API::RSpec::Server.clear_cache unless windows?
|
45
49
|
clean_tmp_path
|
46
50
|
Berkshelf.initialize_filesystem
|
47
51
|
Berkshelf::CookbookStore.instance.initialize_filesystem
|
data/spec/support/git.rb
CHANGED
@@ -21,23 +21,23 @@ module Berkshelf
|
|
21
21
|
|
22
22
|
Dir.chdir(path) do
|
23
23
|
shell_out "git config receive.denyCurrentBranch ignore"
|
24
|
-
shell_out "echo
|
24
|
+
shell_out "echo \"# a change!\" >> content_file"
|
25
25
|
shell_out "git add ."
|
26
|
-
shell_out "git commit -am
|
26
|
+
shell_out "git commit -am \"A commit.\""
|
27
27
|
|
28
28
|
options[:tags].each do |tag|
|
29
|
-
shell_out "echo
|
29
|
+
shell_out "echo \"#{tag}\" > content_file"
|
30
30
|
shell_out "git add content_file"
|
31
|
-
shell_out "git commit -am
|
32
|
-
shell_out "git tag
|
31
|
+
shell_out "git commit -am \"#{tag} content\""
|
32
|
+
shell_out "git tag \"#{tag}\""
|
33
33
|
end if options[:tags]
|
34
34
|
|
35
35
|
options[:branches].each do |branch|
|
36
|
-
shell_out "git checkout -b #{branch} master
|
37
|
-
shell_out "echo
|
36
|
+
shell_out "git checkout -b #{branch} master"
|
37
|
+
shell_out "echo \"#{branch}\" > content_file"
|
38
38
|
shell_out "git add content_file"
|
39
|
-
shell_out "git commit -am
|
40
|
-
shell_out "git checkout master
|
39
|
+
shell_out "git commit -am \"#{branch} content\""
|
40
|
+
shell_out "git checkout master"
|
41
41
|
end if options[:branches]
|
42
42
|
end
|
43
43
|
end
|
data/spec/support/mercurial.rb
CHANGED
@@ -8,7 +8,7 @@ module Berkshelf
|
|
8
8
|
include Berkshelf::RSpec::PathHelpers
|
9
9
|
|
10
10
|
def mercurial_origin_for(repo, options = {})
|
11
|
-
"file://localhost
|
11
|
+
File.join("file://localhost", generate_fake_mercurial_remote(repo, options))
|
12
12
|
end
|
13
13
|
|
14
14
|
def generate_fake_mercurial_remote(uri, options = {})
|
@@ -19,21 +19,21 @@ module Berkshelf
|
|
19
19
|
Dir.chdir(repo_path) do
|
20
20
|
ENV['HGUSER'] = 'test_user'
|
21
21
|
shell_out "hg init"
|
22
|
-
shell_out "echo
|
22
|
+
shell_out "echo \"# a change!\" >> content_file"
|
23
23
|
if options[:is_cookbook]
|
24
|
-
shell_out "echo
|
24
|
+
shell_out "echo \"#cookbook\" >> metadata.rb"
|
25
25
|
end
|
26
26
|
shell_out "hg add ."
|
27
|
-
shell_out "hg commit -m
|
27
|
+
shell_out "hg commit -m \"A commit.\""
|
28
28
|
options[:tags].each do |tag|
|
29
|
-
shell_out "echo
|
30
|
-
shell_out "hg commit -m
|
31
|
-
shell_out "hg tag
|
29
|
+
shell_out "echo \"#{tag}\" > content_file"
|
30
|
+
shell_out "hg commit -m \"#{tag} content\""
|
31
|
+
shell_out "hg tag \"#{tag}\""
|
32
32
|
end if options.has_key? :tags
|
33
33
|
options[:branches].each do |branch|
|
34
34
|
shell_out "hg branch #{branch}"
|
35
|
-
shell_out "echo
|
36
|
-
shell_out "hg commit -m
|
35
|
+
shell_out "echo \"#{branch}\" > content_file"
|
36
|
+
shell_out "hg commit -m \"#{branch} content\""
|
37
37
|
shell_out "hg up default"
|
38
38
|
end if options.has_key? :branches
|
39
39
|
end
|
@@ -68,7 +68,13 @@ describe Berkshelf::Berksfile do
|
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'merges the default options into specified options' do
|
71
|
-
subject.should_receive(:add_dependency)
|
71
|
+
subject.should_receive(:add_dependency)do |arg_name, arg_constraint, arg_options|
|
72
|
+
expect(arg_name).to eq(name)
|
73
|
+
expect(arg_constraint).to eq(constraint)
|
74
|
+
expect(arg_options[:path]).to match(%r{/Users/reset})
|
75
|
+
expect(arg_options[:group]).to eq([])
|
76
|
+
end
|
77
|
+
|
72
78
|
subject.cookbook(name, constraint, path: '/Users/reset')
|
73
79
|
end
|
74
80
|
|
@@ -333,30 +339,25 @@ describe Berkshelf::Berksfile do
|
|
333
339
|
|
334
340
|
describe '#retrieve_locked' do
|
335
341
|
let(:lockfile) { double('lockfile', find: locked) }
|
342
|
+
let(:dependency) { double('dependency', name: 'bacon') }
|
336
343
|
let(:locked) { double('locked', cached_cookbook: cached, locked_version: '1.0.0') }
|
337
344
|
let(:cached) { double('cached') }
|
338
345
|
|
339
346
|
before do
|
340
|
-
subject.stub(:validate_cookbook_names!)
|
341
347
|
subject.stub(:lockfile).and_return(lockfile)
|
342
348
|
end
|
343
349
|
|
344
|
-
it '
|
345
|
-
expect(subject).to receive(:validate_cookbook_names!).once
|
346
|
-
subject.retrieve_locked('bacon')
|
347
|
-
end
|
348
|
-
|
349
|
-
it 'raises an error when the lockfile does not exist' do
|
350
|
+
it 'raises an error when the lockfile does not have the source' do
|
350
351
|
lockfile.stub(:find)
|
351
352
|
expect {
|
352
|
-
subject.retrieve_locked(
|
353
|
-
}.to raise_error(Berkshelf::
|
353
|
+
subject.retrieve_locked(dependency)
|
354
|
+
}.to raise_error(Berkshelf::CookbookNotFound)
|
354
355
|
end
|
355
356
|
|
356
357
|
it 'raises an error when the cookbook is not downloaded' do
|
357
|
-
locked.stub(:
|
358
|
+
locked.stub(:downloaded?).and_return(false)
|
358
359
|
expect {
|
359
|
-
subject.retrieve_locked(
|
360
|
+
subject.retrieve_locked(dependency)
|
360
361
|
}.to raise_error(Berkshelf::CookbookNotFound)
|
361
362
|
end
|
362
363
|
end
|
@@ -483,54 +484,30 @@ describe Berkshelf::Berksfile do
|
|
483
484
|
upload
|
484
485
|
end
|
485
486
|
end
|
486
|
-
end
|
487
|
-
|
488
|
-
describe "#apply" do
|
489
|
-
let(:env_name) { 'berkshelf-test' }
|
490
|
-
let(:server_url) { Berkshelf::RSpec::ChefServer.server_url }
|
491
|
-
let(:client_name) { 'berkshelf' }
|
492
|
-
let(:client_key) { fixtures_path.join('../config/berkshelf.pem').to_s }
|
493
|
-
let(:ridley) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
|
494
487
|
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
[
|
504
|
-
double(name: 'nginx', locked_version: '1.2.3'),
|
505
|
-
double(name: 'artifact', locked_version: '1.4.0')
|
506
|
-
]
|
507
|
-
end
|
508
|
-
|
509
|
-
before do
|
510
|
-
chef_environment('berkshelf')
|
511
|
-
subject.lockfile.stub(:dependencies).and_return(dependencies)
|
512
|
-
end
|
513
|
-
|
514
|
-
it 'installs the Berksfile' do
|
515
|
-
subject.should_receive(:install)
|
516
|
-
subject.apply('berkshelf')
|
488
|
+
context 'when validate is passed' do
|
489
|
+
let(:options) do
|
490
|
+
{
|
491
|
+
force: false,
|
492
|
+
freeze: true,
|
493
|
+
validate: false,
|
494
|
+
name: "cookbook"
|
495
|
+
}
|
517
496
|
end
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
environment = ::JSON.parse(chef_server.data_store.get(['environments', 'berkshelf']))
|
523
|
-
expect(environment['cookbook_versions']).to have(2).items
|
524
|
-
expect(environment['cookbook_versions']['nginx']).to eq('1.2.3')
|
525
|
-
expect(environment['cookbook_versions']['artifact']).to eq('1.4.0')
|
497
|
+
let(:ridley_options) do
|
498
|
+
default_ridley_options.merge(
|
499
|
+
{ server_url: 'http://configured-chef-server/'})
|
526
500
|
end
|
527
|
-
|
501
|
+
let(:cookbook) { double('cookbook', cookbook_name: 'cookbook', path: 'path', version: '1.0.0') }
|
502
|
+
let(:installed_cookbooks) { [ cookbook ] }
|
503
|
+
let(:cookbook_resource) { double('cookbook') }
|
504
|
+
let(:conn) { double('conn') }
|
528
505
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
506
|
+
it 'uses the passed in :validate' do
|
507
|
+
Ridley.should_receive(:open).with(ridley_options).and_yield(conn)
|
508
|
+
conn.should_receive(:cookbook).and_return(cookbook_resource)
|
509
|
+
cookbook_resource.should_receive(:upload).with('path', options )
|
510
|
+
upload
|
534
511
|
end
|
535
512
|
end
|
536
513
|
end
|
@@ -539,7 +516,7 @@ describe Berkshelf::Berksfile do
|
|
539
516
|
context 'when the dependency does not exist' do
|
540
517
|
it 'raises a CookbookNotFound exception' do
|
541
518
|
expect {
|
542
|
-
subject.package('non-existent', output:
|
519
|
+
subject.package('non-existent', output: Dir.tmpdir)
|
543
520
|
}.to raise_error(Berkshelf::CookbookNotFound)
|
544
521
|
end
|
545
522
|
end
|
@@ -547,7 +524,7 @@ describe Berkshelf::Berksfile do
|
|
547
524
|
context 'when the dependency exists' do
|
548
525
|
let(:dependency) { double('dependency') }
|
549
526
|
let(:cached) { double('cached', path: '/foo/bar', cookbook_name: 'cookbook') }
|
550
|
-
let(:options) { { output:
|
527
|
+
let(:options) { { output: Dir.tmpdir } }
|
551
528
|
|
552
529
|
before do
|
553
530
|
FileUtils.stub(:cp_r)
|
@@ -562,7 +539,7 @@ describe Berkshelf::Berksfile do
|
|
562
539
|
end
|
563
540
|
|
564
541
|
it 'returns the output path' do
|
565
|
-
expect(subject.package('non-existent', options)).to eq('
|
542
|
+
expect(subject.package('non-existent', options)).to eq(File.join(Dir.tmpdir, 'non-existent.tar.gz'))
|
566
543
|
end
|
567
544
|
end
|
568
545
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Berkshelf::Cli do
|
4
|
+
let(:subject) { described_class.new }
|
5
|
+
let(:berksfile) { double('Berksfile') }
|
6
|
+
let(:cookbooks) { ['mysql'] }
|
7
|
+
describe '#upload' do
|
8
|
+
it 'calls to upload with params if passed in cli' do
|
9
|
+
Berkshelf::Berksfile.should_receive(:from_file).and_return(berksfile)
|
10
|
+
berksfile.should_receive(:upload).with(include(:skip_syntax_check => true, :freeze => false, :cookbooks => cookbooks))
|
11
|
+
subject.options[:skip_syntax_check] = true
|
12
|
+
subject.options[:no_freeze] = true
|
13
|
+
subject.upload('mysql')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -39,13 +39,11 @@ describe Berkshelf::CookbookGenerator do
|
|
39
39
|
contains 'All rights reserved - Do Not Redistribute'
|
40
40
|
end
|
41
41
|
file 'README.md' do
|
42
|
-
contains 'sparkle_motion
|
43
|
-
contains '
|
44
|
-
contains '- `toaster` - sparkle_motion needs toaster to brown your bagel.'
|
45
|
-
contains '#### sparkle_motion::default'
|
42
|
+
contains '# sparkle_motion-cookbook'
|
43
|
+
contains '### sparkle_motion::default'
|
46
44
|
contains " <td><tt>['sparkle_motion']['bacon']</tt></td>"
|
47
|
-
contains "
|
48
|
-
contains ' "recipe[sparkle_motion]"'
|
45
|
+
contains "Include `sparkle_motion` in your node's `run_list`:"
|
46
|
+
contains ' "recipe[sparkle_motion::default]"'
|
49
47
|
contains 'Author:: YOUR_NAME (<YOUR_EMAIL>)'
|
50
48
|
end
|
51
49
|
file 'metadata.rb' do
|