kuby-core 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +1 -0
  4. data/README.md +4 -2
  5. data/kuby-core.gemspec +2 -1
  6. data/lib/kuby-core.rb +1 -0
  7. data/lib/kuby.rb +7 -0
  8. data/lib/kuby/basic_logger.rb +1 -0
  9. data/lib/kuby/cli_base.rb +1 -0
  10. data/lib/kuby/commands.rb +1 -0
  11. data/lib/kuby/definition.rb +1 -0
  12. data/lib/kuby/dev_setup.rb +1 -0
  13. data/lib/kuby/docker.rb +3 -0
  14. data/lib/kuby/docker/alpine.rb +16 -12
  15. data/lib/kuby/docker/assets_phase.rb +5 -0
  16. data/lib/kuby/docker/bundler_phase.rb +36 -2
  17. data/lib/kuby/docker/cli.rb +36 -2
  18. data/lib/kuby/docker/copy_phase.rb +11 -3
  19. data/lib/kuby/docker/credentials.rb +1 -0
  20. data/lib/kuby/docker/debian.rb +14 -10
  21. data/lib/kuby/docker/dev_spec.rb +82 -18
  22. data/lib/kuby/docker/distro.rb +43 -0
  23. data/lib/kuby/docker/dockerfile.rb +66 -18
  24. data/lib/kuby/docker/errors.rb +8 -0
  25. data/lib/kuby/docker/inline_layer.rb +7 -0
  26. data/lib/kuby/docker/layer.rb +11 -0
  27. data/lib/kuby/docker/layer_stack.rb +43 -6
  28. data/lib/kuby/docker/local_tags.rb +23 -2
  29. data/lib/kuby/docker/metadata.rb +35 -7
  30. data/lib/kuby/docker/package_list.rb +22 -3
  31. data/lib/kuby/docker/package_phase.rb +25 -5
  32. data/lib/kuby/docker/packages.rb +1 -0
  33. data/lib/kuby/docker/packages/managed_package.rb +20 -2
  34. data/lib/kuby/docker/packages/nodejs.rb +8 -0
  35. data/lib/kuby/docker/packages/package.rb +15 -1
  36. data/lib/kuby/docker/packages/simple_managed_package.rb +10 -1
  37. data/lib/kuby/docker/packages/yarn.rb +14 -0
  38. data/lib/kuby/docker/remote_tags.rb +21 -2
  39. data/lib/kuby/docker/setup_phase.rb +35 -4
  40. data/lib/kuby/docker/spec.rb +89 -13
  41. data/lib/kuby/docker/tags.rb +37 -2
  42. data/lib/kuby/docker/timestamp_tag.rb +14 -2
  43. data/lib/kuby/docker/webserver_phase.rb +40 -5
  44. data/lib/kuby/docker/yarn_phase.rb +5 -0
  45. data/lib/kuby/environment.rb +4 -0
  46. data/lib/kuby/kubernetes.rb +1 -0
  47. data/lib/kuby/kubernetes/deploy_task.rb +1 -0
  48. data/lib/kuby/kubernetes/deployer.rb +1 -0
  49. data/lib/kuby/kubernetes/docker_config.rb +1 -0
  50. data/lib/kuby/kubernetes/docker_desktop_provider.rb +1 -0
  51. data/lib/kuby/kubernetes/errors.rb +1 -0
  52. data/lib/kuby/kubernetes/manifest.rb +1 -0
  53. data/lib/kuby/kubernetes/provider.rb +1 -0
  54. data/lib/kuby/kubernetes/registry_secret.rb +1 -0
  55. data/lib/kuby/kubernetes/spec.rb +1 -0
  56. data/lib/kuby/middleware.rb +1 -0
  57. data/lib/kuby/middleware/health_check.rb +1 -0
  58. data/lib/kuby/plugin.rb +1 -0
  59. data/lib/kuby/plugin_registry.rb +1 -0
  60. data/lib/kuby/plugins.rb +1 -0
  61. data/lib/kuby/plugins/nginx_ingress.rb +1 -0
  62. data/lib/kuby/plugins/rails_app.rb +1 -0
  63. data/lib/kuby/plugins/rails_app/asset_copy_task.rb +1 -0
  64. data/lib/kuby/plugins/rails_app/assets.rb +1 -0
  65. data/lib/kuby/plugins/rails_app/database.rb +9 -7
  66. data/lib/kuby/plugins/rails_app/generators/kuby.rb +43 -40
  67. data/lib/kuby/plugins/rails_app/mysql.rb +1 -0
  68. data/lib/kuby/plugins/rails_app/plugin.rb +10 -5
  69. data/lib/kuby/plugins/rails_app/postgres.rb +1 -0
  70. data/lib/kuby/plugins/rails_app/rewrite_db_config.rb +1 -0
  71. data/lib/kuby/plugins/rails_app/sqlite.rb +1 -0
  72. data/lib/kuby/rails_commands.rb +1 -0
  73. data/lib/kuby/railtie.rb +1 -0
  74. data/lib/kuby/tasks.rb +1 -0
  75. data/lib/kuby/trailing_hash.rb +5 -3
  76. data/lib/kuby/version.rb +3 -1
  77. data/spec/docker/metadata_spec.rb +1 -0
  78. data/spec/docker/spec_spec.rb +37 -0
  79. data/spec/docker/timestamp_tag_spec.rb +1 -0
  80. data/spec/dummy/app/channels/application_cable/channel.rb +1 -0
  81. data/spec/dummy/app/channels/application_cable/connection.rb +1 -0
  82. data/spec/dummy/app/controllers/application_controller.rb +1 -0
  83. data/spec/dummy/app/helpers/application_helper.rb +1 -0
  84. data/spec/dummy/app/jobs/application_job.rb +1 -0
  85. data/spec/dummy/app/mailers/application_mailer.rb +1 -0
  86. data/spec/dummy/app/models/application_record.rb +1 -0
  87. data/spec/dummy/config/application.rb +1 -0
  88. data/spec/dummy/config/boot.rb +1 -0
  89. data/spec/dummy/config/environment.rb +1 -0
  90. data/spec/dummy/config/environments/development.rb +1 -0
  91. data/spec/dummy/config/environments/production.rb +1 -0
  92. data/spec/dummy/config/environments/test.rb +1 -0
  93. data/spec/dummy/config/initializers/application_controller_renderer.rb +1 -0
  94. data/spec/dummy/config/initializers/assets.rb +1 -0
  95. data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
  96. data/spec/dummy/config/initializers/content_security_policy.rb +1 -0
  97. data/spec/dummy/config/initializers/cookies_serializer.rb +1 -0
  98. data/spec/dummy/config/initializers/filter_parameter_logging.rb +1 -0
  99. data/spec/dummy/config/initializers/inflections.rb +1 -0
  100. data/spec/dummy/config/initializers/mime_types.rb +1 -0
  101. data/spec/dummy/config/initializers/wrap_parameters.rb +1 -0
  102. data/spec/dummy/config/puma.rb +1 -0
  103. data/spec/dummy/config/routes.rb +1 -0
  104. data/spec/dummy/config/spring.rb +1 -0
  105. data/spec/dummy/db/seeds.rb +1 -0
  106. data/spec/dummy/test/application_system_test_case.rb +1 -0
  107. data/spec/dummy/test/channels/application_cable/connection_test.rb +1 -0
  108. data/spec/dummy/test/test_helper.rb +1 -0
  109. data/spec/spec_helper.rb +10 -0
  110. data/spec/support/docker/fake_cli.rb +1 -0
  111. data/spec/support/docker/remote/fake_client.rb +1 -0
  112. data/spec/trailing_hash_spec.rb +2 -0
  113. metadata +20 -4
