kuby-core 0.11.15 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/Gemfile +1 -2
  4. data/README.md +2 -1
  5. data/kuby-core.gemspec +1 -1
  6. data/lib/kuby/commands.rb +24 -72
  7. data/lib/kuby/docker/alpine.rb +2 -1
  8. data/lib/kuby/docker/app_image.rb +33 -0
  9. data/lib/kuby/docker/bundler_phase.rb +10 -0
  10. data/lib/kuby/docker/cli.rb +7 -13
  11. data/lib/kuby/docker/docker_uri.rb +18 -7
  12. data/lib/kuby/docker/errors.rb +1 -19
  13. data/lib/kuby/docker/image.rb +119 -0
  14. data/lib/kuby/docker/layer.rb +0 -7
  15. data/lib/kuby/docker/local_tags.rb +9 -10
  16. data/lib/kuby/docker/package_phase.rb +0 -5
  17. data/lib/kuby/docker/packages.rb +1 -0
  18. data/lib/kuby/docker/remote_tags.rb +10 -5
  19. data/lib/kuby/docker/setup_phase.rb +17 -9
  20. data/lib/kuby/docker/spec.rb +29 -62
  21. data/lib/kuby/docker/timestamp_tag.rb +8 -1
  22. data/lib/kuby/docker/timestamped_image.rb +113 -0
  23. data/lib/kuby/docker/yarn_phase.rb +1 -4
  24. data/lib/kuby/docker.rb +27 -25
  25. data/lib/kuby/environment.rb +1 -10
  26. data/lib/kuby/kubernetes/bare_metal_provider.rb +16 -4
  27. data/lib/kuby/kubernetes/deployer.rb +1 -1
  28. data/lib/kuby/kubernetes/docker_desktop_provider.rb +0 -15
  29. data/lib/kuby/kubernetes/spec.rb +21 -17
  30. data/lib/kuby/plugin.rb +2 -2
  31. data/lib/kuby/plugins/rails_app/assets.rb +61 -70
  32. data/lib/kuby/plugins/rails_app/assets_image.rb +56 -0
  33. data/lib/kuby/plugins/rails_app/plugin.rb +53 -236
  34. data/lib/kuby/plugins/rails_app.rb +1 -0
  35. data/lib/kuby/tasks.rb +44 -70
  36. data/lib/kuby/version.rb +1 -1
  37. data/lib/kuby.rb +2 -20
  38. data/spec/docker/spec_spec.rb +21 -118
  39. data/spec/docker/timestamped_image_spec.rb +123 -0
  40. data/spec/spec_helper.rb +10 -11
  41. metadata +10 -14
  42. data/lib/kuby/dev_setup.rb +0 -346
  43. data/lib/kuby/docker/dev_spec.rb +0 -202
  44. data/lib/kuby/docker/metadata.rb +0 -90
  45. data/lib/kuby/docker/tags.rb +0 -92
  46. data/lib/kuby/rails_commands.rb +0 -84
  47. data/spec/docker/metadata_spec.rb +0 -73
  48. data/spec/dummy/Gemfile.lock +0 -223
  49. data/spec/dummy/config/master.key +0 -1
  50. 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: '03278595cc2f5eb23fcfb47a15fd8fea9aaf06546e3c9d92a71080953c3d10db'
4
- data.tar.gz: 893a184f166b3bb453f96ef3529fbf65f8fef171f54a7268661645aa30834e99
3
+ metadata.gz: 3b6d5377f043be7d0aa02cddf817a9dd7fdbaa500c2ed94a2fdb92fa7ef0c1cc
4
+ data.tar.gz: 57c6cb1a15c4385a7675a05637dbfd085e2b2f438f5429104ec66203e854dd68
5
5
  SHA512:
