kuby-core 0.8.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -1
  3. data/Gemfile +1 -0
  4. data/README.md +15 -3
  5. data/bin/kuby +4 -0
  6. data/kuby-core.gemspec +7 -3
  7. data/lib/kuby-core.rb +1 -0
  8. data/lib/kuby.rb +60 -18
  9. data/lib/kuby/basic_logger.rb +14 -0
  10. data/lib/kuby/cli_base.rb +126 -4
  11. data/lib/kuby/commands.rb +245 -0
  12. data/lib/kuby/definition.rb +2 -3
  13. data/lib/kuby/dev_setup.rb +256 -0
  14. data/lib/kuby/docker.rb +4 -0
  15. data/lib/kuby/docker/alpine.rb +16 -12
  16. data/lib/kuby/docker/assets_phase.rb +5 -0
  17. data/lib/kuby/docker/bundler_phase.rb +39 -5
  18. data/lib/kuby/docker/cli.rb +60 -3
  19. data/lib/kuby/docker/copy_phase.rb +11 -3
  20. data/lib/kuby/docker/credentials.rb +1 -0
  21. data/lib/kuby/docker/debian.rb +14 -10
  22. data/lib/kuby/docker/dev_spec.rb +195 -0
  23. data/lib/kuby/docker/distro.rb +43 -0
  24. data/lib/kuby/docker/dockerfile.rb +81 -18
  25. data/lib/kuby/docker/errors.rb +9 -0
  26. data/lib/kuby/docker/inline_layer.rb +7 -0
  27. data/lib/kuby/docker/layer.rb +11 -0
  28. data/lib/kuby/docker/layer_stack.rb +47 -6
  29. data/lib/kuby/docker/local_tags.rb +27 -2
  30. data/lib/kuby/docker/metadata.rb +35 -29
  31. data/lib/kuby/docker/package_list.rb +22 -3
  32. data/lib/kuby/docker/package_phase.rb +25 -5
  33. data/lib/kuby/docker/packages.rb +1 -0
  34. data/lib/kuby/docker/packages/managed_package.rb +20 -2
  35. data/lib/kuby/docker/packages/nodejs.rb +8 -0
  36. data/lib/kuby/docker/packages/package.rb +15 -1
  37. data/lib/kuby/docker/packages/simple_managed_package.rb +10 -1
  38. data/lib/kuby/docker/packages/yarn.rb +14 -0
  39. data/lib/kuby/docker/remote_tags.rb +21 -2
  40. data/lib/kuby/docker/setup_phase.rb +37 -5
  41. data/lib/kuby/docker/spec.rb +114 -12
  42. data/lib/kuby/docker/tags.rb +37 -2
  43. data/lib/kuby/docker/timestamp_tag.rb +14 -2
  44. data/lib/kuby/docker/webserver_phase.rb +40 -5
  45. data/lib/kuby/docker/yarn_phase.rb +5 -0
  46. data/lib/kuby/environment.rb +14 -1
  47. data/lib/kuby/kubernetes.rb +10 -9
  48. data/lib/kuby/kubernetes/deploy_task.rb +5 -0
  49. data/lib/kuby/kubernetes/deployer.rb +67 -11
  50. data/lib/kuby/kubernetes/docker_config.rb +1 -0
  51. data/lib/kuby/kubernetes/{minikube_provider.rb → docker_desktop_provider.rb} +5 -4
  52. data/lib/kuby/kubernetes/errors.rb +1 -0
  53. data/lib/kuby/kubernetes/manifest.rb +1 -0
  54. data/lib/kuby/kubernetes/provider.rb +9 -4
  55. data/lib/kuby/kubernetes/registry_secret.rb +1 -0
  56. data/lib/kuby/kubernetes/spec.rb +24 -22
  57. data/lib/kuby/middleware.rb +1 -0
  58. data/lib/kuby/middleware/health_check.rb +1 -0
  59. data/lib/kuby/plugin.rb +1 -0
  60. data/lib/kuby/plugin_registry.rb +28 -0
  61. data/lib/kuby/plugins.rb +1 -0
  62. data/lib/kuby/plugins/nginx_ingress.rb +1 -0
  63. data/lib/kuby/plugins/rails_app.rb +1 -0
  64. data/lib/kuby/plugins/rails_app/asset_copy_task.rb +1 -0
  65. data/lib/kuby/plugins/rails_app/assets.rb +1 -0
  66. data/lib/kuby/plugins/rails_app/database.rb +10 -9
  67. data/lib/kuby/plugins/rails_app/generators/kuby.rb +45 -44
  68. data/lib/kuby/plugins/rails_app/mysql.rb +1 -3
  69. data/lib/kuby/plugins/rails_app/plugin.rb +244 -44
  70. data/lib/kuby/plugins/rails_app/postgres.rb +1 -0
  71. data/lib/kuby/plugins/rails_app/rewrite_db_config.rb +1 -0
  72. data/lib/kuby/plugins/rails_app/sqlite.rb +1 -0
  73. data/lib/kuby/rails_commands.rb +84 -0
  74. data/lib/kuby/railtie.rb +1 -4
  75. data/lib/kuby/tasks.rb +78 -23
  76. data/lib/kuby/trailing_hash.rb +5 -3
  77. data/lib/kuby/version.rb +3 -1
  78. data/spec/docker/metadata_spec.rb +1 -108
  79. data/spec/docker/spec_spec.rb +303 -0
  80. data/spec/docker/timestamp_tag_spec.rb +1 -0
  81. data/spec/dummy/app/channels/application_cable/channel.rb +1 -0
  82. data/spec/dummy/app/channels/application_cable/connection.rb +1 -0
  83. data/spec/dummy/app/controllers/application_controller.rb +1 -0
  84. data/spec/dummy/app/helpers/application_helper.rb +1 -0
  85. data/spec/dummy/app/jobs/application_job.rb +1 -0
  86. data/spec/dummy/app/mailers/application_mailer.rb +1 -0
  87. data/spec/dummy/app/models/application_record.rb +1 -0
  88. data/spec/dummy/config/application.rb +1 -0
  89. data/spec/dummy/config/boot.rb +1 -0
  90. data/spec/dummy/config/environment.rb +1 -0
  91. data/spec/dummy/config/environments/development.rb +1 -0
  92. data/spec/dummy/config/environments/production.rb +1 -0
  93. data/spec/dummy/config/environments/test.rb +1 -0
  94. data/spec/dummy/config/initializers/application_controller_renderer.rb +1 -0
  95. data/spec/dummy/config/initializers/assets.rb +1 -0
  96. data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
  97. data/spec/dummy/config/initializers/content_security_policy.rb +1 -0
  98. data/spec/dummy/config/initializers/cookies_serializer.rb +1 -0
  99. data/spec/dummy/config/initializers/filter_parameter_logging.rb +1 -0
  100. data/spec/dummy/config/initializers/inflections.rb +1 -0
  101. data/spec/dummy/config/initializers/mime_types.rb +1 -0
  102. data/spec/dummy/config/initializers/wrap_parameters.rb +1 -0
  103. data/spec/dummy/config/puma.rb +1 -0
  104. data/spec/dummy/config/routes.rb +1 -0
  105. data/spec/dummy/config/spring.rb +1 -0
  106. data/spec/dummy/db/seeds.rb +1 -0
  107. data/spec/dummy/test/application_system_test_case.rb +1 -0
  108. data/spec/dummy/test/channels/application_cable/connection_test.rb +1 -0
  109. data/spec/dummy/test/test_helper.rb +1 -0
  110. data/spec/spec_helper.rb +18 -1
  111. data/spec/support/docker/fake_cli.rb +1 -0
  112. data/spec/support/docker/remote/fake_client.rb +1 -0
  113. data/spec/trailing_hash_spec.rb +2 -0
  114. metadata +62 -11
  115. data/lib/kuby/tasks/kuby.rake +0 -70