@@ -1,26 +1,56 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class Tags
6
+ extend T::Sig
7
+
4
8
  LATEST = Metadata::LATEST_TAG
5
9
 
6
- attr_reader :cli, :remote_client, :metadata
10
+ sig { returns(CLI) }
11
+ attr_reader :cli
12
+
13
+ sig { returns(::Docker::Remote::Client) }
14
+ attr_reader :remote_client
7
15
 
16
+ sig { returns Metadata }
17
+ attr_reader :metadata
18
+
19
+ sig {
20
+ params(
21
+ cli: CLI,
22
+ remote_client: ::Docker::Remote::Client,
23
+ metadata: Metadata
24
+ )
25
+ .void
26
+ }
8
27
  def initialize(cli, remote_client, metadata)
9
28
  @cli = cli
10
29
  @remote_client = remote_client
11
30
  @metadata = metadata
31
+
32
+ @local = T.let(@local, T.nilable(LocalTags))
33
+ @remote = T.let(@remote, T.nilable(RemoteTags))
34
+ @latest_timestamp_tag = T.let(@latest_timestamp_tag, T.nilable(TimestampTag))
12
35
  end
13
36
 
37
+ sig { returns(T::Array[String]) }
14
38
  def tags
15
39
  (local.tags + remote.tags).uniq
