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,21 +1,29 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  module Packages
4
6
  class Nodejs < Package
7
+ extend T::Sig
8
+
9
+ sig { params(dockerfile: Dockerfile).void }
5
10
  def install_on_debian(dockerfile)
6
11
  install_from_image("node:#{version}", dockerfile)
7
12
  end
8
13
 
14
+ sig { params(dockerfile: Dockerfile).void }
9
15
  def install_on_alpine(dockerfile)
10
16
  install_from_image("node:#{version}-alpine", dockerfile)
11
17
  end
12
18
 
19
+ sig { returns(String) }
13
20
  def version
14
21
  @version || 'current'
15
22
  end
16
23
 
17
24
  private
18
25
 
26
+ sig { params(image: String, dockerfile: Dockerfile).void }
19
27
  def install_from_image(image, dockerfile)
20
28
  dockerfile.insert_at(0) do
21
29
  dockerfile.from(image, as: 'nodejs')
@@ -1,18 +1,32 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  module Packages
4
6
  class Package
5
- attr_reader :name, :version
7
+ extend T::Sig
8
+ extend T::Helpers
9
+
10
+ abstract!
11
+
12
+ sig { returns(Symbol) }
13
+ attr_reader :name
14
+
15
+ sig { returns(T.nilable(String)) }
16
+ attr_reader :version
6
17
 
18
+ sig { params(name: Symbol, version: T.nilable(String)).void }
7
19
  def initialize(name, version = nil)
8
20
  @name = name
9
21
  @version = version
10
22
  end
11
23
 
24
+ sig { params(ver: String).returns(T.self_type) }
12
25
  def with_version(ver)
13
26
  self.class.new(name, ver)
14
27
  end
15
28
 
29
+ sig { returns(T::Boolean) }
16
30
  def managed?
17
31
  false
18
32
  end
@@ -1,21 +1,30 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  module Packages
4
6
  class SimpleManagedPackage
7
+ extend T::Sig
8
+
9
+ sig { returns(String) }
5
10
  attr_reader :name
6
11
 
12
+ sig { params(name: String).void }
7
13
  def initialize(name)
8
14
  @name = name
9
15
  end
10
16
 
17
+ sig { params(distro: Symbol).returns(String) }
11
18
  def package_name_for(distro)
12
19
  name
13
20
  end
14
21
 
15
- def with_version(*)
22
+ sig { params(ver: String).returns(T.self_type) }
23
+ def with_version(ver)
16
24
  self
17
25
  end
18
26
 
27
+ sig { returns(T::Boolean) }
19
28
  def managed?
20
29
  true
21
30
  end
@@ -1,7 +1,19 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  module Packages
4
6
  class Yarn < Package
7
+ extend T::Sig
8
+
9
+ sig { params(name: Symbol, version: T.nilable(String)).void }
10
+ def initialize(name, version = nil)
11
+ super
12
+
13
+ @url = T.let(@url, T.nilable(String))
14
+ end
15
+
16
+ sig { params(dockerfile: Dockerfile).void }
5
17
  def install_on_debian(dockerfile)
6
18
  dockerfile.run(<<~CMD.strip)
7
19
  wget #{url} && \\
@@ -17,6 +29,7 @@ module Kuby
17
29
  dockerfile.env("PATH=$PATH:/opt/yarn/bin")
18
30
  end
19
31
 
32
+ sig { params(dockerfile: Dockerfile).void }
20
33
  def install_on_alpine(dockerfile)
21
34
  dockerfile.run(<<~CMD.strip)
22
35
  wget #{url} && \\
@@ -34,6 +47,7 @@ module Kuby
34
47
 
35
48
  private
36
49
 
50
+ sig { returns(String) }
37
51
  def url
38
52
  @url ||= if version
39
53
  "https://github.com/yarnpkg/yarn/releases/download/v#{version}/yarn-v#{version}.tar.gz"
@@ -1,21 +1,40 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class RemoteTags
4
- attr_reader :remote_client, :metadata
6
+ extend T::Sig
7
+
8
+ sig { returns(::Docker::Remote::Client) }
9
+ attr_reader :remote_client
10
+
11
+ sig { returns(Metadata) }
12
+ attr_reader :metadata
5
13
 