@@ -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,26 +1,43 @@
1
+ # typed: strict
2
+
3
+ require 'digest'
4
+
1
5
  module Kuby
2
6
  module Docker
3
7
  class Dockerfile
8
+ extend T::Sig
9
+
4
10
  class Command
11
+ extend T::Sig
12
+
13
+ sig { returns(T::Array[String]) }
5
14
  attr_reader :args
6
15
 
7
- def initialize(*args)
16
+ sig { params(args: T::Array[String]).void }
17
+ def initialize(args)
8
18
  @args = args
9
19
  end
10
20
 
21
+ sig { returns(String) }
11
22
  def to_s
12
23
  args.join(' ')
13
24
  end
14
25
  end
15
26
 
16
27
  class From < Command
17
- attr_reader :image_url, :as
28
+ sig { returns(String) }
29
+ attr_reader :image_url
18
30
 
31
+ sig { returns(T.nilable(String)) }
32
+ attr_reader :as
33
+
34
+ sig { params(image_url: String, as: T.nilable(String)).void }
19
35
  def initialize(image_url, as: nil)
20
36
  @image_url = image_url
21
37
  @as = as
22
38
  end
23
39
 
40
+ sig { returns(String) }
24
41
  def to_s
25
42
  str = "FROM #{image_url}"