16
40
  end
17
41
 
42
+ sig { returns(T::Array[String]) }
18
43
  def latest_tags
19
44
  (local.latest_tags + remote.latest_tags).uniq
20
45
  end
21
46
 
47
+ sig {
48
+ params(current_tag: String).returns(T.nilable(TimestampTag))
49
+ }
22
50
  def previous_timestamp_tag(current_tag)
23
- current_tag = ::Kuby::Docker::TimestampTag.try_parse(current_tag)
51
+ current_tag = TimestampTag.try_parse(current_tag)
52
+ return nil unless current_tag
53
+
24
54
  all_tags = timestamp_tags.sort
25
55
 
26
56
  idx = all_tags.index do |tag|
@@ -33,22 +63,27 @@ module Kuby
33
63
  all_tags[idx - 1]
34
64
  end
35
65
 
66
+ sig { returns(T::Array[TimestampTag]) }
36
67
  def timestamp_tags
37
68
  (local.timestamp_tags + remote.timestamp_tags).uniq
38
69
  end
39
70
 
71
+ sig { returns(T.nilable(TimestampTag)) }
40
72
  def latest_timestamp_tag
41
73
  @latest_timestamp_tag ||= timestamp_tags.sort.last
42
74
  end
43
75
 
76
+ sig { returns(T.self_type) }
44
77
  def all
45
78
  self
46
79
  end
47
80
 
81
+ sig { returns(LocalTags) }
48
82
  def local
49
83
  @local ||= LocalTags.new(cli, metadata)
50
84
  end
51
85
 
86
+ sig { returns(RemoteTags) }
52
87
  def remote
53
88
  @remote ||= RemoteTags.new(remote_client, metadata)
54
89
  end
@@ -1,10 +1,15 @@
1
+ # typed: strict
2
+
1
3
  require 'time'
2
4
 
3
5
  module Kuby
4
6
  module Docker
5
7
  class TimestampTag
6
- FORMAT = '%Y%m%d%H%M%S'.freeze
8
+ extend T::Sig
9
+
10
+ FORMAT = T.let('%Y%m%d%H%M%S'.freeze, String)
7
11
 
12
+ sig { params(str: String).returns(T.nilable(TimestampTag)) }
8
13
  def self.try_parse(str)
9
14
  time = begin
10
15
  Time.strptime(str, FORMAT)
@@ -15,28 +20,35 @@ module Kuby
15
20
  new(time)
16
21
  end
17
22
 
23
+ sig { returns(Time) }
18
24
  attr_reader :time
19
25
 
26
+ sig { params(time: Time).void }
20
27
  def initialize(time)
21
- @time = time
28
+ @time = T.let(time, Time)
22
29
  end
23
30
 
31
+ sig { returns(String) }
24
32
  def to_s
25
33
  time.strftime(FORMAT)
26
34
  end
27
35
 
36
+ sig { params(other: TimestampTag).returns(T.nilable(Integer)) }
28
37
  def <=>(other)
29
38
  time <=> other.time
30
39
  end
31
40
 
41
+ sig { params(other: TimestampTag).returns(T::Boolean) }
32
42
  def ==(other)
33
43
  time == other.time
34
44
  end
35
45
 
46
+ sig { returns(Integer) }
36
47
  def hash
37
48
  time.hash
38
49
  end
39
50
 
51
+ sig { params(other: TimestampTag).returns(T::Boolean) }
40
52
  def eql?(other)
41
53
  time == other.time
42
54
  end
@@ -1,13 +1,30 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class WebserverPhase < Layer
4
- class Puma
6
+ extend T::Sig
7
+
8
+ class Webserver
9
+ extend T::Sig
10
+ extend T::Helpers
11
+
12
+ abstract!
13
+
14
+ sig { returns(WebserverPhase) }
5
15
  attr_reader :phase
6
16
 
17
+ sig { params(phase: WebserverPhase).void }
7
18
  def initialize(phase)
8
19
  @phase = phase
9
20
  end
10
21
 
22
+ sig { abstract.params(dockerfile: Dockerfile).void }
23
+ def apply_to(dockerfile); end
24
+ end
25
+
26
+ class Puma < Webserver
27
+ sig { override.params(dockerfile: Dockerfile).void }
11
28
  def apply_to(dockerfile)
