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,63 +1,121 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class WebserverDevPhase < Layer
4
- DEFAULT_PORT = 3000
6
+ extend T::Sig
7
+
8
+ DEFAULT_PORT = T.let('3000'.freeze, String)
9
+
10
+ sig { params(port: String).void }
11
+ attr_writer :port
5
12
 
6
- attr_accessor :port
13
+ sig { params(environment: Environment).void }
14
+ def initialize(environment)
15
+ super
16
+
17
+ @port = T.let(@port, T.nilable(String))
18
+ end
7
19
 
20
+ sig { override.params(dockerfile: Dockerfile).void }
8
21
  def apply_to(dockerfile)
9
22
  dockerfile.expose(port)
10
23
  end
11
24
 
25
+ sig { returns(String) }
12
26
  def port
13
27
  @port || DEFAULT_PORT
14
28
  end
15
29
  end
16
30
 
17
31
  class DevSpec
32
+ extend T::Sig
33
+
34
+ sig { returns(Environment) }
18
35
  attr_reader :environment
19
36
 
37
+ sig { params(environment: Environment).void }
20
38
  def initialize(environment)
21
39
  @environment = environment
40
+
41
+ @setup_phase = T.let(@setup_phase, T.nilable(SetupPhase))
42
+ @package_phase = T.let(@package_phase, T.nilable(PackagePhase))
43
+ @webserver_phase = T.let(@webserver_phase, T.nilable(WebserverDevPhase))
44
+ @metadata = T.let(@metadata, T.nilable(Metadata))
45
+ @distro_spec = T.let(@distro_spec, T.nilable(Distro))
46
+ @cli = T.let(@cli, T.nilable(CLI))
47
+ @tags = T.let(@tags, T.nilable(LocalTags))
48
+ @layer_stack = T.let(@layer_stack, T.nilable(Docker::LayerStack))
22
49
  end
23
50
 
51
+ sig { params(dir: String).void }
24
52
  def working_dir(dir)
25
53
  setup_phase.working_dir = dir
26
54
  end
27
55
 
56
+ sig { params(env: String).void }
28
57
  def rails_env(env)
29
58
  setup_phase.rails_env = env
30
59
  end
31
60
 
32
- def package(*args)
33
- package_phase.add(*args)
61
+ sig {
62
+ params(
63
+ package_name: Symbol,
64
+ version: T.nilable(String)
65
+ )
66
+ .void
67
+ }
68
+ def package(package_name, version = nil)
69
+ package_phase.add(package_name, version)
34
70
  end
35
71
 
72
+ sig { params(distro_name: Symbol).void }
36
73
  def distro(distro_name)
37
74
  metadata.distro = distro_name
38
75
  @distro_spec = nil
39
76
  end
40
77
 
78
+ sig { params(port: String).void }
41
79
  def port(port)
42
80
  webserver_phase.port = port
43
81
  end
44
82
 
45
- def use(*args, &block)
46
- layer_stack.use(*args, &block)
83
+ sig {
84
+ params(
85
+ name: Symbol,
86
+ layer: T.nilable(Layer),
87
+ block: T.nilable(T.proc.params(df: Dockerfile).void)
88
+ )
89
+ .void
90
+ }
91
+ def use(name, layer = nil, &block)
92
+ layer_stack.use(name, layer, &block)
47
93
  end
48
94
 
49
- def insert(*args, &block)
50
- layer_stack.insert(*args, &block)
95
+ sig {
96
+ params(
97
+ name: Symbol,
98
+ layer: T.nilable(T.any(Layer, T::Hash[Symbol, T.untyped])),
99
+ options: T::Hash[Symbol, T.untyped],
100
+ block: T.nilable(T.proc.params(df: Dockerfile).void)
101
+ )
102
+ .void
103
+ }
104
+ def insert(name, layer = nil, options = {}, &block)
105
+ layer_stack.insert(name, layer, options, &block)
51
106
  end