6
- metadata.gz: 0d0868b638c06e13db7b4353af14c6fa1d82bc143239cac4322ba3be4f723eca1a3a70c8e271ec5091afea24d088acd2b744e6b7af3347ceeddfff63eabbb285
7
- data.tar.gz: f1a859ddf32f023f9c593345a50f9d11e998287ff05030117cf599920ed2c5b53ed8b54804080f7271be7b47ef9d7cfee8cfee168bf972226ec3e889e35dde60
6
+ metadata.gz: 9c903b0768473d63df1a3ddb9ee3146193abad9c809614f7ccd2e7b7c711a2a3effd3810a3b67780ee68ea3198b8770099fcb3fd4d2a334b39b664f59b8e9e8f
7
+ data.tar.gz: 69fc8934c14181930c03d3d3ffe050e2da0a85edbbd2f5bba38bf0509131149c643ea42577afcec3a4625057eab52f57bab1e00c3271bedcf491d2e11f1ae696
data/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ ## 0.14.0
2
+ * Make RAILS_MASTER_KEY available in the assets image (@palkan, #63)
3
+ * Allow specifying custom docker build options via CLI (@palkan, #65)
4
+
5
+ ## 0.13.0
6
+ * Fix handling rails/rake options in remote exec (@palkan, #60)
7
+ * Add `bundler_phase.gemfiles(*paths)` to allow adding additional gemfiles (@palkan, #61)
8
+
9
+ ## 0.12.0
10
+ * Fix issue causing volume mount errors when k8s tries to schedule asset pods on multiple nodes (fixes #42).
11
+ - Persistent volumes can only be mounted on a single physical node.
12
+ - Kuby now creates a separate assets image powered by nginx.
13
+ - Ingress routes requests to either the Rails service or assets service depending on the URL (i.e. /assets).
14
+ - 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.
15
+ * Plugins can now specify additional Dockerfiles to build during `kuby build`.
16
+ * Switch from TravisCI to Github Actions.
17
+ * Remove support for development environments.
18
+ - Proved to be too difficult to maintain.
19
+ - Kuby is a _deployment_ tool anyway, not a dev tool.
20
+ - Maybe we can turn the dev stuff into a gem at some point.
21
+ * Refactor Docker image logic.
22
+ - Introduced the `Image` class and friends.
23
+ - Deleted the `Kuby::Docker::Metadata` class.
24
+ * Add missing git dependency to Alpine distro.
25
+ * Add a bare metal provider (fixes #10).
26
+
27
+ ## 0.11.16
28
+ * Fix yarn phase
29
+ - Apparently you have to copy at least one file, TIL.
30
+
1
31
  ## 0.11.15
2
32
  * Copy over .npmrc and .yarnrc before running yarn install.
3
33
 
data/Gemfile CHANGED
@@ -6,10 +6,9 @@ group :development, :test do
6
6
  gem 'pry-byebug'
7
7
  gem 'rake'
8
8
  # lock to a specific version to prevent breaking CI when new versions come out
9
- gem 'sorbet', '= 0.5.6397'
9
+ gem 'sorbet', '= 0.5.6433'
10
10
  end
11
11
 
12
12
  group :test do
13
13
  gem 'rspec', '~> 3.0'
14
- gem 'timecop', '~> 0.9'
15
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/kuby-core.gemspec CHANGED
@@ -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
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,66 +62,28 @@ 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|
122
- c.action do |global_options, options, args|
123
- tasks.build
67
+ c.flag [:a, :arg], required: false, multiple: true
68
+ c.flag [:only], required: false
69
+ c.action do |global_options, options, docker_args|
70
+ build_args = {}.tap do |build_args|
71
+ (options[:arg] || []).each do |a|
72
+ key, value = a.split('=', 2)
73
+ value = value[1..-2] if value.start_with?('"') || value.start_with?("'")
74
+ build_args[key] = value
75
+ end
76
+ end
77
+
78
+ tasks.build(build_args, docker_args, options[:only])
124
79
  end
125
80
  end
126
81
 
127
82
  desc 'Pushes the Docker image to the configured registry.'
128
83
  command :push do |c|
84
+ c.flag [:only], required: false
129
85
  c.action do |global_options, options, args|
130
- tasks.push
86
+ tasks.push(options[:only])
131
87
  end
132
88
  end
133
89
 
@@ -138,10 +94,11 @@ module Kuby
138
94
  end
139
95
  end
140
96
 
141
- desc 'Prints the effective Dockerfile used to build the Docker image.'
142
- command :dockerfile do |c|
97
+ desc 'Prints the effective Dockerfiles used to build Docker images.'
98
+ command :dockerfiles do |c|
99
+ c.flag [:only], required: false
143
100
  c.action do |global_options, options, args|
144
- tasks.print_dockerfile
101
+ tasks.print_dockerfiles(options[:only])
145
102
  end
146
103
  end
147
104
 
@@ -163,8 +120,10 @@ module Kuby
163
120
 
164
121
  desc 'Prints the effective Kubernetes resources that will be applied on deploy.'
165
122
  command :resources do |c|
123
+ c.flag [:K, :kind], required: false
124
+ c.flag [:N, :name], required: false
166
125
  c.action do |global_options, options, args|
167
- tasks.print_resources
126
+ tasks.print_resources(options[:kind], options[:name])
168
127
  end
169
128
  end
170
129
 
@@ -197,7 +156,6 @@ module Kuby
197
156
  rc.desc 'Tails (i.e. continuously streams) the Rails log from your running application.'
198
157
  rc.command :logs do |c|
199
158
  c.action do |global_options, options, args|
200
- exit 1 unless tasks.dev_deployment_ok
201
159
  tasks.remote_logs
202
160
  end
203
161
  end
@@ -205,7 +163,6 @@ module Kuby
205
163
  rc.desc 'Lists running Kubernetes pods.'
206
164
  rc.command :status do |c|
207
165
  c.action do |global_options, options, args|
208
- exit 1 unless tasks.dev_deployment_ok
209
166
  tasks.remote_status
210
167
  end
211
168
  end
@@ -213,15 +170,13 @@ module Kuby
213
170
  rc.desc 'Runs an arbitrary command inside a running Rails pod.'
214
171
  rc.command :exec do |c|
215
172
  c.action do |global_options, options, args|
216
- exit 1 unless tasks.dev_deployment_ok
217
- tasks.remote_exec(args)
173
+ tasks.remote_exec([*args, *@rails_options])
218
174
  end
219
175
  end
220
176
 
221
177
  rc.desc 'Establishes a shell inside a running Rails pod.'
222
178
  rc.command :shell do |c|
223
179
  c.action do |global_options, options, args|
224
- exit 1 unless tasks.dev_deployment_ok
225
180
  tasks.remote_shell
226
181
  end
227
182
  end
@@ -229,7 +184,6 @@ module Kuby
229
184
  rc.desc 'Establishes a Rails console inside a running Rails pod.'
230
185
  rc.command :console do |c|
231
186
  c.action do |global_options, options, args|
232
- exit 1 unless tasks.dev_deployment_ok
233
187
  tasks.remote_console
234
188
  end
235
189
  end
@@ -237,7 +191,6 @@ module Kuby
237
191
  rc.desc 'Establishes a database console inside a running Rails pod.'
238
192
  rc.command :dbconsole do |c|
239
193
  c.action do |global_options, options, args|
240
- exit 1 unless tasks.dev_deployment_ok
241
194
  tasks.remote_dbconsole
242
195
  end
243
196
  end
@@ -245,7 +198,6 @@ module Kuby
245
198
  rc.desc "Restarts the Rails app's web pods."
246
199
  rc.command :restart do |c|
247
200
  c.action do |global_options, options, args|
248
- exit 1 unless tasks.dev_deployment_ok
249
201
  tasks.remote_restart
250
202
  end
251
203
  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,33 @@
1
+
2
+ # typed: strict
3
+
4
+ module Kuby
5
+ module Docker
6
+ class AppImage < ::Kuby::Docker::TimestampedImage
7
+ extend T::Sig
8
+
9
+ sig {
10
+ params(
11
+ dockerfile: T.any(Dockerfile, T.proc.returns(Dockerfile)),
12
+ image_url: String,
13
+ credentials: Credentials,
14
+ main_tag: T.nilable(String),
15
+ alias_tags: T::Array[String]
16
+ ).void
17
+ }
18
+ def initialize(dockerfile, image_url, credentials, main_tag = nil, alias_tags = [])
19
+ super
20
+ @identifier = "app"
21
+ end
22
+
23
+ sig { params(build_args: T::Hash[String, String], docker_args: T::Array[String]).returns(AppImage) }
24
+ def build(build_args = {}, docker_args = [])
25
+ unless ENV.fetch('RAILS_MASTER_KEY', '').empty?
26
+ build_args['RAILS_MASTER_KEY'] = T.must(ENV['RAILS_MASTER_KEY'])
27
+ end
28
+
29
+ super(build_args, docker_args)
30
+ end
31
+ end
32
+ end
33
+ 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,6 +52,10 @@ module Kuby
51
52
  dockerfile.copy(gf, '.')
52
53
  dockerfile.copy(lf, '.')
53
54
 
55
+ @gemfiles.each do |file|
56
+ dockerfile.copy(file, file)
57
+ end
58
+
54
59
  unless wo.empty?
55
60
  dockerfile.env("BUNDLE_WITHOUT='#{wo.join(' ')}'")
56
61
  end
@@ -67,6 +72,11 @@ module Kuby
67
72
  dockerfile.env("PATH=./bin:$PATH")
68
73
  end
69
74
 
75
+ sig { params(paths: String).void }
76
+ def gemfiles(*paths)
77
+ @gemfiles.concat(paths)
78
+ end
79
+
70
80
  private
71
81
 
72
82
  sig { returns(String) }
@@ -53,27 +53,21 @@ 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], docker_args: T::Array[String]).void }
57
+ def build(image, build_args: {}, docker_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,
72
- '-f-', '.'
64
+ '-f-',
65
+ *docker_args,
66
+ '.'
73
67
  ]
74
68
 
75
69
  open3_w(cmd) do |stdin, _wait_threads|
76
- stdin.puts(dockerfile.to_s)
70
+ stdin.puts(image.dockerfile.to_s)
77
71
  end
78
72
 
79
73
  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,119 @@
1
+ # typed: strict
2
+
3
+ module Kuby
4
+ module Docker
5
+ class Image
6
+ extend T::Sig
7
+
8
+ sig { returns(T.nilable(String)) }
9
+ attr_reader :identifier
10
+
11
+ sig { returns(String) }
12
+ attr_reader :image_url
13
+
14
+ sig { returns(Credentials) }
15
+ attr_reader :credentials
16
+
17
+ sig { returns(T.nilable(String)) }
18
+ attr_reader :main_tag
19
+
20
+ sig { returns T::Array[String] }
21
+ attr_reader :alias_tags
22
+
23
+ sig {
24
+ params(
25
+ dockerfile: T.any(Dockerfile, T.proc.returns(Dockerfile)),
26
+ image_url: String,
27
+ credentials: Credentials,
28
+ main_tag: T.nilable(String),
29
+ alias_tags: T::Array[String]
30
+ ).void
31
+ }
32
+ def initialize(dockerfile, image_url, credentials, main_tag = nil, alias_tags = [])
33
+ @dockerfile = T.let(dockerfile, T.any(Dockerfile, T.proc.returns(Dockerfile)))
34
+ @image_url = T.let(image_url, String)
35
+ @credentials = T.let(credentials, Credentials)
36
+ @main_tag = T.let(main_tag, T.nilable(String))
37
+ @alias_tags = T.let(alias_tags, T::Array[String])
38
+ @identifier = T.let(@identifier, T.nilable(String))
39
+
40
+ @image_host = T.let(@image_host, T.nilable(String))
41
+ @image_hostname = T.let(@image_hostname, T.nilable(String))
42
+ @image_repo = T.let(@image_repo, T.nilable(String))
43
+ @full_image_uri = T.let(@full_image_uri, T.nilable(DockerURI))
44
+ @docker_cli = T.let(@docker_cli, T.nilable(Docker::CLI))
45
+ end
46
+
47
+ sig { returns(Image) }
48
+ def new_version
49
+ raise NotImplementedError, 'please use a Docker::Image subclass'
50
+ end
51
+
52
+ sig { returns(Image) }
53
+ def current_version
54
+ raise NotImplementedError, 'please use a Docker::Image subclass'
55
+ end
56
+
57
+ sig { params(current_tag: T.nilable(String)).returns(Image) }
58
+ def previous_version(current_tag = nil)
59
+ raise NotImplementedError, 'please use a Docker::Image subclass'
60
+ end
61
+
62
+ sig { returns(Dockerfile) }
63
+ def dockerfile
64
+ if @dockerfile.respond_to?(:call)
65
+ T.cast(@dockerfile, T.proc.returns(Dockerfile)).call
66
+ else
67
+ T.cast(@dockerfile, Dockerfile)
68
+ end
69
+ end
70
+
71
+ sig { returns(String) }
72
+ def image_host
73
+ @image_host ||= "#{image_uri.host}:#{image_uri.port}"
74
+ end
75
+
76
+ sig { returns(String) }
77
+ def image_hostname
78
+ @image_hostname ||= image_uri.host
79
+ end
80
+
81
+ sig { returns(String) }
82
+ def image_repo
83
+ @image_repo ||= image_uri.path
84
+ end
85
+
86
+ sig { returns(DockerURI) }
87
+ def image_uri
88
+ @full_image_uri ||= DockerURI.parse(image_url)
89
+ end
90
+
91
+ sig { returns(T::Array[String]) }
92
+ def tags
93
+ [main_tag, *alias_tags].compact
94
+ end
95
+
96
+ sig { params(build_args: T::Hash[String, String], docker_args: T::Array[String]).void }
97
+ def build(build_args = {}, docker_args = [])
98
+ raise NotImplementedError, 'please use a Docker::Image subclass'
99
+ end
100
+
101
+ sig { params(tag: String).void }
102
+ def push(tag)
103
+ raise NotImplementedError, 'please use a Docker::Image subclass'
104
+ end
105
+
106
+ sig { returns(Docker::CLI) }
107
+ def docker_cli
108
+ @docker_cli ||= Docker::CLI.new
109
+ end
110
+
111
+ private
112
+
113
+ sig { params(main_tag: String, alias_tags: T::Array[String]).returns(Image) }
114
+ def duplicate_with_tags(main_tag, alias_tags)
115
+ self.class.new(dockerfile, image_url, credentials, main_tag, alias_tags)
116
+ end
117
+ end
118
+ end
119
+ 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