horatio 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.rubocop.yml +169 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +25 -0
  6. data/Gemfile +10 -0
  7. data/Guardfile +10 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +73 -0
  10. data/Rakefile +13 -0
  11. data/bin/horatio +33 -0
  12. data/horatio.gemspec +30 -0
  13. data/lib/horatio.rb +64 -0
  14. data/lib/horatio/detector.rb +14 -0
  15. data/lib/horatio/detector/docker.rb +39 -0
  16. data/lib/horatio/detector/dynamic.rb +33 -0
  17. data/lib/horatio/detector/io_handler.rb +44 -0
  18. data/lib/horatio/detector/json_reader.rb +15 -0
  19. data/lib/horatio/detector/json_writer.rb +26 -0
  20. data/lib/horatio/detector/maven.rb +48 -0
  21. data/lib/horatio/detector/node_package.rb +30 -0
  22. data/lib/horatio/detector/null_writer.rb +11 -0
  23. data/lib/horatio/detector/rubygem.rb +32 -0
  24. data/lib/horatio/detector/validator.rb +20 -0
  25. data/lib/horatio/helper/vcs.rb +12 -0
  26. data/lib/horatio/releaser.rb +45 -0
  27. data/lib/horatio/vcs.rb +11 -0
  28. data/lib/horatio/vcs/git.rb +41 -0
  29. data/lib/horatio/vcs/subversion.rb +23 -0
  30. data/lib/horatio/version.rb +3 -0
  31. data/spec/fixtures/dynamic +10 -0
  32. data/spec/fixtures/package.json +105 -0
  33. data/spec/fixtures/pom.xml +822 -0
  34. data/spec/fixtures/test.gemspec +32 -0
  35. data/spec/horatio/detector/docker_spec.rb +30 -0
  36. data/spec/horatio/detector/dynamic_spec.rb +19 -0
  37. data/spec/horatio/detector/maven_spec.rb +27 -0
  38. data/spec/horatio/detector/node_package_spec.rb +19 -0
  39. data/spec/horatio/detector/rubygem_spec.rb +28 -0
  40. data/spec/horatio/releaser_spec.rb +25 -0
  41. data/spec/horatio/vcs/git_spec.rb +22 -0
  42. data/spec/horatio/vcs/subversion_spec.rb +15 -0
  43. data/spec/spec_helper.rb +12 -0
  44. data/spec/support/fixture_copy.rb +28 -0
  45. data/spec/support/reporters.rb +3 -0
  46. metadata +232 -0
