kuby-core 0.11.14 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/Gemfile +2 -2
  4. data/README.md +2 -1
  5. data/bin/kuby +2 -0
  6. data/kuby-core.gemspec +2 -2
  7. data/lib/kuby/basic_logger.rb +1 -1
  8. data/lib/kuby/cli_base.rb +9 -4
  9. data/lib/kuby/commands.rb +16 -69
  10. data/lib/kuby/docker/alpine.rb +2 -1
  11. data/lib/kuby/docker/app_image.rb +19 -0
  12. data/lib/kuby/docker/bundler_phase.rb +9 -3
  13. data/lib/kuby/docker/cli.rb +4 -12
  14. data/lib/kuby/docker/docker_uri.rb +18 -7
  15. data/lib/kuby/docker/errors.rb +1 -19
  16. data/lib/kuby/docker/image.rb +115 -0
  17. data/lib/kuby/docker/layer.rb +0 -7
  18. data/lib/kuby/docker/local_tags.rb +9 -10
  19. data/lib/kuby/docker/package_phase.rb +0 -5
  20. data/lib/kuby/docker/packages.rb +1 -0
  21. data/lib/kuby/docker/remote_tags.rb +10 -5
  22. data/lib/kuby/docker/setup_phase.rb +17 -9
  23. data/lib/kuby/docker/spec.rb +29 -62
  24. data/lib/kuby/docker/timestamp_tag.rb +8 -1
  25. data/lib/kuby/docker/timestamped_image.rb +113 -0
  26. data/lib/kuby/docker/yarn_phase.rb +2 -2
  27. data/lib/kuby/docker.rb +27 -25
  28. data/lib/kuby/environment.rb +1 -10
  29. data/lib/kuby/kubernetes/bare_metal_provider.rb +53 -0
  30. data/lib/kuby/kubernetes/deployer.rb +2 -1
  31. data/lib/kuby/kubernetes/docker_desktop_provider.rb +0 -15
  32. data/lib/kuby/kubernetes/spec.rb +21 -17
  33. data/lib/kuby/kubernetes.rb +1 -0
  34. data/lib/kuby/plugin.rb +2 -2
  35. data/lib/kuby/plugins/rails_app/assets.rb +60 -70
  36. data/lib/kuby/plugins/rails_app/assets_image.rb +55 -0
  37. data/lib/kuby/plugins/rails_app/plugin.rb +54 -213
  38. data/lib/kuby/plugins/rails_app.rb +1 -0
  39. data/lib/kuby/tasks.rb +30 -69
  40. data/lib/kuby/version.rb +1 -1
  41. data/lib/kuby.rb +3 -20
  42. data/spec/docker/spec_spec.rb +21 -118
  43. data/spec/docker/timestamped_image_spec.rb +123 -0
  44. data/spec/spec_helper.rb +10 -11
  45. metadata +11 -14
  46. data/lib/kuby/dev_setup.rb +0 -346
  47. data/lib/kuby/docker/dev_spec.rb +0 -202
  48. data/lib/kuby/docker/metadata.rb +0 -90
  49. data/lib/kuby/docker/tags.rb +0 -92
  50. data/lib/kuby/rails_commands.rb +0 -84
  51. data/spec/docker/metadata_spec.rb +0 -73
  52. data/spec/dummy/Gemfile.lock +0 -223
  53. data/spec/dummy/config/master.key +0 -1
  54. data/spec/dummy/tmp/cache/bootsnap-load-path-cache +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfd902325b0bf78437ea91ba6021ee0cc27f83c67d60a703508a8b0c5a84bc86
4
- data.tar.gz: 9598df94486a386235a3566c4c0422f824c30870551251ce3f4836fc94677b39
3
+ metadata.gz: a443b66d4dff19f6a2112b6365a9579b0490b049ef51ab612ad9e6cf4a807901
4
+ data.tar.gz: 2b38151be094c758a64ecdc95c585f184f4e9eea1affbdc4d071cc7a20d499a0
5
5
  SHA512:
