r10k 0.0.1rc1 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/r10k +13 -1
- data/lib/r10k.rb +1 -0
- data/lib/r10k/action.rb +7 -0
- data/lib/r10k/action/environment.rb +74 -0
- data/lib/r10k/action/module.rb +36 -0
- data/lib/r10k/cli.rb +9 -0
- data/lib/r10k/cli/{environment/cache.rb → cache.rb} +13 -4
- data/lib/r10k/cli/environment.rb +1 -3
- data/lib/r10k/cli/environment/deploy.rb +19 -17
- data/lib/r10k/cli/environment/stale.rb +34 -0
- data/lib/r10k/cli/module/deploy.rb +12 -12
- data/lib/r10k/cli/synchronize.rb +45 -0
- data/lib/r10k/deployment.rb +7 -4
- data/lib/r10k/{environment_collection.rb → deployment/environment_collection.rb} +20 -4
- data/lib/r10k/errors.rb +7 -0
- data/lib/r10k/logging.rb +49 -0
- data/lib/r10k/module/forge.rb +68 -3
- data/lib/r10k/synchro/git.rb +74 -34
- data/lib/r10k/version.rb +1 -1
- data/lib/semver.rb +124 -0
- metadata +71 -15
data/bin/r10k
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'r10k/cli'
|
4
|
+
require 'colored'
|
4
5
|
|
5
|
-
|
6
|
+
begin
|
7
|
+
R10K::CLI.command.run(ARGV)
|
8
|
+
rescue Interrupt
|
9
|
+
$stderr.puts "Aborted!".red
|
10
|
+
exit(1)
|
11
|
+
rescue SystemExit => e
|
12
|
+
exit(e.status)
|
13
|
+
rescue Exception => e
|
14
|
+
$stderr.puts "\nRuntime error: #{e.inspect}".red
|
15
|
+
$stderr.puts e.backtrace.join("\n").red if ARGV.include? '--trace'
|
16
|
+
exit(1)
|
17
|
+
end
|
data/lib/r10k.rb
CHANGED
data/lib/r10k/action.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'r10k/action'
|
2
|
+
require 'r10k/errors'
|
3
|
+
require 'r10k/action/module'
|
4
|
+
require 'r10k/deployment'
|
5
|
+
require 'r10k/logging'
|
6
|
+
|
7
|
+
require 'middleware'
|
8
|
+
|
9
|
+
module R10K::Action::Environment
|
10
|
+
|
11
|
+
class Deploy
|
12
|
+
# Middleware action to deploy an environment
|
13
|
+
|
14
|
+
include R10K::Logging
|
15
|
+
|
16
|
+
# @param [Object] app The next application in the middlware stack
|
17
|
+
# @param [R10K::Module] mod The module to deploy
|
18
|
+
def initialize(app, root)
|
19
|
+
@app, @root = app, root
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [Hash] env
|
23
|
+
#
|
24
|
+
# @option env [true, false] :update_cache
|
25
|
+
# @option env [true, false] :recurse
|
26
|
+
# @option env [true, false] :trace
|
27
|
+
def call(env)
|
28
|
+
@env = env
|
29
|
+
|
30
|
+
logger.notice "Deploying environment #{@root.name}"
|
31
|
+
FileUtils.mkdir_p @root.full_path
|
32
|
+
@root.sync! :update_cache => @env[:update_cache]
|
33
|
+
|
34
|
+
if @env[:recurse]
|
35
|
+
# Build a new middleware chain and run it
|
36
|
+
stack = Middleware::Builder.new
|
37
|
+
@root.modules.each { |mod| stack.use R10K::Action::Module::Deploy, mod }
|
38
|
+
stack.call(@env)
|
39
|
+
end
|
40
|
+
|
41
|
+
@app.call(@env)
|
42
|
+
rescue R10K::ExecutionFailure => e
|
43
|
+
logger.error "Could not synchronize #{@root.full_path}: #{e}".red
|
44
|
+
$stderr.puts e.backtrace.join("\n").red if @env[:trace]
|
45
|
+
@app.call(@env)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Purge
|
50
|
+
# Middleware action to purge stale environments from a directory
|
51
|
+
|
52
|
+
include R10K::Logging
|
53
|
+
|
54
|
+
# @param [Object] app The next application in the middlware stack
|
55
|
+
# @param [String] path The directory path to purge
|
56
|
+
def initialize(app, path)
|
57
|
+
@app, @path = app, path
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param [Hash] env
|
61
|
+
def call(env)
|
62
|
+
@env = env
|
63
|
+
|
64
|
+
stale_directories = R10K::Deployment.instance.collection.stale(@path)
|
65
|
+
|
66
|
+
stale_directories.each do |dir|
|
67
|
+
logger.notice "Purging stale environment #{dir.inspect}"
|
68
|
+
FileUtils.rm_rf(dir, :secure => true)
|
69
|
+
end
|
70
|
+
|
71
|
+
@app.call(@env)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'r10k/action'
|
2
|
+
require 'r10k/errors'
|
3
|
+
require 'r10k/logging'
|
4
|
+
|
5
|
+
require 'middleware'
|
6
|
+
|
7
|
+
module R10K::Action::Module
|
8
|
+
|
9
|
+
class R10K::Action::Module::Deploy
|
10
|
+
# Middleware to deploy a module
|
11
|
+
|
12
|
+
include R10K::Logging
|
13
|
+
|
14
|
+
# @param [Object] app The next application in the middlware stack
|
15
|
+
# @param [R10K::Module] mod The module to deploy
|
16
|
+
def initialize(app, mod)
|
17
|
+
@app, @mod = app, mod
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [Hash] env
|
21
|
+
#
|
22
|
+
# @option env [true, false] :update_cache
|
23
|
+
def call(env)
|
24
|
+
@env = env
|
25
|
+
|
26
|
+
logger.notice "Deploying module #{@mod.name}"
|
27
|
+
@mod.sync! :update_cache => @env[:update_cache]
|
28
|
+
|
29
|
+
@app.call(@env)
|
30
|
+
rescue R10K::ExecutionFailure => e
|
31
|
+
logger.error "Could not synchronize #{@mod.full_path}: #{e}".red
|
32
|
+
$stderr.puts e.backtrace.join("\n").red if @env[:trace]
|
33
|
+
@app.call(@env)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/r10k/cli.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'r10k'
|
2
|
+
require 'r10k/logging'
|
2
3
|
require 'cri'
|
3
4
|
|
4
5
|
module R10K::CLI
|
@@ -21,6 +22,12 @@ module R10K::CLI
|
|
21
22
|
R10K::Deployment.instance.configfile = value
|
22
23
|
end
|
23
24
|
|
25
|
+
required :v, :verbose, 'Set verbosity level' do |value, cmd|
|
26
|
+
R10K::Logging.level = Integer(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
flag :t, :trace, 'Display stack traces on application crash'
|
30
|
+
|
24
31
|
run do |opts, args, cmd|
|
25
32
|
puts cmd.help
|
26
33
|
exit 0
|
@@ -31,3 +38,5 @@ end
|
|
31
38
|
|
32
39
|
require 'r10k/cli/environment'
|
33
40
|
require 'r10k/cli/module'
|
41
|
+
require 'r10k/cli/cache'
|
42
|
+
require 'r10k/cli/synchronize'
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'r10k/cli
|
1
|
+
require 'r10k/cli'
|
2
2
|
require 'r10k/synchro/git'
|
3
3
|
require 'cri'
|
4
4
|
|
5
|
-
module R10K::CLI
|
5
|
+
module R10K::CLI
|
6
6
|
module Cache
|
7
7
|
def self.command
|
8
8
|
@cmd ||= Cri::Command.define do
|
@@ -11,8 +11,17 @@ module R10K::CLI::Environment
|
|
11
11
|
summary 'Update cache for all sources'
|
12
12
|
|
13
13
|
run do |opts, args, cmd|
|
14
|
-
R10K::Deployment.instance[:sources]
|
15
|
-
|
14
|
+
sources = R10K::Deployment.instance[:sources]
|
15
|
+
|
16
|
+
remotes = Set.new
|
17
|
+
|
18
|
+
sources.each_pair do |name, hash|
|
19
|
+
remotes << hash['remote']
|
20
|
+
end
|
21
|
+
|
22
|
+
remotes.each do |remote|
|
23
|
+
puts "Synchronizing #{remote}"
|
24
|
+
synchro = R10K::Synchro::Git.new(remote)
|
16
25
|
synchro.cache
|
17
26
|
end
|
18
27
|
end
|
data/lib/r10k/cli/environment.rb
CHANGED
@@ -9,8 +9,6 @@ module R10K::CLI
|
|
9
9
|
usage 'environment <subcommand>'
|
10
10
|
summary 'Operate on a specific environment'
|
11
11
|
|
12
|
-
required :e, :environment, 'Specify a particular environment'
|
13
|
-
|
14
12
|
run do |opts, args, cmd|
|
15
13
|
puts cmd.help
|
16
14
|
exit 0
|
@@ -23,4 +21,4 @@ end
|
|
23
21
|
|
24
22
|
require 'r10k/cli/environment/list'
|
25
23
|
require 'r10k/cli/environment/deploy'
|
26
|
-
require 'r10k/cli/environment/
|
24
|
+
require 'r10k/cli/environment/stale'
|
@@ -1,43 +1,45 @@
|
|
1
1
|
require 'r10k/cli/environment'
|
2
2
|
require 'r10k/deployment'
|
3
|
-
require '
|
3
|
+
require 'r10k/action'
|
4
4
|
|
5
|
-
require '
|
5
|
+
require 'cri'
|
6
|
+
require 'middleware'
|
6
7
|
|
7
8
|
module R10K::CLI::Environment
|
8
9
|
module Deploy
|
9
10
|
def self.command
|
10
11
|
@cmd ||= Cri::Command.define do
|
11
12
|
name 'deploy'
|
12
|
-
usage 'deploy'
|
13
|
+
usage 'deploy <environment> <...>'
|
13
14
|
summary 'Deploy an environment'
|
14
15
|
|
15
16
|
flag :r, :recurse, 'Recursively update submodules'
|
16
|
-
|
17
|
-
required :u, :update, "Enable or disable cache updating"
|
17
|
+
flag :u, :update, "Enable or disable cache updating"
|
18
18
|
|
19
19
|
run do |opts, args, cmd|
|
20
20
|
deployment = R10K::Deployment.instance
|
21
21
|
env_list = deployment.environments
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
if opts[:environment]
|
26
|
-
environments = env_list.select {|env| env.name == opts[:environment]}
|
23
|
+
if not args.empty?
|
24
|
+
environments = env_list.select {|env| args.include? env.name }
|
27
25
|
else
|
28
26
|
environments = env_list
|
29
27
|
end
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if opts[:recurse]
|
36
|
-
env.modules.each do |mod|
|
37
|
-
mod.sync! :update_cache => update_cache
|
38
|
-
end
|
29
|
+
stack = Middleware::Builder.new do
|
30
|
+
environments.each do |env|
|
31
|
+
use R10K::Action::Environment::Deploy, env
|
39
32
|
end
|
40
33
|
end
|
34
|
+
|
35
|
+
# Prepare middleware environment
|
36
|
+
stack_env = {
|
37
|
+
:update_cache => opts[:update],
|
38
|
+
:recurse => opts[:recurse],
|
39
|
+
:trace => opts[:trace],
|
40
|
+
}
|
41
|
+
|
42
|
+
stack.call(stack_env)
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'r10k/cli/environment'
|
2
|
+
require 'r10k/deployment'
|
3
|
+
require 'cri'
|
4
|
+
|
5
|
+
module R10K::CLI::Environment
|
6
|
+
module Stale
|
7
|
+
def self.command
|
8
|
+
@cmd ||= Cri::Command.define do
|
9
|
+
name 'stale'
|
10
|
+
usage 'stale <directory> [directory ...]'
|
11
|
+
summary 'List all stale environments'
|
12
|
+
|
13
|
+
run do |opts, args, cmd|
|
14
|
+
deployment = R10K::Deployment.instance
|
15
|
+
|
16
|
+
if args.empty?
|
17
|
+
$stderr.print "ERROR: ".red
|
18
|
+
$stderr.puts "#{cmd.name} requires one or more directories"
|
19
|
+
$stderr.puts cmd.help
|
20
|
+
exit(1)
|
21
|
+
end
|
22
|
+
|
23
|
+
args.each do |dir|
|
24
|
+
puts "Stale environments in #{dir}:"
|
25
|
+
output = deployment.collection.stale(dir).each do |stale_dir|
|
26
|
+
puts " - #{stale_dir}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
self.command.add_command(Stale.command)
|
34
|
+
end
|
@@ -9,10 +9,10 @@ module R10K::CLI::Module
|
|
9
9
|
def self.command
|
10
10
|
@cmd ||= Cri::Command.define do
|
11
11
|
name 'deploy'
|
12
|
-
usage 'deploy <module name>'
|
12
|
+
usage 'deploy [module name] <module name> ...'
|
13
13
|
summary 'Deploy a module'
|
14
14
|
|
15
|
-
|
15
|
+
flag :u, :update, "Update module cache"
|
16
16
|
|
17
17
|
run do |opts, args, cmd|
|
18
18
|
|
@@ -21,10 +21,7 @@ module R10K::CLI::Module
|
|
21
21
|
exit 1
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
env_list = deployment.environments
|
26
|
-
|
27
|
-
update_cache = (defined? opts[:update]) ? (opts[:update] == 'true') : false
|
24
|
+
env_list = R10K::Deployment.instance.environments
|
28
25
|
|
29
26
|
if opts[:environment]
|
30
27
|
environments = env_list.select {|env| env.name == opts[:environment]}
|
@@ -33,9 +30,6 @@ module R10K::CLI::Module
|
|
33
30
|
end
|
34
31
|
|
35
32
|
environments.each do |env|
|
36
|
-
FileUtils.mkdir_p env.full_path
|
37
|
-
env.sync! :update_cache => update_cache
|
38
|
-
|
39
33
|
mods = env.modules.select { |mod| mod.name == module_name }
|
40
34
|
|
41
35
|
if mods.empty?
|
@@ -43,9 +37,15 @@ module R10K::CLI::Module
|
|
43
37
|
exit 1
|
44
38
|
end
|
45
39
|
|
46
|
-
|
47
|
-
|
48
|
-
|
40
|
+
stack = Middleware::Builder.new
|
41
|
+
mods.each { |mod| stack.use R10K::Action::Module::Deploy, mod }
|
42
|
+
|
43
|
+
stack_env = {
|
44
|
+
:update_cache => opts[:update],
|
45
|
+
:trace => opts[:trace],
|
46
|
+
}
|
47
|
+
|
48
|
+
stack.call(stack_env)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'r10k/cli'
|
2
|
+
require 'r10k/deployment'
|
3
|
+
require 'r10k/action/environment'
|
4
|
+
|
5
|
+
require 'middleware'
|
6
|
+
require 'cri'
|
7
|
+
|
8
|
+
module R10K::CLI
|
9
|
+
module Synchronize
|
10
|
+
def self.command
|
11
|
+
@cmd ||= Cri::Command.define do
|
12
|
+
name 'synchronize'
|
13
|
+
usage 'synchronize <options>'
|
14
|
+
summary 'Fully synchronize all environments'
|
15
|
+
|
16
|
+
flag :u, :update, "Update cache before running"
|
17
|
+
|
18
|
+
run do |opts, args, cmd|
|
19
|
+
deployment = R10K::Deployment.instance
|
20
|
+
environments = deployment.environments
|
21
|
+
directories = (deployment.config[:purgedirs] || [])
|
22
|
+
|
23
|
+
stack = Middleware::Builder.new do
|
24
|
+
environments.each do |env|
|
25
|
+
use R10K::Action::Environment::Deploy, env
|
26
|
+
end
|
27
|
+
|
28
|
+
directories.each do |dir|
|
29
|
+
use R10K::Action::Environment::Purge, dir
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
stack_env = {
|
34
|
+
:update_cache => opts[:update],
|
35
|
+
:trace => opts[:trace],
|
36
|
+
:recurse => true,
|
37
|
+
}
|
38
|
+
|
39
|
+
stack.call(stack_env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
self.command.add_command(Synchronize.command)
|
45
|
+
end
|
data/lib/r10k/deployment.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'r10k'
|
2
2
|
require 'r10k/synchro/git'
|
3
|
-
require 'r10k/environment_collection'
|
3
|
+
require 'r10k/deployment/environment_collection'
|
4
4
|
require 'yaml'
|
5
5
|
|
6
6
|
class R10K::Deployment
|
@@ -21,10 +21,14 @@ class R10K::Deployment
|
|
21
21
|
#
|
22
22
|
# @return [Array<R10K::Root>]
|
23
23
|
def environments
|
24
|
-
collection = R10K::EnvironmentCollection.new(config)
|
25
24
|
collection.to_a
|
26
25
|
end
|
27
26
|
|
27
|
+
def collection
|
28
|
+
load_config unless @config
|
29
|
+
@collection
|
30
|
+
end
|
31
|
+
|
28
32
|
# Serve up the loaded config if it's already been loaded, otherwise try to
|
29
33
|
# load a config in the current wd.
|
30
34
|
def config
|
@@ -47,8 +51,6 @@ class R10K::Deployment
|
|
47
51
|
File.open(@configfile) { |fh| @config = YAML.load(fh.read) }
|
48
52
|
apply_config_settings
|
49
53
|
@config
|
50
|
-
rescue => e
|
51
|
-
raise "Couldn't load #{configfile}: #{e}"
|
52
54
|
end
|
53
55
|
|
54
56
|
# Apply config settings to the relevant classes after a config has been loaded.
|
@@ -56,5 +58,6 @@ class R10K::Deployment
|
|
56
58
|
if @config[:cachedir]
|
57
59
|
R10K::Synchro::Git.cache_root = @config[:cachedir]
|
58
60
|
end
|
61
|
+
@collection = R10K::EnvironmentCollection.new(@config)
|
59
62
|
end
|
60
63
|
end
|
@@ -4,15 +4,22 @@ class R10K::EnvironmentCollection
|
|
4
4
|
|
5
5
|
attr_reader :update_cache
|
6
6
|
|
7
|
-
def initialize(config, options = {:update_cache =>
|
7
|
+
def initialize(config, options = {:update_cache => false})
|
8
8
|
@config = config
|
9
9
|
@environments = []
|
10
10
|
|
11
11
|
@update_cache = options.delete(:update_cache)
|
12
|
-
|
13
12
|
load_all
|
14
13
|
end
|
15
14
|
|
15
|
+
def current(basedir)
|
16
|
+
basedir = File.expand_path(basedir)
|
17
|
+
tracked_envs = @environments.select do |env|
|
18
|
+
envdir = File.expand_path(env.basedir)
|
19
|
+
envdir == basedir
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
16
23
|
# List subdirectories that aren't associated with an env
|
17
24
|
#
|
18
25
|
# If a branch associated with an environment is deleted then the associated
|
@@ -23,8 +30,17 @@ class R10K::EnvironmentCollection
|
|
23
30
|
# @param [String] basedir The directory to scan
|
24
31
|
#
|
25
32
|
# @return [Array<String>] A list of filenames
|
26
|
-
def
|
27
|
-
|
33
|
+
def stale(basedir)
|
34
|
+
basedir = File.expand_path(basedir)
|
35
|
+
|
36
|
+
all_dirs = Dir.glob("#{basedir}/*").map do |file|
|
37
|
+
File.basename(file) if File.directory?(file)
|
38
|
+
end.compact
|
39
|
+
current_dirs = current(basedir).map(&:name)
|
40
|
+
|
41
|
+
stale_dirs = all_dirs - current_dirs
|
42
|
+
|
43
|
+
stale_dirs.map {|dir| File.join(basedir, dir)}
|
28
44
|
end
|
29
45
|
|
30
46
|
# @return [Array<R10K::Root>]
|
data/lib/r10k/errors.rb
ADDED
data/lib/r10k/logging.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'r10k'
|
2
|
+
|
3
|
+
require 'log4r'
|
4
|
+
require 'log4r/configurator'
|
5
|
+
|
6
|
+
module R10K::Logging
|
7
|
+
|
8
|
+
include Log4r
|
9
|
+
|
10
|
+
def logger
|
11
|
+
unless @logger
|
12
|
+
@logger = Log4r::Logger.new(self.class.name)
|
13
|
+
@logger.add R10K::Logging.outputter
|
14
|
+
end
|
15
|
+
@logger
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
include Log4r
|
21
|
+
def included(klass)
|
22
|
+
unless @log4r_loaded
|
23
|
+
Configurator.custom_levels(*%w{DEBUG2 DEBUG1 DEBUG INFO NOTICE WARN ERROR FATAL})
|
24
|
+
Logger.global.level = Log4r::ALL
|
25
|
+
@log4r_loaded = true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def level
|
30
|
+
@level || Log4r::WARN # Default level is WARN
|
31
|
+
end
|
32
|
+
|
33
|
+
def level=(val)
|
34
|
+
outputter.level = val
|
35
|
+
@level = val
|
36
|
+
end
|
37
|
+
|
38
|
+
def formatter
|
39
|
+
@formatter ||= Log4r::PatternFormatter.new(:pattern => '[%C - %l] %m')
|
40
|
+
end
|
41
|
+
|
42
|
+
def outputter
|
43
|
+
@outputter ||= Log4r::StderrOutputter.new('console',
|
44
|
+
:level => self.level,
|
45
|
+
:formatter => formatter
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/r10k/module/forge.rb
CHANGED
@@ -1,19 +1,84 @@
|
|
1
1
|
require 'r10k'
|
2
2
|
require 'r10k/module'
|
3
|
+
require 'r10k/errors'
|
4
|
+
require 'r10k/logging'
|
5
|
+
|
6
|
+
require 'systemu'
|
7
|
+
require 'semver'
|
8
|
+
require 'json'
|
3
9
|
|
4
10
|
class R10K::Module::Forge < R10K::Module
|
5
11
|
|
6
12
|
def self.implements(name, args)
|
7
|
-
args.is_a? String and args
|
13
|
+
args.is_a? String and SemVer.valid?(args)
|
8
14
|
end
|
9
15
|
|
16
|
+
include R10K::Logging
|
17
|
+
|
10
18
|
def initialize(name, path, args)
|
11
19
|
super
|
12
20
|
|
13
|
-
@
|
21
|
+
@full_name = name
|
22
|
+
|
23
|
+
@owner, @name = name.split('/')
|
24
|
+
@version = SemVer.new(@args)
|
14
25
|
end
|
15
26
|
|
16
27
|
def sync!(options = {})
|
17
|
-
|
28
|
+
return if insync?
|
29
|
+
|
30
|
+
if insync?
|
31
|
+
logger.debug1 "Module #{@full_name} already matches version #{@version}"
|
32
|
+
elsif File.exist? metadata_path
|
33
|
+
logger.debug "Module #{@full_name} is installed but doesn't match version #{@version}, upgrading"
|
34
|
+
cmd = []
|
35
|
+
cmd << 'upgrade'
|
36
|
+
cmd << "--version=#{@version}"
|
37
|
+
cmd << "--ignore-dependencies"
|
38
|
+
cmd << @full_name
|
39
|
+
pmt cmd
|
40
|
+
else
|
41
|
+
logger.debug "Module #{@full_name} is not installed"
|
42
|
+
cmd = []
|
43
|
+
cmd << 'install'
|
44
|
+
cmd << "--version=#{@version}"
|
45
|
+
cmd << "--ignore-dependencies"
|
46
|
+
cmd << @full_name
|
47
|
+
pmt cmd
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def current_version
|
54
|
+
SemVer.new(metadata['version'])
|
55
|
+
end
|
56
|
+
|
57
|
+
def insync?
|
58
|
+
@version == current_version
|
59
|
+
rescue
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def metadata
|
64
|
+
JSON.parse(File.read(metadata_path))
|
65
|
+
end
|
66
|
+
|
67
|
+
def metadata_path
|
68
|
+
File.join(full_path, 'metadata.json')
|
69
|
+
end
|
70
|
+
|
71
|
+
def pmt(args)
|
72
|
+
cmd = "puppet module --modulepath '#{@path}' #{args.join(' ')}"
|
73
|
+
logger.debug1 "Execute: #{cmd}"
|
74
|
+
status, stdout, stderr = systemu(cmd)
|
75
|
+
unless status == 0
|
76
|
+
e = R10K::ExecutionFailure.new("#{cmd.inspect} returned with non-zero exit value #{status.inspect}")
|
77
|
+
e.exit_code = status
|
78
|
+
e.stdout = stdout
|
79
|
+
e.stderr = stderr
|
80
|
+
raise e
|
81
|
+
end
|
82
|
+
stdout
|
18
83
|
end
|
19
84
|
end
|
data/lib/r10k/synchro/git.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'r10k'
|
2
|
-
require '
|
2
|
+
require 'r10k/errors'
|
3
|
+
require 'r10k/logging'
|
4
|
+
|
5
|
+
require 'systemu'
|
3
6
|
require 'fileutils'
|
4
7
|
|
5
8
|
module R10K::Synchro; end
|
@@ -39,6 +42,8 @@ class R10K::Synchro::Git
|
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
45
|
+
include R10K::Logging
|
46
|
+
|
42
47
|
attr_reader :remote
|
43
48
|
|
44
49
|
# Instantiates a new git synchro and optionally prepares for caching
|
@@ -48,7 +53,7 @@ class R10K::Synchro::Git
|
|
48
53
|
@remote = remote
|
49
54
|
|
50
55
|
if self.class.cache_root
|
51
|
-
@cache_path = File.join(self.class.cache_root, @remote.gsub(/[^@\w
|
56
|
+
@cache_path = File.join(self.class.cache_root, @remote.gsub(/[^@\w\.-]/, '-'))
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
@@ -69,7 +74,7 @@ class R10K::Synchro::Git
|
|
69
74
|
end
|
70
75
|
|
71
76
|
# @return [TrueClass] if the git repository is cached
|
72
|
-
def
|
77
|
+
def cached?
|
73
78
|
@cache_path and File.directory? @cache_path
|
74
79
|
end
|
75
80
|
|
@@ -94,10 +99,13 @@ class R10K::Synchro::Git
|
|
94
99
|
|
95
100
|
# Force a cache refresh
|
96
101
|
def cache!
|
97
|
-
if
|
98
|
-
|
102
|
+
if cached?
|
103
|
+
logger.debug "Updating existing cache at #{@cache_path}"
|
104
|
+
git "fetch --prune", :git_dir => @cache_path
|
99
105
|
else
|
100
|
-
|
106
|
+
logger.debug "No cache for #{@remote.inspect}, forcing cache build"
|
107
|
+
cache_root = self.class.cache_root
|
108
|
+
FileUtils.mkdir_p cache_root unless File.exist? cache_root
|
101
109
|
git "clone --mirror #{@remote} #{@cache_path}"
|
102
110
|
end
|
103
111
|
end
|
@@ -106,9 +114,9 @@ class R10K::Synchro::Git
|
|
106
114
|
# object.
|
107
115
|
#
|
108
116
|
# @return [Array<String>] A list of all cached remote branches
|
109
|
-
def branches
|
110
|
-
cache
|
111
|
-
output = git "
|
117
|
+
def branches(options = {:update_cache => false})
|
118
|
+
cache if (options[:update_cache] or not cached?)
|
119
|
+
output = git "branch", :git_dir => @cache_path
|
112
120
|
output.split("\n").map { |str| str[2..-1] }
|
113
121
|
end
|
114
122
|
|
@@ -121,8 +129,9 @@ class R10K::Synchro::Git
|
|
121
129
|
#
|
122
130
|
# @param [String] path The directory to create the repo working directory
|
123
131
|
def clone(path)
|
124
|
-
if
|
132
|
+
if cached?
|
125
133
|
git "clone --reference #{@cache_path} #{@remote} #{path}"
|
134
|
+
git "remote add cache #{@cache_path}", :path => path
|
126
135
|
else
|
127
136
|
FileUtils.mkdir_p path unless File.directory? path
|
128
137
|
git "clone #{@remote} #{path}"
|
@@ -130,10 +139,10 @@ class R10K::Synchro::Git
|
|
130
139
|
end
|
131
140
|
|
132
141
|
def fetch(path)
|
133
|
-
if
|
134
|
-
git "fetch --prune
|
142
|
+
if cached?
|
143
|
+
git "fetch --prune cache", :path => path
|
135
144
|
else
|
136
|
-
git "fetch --prune", path
|
145
|
+
git "fetch --prune origin", :path => path
|
137
146
|
end
|
138
147
|
end
|
139
148
|
|
@@ -142,45 +151,76 @@ class R10K::Synchro::Git
|
|
142
151
|
# @param [String] path The path to the working directory of the git repo
|
143
152
|
# @param [String] ref The git reference to reset to.
|
144
153
|
def reset(path, ref)
|
154
|
+
commit = resolve_commit(ref)
|
145
155
|
|
146
|
-
# Helloooo, hackery. Try to parse the ref as a commit object. If that fails
|
147
|
-
# this probably means that the ref is a remote branch. For the sake of
|
148
|
-
# brevity this code blindly makes that assumption on the failure of
|
149
|
-
# `git rev-parse`.
|
150
156
|
begin
|
151
|
-
|
152
|
-
rescue
|
153
|
-
commit
|
157
|
+
git "reset --hard #{commit}", :path => path
|
158
|
+
rescue R10K::ExecutionFailure => e
|
159
|
+
logger.error "Unable to locate commit object #{commit} in git repo #{path}"
|
160
|
+
raise
|
154
161
|
end
|
162
|
+
end
|
155
163
|
|
156
|
-
|
164
|
+
# Resolve a ref to a commit hash
|
165
|
+
#
|
166
|
+
# @param [String] ref
|
167
|
+
#
|
168
|
+
# @return [String] The dereferenced hash of `ref`
|
169
|
+
def resolve_commit(ref)
|
170
|
+
commit = git "rev-parse #{ref}^{commit}", :git_dir => @cache_path
|
171
|
+
commit.chomp
|
172
|
+
rescue R10K::ExecutionFailure => e
|
173
|
+
logger.error "Could not resolve ref #{ref.inspect} for git cache #{@cache_path}"
|
174
|
+
raise
|
157
175
|
end
|
158
176
|
|
159
177
|
# Wrap git commands
|
160
178
|
#
|
161
179
|
# @param [String] command_line_args The arguments for the git prompt
|
162
|
-
# @param [
|
180
|
+
# @param [Hash] opts
|
181
|
+
#
|
182
|
+
# @option opts [String] :git_dir
|
183
|
+
# @option opts [String] :work_tree
|
184
|
+
# @option opts [String] :work_tree
|
163
185
|
#
|
164
186
|
# @return [String] The git command output
|
165
|
-
def git(command_line_args,
|
166
|
-
args =
|
187
|
+
def git(command_line_args, opts = {})
|
188
|
+
args = %w{git}
|
167
189
|
|
168
|
-
|
169
|
-
|
170
|
-
|
190
|
+
log_event = "git #{command_line_args}"
|
191
|
+
log_event << ", args: #{opts.inspect}" unless opts.empty?
|
192
|
+
|
193
|
+
|
194
|
+
if opts[:path]
|
195
|
+
args << "--git-dir #{opts[:path]}/.git"
|
196
|
+
args << "--work-tree #{opts[:path]}"
|
197
|
+
else
|
198
|
+
if opts[:git_dir]
|
199
|
+
args << "--git-dir #{opts[:git_dir]}"
|
200
|
+
end
|
201
|
+
if opts[:work_tree]
|
202
|
+
args << "--work-tree #{opts[:work_tree]}"
|
203
|
+
end
|
171
204
|
end
|
172
205
|
|
173
|
-
|
206
|
+
logger.debug1 "Execute: '#{log_event}'"
|
174
207
|
|
175
|
-
|
176
|
-
|
208
|
+
args << command_line_args
|
209
|
+
cmd = args.join(' ')
|
177
210
|
|
178
|
-
stderr =
|
179
|
-
stdout = result.stdout.read
|
211
|
+
status, stdout, stderr = systemu(cmd)
|
180
212
|
|
181
|
-
|
182
|
-
|
213
|
+
logger.debug2 "[#{log_event}] STDOUT: #{stdout.chomp}" unless stdout.empty?
|
214
|
+
logger.debug2 "[#{log_event}] STDERR: #{stderr.chomp}" unless stderr.empty?
|
183
215
|
|
216
|
+
unless status == 0
|
217
|
+
msg = "#{cmd.inspect} returned with non-zero exit value #{status.exitstatus}"
|
218
|
+
e = R10K::ExecutionFailure.new(msg)
|
219
|
+
e.exit_code = status
|
220
|
+
e.stdout = stdout
|
221
|
+
e.stderr = stderr
|
222
|
+
raise e
|
223
|
+
end
|
184
224
|
stdout
|
185
225
|
end
|
186
226
|
end
|
data/lib/r10k/version.rb
CHANGED
data/lib/semver.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# Ripped off from puppetlabs/puppet
|
2
|
+
|
3
|
+
# We need to subclass Numeric to force range comparisons not to try to iterate over SemVer
|
4
|
+
# and instead use numeric comparisons (eg >, <, >=, <=)
|
5
|
+
# Ruby 1.8 already did this for all ranges, but Ruby 1.9 changed range include behavior
|
6
|
+
class SemVer < Numeric
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
VERSION = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z-]*|)$/
|
10
|
+
SIMPLE_RANGE = /^v?(\d+|[xX])(?:\.(\d+|[xX])(?:\.(\d+|[xX]))?)?$/
|
11
|
+
|
12
|
+
def self.valid?(ver)
|
13
|
+
VERSION =~ ver
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find_matching(pattern, versions)
|
17
|
+
versions.select { |v| v.matched_by?("#{pattern}") }.sort.last
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.pre(vstring)
|
21
|
+
vstring =~ /-/ ? vstring : vstring + '-'
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.[](range)
|
25
|
+
range.gsub(/([><=])\s+/, '\1').split(/\b\s+(?!-)/).map do |r|
|
26
|
+
case r
|
27
|
+
when SemVer::VERSION
|
28
|
+
SemVer.new(pre(r)) .. SemVer.new(r)
|
29
|
+
when SemVer::SIMPLE_RANGE
|
30
|
+
r += ".0" unless SemVer.valid?(r.gsub(/x/i, '0'))
|
31
|
+
SemVer.new(r.gsub(/x/i, '0'))...SemVer.new(r.gsub(/(\d+)\.x/i) { "#{$1.to_i + 1}.0" } + '-')
|
32
|
+
when /\s+-\s+/
|
33
|
+
a, b = r.split(/\s+-\s+/)
|
34
|
+
SemVer.new(pre(a)) .. SemVer.new(b)
|
35
|
+
when /^~/
|
36
|
+
ver = r.sub(/~/, '').split('.').map(&:to_i)
|
37
|
+
start = (ver + [0] * (3 - ver.length)).join('.')
|
38
|
+
|
39
|
+
ver.pop unless ver.length == 1
|
40
|
+
ver[-1] = ver.last + 1
|
41
|
+
|
42
|
+
finish = (ver + [0] * (3 - ver.length)).join('.')
|
43
|
+
SemVer.new(pre(start)) ... SemVer.new(pre(finish))
|
44
|
+
when /^>=/
|
45
|
+
ver = r.sub(/^>=/, '')
|
46
|
+
SemVer.new(pre(ver)) .. SemVer::MAX
|
47
|
+
when /^<=/
|
48
|
+
ver = r.sub(/^<=/, '')
|
49
|
+
SemVer::MIN .. SemVer.new(ver)
|
50
|
+
when /^>/
|
51
|
+
if r =~ /-/
|
52
|
+
ver = [r[1..-1]]
|
53
|
+
else
|
54
|
+
ver = r.sub(/^>/, '').split('.').map(&:to_i)
|
55
|
+
ver[2] = ver.last + 1
|
56
|
+
end
|
57
|
+
SemVer.new(ver.join('.') + '-') .. SemVer::MAX
|
58
|
+
when /^</
|
59
|
+
ver = r.sub(/^</, '')
|
60
|
+
SemVer::MIN ... SemVer.new(pre(ver))
|
61
|
+
else
|
62
|
+
(1..1)
|
63
|
+
end
|
64
|
+
end.inject { |a,e| a & e }
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :major, :minor, :tiny, :special
|
68
|
+
|
69
|
+
def initialize(ver)
|
70
|
+
unless SemVer.valid?(ver)
|
71
|
+
raise ArgumentError.new("Invalid version string '#{ver}'!")
|
72
|
+
end
|
73
|
+
|
74
|
+
@major, @minor, @tiny, @special = VERSION.match(ver).captures.map do |x|
|
75
|
+
# Because Kernel#Integer tries to interpret hex and octal strings, which
|
76
|
+
# we specifically do not want, and which cannot be overridden in 1.8.7.
|
77
|
+
Float(x).to_i rescue x
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def <=>(other)
|
82
|
+
other = SemVer.new("#{other}") unless other.is_a? SemVer
|
83
|
+
return self.major <=> other.major unless self.major == other.major
|
84
|
+
return self.minor <=> other.minor unless self.minor == other.minor
|
85
|
+
return self.tiny <=> other.tiny unless self.tiny == other.tiny
|
86
|
+
|
87
|
+
return 0 if self.special == other.special
|
88
|
+
return 1 if self.special == ''
|
89
|
+
return -1 if other.special == ''
|
90
|
+
|
91
|
+
return self.special <=> other.special
|
92
|
+
end
|
93
|
+
|
94
|
+
def matched_by?(pattern)
|
95
|
+
# For the time being, this is restricted to exact version matches and
|
96
|
+
# simple range patterns. In the future, we should implement some or all of
|
97
|
+
# the comparison operators here:
|
98
|
+
# https://github.com/isaacs/node-semver/blob/d474801/semver.js#L340
|
99
|
+
|
100
|
+
case pattern
|
101
|
+
when SIMPLE_RANGE
|
102
|
+
pattern = SIMPLE_RANGE.match(pattern).captures
|
103
|
+
pattern[1] = @minor unless pattern[1] && pattern[1] !~ /x/i
|
104
|
+
pattern[2] = @tiny unless pattern[2] && pattern[2] !~ /x/i
|
105
|
+
[@major, @minor, @tiny] == pattern.map { |x| x.to_i }
|
106
|
+
when VERSION
|
107
|
+
self == SemVer.new(pattern)
|
108
|
+
else
|
109
|
+
false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def inspect
|
114
|
+
@vstring || "v#{@major}.#{@minor}.#{@tiny}#{@special}"
|
115
|
+
end
|
116
|
+
alias :to_s :inspect
|
117
|
+
|
118
|
+
MIN = SemVer.new('0.0.0-')
|
119
|
+
MIN.instance_variable_set(:@vstring, 'vMIN')
|
120
|
+
|
121
|
+
MAX = SemVer.new('8.0.0')
|
122
|
+
MAX.instance_variable_set(:@major, (1.0/0)) # => Infinity
|
123
|
+
MAX.instance_variable_set(:@vstring, 'vMAX')
|
124
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: r10k
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
8
|
+
- Adrien Thebo
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: colored
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: cri
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -28,13 +44,13 @@ dependencies:
|
|
28
44
|
- !ruby/object:Gem::Version
|
29
45
|
version: 2.3.0
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
47
|
+
name: systemu
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
33
49
|
none: false
|
34
50
|
requirements:
|
35
51
|
- - ~>
|
36
52
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
53
|
+
version: 2.5.2
|
38
54
|
type: :runtime
|
39
55
|
prerelease: false
|
40
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,15 +58,15 @@ dependencies:
|
|
42
58
|
requirements:
|
43
59
|
- - ~>
|
44
60
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
61
|
+
version: 2.5.2
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
63
|
+
name: middleware
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
49
65
|
none: false
|
50
66
|
requirements:
|
51
67
|
- - ~>
|
52
68
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.1.
|
69
|
+
version: 0.1.0
|
54
70
|
type: :runtime
|
55
71
|
prerelease: false
|
56
72
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,30 +74,69 @@ dependencies:
|
|
58
74
|
requirements:
|
59
75
|
- - ~>
|
60
76
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.1.
|
77
|
+
version: 0.1.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: json
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.7.6
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.7.6
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: log4r
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.1.10
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.1.10
|
62
110
|
description: ! " R10K is an implementation of the Dynamic Puppet environments based
|
63
111
|
on git repositories\n as described in http://puppetlabs.com/blog/git-workflow-and-puppet-environments/.
|
64
112
|
It\n aggressively caches and tries to minimize network activity to ensure that
|
65
113
|
interactive\n deployment is as fast as possible.\n"
|
66
|
-
email:
|
114
|
+
email: adrien@somethingsinistral.net
|
67
115
|
executables:
|
68
116
|
- r10k
|
69
117
|
extensions: []
|
70
118
|
extra_rdoc_files: []
|
71
119
|
files:
|
72
120
|
- bin/r10k
|
73
|
-
- lib/r10k/
|
121
|
+
- lib/r10k/action/environment.rb
|
122
|
+
- lib/r10k/action/module.rb
|
123
|
+
- lib/r10k/action.rb
|
124
|
+
- lib/r10k/cli/cache.rb
|
74
125
|
- lib/r10k/cli/environment/deploy.rb
|
75
126
|
- lib/r10k/cli/environment/list.rb
|
127
|
+
- lib/r10k/cli/environment/stale.rb
|
76
128
|
- lib/r10k/cli/environment.rb
|
77
129
|
- lib/r10k/cli/module/deploy.rb
|
78
130
|
- lib/r10k/cli/module/list.rb
|
79
131
|
- lib/r10k/cli/module.rb
|
132
|
+
- lib/r10k/cli/synchronize.rb
|
80
133
|
- lib/r10k/cli.rb
|
134
|
+
- lib/r10k/deployment/environment_collection.rb
|
81
135
|
- lib/r10k/deployment.rb
|
82
|
-
- lib/r10k/
|
136
|
+
- lib/r10k/errors.rb
|
83
137
|
- lib/r10k/librarian/dsl.rb
|
84
138
|
- lib/r10k/librarian.rb
|
139
|
+
- lib/r10k/logging.rb
|
85
140
|
- lib/r10k/module/forge.rb
|
86
141
|
- lib/r10k/module/git.rb
|
87
142
|
- lib/r10k/module.rb
|
@@ -90,6 +145,7 @@ files:
|
|
90
145
|
- lib/r10k/util/interp.rb
|
91
146
|
- lib/r10k/version.rb
|
92
147
|
- lib/r10k.rb
|
148
|
+
- lib/semver.rb
|
93
149
|
homepage: http://github.com/adrienthebo/r10k
|
94
150
|
licenses: []
|
95
151
|
post_install_message:
|
@@ -105,9 +161,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
162
|
none: false
|
107
163
|
requirements:
|
108
|
-
- - ! '
|
164
|
+
- - ! '>='
|
109
165
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
166
|
+
version: '0'
|
111
167
|
requirements: []
|
112
168
|
rubyforge_project:
|
113
169
|
rubygems_version: 1.8.23
|