kozo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ # Kozo
2
+
3
+ ![Continuous Integration](https://github.com/floriandejonckheere/kozo/workflows/Continuous%20Integration/badge.svg)
4
+ ![Release](https://img.shields.io/github/v/release/floriandejonckheere/kozo?label=Latest%20release)
5
+
6
+ _Kōzō_ (構造) is an open-source tool to manage your cloud resources based on the [infrastructure as code](https://en.wikipedia.org/wiki/Infrastructure_as_code) principle.
7
+ It leverages the power of [Ruby](https://www.ruby-lang.org/en/) to allow you to declare your infrastructure in your favourite language.
8
+
9
+ ## Release
10
+
11
+ Update the changelog and bump the version using the `bin/version` tool.
12
+ Run `bin/version --help` to see all parameters.
13
+ Create a git tag for the version and push it to Github.
14
+ A Ruby gem will automatically be built and pushed to the [RubyGems](https://www.rubygems.org/).
15
+
16
+ ```sh
17
+ bin/version version 1.0.0
18
+ git add lib/kozo/version.rb
19
+ git commit -m "Bump version to v1.0.0"
20
+ git tag v1.0.0
21
+ git push origin master
22
+ git push origin v1.0.0
23
+ ```
24
+
25
+ ## License
26
+
27
+ See [LICENSE.md](LICENSE.md).
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
9
+ rescue LoadError
10
+ puts "RSpec not available."
11
+ end
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+
28
+ bundler_version = nil
29
+ update_index = nil
30
+ ARGV.each_with_index do |a, i|
31
+ bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
32
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/o
33
+
34
+ bundler_version = Regexp.last_match(1)
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../Gemfile", __dir__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+
59
+ lockfile_contents = File.read(lockfile)
60
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/o
61
+
62
+ Regexp.last_match(1)
63
+ end
64
+
65
+ def bundler_version
66
+ @bundler_version ||=
67
+ env_var_version || cli_arg_version ||
68
+ lockfile_version
69
+ end
70
+
71
+ def bundler_requirement
72
+ return "#{Gem::Requirement.default}.a" unless bundler_version
73
+
74
+ bundler_gem_version = Gem::Version.new(bundler_version)
75
+
76
+ requirement = bundler_gem_version.approximate_recommendation
77
+
78
+ return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
79
+
80
+ requirement += ".a" if bundler_gem_version.prerelease?
81
+
82
+ requirement
83
+ end
84
+
85
+ def load_bundler!
86
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
87
+
88
+ activate_bundler
89
+ end
90
+
91
+ def activate_bundler
92
+ gem_error = activation_error_handling do
93
+ gem "bundler", bundler_requirement
94
+ end
95
+ return if gem_error.nil?
96
+
97
+ require_error = activation_error_handling do
98
+ require "bundler/version"
99
+ end
100
+ if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
101
+ return
102
+ end
103
+
104
+ warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
105
+ exit 42
106
+ end
107
+
108
+ def activation_error_handling
109
+ yield
110
+ nil
111
+ rescue StandardError, LoadError => e
112
+ e
113
+ end
114
+ end
115
+
116
+ m.load_bundler!
117
+
118
+ load Gem.bin_path("bundler", "bundle") if m.invoked_as_script?
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../config/application"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../config/application"
5
+
6
+ require "kozo"
7
+ require "byebug"
8
+
9
+ Kozo::CLI.new(ARGV).start
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath)
13
+
14
+ bundle_binstub = File.expand_path("bundle", __dir__)
15
+
16
+ if File.file?(bundle_binstub)
17
+ if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
18
+ load(bundle_binstub)
19
+ else
20
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
21
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
22
+ end
23
+ end
24
+
25
+ require "rubygems"
26
+ require "bundler/setup"
27
+
28
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../config/application"
5
+
6
+ FILE = Kozo.root.join("lib/kozo/version.rb")
7
+
8
+ def usage(error: false)
9
+ puts "Usage: #{$PROGRAM_NAME} [major [VERSION] | minor [VERSION] | patch [VERSION] | pre VERSION]"
10
+ puts " #{$PROGRAM_NAME} major\t\tIncrement major version number"
11
+ puts " #{$PROGRAM_NAME} major VERSION\tSet major version number"
12
+ puts " #{$PROGRAM_NAME} minor\t\tIncrement minor version number"
13
+ puts " #{$PROGRAM_NAME} minor VERSION\tSet minor version number"
14
+ puts " #{$PROGRAM_NAME} patch\t\tIncrement patch version number"
15
+ puts " #{$PROGRAM_NAME} patch VERSION\tSet patch version number"
16
+ puts " #{$PROGRAM_NAME} pre\t\tClear pre version number"
17
+ puts " #{$PROGRAM_NAME} pre VERSION\tSet pre version number"
18
+ puts " #{$PROGRAM_NAME} version VERSION\tSet entire version number"
19
+
20
+ exit 1 if error
21
+ end
22
+
23
+ def bump(hash)
24
+ hash.each do |level, version|
25
+ File.write FILE, File.read(FILE).gsub(/#{level}( +)= [^\n]*/) { "#{level}#{$LAST_MATCH_INFO[1]}= #{version}" }
26
+ end
27
+
28
+ silence_warnings { load FILE }
29
+
30
+ File.write FILE_JS, File.read(FILE_JS).gsub(/"version": "[^"]*"/) { "\"version\": \"#{Kozo::VERSION}\"" }
31
+ end
32
+
33
+ case ARGV.shift&.to_sym
34
+ when nil
35
+ # Print version
36
+ puts "v#{Kozo::VERSION}"
37
+ when :version
38
+ usage(error: true) unless ARGV.any?
39
+
40
+ version, pre = ARGV.shift.split("-")
41
+ major, minor, patch = version.split(".")
42
+
43
+ bump MAJOR: major, MINOR: minor, PATCH: patch, PRE: (pre ? "\"#{pre}\"" : "nil")
44
+ puts "Setting version to #{Kozo::VERSION}"
45
+ when :major
46
+ # Bump major version
47
+ bump MAJOR: (ARGV.pop || Kozo::Version::MAJOR + 1), MINOR: 0, PATCH: 0, PRE: "nil"
48
+ puts "Bumping version to #{Kozo::VERSION}"
49
+ when :minor
50
+ # Bump minor version
51
+ bump MINOR: (ARGV.pop || Kozo::Version::MINOR + 1), PATCH: 0, PRE: "nil"
52
+ puts "Bumping version to #{Kozo::VERSION}"
53
+ when :patch
54
+ # Bump patch version
55
+ bump PATCH: (ARGV.pop || Kozo::Version::PATCH + 1), PRE: "nil"
56
+ puts "Bumping version to #{Kozo::VERSION}"
57
+ when :pre
58
+ # Set or clear patch version
59
+ bump PRE: (ARGV.any? ? "\"#{ARGV.shift}\"" : "nil")
60
+ else
61
+ usage
62
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.join(__dir__, "..", "lib"))
4
+
5
+ require "bundler/setup"
6
+ require "kozo"
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Backends
5
+ #
6
+ register("backend.local") do |directory|
7
+ Kozo::Backends::Local.new(directory)
8
+ end
9
+
10
+ ##
11
+ # Null provider
12
+ #
13
+ register("provider.null") do
14
+ Kozo::Providers::Null::Provider.new
15
+ end
16
+
17
+ register("resource.null") do
18
+ Kozo::Providers::Null::Resources::Null.new
19
+ end
20
+
21
+ ##
22
+ # HCloud
23
+ #
24
+ register("provider.hcloud") do
25
+ Kozo::Providers::HCloud::Provider.new
26
+ end
27
+
28
+ register("resource.hcloud_ssh_key") do
29
+ Kozo::Providers::HCloud::Resources::SSHKey.new
30
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ loader.inflector.inflect(
4
+ "cli" => "CLI",
5
+ "dsl" => "DSL",
6
+ "hcloud" => "HCloud",
7
+ "ssh_key" => "SSHKey",
8
+ )
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/kozo/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "kozo"
7
+ spec.version = Kozo::VERSION
8
+ spec.authors = ["Florian Dejonckheere"]
9
+ spec.email = ["florian@floriandejonckheere.be"]
10
+
11
+ spec.summary = "Declarative cloud infrastructure"
12
+ spec.description = "Declaratively create, modify and destroy cloud infrastructure in your favourite language"
13
+ spec.homepage = "http://github.com/floriandejonckheere/kozo"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.2")
16
+
17
+ spec.metadata["source_code_uri"] = "https://github.com/floriandejonckheere/kozo"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "bin"
25
+ spec.executables = spec.files.grep(%r(^bin/)) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_runtime_dependency "activesupport"
29
+ spec.add_runtime_dependency "zeitwerk"
30
+
31
+ spec.add_development_dependency "rubocop"
32
+ spec.add_development_dependency "rubocop-performance"
33
+ spec.add_development_dependency "rubocop-rspec"
34
+
35
+ spec.add_development_dependency "climate_control"
36
+ spec.add_development_dependency "factory_bot"
37
+ spec.add_development_dependency "ffaker"
38
+ spec.add_development_dependency "overcommit"
39
+ spec.add_development_dependency "pry-byebug"
40
+ spec.add_development_dependency "rspec", "~> 3.10"
41
+ spec.add_development_dependency "shoulda-matchers"
42
+ spec.add_development_dependency "super_diff"
43
+ spec.add_development_dependency "timecop"
44
+ spec.add_development_dependency "webmock"
45
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeitwerk"
4
+ require "active_support/all"
5
+
6
+ module Kozo
7
+ class << self
8
+ attr_reader :loader
9
+
10
+ def root
11
+ @root ||= Pathname.new(File.expand_path(File.join("..", ".."), __FILE__))
12
+ end
13
+
14
+ def options
15
+ @options ||= Options.new
16
+ end
17
+
18
+ def container
19
+ @container ||= Container.new
20
+ end
21
+
22
+ def env
23
+ @env ||= Environment.new
24
+ end
25
+
26
+ def logger
27
+ @logger ||= Logger.new
28
+ end
29
+
30
+ def setup
31
+ @loader = Zeitwerk::Loader.for_gem
32
+
33
+ instance_eval(File.read(root.join("config/inflections.rb")))
34
+
35
+ loader.enable_reloading
36
+ loader.setup
37
+ loader.eager_load
38
+
39
+ container.instance_eval(File.read(root.join("config/dependencies.rb")))
40
+ end
41
+ end
42
+ end
43
+
44
+ def reload!
45
+ Kozo.loader.reload
46
+ end
47
+
48
+ Kozo.setup
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kozo
4
+ module Backends
5
+ class Base
6
+ attr_accessor :directory
7
+
8
+ def initialize(directory)
9
+ @directory = directory
10
+ end
11
+
12
+ def providers
13
+ state.fetch(:providers)
14
+ end
15
+
16
+ def resources
17
+ state.fetch(:resources)
18
+ end
19
+
20
+ protected
21
+
22
+ def state
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def state=(_value)
27
+ raise NotImplementedError
28
+ end
29
+ end
30
+ end
31
+ end