52
107
 
53
- def delete(*args)
54
- layer_stack.delete(*args)
108
+ sig { params(name: Symbol).void }
109
+ def delete(name)
110
+ layer_stack.delete(name)
55
111
  end
56
112
 
57
- def exists?(*args)
58
- layer_stack.includes?(*args)
113
+ sig { params(name: Symbol).returns(T::Boolean) }
114
+ def exists?(name)
115
+ layer_stack.includes?(name)
59
116
  end
60
117
 
118
+ sig { returns(Dockerfile) }
61
119
  def to_dockerfile
62
120
  Dockerfile.new.tap do |df|
63
121
  layer_stack.each { |layer| layer.apply_to(df) }
@@ -65,26 +123,27 @@ module Kuby
65
123
  end
66
124
  end
67
125
 
126
+ sig { returns(SetupPhase) }
68
127
  def setup_phase
69
128
  @setup_phase ||= SetupPhase.new(environment)
70
129
  end
71
130
 
131
+ sig { returns(PackagePhase) }
72
132
  def package_phase
73
133
  @package_phase ||= PackagePhase.new(environment)
74
134
  end
75
135
 
136
+ sig { returns(WebserverDevPhase) }
76
137
  def webserver_phase
77
138
  @webserver_phase ||= WebserverDevPhase.new(environment)
78
139
  end
79
140
 
141
+ sig { returns(Metadata) }
80
142
  def metadata
81
143
  @metadata ||= Metadata.new(environment)
82
144
  end
83
145
 
84
- def cli
85
- @cli ||= Docker::CLI.new
86
- end
87
-
146
+ sig { returns(Distro) }
88
147
  def distro_spec
89
148
  @distro_spec ||= if distro_klass = Kuby.distros[metadata.distro]
90
149
  distro_klass.new(self)
@@ -93,6 +152,7 @@ module Kuby
93
152
  end
94
153
  end
95
154
 
155
+ sig { returns(String) }
96
156
  def tag
97
157
  t = ENV.fetch('KUBY_DOCKER_TAG') do
98
158
  tags.latest_timestamp_tag
@@ -105,22 +165,26 @@ module Kuby
105
165
  t.to_s
106
166
  end
107
167
 
108
- def previous_tag(*)
168
+ sig { params(current_tag: String).returns(String) }
169
+ def previous_tag(current_tag)
109
170
  raise MissingTagError, 'cannot roll back in the development environment'
110
171
  end
111
172
 
173
+ sig { returns(CLI) }
112
174
  def cli
113
175
  @cli ||= Docker::CLI.new
114
176
  end
115
177
 
116
178
  private
117
179
 
180
+ sig { returns(LocalTags) }
118
181
  def tags
119
182
  @tags ||= LocalTags.new(cli, metadata)
120
183
  end
121
184
 
185
+ sig { returns(Docker::LayerStack) }
122
186
  def layer_stack
123
- @layer_stack ||= LayerStack.new.tap do |stack|
187
+ @layer_stack ||= Docker::LayerStack.new.tap do |stack|
124
188
  stack.use(:setup_phase, setup_phase)
125
189
  stack.use(:package_phase, package_phase)
126
190
  stack.use(:webserver_phase, webserver_phase)