14
+ sig {
15
+ params(
16
+ remote_client: ::Docker::Remote::Client,
17
+ metadata: Metadata
18
+ )
19
+ .void
20
+ }
6
21
  def initialize(remote_client, metadata)
7
22
  @remote_client = remote_client
8
23
  @metadata = metadata
9
24
  end
10
25
 
26
+ sig { returns(T::Array[String]) }
11
27
  def tags
12
28
  remote_client.tags
13
29
  end
14
30
 
31
+ sig { returns(T::Array[String]) }
15
32
  def latest_tags
16
- raise NotImplementedError, 'latest tags are not available for remote repos'
33
+ # not available for remote repos
34
+ []
17
35
  end
18
36
 
37
+ sig { returns(T::Array[TimestampTag]) }
19
38
  def timestamp_tags
20
39
  tags.map { |t| TimestampTag.try_parse(t) }.compact
21
40
  end
@@ -1,10 +1,40 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class SetupPhase < Layer
4
- DEFAULT_WORKING_DIR = '/usr/src/app'.freeze
6
+ extend T::Sig
7
+
8
+ DEFAULT_WORKING_DIR = T.let('/usr/src/app'.freeze, String)
9
+
10
+ sig { returns(T.nilable(String)) }
11
+ attr_reader :base_image
12
+
13
+ sig { params(base_image: String).void }
14
+ attr_writer :base_image
15
+
16
+ sig { returns(T.nilable(String)) }
17
+ attr_reader :working_dir
5
18
 
6
- attr_accessor :base_image, :working_dir, :rails_env
19
+ sig { params(working_dir: String).void }
20
+ attr_writer :working_dir
21
+
22
+ sig { returns(T.nilable(String)) }
23
+ attr_reader :rails_env
24
+
25
+ sig { params(rails_env: String).void }
26
+ attr_writer :rails_env
27
+
28
+ sig { params(environment: Environment).void }
29
+ def initialize(environment)
30
+ super
31
+
32
+ @base_image = T.let(@base_image, T.nilable(String))
33
+ @working_dir = T.let(@working_dir, T.nilable(String))
34
+ @rails_env = T.let(@rails_env, T.nilable(String))
35
+ end
7
36
 
37
+ sig { override.params(dockerfile: Dockerfile).void }
8
38
  def apply_to(dockerfile)
9
39
  dockerfile.from(base_image || default_base_image)
10
40
  dockerfile.workdir(working_dir || DEFAULT_WORKING_DIR)
@@ -15,14 +45,15 @@ module Kuby
15
45
 
16
46
  private
17
47
 
48
+ sig { returns(String) }
18
49
  def default_base_image
19
- @default_base_image ||= case metadata.distro
50
+ case metadata.distro
20
51
  when :debian
21
52
  "ruby:#{RUBY_VERSION}"
22
53
  when :alpine
23
54
  "ruby:#{RUBY_VERSION}-alpine"
24
55
  else
25
- # ERROR
56
+ raise MissingDistroError, "distro '#{metadata.distro}' hasn't been registered"
26
57
  end
27
58
  end
28
59
  end
@@ -1,115 +1,185 @@
1
+ # typed: strict
2
+
1
3
  require 'docker/remote'
2
4
 
3
5
  module Kuby
4
6
  module Docker
5
7
  class Spec
8
+ extend T::Sig
9
+
10
+ sig { returns(Environment) }
6
11
  attr_reader :environment
7
12
 
13
+ sig { params(environment: Environment).void }
8
14
  def initialize(environment)
9
15
  @environment = environment