6
- metadata.gz: 2ba1c29f18311795a39c8038940c6bc53ae6868523d520af81a52543ee6726282696f07af78b2cd8d6736ce5d0e7bc98ffd14f61693cf0b7421b7cccbbe6ea70
7
- data.tar.gz: 801f401ba743d5375e59c33e1be57b6ae7767d5580e37bef0186dd2e299e7293f1a9e2e277a10b43b94977e0f982be8908e57153fb14d136a9e54aea92031fdf
6
+ metadata.gz: 6cf93a88bc24ab142fa497daddc7227d417c138391f46db6f5b77a862c96e9c2733d880eded21d464170963902364ac0f2806f84cd083d0a5b408231987bcf2b
7
+ data.tar.gz: dab2dcd180ff19421ef44aef1a3384e1faa0b49511925e6557d54500a652a5c854217a8c463cd738cd6a745b2eb1804262e35539635fdb4d98ed13d2abc90aa2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## 0.13.0
2
+ * Fix handling rails/rake options in remote exec (@palkan, #60)
3
+ * Add `bundler_phase.gemfiles(*paths)` to allow adding additional gemfiles (@palkan, #61)
4
+
5
+ ## 0.12.0
6
+ * Fix issue causing volume mount errors when k8s tries to schedule asset pods on multiple nodes (fixes #42).
7
+ - Persistent volumes can only be mounted on a single physical node.
8
+ - Kuby now creates a separate assets image powered by nginx.
9
+ - Ingress routes requests to either the Rails service or assets service depending on the URL (i.e. /assets).
10
+ - Since the ingress layer is now essential, the Docker Desktop provider no longer deletes ingresses or monkeys with service objects. You'll have to either 1) add an entry for your hostname to your hosts file, or 2) set the `Host` header when making requests to your app.
11
+ * Plugins can now specify additional Dockerfiles to build during `kuby build`.
12
+ * Switch from TravisCI to Github Actions.
13
+ * Remove support for development environments.
14
+ - Proved to be too difficult to maintain.
15
+ - Kuby is a _deployment_ tool anyway, not a dev tool.
16
+ - Maybe we can turn the dev stuff into a gem at some point.
17
+ * Refactor Docker image logic.
18
+ - Introduced the `Image` class and friends.
19
+ - Deleted the `Kuby::Docker::Metadata` class.
20
+ * Add missing git dependency to Alpine distro.
21
+ * Add a bare metal provider (fixes #10).
22
+
23
+ ## 0.11.16
24
+ * Fix yarn phase
25
+ - Apparently you have to copy at least one file, TIL.
26
+
27
+ ## 0.11.15
28
+ * Copy over .npmrc and .yarnrc before running yarn install.
29
+
1
30
  ## 0.11.14
2
31
  * Don't include port in image host for registry secrets (no idea why)
3
32
 
data/Gemfile CHANGED
@@ -5,10 +5,10 @@ gemspec
5
5
  group :development, :test do
6
6
  gem 'pry-byebug'
7
7
  gem 'rake'
8
- gem 'sorbet', '~> 0.5'
8
+ # lock to a specific version to prevent breaking CI when new versions come out
9
+ gem 'sorbet', '= 0.5.6433'
9
10
  end
10
11
 
11
12
  group :test do
12
13
  gem 'rspec', '~> 3.0'
13
- gem 'timecop', '~> 0.9'
14
14
  end
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  ## Kuby
2
2
 
3
- [![Build Status](https://travis-ci.com/getkuby/kuby-core.svg?branch=master)](https://travis-ci.com/getkuby/kuby-core)
3
+ ![Unit Tests](https://github.com/getkuby/kuby-core/actions/workflows/unit_tests.yml/badge.svg?branch=master)
4
+ ![Integration Tests](https://github.com/getkuby/kuby-core/actions/workflows/integration_tests.yml/badge.svg?branch=master)
4
5
 
5
6
  Deploy your Rails app the easy way.
6
7
 
data/bin/kuby CHANGED
@@ -1,4 +1,6 @@
1
1
  #! /usr/bin/env ruby
2
2
 
3
+ $stdout.sync = true
4
+
3
5
  require 'kuby'
4
6
  exit Kuby::Commands.run(ARGV)
data/kuby-core.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- $:.unshift File.join(File.dirname(__FILE__), 'lib')
1
+ $:.unshift File.expand_path('lib', __dir__)
2
2
  require 'kuby/version'
3
3
 
4
4
  Gem::Specification.new do |s|
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
13
13
  s.platform = Gem::Platform::RUBY
14
14
 
15
15
  s.add_dependency 'colorize', '~> 0.8'
16
- s.add_dependency 'docker-remote', '~> 0.5'
16
+ s.add_dependency 'docker-remote', '~> 0.6'
17
17
  s.add_dependency 'gli', '~> 2.0'
18
18
  s.add_dependency 'helm-cli', '~> 0.3'
19
19
  # See: https://github.com/Shopify/krane/pull/720
@@ -52,7 +52,7 @@ module Kuby
52
52
  block: T.nilable(T.proc.returns(T.untyped))
53
53
  ).void
54
54
  }
55
- def fatal(progname_or_msg, &block)
55
+ def fatal(progname_or_msg = nil, &block)
56
56
  if block
57
57
  super(progname_or_msg) { ColorizedString[block.call].red }
58
58
  else
data/lib/kuby/cli_base.rb CHANGED
@@ -7,21 +7,26 @@ module Kuby
7
7
  class CLIBase
8
8
  extend T::Sig
9
9
 
10
+ BeforeCallback = T.type_alias { T.proc.params(cmd: T::Array[String]).void }
11
+ AfterCallback = T.type_alias do
12
+ T.proc.params(cmd: T::Array[String], last_status: T.nilable(Process::Status)).void
13
+ end
14
+
10
15
  sig { returns(T.nilable(Process::Status)) }
11
16
  def last_status
12
17
  Thread.current[status_key]
13
18
  end
14
19
 
15
- sig { params(block: T.proc.params(cmd: String).void).void }
20
+ sig { params(block: BeforeCallback).void }
16
21
  def before_execute(&block)
17
- @before_execute = T.let(@before_execute, T.nilable(T::Array[T.proc.params(cmd: String).void]))
22
+ @before_execute = T.let(@before_execute, T.nilable(T::Array[BeforeCallback]))
18
23
  @before_execute ||= []
19
24
  @before_execute << block
20
25
  end
21
26
 
22
- sig { params(block: T.proc.params(cmd: String).void).void }
27
+ sig { params(block: AfterCallback).void }
23
28
  def after_execute(&block)
24
- @after_execute = T.let(@after_execute, T.nilable(T::Array[T.proc.params(cmd: String).void]))
29
+ @after_execute = T.let(@after_execute, T.nilable(T::Array[AfterCallback]))
25
30
  @after_execute ||= []
26
31
  @after_execute << block
27
32
  end
data/lib/kuby/commands.rb CHANGED
@@ -25,9 +25,10 @@ module Kuby
25
25
  def run(args)
26
26
  if idx = args.index('rails') || idx = args.index('rake')
27
27
  @rails_options = T.let(@rails_options, T.nilable(T::Array[String]))
28
- @rails_options = args[idx..-1]
28
+ @rails_options = args[(idx + 1)..-1]
29
29
  super(args[0..idx])
30
30
  else
31
+ @rails_options = []
31
32
  super
32
33
  end
33
34
  end
@@ -38,13 +39,6 @@ module Kuby
38
39
  Kuby::Tasks.new(Kuby.environment)
39
40
  end
40
41
 
41
- sig { void }
42
- def self.must_be_dev_env!
43
- unless Kuby.environment.development?
44
- fail "Command not supported in the '#{Kuby.environment.name}' environment"
45
- end
46
- end
47
-
48
42
  program_desc 'Kuby command-line interface. Kuby is a convention '\
49
43
  'over configuration approach for running Rails apps in Kubernetes.'
50
44
 
@@ -68,59 +62,19 @@ module Kuby
68
62
  true
69
63
  end
70
64
 
71
- # These are only stubs included to fill out the help screens. Rails
72
- # commands are handled by the RailsCommands class.
73
- desc 'Runs a Rails command.'
74
- command :rails do |rc|
75
- rc.action do |global_options, options, args|
76
- must_be_dev_env!
77
- exit 1 unless tasks.dev_deployment_ok
78
- @rails_options = T.let(@rails_options, T.nilable(T::Array[String]))
79
- Kuby::RailsCommands.run(@rails_options)
80
- end
81
-
82
- rc.desc 'Runs the rails server (run `rails server --help` for options)'
83
- rc.command [:server, :s] do |c|
84
- c.action do |global_options, options, args|
85
- must_be_dev_env!
86
- exit 1 unless tasks.dev_deployment_ok
87
- Kuby::RailsCommands.run(@rails_options)
88
- end
89
- end
90
-
91
- rc.desc 'Runs a script in the Rails environment (run `rails runner --help` for options)'
92
- rc.command [:runner, :r] do |c|
93
- c.action do |global_options, options, args|
94
- must_be_dev_env!
95
- exit 1 unless tasks.dev_deployment_ok
96
- Kuby::RailsCommands.run(@rails_options)
97
- end
98
- end
99
-
100
- rc.desc 'Starts an interactive Ruby console with the Rails environment loaded '\
101
- '(run `rails console --help` for options)'
102
- rc.command [:console, :c] do |c|
103
- c.action do |global_options, options, args|
104
- must_be_dev_env!
105
- exit 1 unless tasks.dev_deployment_ok
106
- Kuby::RailsCommands.run(@rails_options)
107
- end
108
- end
109
- end
110
-
111
- desc 'Runs a rake task.'
112
- command :rake do |rc|
113
- rc.action do |global_options, options, args|
114
- must_be_dev_env!
115
- exit 1 unless tasks.dev_deployment_ok
116
- Kuby::RailsCommands.run(@rails_options)
117
- end
118
- end
119
-
120
65
  desc 'Builds the Docker image.'
121
66
  command :build do |c|
67
+ c.flag [:a, :arg], required: false, multiple: true
122
68
  c.action do |global_options, options, args|
123
- tasks.build
69
+ build_args = {}.tap do |build_args|
70
+ (options[:arg] || []).each do |a|
71
+ key, value = a.split('=')
72
+ value = value[1..-2] if value.start_with?('"') || value.start_with?("'")
73
+ build_args[key] = value
74
+ end
75
+ end
76
+
77
+ tasks.build(build_args)
124
78
  end
125
79
  end
126
80
 
@@ -138,10 +92,10 @@ module Kuby
138
92
  end
139
93
  end
140
94
 
141
- desc 'Prints the effective Dockerfile used to build the Docker image.'
142
- command :dockerfile do |c|
95
+ desc 'Prints the effective Dockerfiles used to build Docker images.'
96
+ command :dockerfiles do |c|
143
97
  c.action do |global_options, options, args|
144
- tasks.print_dockerfile
98
+ tasks.print_dockerfiles
145
99
  end
146
100
  end
147
101
 
@@ -197,7 +151,6 @@ module Kuby
197
151
  rc.desc 'Tails (i.e. continuously streams) the Rails log from your running application.'
198
152
  rc.command :logs do |c|
199
153
  c.action do |global_options, options, args|
200
- exit 1 unless tasks.dev_deployment_ok
201
154
  tasks.remote_logs
202
155
  end
203
156
  end
@@ -205,7 +158,6 @@ module Kuby
205
158
  rc.desc 'Lists running Kubernetes pods.'
206
159
  rc.command :status do |c|
207
160
  c.action do |global_options, options, args|
208
- exit 1 unless tasks.dev_deployment_ok
209
161
  tasks.remote_status
210
162
  end
211
163
  end
@@ -213,15 +165,13 @@ module Kuby
213
165
  rc.desc 'Runs an arbitrary command inside a running Rails pod.'
214
166
  rc.command :exec do |c|
215
167
  c.action do |global_options, options, args|
216
- exit 1 unless tasks.dev_deployment_ok
217
- tasks.remote_exec(args)
168
+ tasks.remote_exec([*args, *@rails_options])
218
169
  end
219
170
  end
220
171
 
221
172
  rc.desc 'Establishes a shell inside a running Rails pod.'
222
173
  rc.command :shell do |c|
223
174
  c.action do |global_options, options, args|
224
- exit 1 unless tasks.dev_deployment_ok
225
175
  tasks.remote_shell
226
176
  end
227
177
  end
@@ -229,7 +179,6 @@ module Kuby
229
179
  rc.desc 'Establishes a Rails console inside a running Rails pod.'
230
180
  rc.command :console do |c|
231
181
  c.action do |global_options, options, args|
232
- exit 1 unless tasks.dev_deployment_ok
233
182
  tasks.remote_console
234
183
  end
235
184
  end
@@ -237,7 +186,6 @@ module Kuby
237
186
  rc.desc 'Establishes a database console inside a running Rails pod.'
238
187
  rc.command :dbconsole do |c|
239
188
  c.action do |global_options, options, args|
240
- exit 1 unless tasks.dev_deployment_ok
241
189
  tasks.remote_dbconsole
242
190
  end
243
191
  end
@@ -245,7 +193,6 @@ module Kuby
245
193
  rc.desc "Restarts the Rails app's web pods."
246
194
  rc.command :restart do |c|
247
195
  c.action do |global_options, options, args|
248
- exit 1 unless tasks.dev_deployment_ok
249
196
  tasks.remote_restart
250
197
  end
251
198
  end
@@ -10,7 +10,8 @@ module Kuby
10
10
  [:nodejs, '12.14.1'],
11
11
  [:yarn, '1.21.1'],
12
12
  [:c_toolchain, nil],
13
- [:tzdata, nil]
13
+ [:tzdata, nil],
14
+ [:git, nil]
14
15
  ].freeze, T::Array[[Symbol, T.nilable(String)]])
15
16
 
16
17
  sig { returns(Layer) }
@@ -0,0 +1,19 @@
1
+
2
+ # typed: strict
3
+
4
+ module Kuby
5
+ module Docker
6
+ class AppImage < ::Kuby::Docker::TimestampedImage
7
+ extend T::Sig
8
+
9
+ sig { params(build_args: T::Hash[String, String]).returns(AppImage) }
10
+ def build(build_args = {})
11
+ unless ENV.fetch('RAILS_MASTER_KEY', '').empty?
12
+ build_args['RAILS_MASTER_KEY'] = T.must(ENV['RAILS_MASTER_KEY'])
13
+ end
14
+
15
+ super(build_args)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -35,6 +35,7 @@ module Kuby
35
35
 
36
36
  @version = T.let(@version, T.nilable(String))
37
37
  @gemfile = T.let(@gemfile, T.nilable(String))
38
+ @gemfiles = T.let([], T::Array[String])
38
39
  @without = T.let(@without, T.nilable(T::Array[String]))
39
40
  end
40
41
 
@@ -51,9 +52,9 @@ module Kuby
51
52
  dockerfile.copy(gf, '.')
52
53
  dockerfile.copy(lf, '.')
53
54
 
54
- # set bundle path so docker will cache the bundle
55
- dockerfile.run('mkdir', './bundle')
56
- dockerfile.env('BUNDLE_PATH=./bundle')
55
+ @gemfiles.each do |file|
56
+ dockerfile.copy(file, file)
57
+ end
57
58
 
58
59
  unless wo.empty?
59
60
  dockerfile.env("BUNDLE_WITHOUT='#{wo.join(' ')}'")
@@ -71,6 +72,11 @@ module Kuby
71
72
  dockerfile.env("PATH=./bin:$PATH")
72
73
  end
73
74
 
75
+ sig { params(paths: String).void }
76
+ def gemfiles(*paths)
77
+ @gemfiles.concat(paths)
78
+ end
79
+
74
80
  private
75
81
 
76
82
  sig { returns(String) }
@@ -53,19 +53,11 @@ module Kuby
53
53
  config.fetch('auths', {}).keys
54
54
  end
55
55
 
56
- sig {
57
- params(
58
- dockerfile: Dockerfile,
59
- image_url: String,
60
- tags: T::Array[String],
61
- build_args: T::Hash[T.any(Symbol, String), String]
62
- )
63
- .void
64
- }
65
- def build(dockerfile:, image_url:, tags:, build_args: {})
56
+ sig { params(image: Image, build_args: T::Hash[T.any(Symbol, String), String]).void }
57
+ def build(image, build_args: {})
66
58
  cmd = [
67
59
  executable, 'build',
68
- *tags.flat_map { |tag| ['-t', "#{image_url}:#{tag}"] },
60
+ *image.tags.flat_map { |tag| ['-t', "#{image.image_url}:#{tag}"] },
69
61
  *build_args.flat_map do |arg, val|
70
62
  ['--build-arg', Shellwords.shellescape("#{arg}=#{val}")]
71
63
  end,
@@ -73,7 +65,7 @@ module Kuby
73
65
  ]
74
66
 
75
67
  open3_w(cmd) do |stdin, _wait_threads|
76
- stdin.puts(dockerfile.to_s)
68
+ stdin.puts(image.dockerfile.to_s)
77
69
  end
78
70
 
79
71
  unless T.must(last_status).success?
@@ -1,11 +1,14 @@
1
- # typed: false
1
+ # typed: strict
2
2
 
3
3
  module Kuby
4
4
  module Docker
5
5
  class DockerURI
6
- DEFAULT_REGISTRY_HOST = 'index.docker.io'.freeze
7
- DEFAULT_REGISTRY_PORT = 443
6
+ extend T::Sig
8
7
 
8
+ DEFAULT_REGISTRY_HOST = T.let('index.docker.io'.freeze, String)
9
+ DEFAULT_REGISTRY_PORT = T.let(443, Integer)
10
+
11
+ sig { params(url: String).returns(DockerURI) }
9
12
  def self.parse(url)
10
13
  if idx = url.index('://')
11
14
  url = url[(idx + 3)..-1] || ''
@@ -13,17 +16,25 @@ module Kuby
13
16
 
14
17
  host_port, *path = url.split('/')
15
18
  host, port, *path = if host_port =~ /[.:]/
16
- hst, prt = host_port.split(':')
17
- [hst, prt || DEFAULT_REGISTRY_PORT, *path]
19
+ hst, prt = T.must(host_port).split(':')
20
+ [T.must(hst), prt || DEFAULT_REGISTRY_PORT, *path]
18
21
  else
19
22
  [DEFAULT_REGISTRY_HOST, DEFAULT_REGISTRY_PORT, host_port, *path]
20
23
  end
21
24
 
22
- new(host, port.to_i, path.join('/'))
25
+ new(host.to_s, port.to_i, (path || []).join('/'))
23
26
  end
24
27
 
25
- attr_reader :host, :port, :path
28
+ sig { returns(String) }
29
+ attr_reader :host
30
+
31
+ sig { returns(Integer) }
32
+ attr_reader :port
33
+
34
+ sig { returns(String) }
35
+ attr_reader :path
26
36
 
37
+ sig { params(host: String, port: Integer, path: String).void }
27
38
  def initialize(host, port, path)
28
39
  @host = host
29
40
  @port = port
@@ -6,25 +6,7 @@ module Kuby
6
6
  class PushError < StandardError; end
7
7
  class PullError < StandardError; end
8
8
  class LoginError < StandardError; end
9
-
10
- class MissingTagError < StandardError
11
- extend T::Sig
12
-
13
- sig { returns(String) }
14
- attr_reader :tag
15
-
16
- sig { params(tag: String).void }
17
- def initialize(tag)
18
- @tag = tag
19
- @message = T.let(@message, T.nilable(String))
20
- end
21
-
22
- sig { returns(String) }
23
- def message
24
- @message ||= "Could not find tag '#{tag}'."
25
- end
26
- end
27
-
9
+ class MissingTagError < StandardError; end
28
10
  class UnsupportedDistroError < StandardError; end
29
11
  class MissingPackageError < StandardError; end
30
12
  class MissingDistroError < StandardError; end
@@ -0,0 +1,115 @@
1
+ # typed: strict
2
+
3
+ module Kuby
4
+ module Docker
5
+ class Image
6
+ extend T::Sig
7
+
8
+ sig { returns(String) }
9
+ attr_reader :image_url
10
+
11
+ sig { returns(Credentials) }
12
+ attr_reader :credentials
13
+
14
+ sig { returns(T.nilable(String)) }
15
+ attr_reader :main_tag
16
+
17
+ sig { returns T::Array[String] }
18
+ attr_reader :alias_tags
19
+
20
+ sig {
21
+ params(
22
+ dockerfile: T.any(Dockerfile, T.proc.returns(Dockerfile)),
23
+ image_url: String,
24
+ credentials: Credentials,
25
+ main_tag: T.nilable(String),
26
+ alias_tags: T::Array[String]
27
+ ).void
28
+ }
29
+ def initialize(dockerfile, image_url, credentials, main_tag = nil, alias_tags = [])
30
+ @dockerfile = T.let(dockerfile, T.any(Dockerfile, T.proc.returns(Dockerfile)))
31
+ @image_url = T.let(image_url, String)
32
+ @credentials = T.let(credentials, Credentials)
33
+ @main_tag = T.let(main_tag, T.nilable(String))
34
+ @alias_tags = T.let(alias_tags, T::Array[String])
35
+
36
+ @image_host = T.let(@image_host, T.nilable(String))
37
+ @image_hostname = T.let(@image_hostname, T.nilable(String))
38
+ @image_repo = T.let(@image_repo, T.nilable(String))
39
+ @full_image_uri = T.let(@full_image_uri, T.nilable(DockerURI))
40
+ @docker_cli = T.let(@docker_cli, T.nilable(Docker::CLI))
41
+ end
42
+
43
+ sig { returns(Image) }
44
+ def new_version
45
+ raise NotImplementedError, 'please use a Docker::Image subclass'
46
+ end
47
+
48
+ sig { returns(Image) }
49
+ def current_version
50
+ raise NotImplementedError, 'please use a Docker::Image subclass'
51
+ end
52
+
53
+ sig { params(current_tag: T.nilable(String)).returns(Image) }
54
+ def previous_version(current_tag = nil)
55
+ raise NotImplementedError, 'please use a Docker::Image subclass'
56
+ end
57
+
58
+ sig { returns(Dockerfile) }
59
+ def dockerfile
60
+ if @dockerfile.respond_to?(:call)
61
+ T.cast(@dockerfile, T.proc.returns(Dockerfile)).call
62
+ else
63
+ T.cast(@dockerfile, Dockerfile)
64
+ end
65
+ end
66
+
67
+ sig { returns(String) }
68
+ def image_host
69
+ @image_host ||= "#{image_uri.host}:#{image_uri.port}"
70
+ end
71
+
72
+ sig { returns(String) }
73
+ def image_hostname
74
+ @image_hostname ||= image_uri.host
75
+ end
76
+
77
+ sig { returns(String) }
78
+ def image_repo
79
+ @image_repo ||= image_uri.path
80
+ end
81
+
82
+ sig { returns(DockerURI) }
83
+ def image_uri
84
+ @full_image_uri ||= DockerURI.parse(image_url)
85
+ end
86
+
87
+ sig { returns(T::Array[String]) }
88
+ def tags
89
+ [main_tag, *alias_tags].compact
90
+ end
91
+
92
+ sig { params(build_args: T::Hash[String, String]).void }
93
+ def build(build_args = {})
94
+ raise NotImplementedError, 'please use a Docker::Image subclass'
95
+ end
96
+
97
+ sig { params(tag: String).void }
98
+ def push(tag)
99
+ raise NotImplementedError, 'please use a Docker::Image subclass'
100
+ end
101
+
102
+ sig { returns(Docker::CLI) }
103
+ def docker_cli
104
+ @docker_cli ||= Docker::CLI.new
105
+ end
106
+
107
+ private
108
+
109
+ sig { params(main_tag: String, alias_tags: T::Array[String]).returns(Image) }
110
+ def duplicate_with_tags(main_tag, alias_tags)
111
+ self.class.new(dockerfile, image_url, credentials, main_tag, alias_tags)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -21,13 +21,6 @@ module Kuby
21
21
  raise NotImplementedError,
22
22
  "#{__method__} must be defined in derived classes"
23
23
  end
24
-
25
- private
26
-
27
- sig { returns(Metadata) }
28
- def metadata
29
- environment.docker.metadata
30
- end
31
24
  end
32
25
  end
33
26
  end
@@ -8,37 +8,36 @@ module Kuby
8
8
  sig { returns CLI }
9
9
  attr_reader :cli
10
10
 
11
- sig { returns(Metadata) }
12
- attr_reader :metadata
11
+ sig { returns(String) }
12
+ attr_reader :image_url
13
13
 
14
14
  sig {
15
15
  params(
16
16
  cli: CLI,
17
- metadata: Metadata
17
+ image_url: String
18
18
  )
19
19
  .void
20
20
  }
21
- def initialize(cli, metadata)
21
+ def initialize(cli, image_url)
22
22
  @cli = cli
23
- @metadata = metadata
24
-
23
+ @image_url = image_url
25
24
  @latest_timestamp_tag = T.let(@latest_timestamp_tag, T.nilable(TimestampTag))
26
25
  end
27
26
 
28
27
  sig { returns(T::Array[String]) }
29
28
  def tags
30
- images = cli.images(metadata.image_url)
29
+ images = cli.images(image_url)
31
30
  images.map { |image| T.must(image[:tag]) }
32
31
  end
33
32
 
34
33
  sig { returns(T::Array[String]) }
35
34
  def latest_tags
36
35
  # find "latest" tag
37
- images = cli.images(metadata.image_url)
38
- latest = images.find { |image| image[:tag] == Tags::LATEST }
36
+ images = cli.images(image_url)
37
+ latest = images.find { |image| image[:tag] == Kuby::Docker::LATEST_TAG }
39
38
 
40
39
  unless latest
41
- raise MissingTagError.new(Tags::LATEST)
40
+ raise MissingTagError, "could not find tag #{Kuby::Docker::LATEST_TAG}"
42
41
  end
43
42
 
44
43
  # find all tags that point to the same image as 'latest'
@@ -69,11 +69,6 @@ module Kuby
69
69
  raise MissingPackageError, "package '#{package_name}' hasn't been registered"
70
70
  end
71
71
  end
72
-
73
- sig { returns(Metadata) }
74
- def metadata
75
- environment.docker.metadata
76
- end
77
72
  end
78
73
  end
79
74
  end
@@ -1,4 +1,5 @@
1
1
  # typed: strict
2
+
2
3
  module Kuby
3
4
  module Docker
4
5
  module Packages