builderator 0.3.15 → 1.0.0.pre.rc.1

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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +440 -0
  4. data/README.md +72 -18
  5. data/Rakefile +1 -2
  6. data/VERSION +1 -1
  7. data/bin/build-clean +102 -0
  8. data/bin/build-data +45 -0
  9. data/builderator.gemspec +7 -4
  10. data/docs/configuration.md +154 -0
  11. data/docs/configuration/cookbook.md +19 -0
  12. data/docs/configuration/profile.md +71 -0
  13. data/docs/versioning.md +65 -0
  14. data/lib/builderator.rb +3 -0
  15. data/lib/builderator/config.rb +93 -0
  16. data/lib/builderator/config/attributes.rb +287 -0
  17. data/lib/builderator/config/defaults.rb +163 -0
  18. data/lib/builderator/config/file.rb +336 -0
  19. data/lib/builderator/config/rash.rb +80 -0
  20. data/lib/builderator/control/cleaner.rb +138 -0
  21. data/lib/builderator/control/cookbook.rb +16 -0
  22. data/lib/builderator/control/data.rb +16 -0
  23. data/lib/builderator/control/data/image.rb +98 -0
  24. data/lib/builderator/control/version.rb +128 -0
  25. data/lib/builderator/control/version/auto.rb +48 -0
  26. data/lib/builderator/control/version/bump.rb +82 -0
  27. data/lib/builderator/control/version/comparable.rb +77 -0
  28. data/lib/builderator/control/version/git.rb +45 -0
  29. data/lib/builderator/control/version/scm.rb +92 -0
  30. data/lib/builderator/interface.rb +67 -0
  31. data/lib/builderator/interface/berkshelf.rb +38 -0
  32. data/lib/builderator/interface/packer.rb +75 -0
  33. data/lib/builderator/interface/vagrant.rb +31 -0
  34. data/lib/builderator/metadata.rb +5 -3
  35. data/lib/builderator/model/cleaner.rb +49 -0
  36. data/lib/builderator/model/cleaner/images.rb +93 -0
  37. data/lib/builderator/model/cleaner/instances.rb +58 -0
  38. data/lib/builderator/model/cleaner/launch_configs.rb +47 -0
  39. data/lib/builderator/model/cleaner/scaling_groups.rb +45 -0
  40. data/lib/builderator/model/cleaner/snapshots.rb +50 -0
  41. data/lib/builderator/model/cleaner/volumes.rb +48 -0
  42. data/lib/builderator/patch/berkshelf.rb +18 -0
  43. data/lib/builderator/patch/thor-actions.rb +47 -0
  44. data/lib/builderator/tasks.rb +127 -17
  45. data/lib/builderator/tasks/berkshelf.rb +63 -0
  46. data/lib/builderator/tasks/packer.rb +17 -56
  47. data/lib/builderator/tasks/vagrant.rb +111 -42
  48. data/lib/builderator/tasks/vendor.rb +94 -0
  49. data/lib/builderator/tasks/version.rb +58 -0
  50. data/lib/builderator/util.rb +37 -11
  51. data/lib/builderator/util/aws_exception.rb +1 -1
  52. data/lib/builderator/util/limit_exception.rb +12 -11
  53. data/lib/builderator/util/task_exception.rb +0 -2
  54. data/mkmf.log +4 -0
  55. data/spec/config_spec.rb +30 -0
  56. data/spec/data/Berksfile +6 -0
  57. data/spec/data/Buildfile +0 -0
  58. data/spec/data/Vagrantfile +0 -0
  59. data/spec/data/history.json +483 -0
  60. data/spec/data/packer.json +0 -0
  61. data/spec/interface_spec.rb +36 -0
  62. data/spec/resource/Buildfile +27 -0
  63. data/spec/spec_helper.rb +90 -0
  64. data/spec/version_spec.rb +282 -0
  65. data/template/Berksfile.erb +10 -0
  66. data/template/Buildfile.erb +28 -0
  67. data/template/Gemfile.erb +16 -0
  68. data/template/README.md.erb +61 -0
  69. data/template/Vagrantfile.erb +75 -0
  70. data/template/gitignore.erb +104 -0
  71. data/{.rubocop.yml → template/rubocop.erb} +0 -0
  72. metadata +203 -56
  73. data/.gitignore +0 -14
  74. data/lib/builderator/control/ami.rb +0 -65
  75. data/lib/builderator/control/clean.rb +0 -130
  76. data/lib/builderator/model.rb +0 -46
  77. data/lib/builderator/model/images.rb +0 -89
  78. data/lib/builderator/model/instances.rb +0 -55
  79. data/lib/builderator/model/launch_configs.rb +0 -46
  80. data/lib/builderator/model/scaling_groups.rb +0 -43
  81. data/lib/builderator/model/snapshots.rb +0 -49
  82. data/lib/builderator/model/volumes.rb +0 -48
  83. data/lib/builderator/tasks/ami.rb +0 -47
  84. data/lib/builderator/tasks/berks.rb +0 -68
  85. data/lib/builderator/tasks/clean.rb +0 -97
  86. data/lib/builderator/util/berkshim.rb +0 -34
  87. data/lib/builderator/util/cookbook.rb +0 -87
  88. data/lib/builderator/util/packer.rb +0 -39
  89. 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