berks-monolith 0.1.0
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/.gitignore +12 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +8 -0
- data/berks-monolith.gemspec +29 -0
- data/bin/berks-monolith +6 -0
- data/lib/monolith.rb +12 -0
- data/lib/monolith/berksfile.rb +69 -0
- data/lib/monolith/commands.rb +71 -0
- data/lib/monolith/formatter.rb +50 -0
- data/lib/monolith/gitexclude.rb +54 -0
- data/lib/monolith/locations/base.rb +37 -0
- data/lib/monolith/locations/default.rb +24 -0
- data/lib/monolith/locations/git.rb +60 -0
- data/lib/monolith/locations/github.rb +6 -0
- data/lib/monolith/locations/path.rb +23 -0
- data/lib/monolith/version.rb +3 -0
- data/test/.gitignore +1 -0
- data/test/helpers.rb +62 -0
- data/test/test_command_clean.rb +30 -0
- data/test/test_command_install.rb +25 -0
- data/test/test_command_update.rb +32 -0
- data/test/test_gitlocation.rb +48 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6e00e4691862cc03e4cca97a0722ad297e535391
|
4
|
+
data.tar.gz: 4183cdf8be169fc1b52c22f83e9f0fb4c8d49115
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: caf6a7a55dd3b38d1e6fde05e7df7efddd6f6c8aa247af5b835aad685d455db71015cda82e1d2d9046cf84ae24d3b8340941be58973afff3a1f095dd9eb79496
|
7
|
+
data.tar.gz: 82ff7940b2e02d68125bc479c40a2c27f06af2d712bc00b4d367d6a49588e8f8be28da8d40e7eaca5b9429901785a067baeffe174535adc0af8d05cd6f968fce
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Mark Harrison
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
[](https://waffle.io/mivok/berks-monolith)
|
2
|
+
[](https://travis-ci.org/mivok/berks-monolith)
|
3
|
+
|
4
|
+
# berks-monolith
|
5
|
+
|
6
|
+
Berks-monolith is a companion command to berkshelf that takes all cookbooks
|
7
|
+
mentioned in a Berksfile and places development friendly versions of them
|
8
|
+
under a single directory. Usually, this means you will end up with git clones
|
9
|
+
for all cookbooks with git repositories in the Berksfile, and static copies of
|
10
|
+
cookbooks that don't have identifiable VCS repositories.
|
11
|
+
|
12
|
+
## Use cases
|
13
|
+
|
14
|
+
* You have a Berksfile with many git based sources, and want a quick way to
|
15
|
+
clone them all under a single directory.
|
16
|
+
* You have a mostly monolithic repository, but make use of berkshelf to manage
|
17
|
+
dependencies and use external cookbook sources, and you'd like to have
|
18
|
+
everything in one place to be able to search.
|
19
|
+
* You are transitioning between a monolithic repository workflow and a
|
20
|
+
independent software artefacts workflow, and have a mix of artefacts in a
|
21
|
+
Berksfile as well as cookbooks in a monolithic repository, and you want all
|
22
|
+
cookbooks in one place.
|
23
|
+
|
24
|
+
## Why not just use X?
|
25
|
+
|
26
|
+
The `berks vendor` command comes close to what monolith does, grabbing all
|
27
|
+
cookbooks mentioned in a Berksfile and putting copies of them under a single
|
28
|
+
directory. However, berks vendor is intended for production rather than
|
29
|
+
development use, and explicitly strips any VCS directories, chef ignored
|
30
|
+
files, and metadata.rb files.
|
31
|
+
|
32
|
+
The `berks install` command collects all cookbooks into
|
33
|
+
`~/.berkshelf/cookbooks`, but again VCS information is stripped out, and this
|
34
|
+
contains all cookbooks, not just those associated with a specific Berksfile.
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
### berks-monolith install
|
39
|
+
|
40
|
+
Clones/copies all cookbooks mentioned in the berksfile. By default they go
|
41
|
+
into the 'cookbooks' directory. You can specify an alternate path if you wish
|
42
|
+
by specifying it on the command line: `berks-monolith install vendor`.
|
43
|
+
|
44
|
+
Exactly what you get depends on what the source of the cookbook is in the
|
45
|
+
berksfile:
|
46
|
+
|
47
|
+
* Normal community cookbooks (e.g. if you just specify `cookbook 'foo'` with
|
48
|
+
no other options) are just copied in place from the berkshelf directory.
|
49
|
+
* Git cookbooks will result in a clone of the repository pointing to the
|
50
|
+
original source repository.
|
51
|
+
* Path cookbooks will be skipped completely. This means you don't have to
|
52
|
+
worry if you have existing local cookbooks in a monolithic repository in
|
53
|
+
your Berksfile. They won't be copied again.
|
54
|
+
|
55
|
+
### berks-monolith update
|
56
|
+
|
57
|
+
Updates the cloned copies of cookbooks if possible. In practice this means
|
58
|
+
'run git pull' for all git clones.
|
59
|
+
|
60
|
+
### berks-monolith clean
|
61
|
+
|
62
|
+
Removes all cookbooks that were installed with `berks-monolith install`.
|
63
|
+
Anything else in the cookbooks directory is left alone.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'monolith/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "berks-monolith"
|
8
|
+
spec.version = Monolith::VERSION
|
9
|
+
spec.authors = ["Mark Harrison"]
|
10
|
+
spec.email = ["mark@mivok.net"]
|
11
|
+
spec.summary = %q{Berkshelf monolithic repository tools}
|
12
|
+
spec.description = %q{Tools for working with cookbooks as if they were inside a monolithic repository}
|
13
|
+
spec.homepage = "http://github.com/mivok/berks-monolith"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 1.9.2'
|
22
|
+
|
23
|
+
spec.add_dependency 'berkshelf', '~> 3.0', '>= 3.0.0'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
28
|
+
spec.add_development_dependency 'pry', '~> 0.10'
|
29
|
+
end
|
data/bin/berks-monolith
ADDED
data/lib/monolith.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'monolith/commands'
|
2
|
+
|
3
|
+
require_relative 'monolith/locations/git'
|
4
|
+
require_relative 'monolith/locations/github'
|
5
|
+
require_relative 'monolith/locations/path'
|
6
|
+
require_relative 'monolith/locations/default'
|
7
|
+
|
8
|
+
module Monolith
|
9
|
+
def self.formatter
|
10
|
+
@formatter ||= Monolith::Formatter.new
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'berkshelf'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Monolith
|
5
|
+
class Berksfile
|
6
|
+
attr_reader :berksfile
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
Berkshelf.ui.mute! if Monolith.formatter.quiet
|
10
|
+
begin
|
11
|
+
@berksfile = Berkshelf::Berksfile.from_options(options)
|
12
|
+
rescue Berkshelf::BerksfileNotFound => e
|
13
|
+
Monolith.formatter.error(e)
|
14
|
+
exit(e.status_code)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Runs berks install. This is needed before we install cookbooks ourselves
|
19
|
+
# to make sure berkshelf has a local copy of them for us to clone from or
|
20
|
+
# copy. However, it's not needed for other commands, so it separated out
|
21
|
+
# here.
|
22
|
+
def install
|
23
|
+
@berksfile.install
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieve all cookbooks listed in the berksfile.
|
27
|
+
#
|
28
|
+
# Can take a block to do something with each cookbook.
|
29
|
+
def cookbooks(path)
|
30
|
+
FileUtils.mkdir_p(path)
|
31
|
+
cached_cookbooks = @berksfile.cookbooks
|
32
|
+
if block_given?
|
33
|
+
cached_cookbooks.each do |cookbook|
|
34
|
+
destination = File.join(File.expand_path(path),
|
35
|
+
cookbook.cookbook_name)
|
36
|
+
dep = berksfile.get_dependency(cookbook.cookbook_name)
|
37
|
+
if dep
|
38
|
+
yield cookbook, dep, destination
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
cached_cookbooks
|
43
|
+
end
|
44
|
+
|
45
|
+
def monolith_action(action, cookbook, dep, destination)
|
46
|
+
obj = monolith_obj(cookbook, dep, destination)
|
47
|
+
if obj.nil?
|
48
|
+
Monolith.formatter.unsupported_location(cookbook, dep)
|
49
|
+
else
|
50
|
+
obj.send(action)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Feteches the appropriate monolith location object for a given cookbook
|
55
|
+
# dependency. I.e. Monolith::FooLocation.
|
56
|
+
def monolith_obj(cookbook, dep, destination)
|
57
|
+
if dep.location.nil?
|
58
|
+
Monolith::DefaultLocation.new(cookbook, dep, destination)
|
59
|
+
else
|
60
|
+
klass = dep.location.class.name.split('::')[-1]
|
61
|
+
Monolith.formatter.debug("Location class for " \
|
62
|
+
"#{cookbook.cookbook_name} is #{klass}")
|
63
|
+
if Monolith.const_defined?(klass)
|
64
|
+
Monolith.const_get(klass).new(cookbook, dep, destination)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'monolith/berksfile'
|
3
|
+
require 'monolith/formatter'
|
4
|
+
require 'monolith/gitexclude'
|
5
|
+
|
6
|
+
module Monolith
|
7
|
+
class Command < Thor
|
8
|
+
namespace ''
|
9
|
+
|
10
|
+
class_option :quiet,
|
11
|
+
:type => :boolean,
|
12
|
+
:desc => "Don't print out any informational messages",
|
13
|
+
:aliases => '-q',
|
14
|
+
:default => false
|
15
|
+
|
16
|
+
class_option :debug,
|
17
|
+
:type => :boolean,
|
18
|
+
:desc => 'Print additional debug messages',
|
19
|
+
:aliases => '-d',
|
20
|
+
:default => false
|
21
|
+
|
22
|
+
class_option :berksfile,
|
23
|
+
:desc => 'Location of the Berksfile to use',
|
24
|
+
:aliases => '-b'
|
25
|
+
|
26
|
+
class_option :git_exclude,
|
27
|
+
:type => :boolean,
|
28
|
+
:desc => 'Add installed cookbooks to git exclude file',
|
29
|
+
:default => true
|
30
|
+
|
31
|
+
def initialize(*args)
|
32
|
+
super(*args)
|
33
|
+
|
34
|
+
Monolith.formatter.quiet = @options[:quiet]
|
35
|
+
Monolith.formatter.debug = @options[:debug]
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'install [PATH]', 'Clone all cookbooks into the cookbooks directory'
|
39
|
+
def install(path = File.join(Dir.pwd, "cookbooks"))
|
40
|
+
berksfile = Monolith::Berksfile.new(options.dup)
|
41
|
+
berksfile.install # We need to run berks install first
|
42
|
+
gitpath = File.expand_path('../.git', berksfile.berksfile.filepath)
|
43
|
+
gitexclude = GitExclude.new(gitpath, options)
|
44
|
+
berksfile.cookbooks(path) do |cookbook, dep, destination|
|
45
|
+
berksfile.monolith_action(:install, cookbook, dep, destination)
|
46
|
+
gitexclude.add(destination)
|
47
|
+
end
|
48
|
+
gitexclude.update
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'update [PATH]', 'Update all cloned cookbooks'
|
52
|
+
def update(path = File.join(Dir.pwd, "cookbooks"))
|
53
|
+
berksfile = Monolith::Berksfile.new(options.dup)
|
54
|
+
berksfile.cookbooks(path) do |cookbook, dep, destination|
|
55
|
+
berksfile.monolith_action(:update, cookbook, dep, destination)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'clean [PATH]', 'Delete all cloned cookbooks'
|
60
|
+
def clean(path = File.join(Dir.pwd, "cookbooks"))
|
61
|
+
berksfile = Monolith::Berksfile.new(options.dup)
|
62
|
+
gitpath = File.expand_path('../.git', berksfile.berksfile.filepath)
|
63
|
+
gitexclude = GitExclude.new(gitpath, options)
|
64
|
+
berksfile.cookbooks(path) do |cookbook, dep, destination|
|
65
|
+
berksfile.monolith_action(:clean, cookbook, dep, destination)
|
66
|
+
gitexclude.remove(destination)
|
67
|
+
end
|
68
|
+
gitexclude.update
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Monolith
|
2
|
+
class Formatter
|
3
|
+
attr_accessor :quiet
|
4
|
+
attr_accessor :debug
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@quiet = false
|
8
|
+
@debug = false
|
9
|
+
@base_path = Pathname.new(Dir.pwd)
|
10
|
+
end
|
11
|
+
|
12
|
+
def install(cookbook, destination)
|
13
|
+
msg "Installing #{cookbook.cookbook_name} to #{rel_dir(destination)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(cookbook, destination)
|
17
|
+
msg "Updating #{cookbook.cookbook_name} at #{rel_dir(destination)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def clean(cookbook, destination)
|
21
|
+
msg "Removing #{cookbook.cookbook_name} from #{rel_dir(destination)}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def skip(cookbook, reason)
|
25
|
+
msg "Skipping #{cookbook.cookbook_name} (#{reason})"
|
26
|
+
end
|
27
|
+
|
28
|
+
def unsupported_location(cookbook, dep)
|
29
|
+
loctype = dep.location.class.name.split('::')[-1]
|
30
|
+
msg "Unsupported location type #{loctype} for cookbook " \
|
31
|
+
"#{cookbook.cookbook_name}. Skipping."
|
32
|
+
end
|
33
|
+
|
34
|
+
def debug(msg)
|
35
|
+
puts "DEBUG: #{msg}" if @debug
|
36
|
+
end
|
37
|
+
|
38
|
+
def msg(msg)
|
39
|
+
puts msg unless @quiet
|
40
|
+
end
|
41
|
+
|
42
|
+
def error(msg)
|
43
|
+
STDERR.puts msg
|
44
|
+
end
|
45
|
+
|
46
|
+
def rel_dir(dir)
|
47
|
+
return Pathname.new(dir).relative_path_from(@base_path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Monolith
|
2
|
+
class GitExclude
|
3
|
+
def initialize(git_dir, options)
|
4
|
+
@lines_to_add = []
|
5
|
+
@lines_to_remove = []
|
6
|
+
@git_dir = Pathname.new(git_dir)
|
7
|
+
@filename = @git_dir.join('info', 'exclude')
|
8
|
+
@enabled = options[:git_exclude]
|
9
|
+
end
|
10
|
+
|
11
|
+
def relative_path(path)
|
12
|
+
Pathname.new(path).relative_path_from(@git_dir.parent).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(line)
|
16
|
+
@lines_to_add << relative_path(line)
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove(line)
|
20
|
+
@lines_to_remove << relative_path(line)
|
21
|
+
end
|
22
|
+
|
23
|
+
def update
|
24
|
+
return unless @enabled
|
25
|
+
|
26
|
+
# We don't want to do anything if we're not actually in a git repo
|
27
|
+
return unless File.directory?(@git_dir)
|
28
|
+
|
29
|
+
if File.exist?(@filename)
|
30
|
+
data = File.read(@filename).split("\n")
|
31
|
+
else
|
32
|
+
data = []
|
33
|
+
end
|
34
|
+
# Don't go creating a file if there's nothing to add and we're already
|
35
|
+
# empty
|
36
|
+
return if data.empty? and @lines_to_add.empty?
|
37
|
+
|
38
|
+
# Now add/remove lines - additions first
|
39
|
+
data.concat(@lines_to_add.reject { |l| data.include?(l) })
|
40
|
+
data.reject! { |l| @lines_to_remove.include?(l) }
|
41
|
+
|
42
|
+
# And write out the new file
|
43
|
+
File.open(@filename, "w") do |file|
|
44
|
+
data.each do |l|
|
45
|
+
file.puts(l)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Reset the list of lines to add/remove
|
50
|
+
@lines_to_add = []
|
51
|
+
@lines_to_remove = []
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Monolith
|
2
|
+
class BaseLocation
|
3
|
+
def initialize(cookbook, dep, destination)
|
4
|
+
@dep = dep
|
5
|
+
@location = dep.location
|
6
|
+
@cookbook = cookbook
|
7
|
+
@destination = destination
|
8
|
+
end
|
9
|
+
|
10
|
+
# Install the cookbook in the development environment. If possible, the
|
11
|
+
# installed cookbook should look exactly as it would when used for
|
12
|
+
# development (e.g. a git checkout with all git metadata, no compiled
|
13
|
+
# artefacts).
|
14
|
+
def install
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Update the cookbook in the development environment to the latest
|
19
|
+
# version. E.g. if git is used, run git pull.
|
20
|
+
def update
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Remove a previously installed cookbook. If a cookbook was never
|
25
|
+
# installed in the first place (either because install wasn't run, or
|
26
|
+
# because of the location type), then this should do nothing.
|
27
|
+
def clean
|
28
|
+
if File.exist?(@destination)
|
29
|
+
Monolith.formatter.clean(@cookbook, @destination)
|
30
|
+
FileUtils.rm_rf(@destination)
|
31
|
+
else
|
32
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
33
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} doesn't exist")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Default location aka community/supermarket cookbook
|
2
|
+
module Monolith
|
3
|
+
class DefaultLocation < BaseLocation
|
4
|
+
def install
|
5
|
+
# For now we just copy any community cookbooks. It would be nice to be
|
6
|
+
# able to grab them from the source URL, but that isn't readily
|
7
|
+
# accessible, and then you have to guess how to check it out.
|
8
|
+
if File.directory?(@destination)
|
9
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
10
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} already exists")
|
11
|
+
else
|
12
|
+
Monolith.formatter.install(@cookbook, @destination)
|
13
|
+
FileUtils.cp_r(@cookbook.path, @destination)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def update
|
18
|
+
# There isn't anything to do for updating a community cookbook except
|
19
|
+
# blowing it away and recreating it. For the moment I'm opting not to do
|
20
|
+
# that (it may be able ot be an option later)
|
21
|
+
Monolith.formatter.skip(@cookbook, "Not updating community cookbook")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'berkshelf/mixin/git'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
module Monolith
|
5
|
+
class GitLocation < BaseLocation
|
6
|
+
include Berkshelf::Mixin::Git
|
7
|
+
|
8
|
+
def install
|
9
|
+
unless File.directory?(@destination)
|
10
|
+
Monolith.formatter.install(@cookbook, @destination)
|
11
|
+
# Clone from the cache. We've already done an install by this point, so
|
12
|
+
# berkshelf already made sure the cache exists and is up to date.
|
13
|
+
git %|clone "#{cache_path}" "#{@destination}"|
|
14
|
+
|
15
|
+
# Make sure the origin is correct and doesn't point to the cached
|
16
|
+
# version.
|
17
|
+
cached_origin_url = origin_url(cache_path)
|
18
|
+
set_origin_url(@destination, cached_origin_url)
|
19
|
+
|
20
|
+
# Not sure if I want to do this - should probably be an option
|
21
|
+
#git %|reset --hard #{@revision}|
|
22
|
+
else
|
23
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
24
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} already exists")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
if File.directory?(@destination)
|
30
|
+
Monolith.formatter.update(@cookbook, @destination)
|
31
|
+
Dir.chdir(@destination) do
|
32
|
+
git %|pull|
|
33
|
+
end
|
34
|
+
else
|
35
|
+
rel_dest = Monolith.formatter.rel_dir(@destination)
|
36
|
+
Monolith.formatter.skip(@cookbook, "#{rel_dest} doesn't exist")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Taken from Berkshelf::GitLocation
|
43
|
+
def cache_path
|
44
|
+
Pathname.new(Berkshelf.berkshelf_path)
|
45
|
+
.join('.cache', 'git', Digest::SHA1.hexdigest(@location.uri))
|
46
|
+
end
|
47
|
+
|
48
|
+
def origin_url(repo_dir)
|
49
|
+
Dir.chdir(repo_dir) do
|
50
|
+
git %|config --local --get remote.origin.url|
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_origin_url(repo_dir, url)
|
55
|
+
Dir.chdir(repo_dir) do
|
56
|
+
git %|remote set-url origin "#{url}"|
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# If a Berksfile mentions a cookbook with a path location, then we can
|
2
|
+
# assume it's already available locally in a form suitable for
|
3
|
+
# development. An example of this is if you have a (mostly) monolithic
|
4
|
+
# chef repository and want to refer to cookbooks in this repository in
|
5
|
+
# your Berksfile.
|
6
|
+
module Monolith
|
7
|
+
class PathLocation < BaseLocation
|
8
|
+
def install
|
9
|
+
Monolith.formatter.debug("Skipping cookbook #{@cookbook.cookbook_name}" \
|
10
|
+
"with path location")
|
11
|
+
end
|
12
|
+
|
13
|
+
def update
|
14
|
+
Monolith.formatter.debug("Skipping cookbook #{@cookbook.cookbook_name}" \
|
15
|
+
"with path location")
|
16
|
+
end
|
17
|
+
|
18
|
+
def clean
|
19
|
+
Monolith.formatter.debug("Skipping cookbook #{@cookbook.cookbook_name}" \
|
20
|
+
"with path location")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/test/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
tmp
|
data/test/helpers.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Monolith
|
5
|
+
module TestHelpers
|
6
|
+
def tmp_path
|
7
|
+
Pathname.new(File.expand_path("../tmp", __FILE__))
|
8
|
+
end
|
9
|
+
|
10
|
+
def clean_tmp_path
|
11
|
+
FileUtils.rm_rf(tmp_path)
|
12
|
+
FileUtils.mkdir_p(tmp_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_git_repo(name)
|
16
|
+
# Makes an example git repo with a single file in and one commit
|
17
|
+
repo_path = tmp_path.join("git", name)
|
18
|
+
FileUtils.mkdir_p(repo_path)
|
19
|
+
Dir.chdir(repo_path) do
|
20
|
+
%x|git init|
|
21
|
+
File.open('metadata.rb', 'w') do |f|
|
22
|
+
f.puts "name '#{name}'"
|
23
|
+
end
|
24
|
+
%x|git add metadata.rb|
|
25
|
+
%x|git config --local user.name Me|
|
26
|
+
%x|git config --local user.email me@example.com|
|
27
|
+
%x|git commit -m "Test commit"|
|
28
|
+
%x|git remote add origin "git@git.example.com:#{name}"|
|
29
|
+
end
|
30
|
+
repo_path
|
31
|
+
end
|
32
|
+
|
33
|
+
def make_change_git(name)
|
34
|
+
repo_path = tmp_path.join("git", name)
|
35
|
+
Dir.chdir(repo_path) do
|
36
|
+
File.open('test.txt', 'w') do |f|
|
37
|
+
f.puts 'Testing'
|
38
|
+
end
|
39
|
+
%x|git add test.txt|
|
40
|
+
%x|git commit --author "Me <me@example.com>" -m "Update"|
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def make_berksfile(types)
|
45
|
+
File.open(tmp_path.join('Berksfile'), 'w') do |berksfile|
|
46
|
+
berksfile.puts "source 'https://supermarket.chef.io/'"
|
47
|
+
types.each do |type|
|
48
|
+
if type == :git
|
49
|
+
repo_path = make_git_repo('test_git')
|
50
|
+
berksfile.puts("cookbook 'test_git', :git => '#{repo_path}'")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if block_given?
|
56
|
+
Dir.chdir(tmp_path) do
|
57
|
+
yield
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative 'helpers'
|
3
|
+
|
4
|
+
# Fix 'Celluloid::Error Thread pool is not running' error.
|
5
|
+
# See https://github.com/celluloid/celluloid/pull/162
|
6
|
+
require 'celluloid/test'
|
7
|
+
Celluloid.init
|
8
|
+
|
9
|
+
require 'monolith'
|
10
|
+
|
11
|
+
class TestCommandInstall < MiniTest::Test
|
12
|
+
include Monolith::TestHelpers
|
13
|
+
|
14
|
+
def setup
|
15
|
+
clean_tmp_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_clean_command
|
19
|
+
make_berksfile([:git]) do
|
20
|
+
# We need to install it first
|
21
|
+
Monolith::Command.start(['install', '-q'])
|
22
|
+
make_change_git('test_git')
|
23
|
+
# Verify the 'before' state
|
24
|
+
assert File.exist?("cookbooks/test_git")
|
25
|
+
# Perform the clean
|
26
|
+
Monolith::Command.start(['clean', '-q'])
|
27
|
+
refute File.exist?("cookbooks/test_git")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative 'helpers'
|
3
|
+
|
4
|
+
# Fix 'Celluloid::Error Thread pool is not running' error.
|
5
|
+
# See https://github.com/celluloid/celluloid/pull/162
|
6
|
+
require 'celluloid/test'
|
7
|
+
Celluloid.init
|
8
|
+
|
9
|
+
require 'monolith'
|
10
|
+
|
11
|
+
class TestCommandInstall < MiniTest::Test
|
12
|
+
include Monolith::TestHelpers
|
13
|
+
|
14
|
+
def setup
|
15
|
+
clean_tmp_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_install_command
|
19
|
+
make_berksfile([:git]) do
|
20
|
+
Monolith::Command.start(['install', '-q'])
|
21
|
+
assert File.exist?("cookbooks/test_git")
|
22
|
+
assert File.exist?("cookbooks/test_git/.git")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative 'helpers'
|
3
|
+
|
4
|
+
# Fix 'Celluloid::Error Thread pool is not running' error.
|
5
|
+
# See https://github.com/celluloid/celluloid/pull/162
|
6
|
+
require 'celluloid/test'
|
7
|
+
Celluloid.init
|
8
|
+
|
9
|
+
require 'monolith'
|
10
|
+
|
11
|
+
class TestCommandInstall < MiniTest::Test
|
12
|
+
include Monolith::TestHelpers
|
13
|
+
|
14
|
+
def setup
|
15
|
+
clean_tmp_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_update_command
|
19
|
+
make_berksfile([:git]) do
|
20
|
+
# We need to install it first
|
21
|
+
Monolith::Command.start(['install', '-q'])
|
22
|
+
make_change_git('test_git')
|
23
|
+
# Verify the 'before' state
|
24
|
+
refute File.exist?("cookbooks/test_git/test.txt")
|
25
|
+
# Perform the update
|
26
|
+
Monolith::Command.start(['update', '-q'])
|
27
|
+
assert File.exist?("cookbooks/test_git")
|
28
|
+
assert File.exist?("cookbooks/test_git/.git")
|
29
|
+
assert File.exist?("cookbooks/test_git/test.txt")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require 'berkshelf'
|
5
|
+
require 'monolith/locations/git'
|
6
|
+
|
7
|
+
class TestGitLocation < MiniTest::Test
|
8
|
+
|
9
|
+
def setup
|
10
|
+
# Path variables
|
11
|
+
@test_cookbook = "test_cookbook"
|
12
|
+
@test_base = File.expand_path('../tmp', __FILE__)
|
13
|
+
@mock_cache = File.join(@test_base, 'cache', @test_cookbook)
|
14
|
+
@mock_destination = File.join(@test_base, 'cloned', @test_cookbook)
|
15
|
+
@mock_origin = 'user@example.com:some/repo'
|
16
|
+
# Set up a repo to clone from rather than using the real berkshelf cache
|
17
|
+
# dir.
|
18
|
+
FileUtils.rm_rf(@test_base)
|
19
|
+
FileUtils.mkdir_p(@mock_cache)
|
20
|
+
Dir.chdir(@mock_cache) do
|
21
|
+
%x|git init|
|
22
|
+
%x|git remote add origin #{@mock_origin}|
|
23
|
+
end
|
24
|
+
# Don't print informational messages while testing
|
25
|
+
Monolith.formatter.quiet = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def teardown
|
29
|
+
FileUtils.rm_rf(@test_base)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_install
|
33
|
+
# Actually do the install
|
34
|
+
@mock_cookbook = Minitest::Mock.new
|
35
|
+
@mock_cookbook.expect :cookbook_name, @test_cookbook
|
36
|
+
@mock_dep = Minitest::Mock.new
|
37
|
+
@mock_dep.expect :location, nil
|
38
|
+
location = Monolith::GitLocation.new(@mock_cookbook, @mock_dep,
|
39
|
+
@mock_destination)
|
40
|
+
location.stub(:cache_path, @mock_cache) do
|
41
|
+
location.install
|
42
|
+
end
|
43
|
+
|
44
|
+
assert File.directory?(@mock_destination)
|
45
|
+
assert File.directory?(File.join(@mock_destination, '.git'))
|
46
|
+
assert_equal @mock_origin, location.send(:origin_url, @mock_destination)
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: berks-monolith
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Harrison
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: berkshelf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.5'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.5'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: minitest
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '5.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '5.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: pry
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0.10'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.10'
|
89
|
+
description: Tools for working with cookbooks as if they were inside a monolithic
|
90
|
+
repository
|
91
|
+
email:
|
92
|
+
- mark@mivok.net
|
93
|
+
executables:
|
94
|
+
- berks-monolith
|
95
|
+
extensions: []
|
96
|
+
extra_rdoc_files: []
|
97
|
+
files:
|
98
|
+
- ".gitignore"
|
99
|
+
- ".travis.yml"
|
100
|
+
- Gemfile
|
101
|
+
- LICENSE.txt
|
102
|
+
- README.md
|
103
|
+
- Rakefile
|
104
|
+
- berks-monolith.gemspec
|
105
|
+
- bin/berks-monolith
|
106
|
+
- lib/monolith.rb
|
107
|
+
- lib/monolith/berksfile.rb
|
108
|
+
- lib/monolith/commands.rb
|
109
|
+
- lib/monolith/formatter.rb
|
110
|
+
- lib/monolith/gitexclude.rb
|
111
|
+
- lib/monolith/locations/base.rb
|
112
|
+
- lib/monolith/locations/default.rb
|
113
|
+
- lib/monolith/locations/git.rb
|
114
|
+
- lib/monolith/locations/github.rb
|
115
|
+
- lib/monolith/locations/path.rb
|
116
|
+
- lib/monolith/version.rb
|
117
|
+
- test/.gitignore
|
118
|
+
- test/helpers.rb
|
119
|
+
- test/test_command_clean.rb
|
120
|
+
- test/test_command_install.rb
|
121
|
+
- test/test_command_update.rb
|
122
|
+
- test/test_gitlocation.rb
|
123
|
+
homepage: http://github.com/mivok/berks-monolith
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: 1.9.2
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 2.4.1
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: Berkshelf monolithic repository tools
|
147
|
+
test_files:
|
148
|
+
- test/.gitignore
|
149
|
+
- test/helpers.rb
|
150
|
+
- test/test_command_clean.rb
|
151
|
+
- test/test_command_install.rb
|
152
|
+
- test/test_command_update.rb
|
153
|
+
- test/test_gitlocation.rb
|
154
|
+
has_rdoc:
|