12
29
  dockerfile.cmd(
13
30
  'puma',
@@ -22,25 +39,43 @@ module Kuby
22
39
  end
23
40
  end
24
41
 
25
- DEFAULT_PORT = 8080
26
- WEBSERVER_MAP = { puma: Puma }.freeze
42
+ DEFAULT_PORT = T.let('8080', String)
43
+ WEBSERVER_MAP = T.let({ puma: Puma }.freeze, T::Hash[Symbol, T.class_of(Webserver)])
27
44
 
28
- attr_accessor :port, :webserver
45
+ sig { params(port: String).void }
46
+ attr_writer :port
47
+
48
+ sig { returns(T.nilable(Symbol)) }
49
+ attr_reader :webserver
50
+
51
+ sig { params(webserver: Symbol).void }
52
+ attr_writer :webserver
53
+
54
+ sig { override.params(environment: Environment).void }
55
+ def initialize(environment)
56
+ super
57
+
58
+ @port = T.let(@port, T.nilable(String))
59
+ @webserver = T.let(@webserver, T.nilable(Symbol))
60
+ end
29
61
 
62
+ sig { override.params(dockerfile: Dockerfile).void }
30
63
  def apply_to(dockerfile)
31
64
  ws = webserver || default_webserver
32
- ws_class = WEBSERVER_MAP[ws]
65
+ ws_class = WEBSERVER_MAP[T.must(ws)]
33
66
  raise "No webserver named #{ws}" unless ws_class
34
67
 
35
68
  ws_class.new(self).apply_to(dockerfile)
36
69
  end
37
70
 
71
+ sig { returns(String) }
38
72
  def port
39
73
  @port || DEFAULT_PORT
40
74
  end
41
75
 
42
76
  private
43
77
 
78
+ sig { returns(T.nilable(Symbol)) }
44
79
  def default_webserver
45
80
  if Gem.loaded_specs.include?('puma')
46
81
  :puma
@@ -1,6 +1,11 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class YarnPhase < Layer
6
+ extend T::Sig
7
+
8
+ sig { params(dockerfile: Dockerfile).void }
4
9
  def apply_to(dockerfile)
5
10
  dockerfile.copy('package.json', '.')
6
11
  dockerfile.copy('yarn.lock*', '.')
@@ -1,6 +1,10 @@
1
+ # typed: true
1
2
  module Kuby
2
3
  class Environment
3
4
  attr_reader :name, :definition
5
+ attr_accessor :configured
6
+
7
+ alias_method :configured?, :configured
4
8
 
5
9
  def initialize(name, definition, &block)
6
10
  @name = name
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  require 'kuby/kubernetes/errors'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  require 'krane'
2
3
  require 'kubectl-rb'
3
4
 
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  require 'fileutils'
2
3
  require 'securerandom'
3
4
  require 'yaml'
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  require 'base64'
2
3
  require 'kube-dsl'
3
4
 
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  require 'kube-dsl'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Kuby
2
3
  module Kubernetes
3
4
  class MissingDeploymentError < StandardError; end
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  require 'set'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  require 'kubernetes-cli'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  require 'base64'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  require 'kube-dsl'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Kuby
2
3
  module Middleware
3
4
  autoload :HealthCheck, 'kuby/middleware/health_check'
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  module Kuby
2
3
  module Middleware
3
4
  class HealthCheck
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  module Kuby
2
3
  class Plugin
3
4
  attr_reader :environment
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  module Kuby
2
3
  class PluginRegistry
3
4
  ANY = 'any'.freeze
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Kuby
2
3
  module Plugins
3
4
  autoload :NginxIngress, 'kuby/plugins/nginx_ingress'
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  require 'kube-dsl'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Kuby
2
3
  module Plugins
3
4
  module RailsApp
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  require 'fileutils'
2
3
  require 'pathname'
3
4
 
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  require 'kube-dsl'
2
3
 
3
4
  module Kuby
@@ -1,3 +1,4 @@
1
+ # typed: false
1
2
  require 'yaml'
2
3
 
3
4
  module Kuby
@@ -56,17 +57,18 @@ module Kuby
56
57
  def db_config_path
57
58
  @db_config_path ||= begin
58
59
  db_config_paths.first or
59
- raise "Couldn't find database config at #{rails_app.root}"
60
+ raise "Couldn't find database config in #{db_config_pattern}"
60
61
  end
61
62
  end
62
63
 
63
64
  def db_config_paths
64
- @db_config_paths ||=
65
- Dir.glob(
66
- File.join(
67
- rails_app.root, 'config', 'database.{yml,erb,yml.erb,yaml,yaml.erb}'
68
- )
69
- )
65
+ @db_config_paths ||= Dir.glob(db_config_pattern)
66
+ end
67
+
68
+ def db_config_pattern
69
+ @db_config_pattern ||= File.join(
70
+ rails_app.root, 'config', 'database.{yml,erb,yml.erb,yaml,yaml.erb}'
71
+ )
70
72
  end
71
73
  end
72
74
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  require 'rails/generators'
2
3
  require 'rails/generators/base'
3
4
 
@@ -10,51 +11,53 @@ class KubyGenerator < Rails::Generators::Base
10
11
  require 'active_support/encrypted_configuration'
11
12
 
12
13
  # Define a production Kuby deploy environment
13
- Kuby.define(:production) do
14
- # Because the Rails environment isn't always loaded when
15
- # your Kuby config is loaded, provide access to Rails
16
- # credentials manually.
17
- app_creds = ActiveSupport::EncryptedConfiguration.new(
18
- config_path: File.join('config', 'credentials.yml.enc'),
19
- key_path: File.join('config', 'master.key'),
20
- env_key: 'RAILS_MASTER_KEY',
21
- raise_if_missing_key: true
22
- )
14
+ Kuby.define('#{Rails.application.class.module_parent_name}') do
15
+ environment(:production) do
16
+ # Because the Rails environment isn't always loaded when
17
+ # your Kuby config is loaded, provide access to Rails
18
+ # credentials manually.
19
+ app_creds = ActiveSupport::EncryptedConfiguration.new(
20
+ config_path: File.join('config', 'credentials.yml.enc'),
21
+ key_path: File.join('config', 'master.key'),
22
+ env_key: 'RAILS_MASTER_KEY',
23
+ raise_if_missing_key: true
24
+ )
23
25
 
24
- docker do
25
- # Configure your Docker registry credentials here. Add them to your
26
- # Rails credentials file by running `bundle exec rake credentials:edit`.
27
- credentials do
28
- username app_creds[:KUBY_DOCKER_USERNAME]
29
- password app_creds[:KUBY_DOCKER_PASSWORD]
30
- email app_creds[:KUBY_DOCKER_EMAIL]
31
- end
26
+ docker do
27
+ # Configure your Docker registry credentials here. Add them to your
28
+ # Rails credentials file by running `bundle exec rake credentials:edit`.
29
+ credentials do
30
+ username app_creds[:KUBY_DOCKER_USERNAME]
31
+ password app_creds[:KUBY_DOCKER_PASSWORD]
32
+ email app_creds[:KUBY_DOCKER_EMAIL]
33
+ end
32
34
 
33
- # Configure the URL to your Docker image here, eg:
34
- # image_url 'foo.bar.com/me/myproject'
35
- #
36
- # If you're using Gitlab's Docker registry, try something like this:
37
- # image_url 'registry.gitlab.com/<username>/<repo>'
38
- end
35
+ # Configure the URL to your Docker image here, eg:
36
+ # image_url 'foo.bar.com/me/myproject'
37
+ #
38
+ # If you're using Gitlab's Docker registry, try something like this:
39
+ # image_url 'registry.gitlab.com/<username>/<repo>'
40
+ end
39
41
 
40
- kubernetes do
41
- # Add a plugin that facilitates deploying a Rails app.
42
- add_plugin :rails_app do
43
- # configure database credentials
44
- database do
45
- user app_creds[:KUBY_DB_USER]
46
- password app_creds[:KUBY_DB_PASSWORD]
42
+ kubernetes do
43
+ # Add a plugin that facilitates deploying a Rails app.
44
+ add_plugin :rails_app do
45
+ # configure database credentials
46
+ database do
47
+ user app_creds[:KUBY_DB_USER]
48
+ password app_creds[:KUBY_DB_PASSWORD]
49
+ end
47
50
  end
48
- end
49
51
 
50
- # Use Docker Desktop as the provider.
51
- # See: https://www.docker.com/products/docker-desktop
52
- #
53
- # Note: you will likely want to use a different provider when deploying
54
- # your application into a production environment. To configure a different
55
- # provider, add the corresponding gem to your gemfile and update the
56
- # following line according to the provider gem's README.
57
- provider :docker_desktop
52
+ # Use Docker Desktop as the provider.
53
+ # See: https://www.docker.com/products/docker-desktop
54
+ #
55
+ # Note: you will likely want to use a different provider when deploying
56
+ # your application into a production environment. To configure a different
57
+ # provider, add the corresponding gem to your gemfile and update the
58
+ # following line according to the provider gem's README.
59
+ provider :docker_desktop
60
+ end
58
61
  end
59
62
  end
60
63
  END