@@ -0,0 +1,43 @@
1
+ # typed: strict
2
+
3
+ module Kuby
4
+ module Docker
5
+ class Distro
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ abstract!
10
+
11
+ PackageImpl = T.type_alias {
12
+ T.any(Packages::Package, Packages::ManagedPackage, Packages::SimpleManagedPackage)
13
+ }
14
+
15
+ ManagedPackageImpl = T.type_alias {
16
+ T.any(Packages::ManagedPackage, Packages::SimpleManagedPackage)
17
+ }
18
+
19
+ sig { params(phase: Layer).void }
20
+ def initialize(phase)
21
+ @phase = phase
22
+ end
23
+
24
+ sig { params(packages: T::Array[PackageImpl], into: Dockerfile).void }
25
+ def install(packages, into:)
26
+ raise NotImplementedError,
27
+ "#{__method__} must be defined in derived classes"
28
+ end
29
+
30
+ sig { returns(T::Array[[Symbol, T.nilable(String)]]) }
31
+ def default_packages
32
+ raise NotImplementedError,
33
+ "#{__method__} must be defined in derived classes"
34
+ end
35
+
36
+ sig { returns(String) }
37
+ def shell_exe
38
+ raise NotImplementedError,
39
+ "#{__method__} must be defined in derived classes"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,28 +1,43 @@
1
+ # typed: strict
2
+
1
3
  require 'digest'
2
4
 
3
5
  module Kuby
4
6
  module Docker
5
7
  class Dockerfile
8
+ extend T::Sig
9
+
6
10
  class Command
11
+ extend T::Sig
12
+
13
+ sig { returns(T::Array[String]) }
7
14
  attr_reader :args
8
15
 
9
- def initialize(*args)
16
+ sig { params(args: T::Array[String]).void }
17
+ def initialize(args)
10
18
  @args = args
11
19
  end
12
20
 
21
+ sig { returns(String) }
13
22
  def to_s
14
23
  args.join(' ')
15
24
  end
16
25
  end
17
26
 
18
27
  class From < Command
19
- attr_reader :image_url, :as
28
+ sig { returns(String) }
29
+ attr_reader :image_url
30
+
31
+ sig { returns(T.nilable(String)) }
32
+ attr_reader :as
20
33
 
34
+ sig { params(image_url: String, as: T.nilable(String)).void }
21
35
  def initialize(image_url, as: nil)
22
36
  @image_url = image_url
23
37
  @as = as
24
38
  end
25
39
 
40
+ sig { returns(String) }
26
41
  def to_s
27
42
  str = "FROM #{image_url}"
28
43
  str << " AS #{as}" if as
@@ -31,26 +46,38 @@ module Kuby
31
46
  end
32
47
 
33
48
  class Workdir < Command
49
+ sig { returns(String) }
34
50
  def to_s; "WORKDIR #{super}"; end
35
51
  end
36
52
 
37
53
  class Env < Command
54
+ sig { returns(String) }
38
55
  def to_s; "ENV #{super}"; end
39
56
  end
40
57
 
41
58
  class Run < Command
59
+ sig { returns(String) }
42
60
  def to_s; "RUN #{super}"; end
43
61
  end
44
62
 
45
63
  class Copy < Command
46
- attr_reader :source, :dest, :from
64
+ sig { returns(String) }
65
+ attr_reader :source
47
66
 
67
+ sig { returns(String) }
68
+ attr_reader :dest
69
+
70
+ sig { returns(T.nilable(String)) }
71
+ attr_reader :from
72
+
73
+ sig { params(source: String, dest: String, from: T.nilable(String)).void }
48
74
  def initialize(source, dest, from: nil)
49
75
  @source = source
50
76
  @dest = dest
51
77
  @from = from
52
78
  end
53
79
 
80
+ sig { returns(String) }
54
81
  def to_s
55
82
  cmd = ['COPY']
56
83
  cmd << "--from=#{from}" if from
@@ -60,72 +87,92 @@ module Kuby
60
87
  end
61
88
 
62
89
  class Expose < Command
90
+ sig { returns(String) }
63
91
  def to_s; "EXPOSE #{super}"; end
64
92
  end
65
93
 
66
94
  class Cmd < Command
95
+ sig { returns(String) }
67
96
  def to_s; "CMD #{super}"; end
68
97
  end
69
98
 
70
99
  class Arg < Command
100
+ sig { returns(String) }
71
101
  def to_s; "ARG #{super}"; end
72
102
  end
73
103
 