26
43
  str << " AS #{as}" if as
@@ -29,26 +46,38 @@ module Kuby
29
46
  end
30
47
 
31
48
  class Workdir < Command
49
+ sig { returns(String) }
32
50
  def to_s; "WORKDIR #{super}"; end
33
51
  end
34
52
 
35
53
  class Env < Command
54
+ sig { returns(String) }
36
55
  def to_s; "ENV #{super}"; end
37
56
  end
38
57
 
39
58
  class Run < Command
59
+ sig { returns(String) }
40
60
  def to_s; "RUN #{super}"; end
41
61
  end
42
62
 
43
63
  class Copy < Command
44
- attr_reader :source, :dest, :from
64
+ sig { returns(String) }
65
+ attr_reader :source
66
+
67
+ sig { returns(String) }
68
+ attr_reader :dest
69
+
70
+ sig { returns(T.nilable(String)) }
71
+ attr_reader :from
45
72
 
73
+ sig { params(source: String, dest: String, from: T.nilable(String)).void }
46
74
  def initialize(source, dest, from: nil)
47
75
  @source = source
48
76
  @dest = dest
49
77
  @from = from
50
78
  end
51
79
 
80
+ sig { returns(String) }
52
81
  def to_s
53
82
  cmd = ['COPY']
54
83
  cmd << "--from=#{from}" if from
@@ -58,59 +87,92 @@ module Kuby
58
87
  end
59
88
 
60
89
  class Expose < Command
90
+ sig { returns(String) }
61
91
  def to_s; "EXPOSE #{super}"; end
62
92
  end
63
93
 
64
94
  class Cmd < Command
95
+ sig { returns(String) }
65
96
  def to_s; "CMD #{super}"; end
66
97
  end
67
98
 
68
- attr_reader :commands, :cursor
99
+ class Arg < Command
100
+ sig { returns(String) }
101
+ def to_s; "ARG #{super}"; end
102
+ end
103
+
104
+ sig { returns(T::Array[Command]) }
105
+ attr_reader :commands
69
106
 
107
+ sig { returns(Integer) }
108
+ attr_reader :cursor
109
+
110
+ sig { void }
70
111
  def initialize
71
- @commands = []
72
- @cursor = 0
112
+ @commands = T.let([], T::Array[Command])
113
+ @cursor = T.let(0, Integer)
73
114
  end
74
115
 
75
- def from(*args, **kwargs)
76
- 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)
77
119
  end
78
120
 
121
+ sig { params(args: String).void }
79
122
  def workdir(*args)
80
- add Workdir.new(*args)
123
+ add Workdir.new(args)
81
124
  end
82
125
 
126
+ sig { params(args: String).void }
83
127
  def env(*args)
84
- add Env.new(*args)
128
+ add Env.new(args)
85
129
  end
86
130
 
131
+ sig { params(args: String).void }
132
+ def arg(*args)
133
+ add Arg.new(args)
134
+ end
135
+
136
+ sig { params(args: String).void }
87
137
  def run(*args)