16
+
17
+ @credentials = T.let(@credentials, T.nilable(Credentials))
18
+ @setup_phase = T.let(@setup_phase, T.nilable(SetupPhase))
19
+ @package_phase = T.let(@package_phase, T.nilable(PackagePhase))
20
+ @bundler_phase = T.let(@bundler_phase, T.nilable(BundlerPhase))
21
+ @yarn_phase = T.let(@yarn_phase, T.nilable(YarnPhase))
22
+ @copy_phase = T.let(@copy_phase, T.nilable(CopyPhase))
23
+ @assets_phase = T.let(@assets_phase, T.nilable(AssetsPhase))
24
+ @webserver_phase = T.let(@webserver_phase, T.nilable(WebserverPhase))
25
+ @metadata = T.let(@metadata, T.nilable(Metadata))
26
+
27
+ @distro_spec = T.let(@distro_spec, T.nilable(Distro))
28
+ @cli = T.let(@cli, T.nilable(CLI))
29
+ @remote_client = T.let(@remote_client, T.nilable(::Docker::Remote::Client))
30
+ @tags = T.let(@tags, T.nilable(Tags))
31
+ @layer_stack = T.let(@layer_stack, T.nilable(Kuby::Docker::LayerStack))
10
32
  end
11
33
 
34
+ sig { params(image_url: String).void }
12
35
  def base_image(image_url)
13
36
  setup_phase.base_image = image_url
14
37
  end
15
38
 
39
+ sig { params(dir: String).void }
16
40
  def working_dir(dir)
17
41
  setup_phase.working_dir = dir
18
42
  end
19
43
 
44
+ sig { params(env: String).void }
20
45
  def rails_env(env)
21
46
  setup_phase.rails_env = env
22
47
  end
23
48
 
49
+ sig { params(version: String).void }
24
50
  def bundler_version(version)
25
51
  bundler_phase.version = version
26
52
  end
27
53
 
54
+ sig { params(path: String).void }
28
55
  def gemfile(path)
29
56
  bundler_phase.gemfile = path
30
57
  end
31
58
 
32
- def package(*args)
33
- package_phase.add(*args)
59
+ sig {
60
+ params(
61
+ package_name: Symbol,
62
+ version: T.nilable(String)
63
+ )
64
+ .void
65
+ }
66
+ def package(package_name, version = nil)
67
+ package_phase.add(package_name, version)
34
68
  end
35
69
 
70
+ sig { params(distro_name: Symbol).void }
36
71
  def distro(distro_name)
37
72
  metadata.distro = distro_name
38
73
  @distro_spec = nil
39
74
  end
40
75
 
76
+ sig { params(path: String).void }
41
77
  def files(path)
42
78
  copy_phase << path
43
79
  end
44
80
 
81
+ sig { params(port: String).void }
45
82
  def port(port)
46
83
  webserver_phase.port = port
47
84
  end
48
85
 
86
+ sig { params(url: String).void }
49
87
  def image_url(url)
50
88
  metadata.image_url = url
51
89
  end
52
90
 
53
- def use(*args, &block)
54
- layer_stack.use(*args, &block)
55
- end
56
-
57
- def insert(*args, &block)
58
- layer_stack.insert(*args, &block)
91
+ sig {
92
+ params(
93
+ name: Symbol,
94
+ layer: T.nilable(Layer),
95
+ block: T.nilable(T.proc.params(df: Dockerfile).void)
96
+ )
97
+ .void
98
+ }
99
+ def use(name, layer = nil, &block)
100
+ layer_stack.use(name, layer, &block)
101
+ end
102
+
103
+ sig {
104
+ params(
105
+ name: Symbol,
106
+ layer: T.nilable(T.any(Layer, T::Hash[Symbol, T.untyped])),
107
+ options: T::Hash[Symbol, T.untyped],
108
+ block: T.nilable(T.proc.params(df: Dockerfile).void)
109
+ )
110
+ .void
111
+ }
112
+ def insert(name, layer = nil, options = {}, &block)
113
+ layer_stack.insert(name, layer, options, &block)
59
114
  end
60
115
 
61
- def delete(*args)
62
- layer_stack.delete(*args)
116
+ sig { params(name: Symbol).void }
117
+ def delete(name)
118
+ layer_stack.delete(name)
63
119
  end
64
120
 
65
- def exists?(*args)
66
- layer_stack.includes?(*args)
121
+ sig { params(name: Symbol).returns(T::Boolean) }
122
+ def exists?(name)
123
+ layer_stack.includes?(name)
67
124
  end