74
- attr_reader :commands, :cursor
104
+ sig { returns(T::Array[Command]) }
105
+ attr_reader :commands
106
+
107
+ sig { returns(Integer) }
108
+ attr_reader :cursor
75
109
 
110
+ sig { void }
76
111
  def initialize
77
- @commands = []
78
- @cursor = 0
112
+ @commands = T.let([], T::Array[Command])
113
+ @cursor = T.let(0, Integer)
79
114
  end
80
115
 
81
- def from(*args, **kwargs)
82
- add From.new(*args, **kwargs)
116
+ sig { params(image_url: String, as: T.nilable(String)).void }
117
+ def from(image_url, as: nil)
118
+ add From.new(image_url, as: as)
83
119
  end
84
120
 
121
+ sig { params(args: String).void }
85
122
  def workdir(*args)
86
- add Workdir.new(*args)
123
+ add Workdir.new(args)
87
124
  end
88
125
 
126
+ sig { params(args: String).void }
89
127
  def env(*args)
90
- add Env.new(*args)
128
+ add Env.new(args)
91
129
  end
92
130
 
131
+ sig { params(args: String).void }
93
132
  def arg(*args)
94
- add Arg.new(*args)
133
+ add Arg.new(args)
95
134
  end
96
135
 
136
+ sig { params(args: String).void }
97
137
  def run(*args)
98
- add Run.new(*args)
138
+ add Run.new(args)
99
139
  end
100
140
 
101
- def copy(*args, **kwargs)
102
- add Copy.new(*args, **kwargs)
141
+ sig { params(source: String, dest: String, from: T.nilable(String)).void }
142
+ def copy(source, dest, from: nil)
143
+ add Copy.new(source, dest, from: from)
103
144
  end
104
145
 
146
+ sig { params(args: String).void }
105
147
  def expose(*args)
106
- add Expose.new(*args)
148
+ add Expose.new(args)
107
149
  end
108
150
 
151
+ sig { params(args: String).void }
109
152
  def cmd(*args)
110
- add Cmd.new(*args)
153
+ add Cmd.new(args)
111
154
  end
112
155
 
156
+ sig { returns(String) }
113
157
  def to_s
114
158
  # ensure trailing newline
115
159
  "#{commands.map(&:to_s).join("\n")}\n"
116
160
  end
117
161
 
162
+ sig { returns(String) }
118
163
  def checksum
119
164
  Digest::SHA256.hexdigest(to_s)
120
165
  end
121
166
 
167
+ sig { returns(T::Array[String]) }
122
168
  def exposed_ports
123
169
  commands
124
170
  .select { |c| c.is_a?(Expose) }
125
- .map { |c| c.args.first }
171
+ .map { |c| T.must(c.args.first) }
126
172
  end
127
173
 
128
- def insert_at(pos)
174
+ sig { params(pos: Integer, block: T.proc.void).void }
175
+ def insert_at(pos, &block)
129
176
  @cursor = pos
130
177
  yield
131
178
  ensure
@@ -134,6 +181,7 @@ module Kuby
134
181
 
135
182
  private
136
183
 
184
+ sig { params(cmd: Command).void }
137
185
  def add(cmd)
138
186
  commands.insert(cursor, cmd)
139
187
  @cursor += 1
@@ -1,3 +1,5 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class BuildError < StandardError; end
@@ -6,12 +8,18 @@ module Kuby
6
8
  class LoginError < StandardError; end
7
9
 
8
10
  class MissingTagError < StandardError
11
+ extend T::Sig
12
+
13
+ sig { returns(String) }
9
14
  attr_reader :tag
10
15
 
16
+ sig { params(tag: String).void }
11
17
  def initialize(tag)
12
18
  @tag = tag
19
+ @message = T.let(@message, T.nilable(String))
13
20
  end
14
21
 
22
+ sig { returns(String) }
15
23
  def message
16
24
  @message ||= "Could not find tag '#{tag}'."
17
25
  end