88
- add Run.new(*args)
138
+ add Run.new(args)
89
139
  end
90
140
 
91
- def copy(*args, **kwargs)
92
- 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)
93
144
  end
94
145
 
146
+ sig { params(args: String).void }
95
147
  def expose(*args)
96
- add Expose.new(*args)
148
+ add Expose.new(args)
97
149
  end
98
150
 
151
+ sig { params(args: String).void }
99
152
  def cmd(*args)
100
- add Cmd.new(*args)
153
+ add Cmd.new(args)
101
154
  end
102
155
 
156
+ sig { returns(String) }
103
157
  def to_s
104
- commands.map(&:to_s).join("\n")
158
+ # ensure trailing newline
159
+ "#{commands.map(&:to_s).join("\n")}\n"
160
+ end
161
+
162
+ sig { returns(String) }
163
+ def checksum
164
+ Digest::SHA256.hexdigest(to_s)
105
165
  end
106
166
 
167
+ sig { returns(T::Array[String]) }
107
168
  def exposed_ports
108
169
  commands
109
170
  .select { |c| c.is_a?(Expose) }
110
- .map { |c| c.args.first }
171
+ .map { |c| T.must(c.args.first) }
111
172
  end
112
173
 
113
- def insert_at(pos)
174
+ sig { params(pos: Integer, block: T.proc.void).void }
175
+ def insert_at(pos, &block)
114
176
  @cursor = pos
115
177
  yield
116
178
  ensure
@@ -119,6 +181,7 @@ module Kuby
119
181
 
120
182
  private
121
183
 
184
+ sig { params(cmd: Command).void }
122
185
  def add(cmd)
123
186
  commands.insert(cursor, cmd)
124
187
  @cursor += 1
@@ -1,16 +1,25 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class BuildError < StandardError; end
4
6
  class PushError < StandardError; end
7
+ class PullError < StandardError; end
5
8
  class LoginError < StandardError; end
6
9
 
7
10
  class MissingTagError < StandardError
11
+ extend T::Sig
12
+
13
+ sig { returns(String) }
8
14
  attr_reader :tag
9
15
 
16
+ sig { params(tag: String).void }
10
17
  def initialize(tag)
11
18
  @tag = tag
19
+ @message = T.let(@message, T.nilable(String))
12
20
  end
13
21
 
22
+ sig { returns(String) }
14
23
  def message
15
24
  @message ||= "Could not find tag '#{tag}'."
16
25
  end
@@ -1,12 +1,19 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class InlineLayer < Layer
6
+ extend T::Sig
7
+
8
+ sig { returns(T.proc.params(df: Dockerfile).void) }
4
9
  attr_reader :block
5
10
 
11
+ sig { params(block: T.proc.params(df: Dockerfile).void).void }
6
12
  def initialize(block)
7
13
  @block = block
8
14
  end
9
15
 
16
+ sig { override.params(dockerfile: Dockerfile).void }
10
17
  def apply_to(dockerfile)
11
18
  block.call(dockerfile)
12
19
  end
@@ -1,12 +1,22 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class Layer
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ abstract!
10
+
11
+ sig { returns(Environment) }
4
12
  attr_reader :environment
5
13
 
14
+ sig { params(environment: Environment).void }
6
15
  def initialize(environment)
7
16
  @environment = environment
8
17
  end
9
18
 
19
+ sig { params(dockerfile: Dockerfile).void }
10
20
  def apply_to(dockerfile)
11
21
  raise NotImplementedError,
12
22
  "#{__method__} must be defined in derived classes"
@@ -14,6 +24,7 @@ module Kuby
14
24
 
15
25
  private
16
26
 
27
+ sig { returns(Metadata) }
17
28
  def metadata
18
29
  environment.docker.metadata
19
30
  end
@@ -1,20 +1,46 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class LayerStack
6
+ extend T::Sig
7
+ extend T::Generic
8
+
9
+ Elem = type_member(fixed: Layer)
10
+
4
11
  include Enumerable
5
12
 
6
- attr_reader :stack, :layers
13
+ sig { returns(T::Array[Symbol]) }
14
+ attr_reader :stack
7
15
 