68
125
 
126
+ sig {
127
+ params(block: T.nilable(T.proc.void)).returns(Credentials)
128
+ }
69
129
  def credentials(&block)
70
130
  @credentials ||= Credentials.new
71
131
  @credentials.instance_eval(&block) if block
72
132
  @credentials
73
133
  end
74
134
 
135
+ sig { returns(Dockerfile) }
75
136
  def to_dockerfile
76
137
  Dockerfile.new.tap do |df|
77
138
  layer_stack.each { |layer| layer.apply_to(df) }
78
139
  end
79
140
  end
80
141
 
142
+ sig { returns(SetupPhase) }
81
143
  def setup_phase
82
144
  @setup_phase ||= SetupPhase.new(environment)
83
145
  end
84
146
 
147
+ sig { returns(PackagePhase) }
85
148
  def package_phase
86
149
  @package_phase ||= PackagePhase.new(environment)
87
150
  end
88
151
 
152
+ sig { returns(BundlerPhase) }
89
153
  def bundler_phase
90
154
  @bundler_phase ||= BundlerPhase.new(environment)
91
155
  end
92
156
 
157
+ sig { returns(YarnPhase) }
93
158
  def yarn_phase
94
159
  @yarn_phase ||= YarnPhase.new(environment)
95
160
  end
96
161
 
162
+ sig { returns(CopyPhase) }
97
163
  def copy_phase
98
164
  @copy_phase ||= CopyPhase.new(environment)
99
165
  end
100
166
 
167
+ sig { returns(AssetsPhase) }
101
168
  def assets_phase
102
169
  @assets_phase ||= AssetsPhase.new(environment)
103
170
  end
104
171
 
172
+ sig { returns(WebserverPhase) }
105
173
  def webserver_phase
106
174
  @webserver_phase ||= WebserverPhase.new(environment)
107
175
  end
108
176
 
177
+ sig { returns(Metadata) }
109
178
  def metadata
110
179
  @metadata ||= Metadata.new(environment)
111
180
  end
112
181
 
182
+ sig { returns(String) }
113
183
  def tag
114
184
  t = ENV.fetch('KUBY_DOCKER_TAG') do
115
185
  tags.latest_timestamp_tag
@@ -122,6 +192,7 @@ module Kuby
122
192
  t.to_s
123
193
  end
124
194
 
195
+ sig { params(current_tag: String).returns(String) }
125
196
  def previous_tag(current_tag)
126
197
  t = tags.previous_timestamp_tag(current_tag)
127
198
 
@@ -132,10 +203,12 @@ module Kuby
132
203
  t.to_s
133
204
  end
134
205
 
206
+ sig { returns(CLI) }
135
207
  def cli
136
208
  @cli ||= Docker::CLI.new
137
209
  end
138
210
 
211
+ sig { returns(::Docker::Remote::Client) }
139
212
  def remote_client
140
213
  @remote_client ||= ::Docker::Remote::Client.new(
141
214
  metadata.image_host, metadata.image_repo,
@@ -143,6 +216,7 @@ module Kuby
143
216
  )
144
217
  end
145
218
 
219
+ sig { returns(Distro) }
146
220
  def distro_spec
147
221
  @distro_spec ||= if distro_klass = Kuby.distros[metadata.distro]
148
222
  distro_klass.new(self)
@@ -151,14 +225,16 @@ module Kuby
151
225
  end
152
226
  end
153
227
 
228
+ sig { returns(Tags) }
154
229
  def tags
155
230
  @tags ||= Tags.new(cli, remote_client, metadata)
156
231
  end
157
232
 
158
233
  private
159
234
 
235
+ sig { returns(Kuby::Docker::LayerStack) }
160
236
  def layer_stack
161
- @layer_stack ||= LayerStack.new.tap do |stack|
237
+ @layer_stack ||= Kuby::Docker::LayerStack.new.tap do |stack|
162
238
  stack.use(:setup_phase, setup_phase)
163
239
  stack.use(:package_phase, package_phase)
164
240
  stack.use(:bundler_phase, bundler_phase)