@@ -0,0 +1,14 @@
1
+ require "horatio/detector/docker"
2
+ require "horatio/detector/rubygem"
3
+ require "horatio/detector/maven"
4
+ require "horatio/detector/node_package"
5
+ require "horatio/detector/dynamic"
6
+
7
+ module Horatio
8
+ module Detector
9
+ def self.detect
10
+ detected = [Dynamic, Docker, Maven, RubyGem, NodePackage].detect { |d| d.detect }
11
+ detected ? detected.new : raise("couldn't detect a supported project type, takes docker, maven, gem, horatio")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ require 'json'
2
+
3
+ require 'horatio/detector/validator'
4
+ require 'horatio/detector/json_reader'
5
+ require 'horatio/detector/json_writer'
6
+ require 'horatio/detector/io_handler'
7
+
8
+ module Horatio
9
+ module Detector
10
+ class Docker
11
+ include Validator
12
+ include IOHandler
13
+ include JSONReader
14
+ include JSONWriter
15
+
16
+ def default_input
17
+ 'horatio.json'
18
+ end
19
+
20
+ def default_output
21
+ 'horatio.json'
22
+ end
23
+
24
+ def default_commit
25
+ true
26
+ end
27
+
28
+ def info
29
+ memo_read do
30
+ JSON.parse(File.open(input, 'r').read)
31
+ end
32
+ end
33
+
34
+ def description
35
+ 'horatio.json'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ require 'json'
2
+
3
+ require 'horatio/detector/validator'
4
+ require 'horatio/detector/json_reader'
5
+ require 'horatio/detector/io_handler'
6
+ require 'horatio/detector/null_writer'
7
+
8
+ module Horatio
9
+ module Detector
10
+ class Dynamic
11
+ include Validator
12
+ include IOHandler
13
+ include JSONReader
14
+ include NULLWritter
15
+
16
+ def default_input
17
+ 'horatio'
18
+ end
19
+
20
+ def info
21
+ memo_read do
22
+ out = `./#{input}`
23
+ raise StandardError, "dynamic horatio exec failed: #{out}" unless out
24
+ JSON.parse(out)
25
+ end
26
+ end
27
+
28
+ def description
29
+ 'dynamic Horatio data generator'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ module Horatio
2
+ module Detector
3
+ module IOHandler
4
+ module ClassMethods
5
+ def detect
6
+ new.detect
7
+ end
8
+ end
9
+
10
+ attr_reader :input, :output
11
+
12
+ def default_input
13
+ 'horatio.json'
14
+ end
15
+
16
+ def default_output
17
+ 'horatio.json'
18
+ end
19
+
20
+ def initialize(input: nil, output: nil)
21
+ @input = input || default_input
22
+ @output = output || default_output
23
+ @info = {}
24
+ @read = false
25
+ end
26
+
27
+ def detect
28
+ File.exists?(@input) ? true : nil
29
+ end
30
+
31
+ def memo_read
32
+ return @info if @read
33
+ return unless block_given?
34
+ @info = yield
35
+ @read = true
36
+ @info
37
+ end
38
+
39
+ def self.included(base)
40
+ base.extend(ClassMethods)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ require 'json'
2
+
3
+ module Horatio
4
+ module Detector
5
+ module JSONReader
6
+ def name
7
+ info['name']
8
+ end
9
+
10
+ def version
11
+ info['version']
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ require 'json'
2
+
3
+ module Horatio
4
+ module Detector
5
+ module JSONWriter
6
+ def increment(releaser)
7
+ increment_version
8
+ if ENV['DRY_RUN']
9
+ color { Log.info "dry run: would've saved updated #{output}" }
10
+ return
11
+ end
12
+ color { Log.info "saving updated #{output}" }
13
+ File.open(output, 'w') { |f| f.write(JSON.pretty_generate(info)) } unless ENV['DRY_RUN']
14
+ releaser.vcs.commit(output)
15
+ end
16
+
17
+ def increment_version
18
+ parts = info['version'].split('.')
19
+ parts[-1] = parts[-1].to_i + 1
20
+ version = parts.join('.')
21
+ color { Log.info "incrementing version from #{info['version']} to #{version}"}
22
+ info['version'] = version
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,48 @@
1
+ require 'nori'
2
+
3
+ require 'horatio/detector/validator'
4
+ require 'horatio/detector/io_handler'
5
+ require 'horatio/detector/null_writer'
6
+
7
+ module Horatio
8
+ module Detector
9
+ class Maven
10
+ include Validator
11
+ include IOHandler
12
+
13
+ def default_input
14
+ 'pom.xml'
15
+ end
16
+
17
+ def info
18
+ memo_read do
19
+ File.open('pom.xml', 'r') { |f| Nori.new.parse(f.read) }
20
+ end
21
+ end
22
+
23
+ def name
24
+ info['project']['artifactId']
25
+ end
26
+
27
+ ##
28
+ # Maven version reader
29
+ #
30
+ # We need to decrease the number if we see SNAPSHOT, this is becasue
31
+ # maven increments it in anticipation for the next build
32
+ #
33
+ def version
34
+ version = info['project']['version'] || info['project']['parent']['version']
35
+ return version unless version =~ /-SNAPSHOT$/
36
+ version = version.split('-')[0]
37
+ version = version.split('.')
38
+ minor = version.last.to_i > 1 ? version.last.to_i - 1 : version.last
39
+ version[-1] = minor
40
+ version.join('.')
41
+ end
42
+
43
+ def description
44
+ 'JAVA Maven pom.xml'
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+
3
+ require 'horatio/detector/validator'
4
+ require 'horatio/detector/json_reader'
5
+ require 'horatio/detector/null_writer'
6
+
7
+ module Horatio
8
+ module Detector
9
+ class NodePackage
10
+ include Validator
11
+ include IOHandler
12
+ include JSONReader
13
+ include NULLWritter
14
+
15
+ def default_input
16
+ 'package.json'
17
+ end
18
+
19
+ def info
20
+ memo_read do
21
+ File.open(input, 'r') { |f| JSON.parse(f.read) }
22
+ end
23
+ end
24
+
25
+ def description
26
+ 'Node.js package.json'
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ require 'json'
2
+
3
+ module Horatio
4
+ module Detector
5
+ module NULLWritter
6
+ def increment(_release)
7
+ color { Log.info "skipping incrementation of version number, we rely on the #{description} for that" }
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ require 'horatio/detector/validator'
2
+ require 'horatio/detector/null_writer'
3
+
4
+ module Horatio
5
+ module Detector
6
+ class RubyGem
7
+ include Validator
8
+ include NULLWritter
9
+
10
+ def initialize
11
+ File.open(Dir.glob('*.gemspec').first, 'r') { |f| @spec_file = f.read }
12
+ end
13
+
14
+ def self.detect
15
+ Dir.glob('*.gemspec').any?
16
+ end
17
+
18
+ def name
19
+ @spec_file.match(/spec\.name.*$/i).to_s.split('=')[1].strip.gsub(/[\'\"\\]/, '')
20
+ end
21
+
22
+ def version
23
+ File.open(Dir.glob('lib/**/version.rb').first, 'rb') { |f| @version_file = f.read }
24
+ @version_file.match(/(\d.)+\d/).to_s.strip.gsub(/[\'\"\\]/, '')
25
+ end
26
+
27
+ def description
28
+ 'Ruby gemspec'
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ module Horatio
2
+ module Detector
3
+ module Validator
4
+ def validate_name
5
+ color { Log.info "validating passed in name"}
6
+ name.match(/^[\w\-\.]*$/i) ? true : raise("name specified using invalid format")
7
+ end
8
+
9
+ def validate_version
10
+ color { Log.info "validating passed in version"}
11
+ version.match(/^(\d+.)+\d+/i) ? true : raise("version specified using invalid format")
12
+ end
13
+
14
+ def validate
15
+ validate_version
16
+ validate_name
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Horatio
2
+ module Helper
3
+ # Version Control Systems Helper
4
+ module VCS
5
+
6
+ def initialize(options={})
7
+ @options = options
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ require 'json'
2
+
3
+ module Horatio
4
+ class Releaser
5
+
6
+ attr_accessor :release, :vcs
7
+
8
+ def initialize(options={})
9
+ @options = options
10
+ @registry = @options['registry']
11
+ @release = Horatio::Detector.detect
12
+ color { Log.info "detected #{@release.description}" }
13
+ @vcs = Horatio::VCS.detect(@options)
14
+ end
15
+
16
+ def generate_artifact
17
+ contents = JSON.pretty_generate({'name' => @release.name,
18
+ 'version' => "#{@release.version}-#{@vcs.latest_revision}",
19
+ 'app_version' => @release.version,
20
+ 'source_revision' => @vcs.latest_revision,
21
+ 'url' => "#{@registry}/#{@release.name}:#{@release.version}-#{@vcs.latest_revision}"})
22
+
23
+ File.open('docker-image.json', 'w') { |f | f.write(contents); }
24
+ end
25
+
26
+ def run
27
+ color { Log.info "Running Docker build for #{@release.name}-#{@release.version}" }
28
+
29
+ @release.validate
30
+
31
+ color { Log.info "latest revision is #{@vcs.latest_revision }" }
32
+
33
+ no_cache = ENV['DOCKER_BUILD_NO_CACHE'] ? "--no-cache " : ""
34
+
35
+ run_sh "docker build " + no_cache + "-t #{@registry}/#{@release.name}:#{@release.version}-#{@vcs.latest_revision} ."
36
+ run_sh "docker push #{@registry}/#{@release.name}"
37
+
38
+ generate_artifact
39
+
40
+ @release.increment(self)
41
+
42
+ return true
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ require 'horatio/vcs/git'
2
+ require 'horatio/vcs/subversion'
3
+
4
+ module Horatio
5
+ module VCS
6
+ def self.detect(options={})
7
+ vcs = [Git, Subversion].detect { |d| d.detect }
8
+ vcs ? vcs.new(options) : abort('No VCS detected (git/subversion)')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ require "open3"
2
+ require "horatio/helper/vcs"
3
+
4
+ module Horatio
5
+ module VCS
6
+ class Git
7
+
8
+ include Horatio::Helper::VCS
9
+
10
+ def self.detect
11
+ sh('git rev-parse HEAD').last.exitstatus == 0
12
+ end
13
+
14
+ def latest_revision
15
+ sh('git rev-parse --short HEAD').first.strip
16
+ end
17
+
18
+ def commit(file)
19
+ color { Log.info "Adding remote before pushing verion update: #{remote_url}" }
20
+ sh "git remote rm horatio &> /dev/null"
21
+ run_sh "git remote add horatio #{remote_url}"
22
+ run_sh "git commit -m 'image release' #{file}"
23
+ run_sh "git push horatio master"
24
+ end
25
+
26
+ def remote_url
27
+ begin
28
+ url = @options.fetch('git-repo-url')
29
+ rescue => e
30
+ color(ERROR) { Log.error "Since Horatio 1.0 you must specify a remote repo URL when building a docker only / horatio build" }
31
+ color(ERROR) { Log.error "If you see this message update your build to look like the following example: 'horatio --git-repo-url http://github.com/test/test.git'" }
32
+
33
+ raise e
34
+ end
35
+
36
+ url
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ require 'horatio/helper/vcs'
2
+
3
+ module Horatio
4
+ module VCS
5
+ class Subversion
6
+
7
+ include Horatio::Helper::VCS
8
+
9
+ def self.detect
10
+ ['.svn', '.subversion'].any? { |f| File.exist?(f) }
11
+ end
12
+
13
+ def latest_revision
14
+ sh('svnversion').first.strip.split(':')[0]
15
+ end
16
+
17
+ def commit(file)
18
+ run_sh "svn commit -m 'image release' #{file}"
19
+ end
20
+
21
+ end
22
+ end
23
+ end