16
+ sig { returns(T::Hash[Symbol, Layer]) }
17
+ attr_reader :layers
18
+
19
+ sig { void }
8
20
  def initialize
9
- @stack = []
10
- @layers = {}
21
+ @stack = T.let([], T::Array[Symbol])
22
+ @layers = T.let({}, T::Hash[Symbol, Layer])
11
23
  end
12
24
 
13
- def each
14
- return to_enum(__method__) unless block_given?
15
- @stack.each { |name| yield layers[name] }
25
+ sig {
26
+ override.params(
27
+ block: T.nilable(T.proc.params(layer: Layer).void)
28
+ )
29
+ .void
30
+ }
31
+ def each(&block)
32
+ return to_enum(T.must(__method__)) unless block_given?
33
+ @stack.each { |name| yield T.must(layers[name]) }
16
34
  end
17
35
 
36
+ sig {
37
+ params(
38
+ name: Symbol,
39
+ layer: T.nilable(Layer),
40
+ block: T.nilable(T.proc.params(df: Dockerfile).void)
41
+ )
42
+ .void
43
+ }
18
44
  def use(name, layer = nil, &block)
19
45
  stack << name
20
46
 
@@ -27,6 +53,15 @@ module Kuby
27
53
  end
28
54
  end
29
55
 
56
+ sig {
57
+ params(
58
+ name: Symbol,
59
+ layer: T.nilable(T.any(Layer, T::Hash[Symbol, T.untyped])),
60
+ options: T::Hash[Symbol, T.untyped],
61
+ block: T.nilable(T.proc.params(df: Dockerfile).void)
62
+ )
63
+ .void
64
+ }
30
65
  def insert(name, layer = nil, options = {}, &block)
31
66
  # this is truly gross but it's the only way I can think of to be able
32
67
  # to call insert these two ways:
@@ -59,10 +94,16 @@ module Kuby
59
94
  end
60
95
  end
61
96
 
97
+ sig { params(name: Symbol).void }
62
98
  def delete(name)
63
99
  stack.delete(name)
64
100
  layers.delete(name)
65
101
  end
102
+
103
+ sig { params(name: Symbol).returns(T::Boolean) }
104
+ def includes?(name)
105
+ layers.include?(name)
106
+ end
66
107
  end
67
108
  end
68
109
  end
@@ -1,18 +1,37 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class LocalTags
4
- attr_reader :cli, :metadata
6
+ extend T::Sig
7
+
8
+ sig { returns CLI }
9
+ attr_reader :cli
10
+
11
+ sig { returns(Metadata) }
12
+ attr_reader :metadata
5
13
 
14
+ sig {
15
+ params(
16
+ cli: CLI,
17
+ metadata: Metadata
18
+ )
19
+ .void
20
+ }
6
21
  def initialize(cli, metadata)
7
22
  @cli = cli
8
23
  @metadata = metadata
24
+
25
+ @latest_timestamp_tag = T.let(@latest_timestamp_tag, T.nilable(TimestampTag))
9
26
  end
10
27
 
28
+ sig { returns(T::Array[String]) }
11
29
  def tags
12
30
  images = cli.images(metadata.image_url)
13
- images.map { |image| image[:tag] }
31
+ images.map { |image| T.must(image[:tag]) }
14
32
  end
15
33
 
34
+ sig { returns(T::Array[String]) }
16
35
  def latest_tags
17
36
  # find "latest" tag
18
37
  images = cli.images(metadata.image_url)
@@ -30,9 +49,15 @@ module Kuby
30
49
  end
31
50
  end
32
51
 
52
+ sig { returns(T::Array[TimestampTag]) }
33
53
  def timestamp_tags
34
54
  tags.map { |t| TimestampTag.try_parse(t) }.compact
35
55
  end
56
+
57
+ sig { returns(T.nilable(TimestampTag)) }
58
+ def latest_timestamp_tag
59
+ @latest_timestamp_tag ||= timestamp_tags.sort.last
60
+ end
36
61
  end
37
62
  end
38
63
  end