builderator 0.3.15 → 1.0.0.pre.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +9 -0
- data/Gemfile.lock +440 -0
- data/README.md +72 -18
- data/Rakefile +1 -2
- data/VERSION +1 -1
- data/bin/build-clean +102 -0
- data/bin/build-data +45 -0
- data/builderator.gemspec +7 -4
- data/docs/configuration.md +154 -0
- data/docs/configuration/cookbook.md +19 -0
- data/docs/configuration/profile.md +71 -0
- data/docs/versioning.md +65 -0
- data/lib/builderator.rb +3 -0
- data/lib/builderator/config.rb +93 -0
- data/lib/builderator/config/attributes.rb +287 -0
- data/lib/builderator/config/defaults.rb +163 -0
- data/lib/builderator/config/file.rb +336 -0
- data/lib/builderator/config/rash.rb +80 -0
- data/lib/builderator/control/cleaner.rb +138 -0
- data/lib/builderator/control/cookbook.rb +16 -0
- data/lib/builderator/control/data.rb +16 -0
- data/lib/builderator/control/data/image.rb +98 -0
- data/lib/builderator/control/version.rb +128 -0
- data/lib/builderator/control/version/auto.rb +48 -0
- data/lib/builderator/control/version/bump.rb +82 -0
- data/lib/builderator/control/version/comparable.rb +77 -0
- data/lib/builderator/control/version/git.rb +45 -0
- data/lib/builderator/control/version/scm.rb +92 -0
- data/lib/builderator/interface.rb +67 -0
- data/lib/builderator/interface/berkshelf.rb +38 -0
- data/lib/builderator/interface/packer.rb +75 -0
- data/lib/builderator/interface/vagrant.rb +31 -0
- data/lib/builderator/metadata.rb +5 -3
- data/lib/builderator/model/cleaner.rb +49 -0
- data/lib/builderator/model/cleaner/images.rb +93 -0
- data/lib/builderator/model/cleaner/instances.rb +58 -0
- data/lib/builderator/model/cleaner/launch_configs.rb +47 -0
- data/lib/builderator/model/cleaner/scaling_groups.rb +45 -0
- data/lib/builderator/model/cleaner/snapshots.rb +50 -0
- data/lib/builderator/model/cleaner/volumes.rb +48 -0
- data/lib/builderator/patch/berkshelf.rb +18 -0
- data/lib/builderator/patch/thor-actions.rb +47 -0
- data/lib/builderator/tasks.rb +127 -17
- data/lib/builderator/tasks/berkshelf.rb +63 -0
- data/lib/builderator/tasks/packer.rb +17 -56
- data/lib/builderator/tasks/vagrant.rb +111 -42
- data/lib/builderator/tasks/vendor.rb +94 -0
- data/lib/builderator/tasks/version.rb +58 -0
- data/lib/builderator/util.rb +37 -11
- data/lib/builderator/util/aws_exception.rb +1 -1
- data/lib/builderator/util/limit_exception.rb +12 -11
- data/lib/builderator/util/task_exception.rb +0 -2
- data/mkmf.log +4 -0
- data/spec/config_spec.rb +30 -0
- data/spec/data/Berksfile +6 -0
- data/spec/data/Buildfile +0 -0
- data/spec/data/Vagrantfile +0 -0
- data/spec/data/history.json +483 -0
- data/spec/data/packer.json +0 -0
- data/spec/interface_spec.rb +36 -0
- data/spec/resource/Buildfile +27 -0
- data/spec/spec_helper.rb +90 -0
- data/spec/version_spec.rb +282 -0
- data/template/Berksfile.erb +10 -0
- data/template/Buildfile.erb +28 -0
- data/template/Gemfile.erb +16 -0
- data/template/README.md.erb +61 -0
- data/template/Vagrantfile.erb +75 -0
- data/template/gitignore.erb +104 -0
- data/{.rubocop.yml → template/rubocop.erb} +0 -0
- metadata +203 -56
- data/.gitignore +0 -14
- data/lib/builderator/control/ami.rb +0 -65
- data/lib/builderator/control/clean.rb +0 -130
- data/lib/builderator/model.rb +0 -46
- data/lib/builderator/model/images.rb +0 -89
- data/lib/builderator/model/instances.rb +0 -55
- data/lib/builderator/model/launch_configs.rb +0 -46
- data/lib/builderator/model/scaling_groups.rb +0 -43
- data/lib/builderator/model/snapshots.rb +0 -49
- data/lib/builderator/model/volumes.rb +0 -48
- data/lib/builderator/tasks/ami.rb +0 -47
- data/lib/builderator/tasks/berks.rb +0 -68
- data/lib/builderator/tasks/clean.rb +0 -97
- data/lib/builderator/util/berkshim.rb +0 -34
- data/lib/builderator/util/cookbook.rb +0 -87
- data/lib/builderator/util/packer.rb +0 -39
- data/lib/builderator/util/shell.rb +0 -44
@@ -0,0 +1,48 @@
|
|
1
|
+
module Builderator
|
2
|
+
module Control
|
3
|
+
class Version
|
4
|
+
##
|
5
|
+
# Search through commits since current version for #TYPE tags
|
6
|
+
#
|
7
|
+
# Included in Version
|
8
|
+
##
|
9
|
+
module Auto
|
10
|
+
DEFAULT_TYPE = 'patch'.freeze
|
11
|
+
MESSAGE_KEYWORDS = /#(?<type>build|prerelease|release|patch\-prerelease|patch|minor\-prerelease|minor|major\-prerelease|major)(?:=(?<prerelease>[a-zA-Z0-9\-_]+))?/
|
12
|
+
|
13
|
+
def auto_type
|
14
|
+
fail 'Version-bump type `auto` is unsuppoeted for this SCM. Version does not'\
|
15
|
+
' have a valid `ref` value' if ref.nil?
|
16
|
+
|
17
|
+
## Get commits since self.ref (e.g. commits since this tag)
|
18
|
+
history_since_current = SCM.history.take_while do |commit|
|
19
|
+
commit.id != ref
|
20
|
+
end
|
21
|
+
|
22
|
+
## Search for the highest-precedence #TAG in those commit messages
|
23
|
+
## Search from oldest-to-newest. Newer #TAGs of equal precedence win
|
24
|
+
result = history_since_current.reverse.reduce(nil) do |highest, commit|
|
25
|
+
## Not going to bother parsing multiple matches. If you're
|
26
|
+
## putting more than one #TYPE in your commit message, you
|
27
|
+
## deserve what you get...
|
28
|
+
found_type = commit.message.scan(MESSAGE_KEYWORDS).first
|
29
|
+
|
30
|
+
## No #TYPE in message
|
31
|
+
next highest if found_type.nil?
|
32
|
+
|
33
|
+
## First match
|
34
|
+
next found_type if highest.nil?
|
35
|
+
|
36
|
+
## Retrun higher precedence release type
|
37
|
+
RELEASE_TYPES[found_type.first.to_s] <= RELEASE_TYPES[highest.first.to_s] ? found_type : highest
|
38
|
+
end
|
39
|
+
|
40
|
+
return ['prerelease', nil] if result.nil? && is_prerelease
|
41
|
+
return [DEFAULT_TYPE, nil] if result.nil?
|
42
|
+
|
43
|
+
result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Builderator
|
2
|
+
module Control
|
3
|
+
class Version
|
4
|
+
##
|
5
|
+
# Increment version's parameters by specified steps
|
6
|
+
#
|
7
|
+
# Included in Version
|
8
|
+
##
|
9
|
+
module Bump
|
10
|
+
def bump(type = 'auto', prerelease_name = nil) # rubocop:disable Metrics/PerceivedComplexity
|
11
|
+
## Grok commits since current for a #TYPE string
|
12
|
+
type, prerelease_name = auto_type if type.to_s == 'auto'
|
13
|
+
|
14
|
+
fail "Unrecognized release type #{type}" unless RELEASE_TYPES.include?(type.to_s)
|
15
|
+
type_num = RELEASE_TYPES[type.to_s]
|
16
|
+
|
17
|
+
##
|
18
|
+
# Reset lower-precendence parameters to nil/0
|
19
|
+
##
|
20
|
+
self.build = nil if type_num < RELEASE_TYPES['build']
|
21
|
+
|
22
|
+
## Clear pre-release flags
|
23
|
+
if type_num < RELEASE_TYPES['prerelease']
|
24
|
+
self.is_prerelease = false
|
25
|
+
self.prerelease_name = nil
|
26
|
+
self.prerelease_iteration = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
self.patch = 0 if type_num < RELEASE_TYPES['patch']
|
30
|
+
self.minor = 0 if type_num < RELEASE_TYPES['minor']
|
31
|
+
self.major = 0 if type_num < RELEASE_TYPES['major']
|
32
|
+
|
33
|
+
## Set new version's ref
|
34
|
+
self.ref = SCM.history.first.id
|
35
|
+
|
36
|
+
##
|
37
|
+
# Increment specified parameters
|
38
|
+
##
|
39
|
+
case type.to_s
|
40
|
+
when 'build'
|
41
|
+
if build.nil?
|
42
|
+
self.build = 0
|
43
|
+
else
|
44
|
+
self.build += 1
|
45
|
+
end
|
46
|
+
|
47
|
+
when 'prerelease'
|
48
|
+
## Start a prerelease train from a new patch version
|
49
|
+
## if it doesn't already exist
|
50
|
+
self.patch += 1 unless is_prerelease
|
51
|
+
prerelease(prerelease_name)
|
52
|
+
|
53
|
+
when 'release'
|
54
|
+
## Remove pre-release parameters from the current patch
|
55
|
+
## (already done above ^^)
|
56
|
+
|
57
|
+
when 'patch-prerelease'
|
58
|
+
## Force a new pre-release train from a new patch version
|
59
|
+
self.patch += 1
|
60
|
+
prerelease(prerelease_name)
|
61
|
+
|
62
|
+
when 'patch' then self.patch += 1
|
63
|
+
|
64
|
+
when 'minor-prerelease'
|
65
|
+
self.minor += 1
|
66
|
+
prerelease(prerelease_name)
|
67
|
+
|
68
|
+
when 'minor' then self.minor += 1
|
69
|
+
|
70
|
+
when 'major-prerelease'
|
71
|
+
self.major += 1
|
72
|
+
prerelease(prerelease_name)
|
73
|
+
|
74
|
+
when 'major' then self.major += 1
|
75
|
+
end
|
76
|
+
|
77
|
+
self
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Builderator
|
2
|
+
module Control
|
3
|
+
class Version
|
4
|
+
##
|
5
|
+
# Sort earliest -> latest
|
6
|
+
# (Array.last -> latest (e.g. 1.0.0), Array.first -> earliest(e.g. 0.0.1))
|
7
|
+
##
|
8
|
+
module Comparable
|
9
|
+
include ::Comparable
|
10
|
+
|
11
|
+
def <=>(other)
|
12
|
+
## Simple version comparison
|
13
|
+
return major <=> other.major unless same?(:major, other)
|
14
|
+
return minor <=> other.minor unless same?(:minor, other)
|
15
|
+
return patch <=> other.patch unless same?(:patch, other)
|
16
|
+
|
17
|
+
## Prereleases: prerelease < non-prerelease
|
18
|
+
return compare(:is_prerelease, other) if one?(:is_prerelease, other)
|
19
|
+
|
20
|
+
if both?(:is_prerelease, other)
|
21
|
+
## This is a little sketchy... We're assuming that pre-releases
|
22
|
+
## have a lexicological order.
|
23
|
+
return prerelease_name <=> other.prerelease_name unless same?(:prerelease_name, other)
|
24
|
+
return prerelease_iteration <=> other.prerelease_iteration unless same?(:prerelease_iteration, other)
|
25
|
+
end
|
26
|
+
|
27
|
+
## Build number. With build number > without build number
|
28
|
+
compare(:build, other)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
## this == that
|
34
|
+
def same?(parameter, other)
|
35
|
+
send(parameter) == other.send(parameter)
|
36
|
+
end
|
37
|
+
|
38
|
+
## this && that
|
39
|
+
def both?(parameter, other)
|
40
|
+
send(parameter) && other.send(parameter)
|
41
|
+
end
|
42
|
+
|
43
|
+
## this ^ that (XOR)
|
44
|
+
def one?(parameter, other)
|
45
|
+
(send(parameter)) ^ (other.send(parameter))
|
46
|
+
end
|
47
|
+
|
48
|
+
## this || that
|
49
|
+
def either?(parameter, other)
|
50
|
+
send(parameter) || other.send(parameter)
|
51
|
+
end
|
52
|
+
|
53
|
+
## !(this || that)
|
54
|
+
def neither?(parameter, other)
|
55
|
+
!either?(parameter, other)
|
56
|
+
end
|
57
|
+
|
58
|
+
## Compare with support for `nil` values
|
59
|
+
def compare(parameter, other)
|
60
|
+
a = send(parameter)
|
61
|
+
b = other.send(parameter)
|
62
|
+
|
63
|
+
## NilClass, TrueClass, and FalseClass' <=> operators return nil
|
64
|
+
return a <=> b unless a.nil? || b.nil? ||
|
65
|
+
a.is_a?(TrueClass) || b.is_a?(TrueClass) ||
|
66
|
+
a.is_a?(FalseClass) || b.is_a?(FalseClass)
|
67
|
+
|
68
|
+
return 1 if a && !b
|
69
|
+
return -1 if !a && b
|
70
|
+
|
71
|
+
## a && b || !a && !b
|
72
|
+
0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative './scm'
|
2
|
+
require_relative '../../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
module Control
|
6
|
+
# :nodoc:
|
7
|
+
class Version
|
8
|
+
##
|
9
|
+
# SCM implementation for Git
|
10
|
+
##
|
11
|
+
module Git
|
12
|
+
extend SCM
|
13
|
+
|
14
|
+
COMMIT_FORMAT = /^(?<hash>[a-f0-9]+)(?:\s+\((?<tags>.+?)\))?\s+(?<message>.+)$/
|
15
|
+
TAG_FORMAT = %r{tag: ([a-zA-Z0-9\.\-\+/_]+)}
|
16
|
+
|
17
|
+
## Is there a .git repo in the project root?
|
18
|
+
def self.supported?
|
19
|
+
Util.relative_path('.git').exist?
|
20
|
+
end
|
21
|
+
|
22
|
+
def self._history
|
23
|
+
`git log --pretty='format:%H %d %s' HEAD`.chomp
|
24
|
+
.split("\n")
|
25
|
+
.map { |string| string.match(COMMIT_FORMAT) }
|
26
|
+
.reject(&:nil?)
|
27
|
+
.map do |commit|
|
28
|
+
{
|
29
|
+
:id => commit[:hash],
|
30
|
+
:message => commit[:message]
|
31
|
+
}.tap do |c|
|
32
|
+
tag_match = commit[:tags].scan(TAG_FORMAT)
|
33
|
+
.flatten
|
34
|
+
.reject(&:nil?) unless commit[:tags].nil?
|
35
|
+
|
36
|
+
c[:tags] = tag_match unless tag_match.nil? || tag_match.empty?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
SCM.register(Git)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Builderator
|
2
|
+
module Control
|
3
|
+
class Version
|
4
|
+
##
|
5
|
+
# Generic SCM interface
|
6
|
+
##
|
7
|
+
module SCM
|
8
|
+
## Fetch and cache history for the current HEAD/TIP
|
9
|
+
def history
|
10
|
+
@history ||= _history.map { |commit| Commit.new(commit) }
|
11
|
+
end
|
12
|
+
|
13
|
+
## Find all tags in the branch's history
|
14
|
+
def tags
|
15
|
+
@tags ||= _tags
|
16
|
+
.map { |tag, ref| Version.from_string(tag, :ref => ref) }
|
17
|
+
.sort
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# OVERRIDE: Return true if this provider will work for `path`
|
22
|
+
##
|
23
|
+
def supported?
|
24
|
+
fail 'Method `supported?` must be implemented in SCM providers!'
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# OVERRIDE: Return an array of hashes with keys
|
29
|
+
# - id -> SCM commit identity
|
30
|
+
# - message -> SCM commit message
|
31
|
+
# - tags -> nil or an array of strings
|
32
|
+
##
|
33
|
+
def _history
|
34
|
+
fail 'Method `_history` must be implemented in SCM providers!'
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# OVERRIDE: Return an array of [tag, commit-id] tuples
|
39
|
+
##
|
40
|
+
def _tags
|
41
|
+
history.reject { |commit| commit.tags.empty? }
|
42
|
+
.map { |commit| commit.tags.map { |tag| [tag, commit.id] } }
|
43
|
+
.each_with_object([]) { |commit, tags| tags.push(*commit) }
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def history
|
48
|
+
provider.history
|
49
|
+
end
|
50
|
+
|
51
|
+
def tags
|
52
|
+
provider.tags
|
53
|
+
end
|
54
|
+
|
55
|
+
def register(klass)
|
56
|
+
fail 'Provider module must extend '\
|
57
|
+
'Builderator::Control::Version::SCM' unless
|
58
|
+
klass.singleton_class.include?(SCM)
|
59
|
+
|
60
|
+
## Make newer providers override those with the same capability
|
61
|
+
providers.unshift(klass)
|
62
|
+
end
|
63
|
+
|
64
|
+
def providers
|
65
|
+
@providers ||= []
|
66
|
+
end
|
67
|
+
|
68
|
+
## Find a version provider for this build
|
69
|
+
def provider
|
70
|
+
providers.find(&:supported?).tap do |found|
|
71
|
+
fail 'Builderator::Control::Version: '\
|
72
|
+
'Unsupported SCM' if found.nil?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
## An SCM commit entity
|
78
|
+
class Commit
|
79
|
+
attr_reader :id
|
80
|
+
attr_reader :message
|
81
|
+
attr_reader :tags
|
82
|
+
|
83
|
+
def initialize(match)
|
84
|
+
@id = match[:id]
|
85
|
+
@message = match[:message]
|
86
|
+
@tags = match.fetch(:tags, [])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
require_relative './config/attributes'
|
6
|
+
require_relative './config/rash'
|
7
|
+
require_relative './util'
|
8
|
+
|
9
|
+
module Builderator
|
10
|
+
##
|
11
|
+
# Base class for integration interfaces
|
12
|
+
##
|
13
|
+
class Interface
|
14
|
+
class << self
|
15
|
+
def command(arg = nil)
|
16
|
+
@command = arg unless arg.nil?
|
17
|
+
@command
|
18
|
+
end
|
19
|
+
|
20
|
+
def from_gem(arg = nil)
|
21
|
+
@from_gem = arg unless arg.nil?
|
22
|
+
@from_gem || @command
|
23
|
+
end
|
24
|
+
|
25
|
+
def template(arg = nil)
|
26
|
+
@template = arg unless arg.nil?
|
27
|
+
@template
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
## Is vagrant in this bundle?
|
32
|
+
def bundled?
|
33
|
+
Gem.loaded_specs.key?(self.class.from_gem)
|
34
|
+
end
|
35
|
+
|
36
|
+
def which
|
37
|
+
return self.class.command if bundled?
|
38
|
+
|
39
|
+
## Not in the bundle. Use system path
|
40
|
+
`which #{self.class.command}`.chomp.tap { |path| fail "Unable to locate a #{self.class.command} executable" if path.empty? }
|
41
|
+
end
|
42
|
+
alias_method :command, :which
|
43
|
+
|
44
|
+
def directory
|
45
|
+
Util.workspace
|
46
|
+
end
|
47
|
+
|
48
|
+
def render
|
49
|
+
ERB.new(Util.source_path(self.class.template).binread,
|
50
|
+
nil, '-', '@output_buffer').result(Config.instance_eval('binding'))
|
51
|
+
end
|
52
|
+
|
53
|
+
def source
|
54
|
+
fail 'Interface does not provide a source!'
|
55
|
+
end
|
56
|
+
|
57
|
+
def write
|
58
|
+
directory.mkpath
|
59
|
+
source.write(render)
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def clean
|
64
|
+
source.unlink
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../interface'
|
2
|
+
require_relative '../util'
|
3
|
+
|
4
|
+
module Builderator
|
5
|
+
# :nodoc:
|
6
|
+
class Interface
|
7
|
+
class << self
|
8
|
+
def berkshelf
|
9
|
+
@berkshelf ||= Berkshelf.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Render an updated Berksfile
|
15
|
+
##
|
16
|
+
class Berkshelf < Interface
|
17
|
+
from_gem 'berkshelf'
|
18
|
+
command 'berks'
|
19
|
+
template 'template/Berksfile.erb'
|
20
|
+
|
21
|
+
def vendor
|
22
|
+
Config.local.cookbook_path
|
23
|
+
end
|
24
|
+
|
25
|
+
def lockfile
|
26
|
+
Util.workspace('Berksfile.lock')
|
27
|
+
end
|
28
|
+
|
29
|
+
def berkshelf_config
|
30
|
+
Config.cookbook.berkshelf_config
|
31
|
+
end
|
32
|
+
|
33
|
+
def source
|
34
|
+
directory.join('Berksfile')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|