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.
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