kuby-core 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/Gemfile +6 -2
  4. data/Rakefile +5 -3
  5. data/bin/tapioca +29 -0
  6. data/kuby-core.gemspec +9 -11
  7. data/lib/kuby/basic_logger.rb +34 -34
  8. data/lib/kuby/cli_base.rb +43 -43
  9. data/lib/kuby/commands.rb +94 -11
  10. data/lib/kuby/definition.rb +12 -12
  11. data/lib/kuby/dependable.rb +20 -0
  12. data/lib/kuby/dependency.rb +14 -0
  13. data/lib/kuby/docker/alpine.rb +10 -10
  14. data/lib/kuby/docker/app_image.rb +11 -11
  15. data/lib/kuby/docker/app_phase.rb +36 -0
  16. data/lib/kuby/docker/assets_phase.rb +2 -2
  17. data/lib/kuby/docker/bundler_phase.rb +42 -40
  18. data/lib/kuby/docker/cli.rb +71 -43
  19. data/lib/kuby/docker/copy_phase.rb +7 -7
  20. data/lib/kuby/docker/credentials.rb +1 -0
  21. data/lib/kuby/docker/debian.rb +10 -10
  22. data/lib/kuby/docker/distro.rb +13 -13
  23. data/lib/kuby/docker/docker_uri.rb +20 -20
  24. data/lib/kuby/docker/dockerfile.rb +48 -39
  25. data/lib/kuby/docker/image.rb +66 -54
  26. data/lib/kuby/docker/inline_layer.rb +4 -4
  27. data/lib/kuby/docker/layer.rb +6 -6
  28. data/lib/kuby/docker/layer_stack.rb +35 -35
  29. data/lib/kuby/docker/local_tags.rb +16 -16
  30. data/lib/kuby/docker/package_list.rb +16 -16
  31. data/lib/kuby/docker/package_phase.rb +16 -16
  32. data/lib/kuby/docker/packages/managed_package.rb +13 -13
  33. data/lib/kuby/docker/packages/nodejs.rb +5 -5
  34. data/lib/kuby/docker/packages/package.rb +8 -8
  35. data/lib/kuby/docker/packages/simple_managed_package.rb +7 -7
  36. data/lib/kuby/docker/packages/yarn.rb +6 -6
  37. data/lib/kuby/docker/remote_tags.rb +16 -16
  38. data/lib/kuby/docker/setup_phase.rb +18 -20
  39. data/lib/kuby/docker/spec.rb +93 -72
  40. data/lib/kuby/docker/timestamp_tag.rb +16 -11
  41. data/lib/kuby/docker/timestamped_image.rb +59 -40
  42. data/lib/kuby/docker/webserver_phase.rb +20 -20
  43. data/lib/kuby/docker/yarn_phase.rb +29 -5
  44. data/lib/kuby/docker.rb +2 -1
  45. data/lib/kuby/kubernetes/bare_metal_provider.rb +9 -9
  46. data/lib/kuby/kubernetes/deployer.rb +22 -10
  47. data/lib/kuby/kubernetes/docker_config.rb +1 -0
  48. data/lib/kuby/kubernetes/provider.rb +1 -0
  49. data/lib/kuby/kubernetes/spec.rb +47 -7
  50. data/lib/kuby/plugin.rb +22 -1
  51. data/lib/kuby/plugins/nginx_ingress.rb +8 -6
  52. data/lib/kuby/plugins/rails_app/assets.rb +16 -4
  53. data/lib/kuby/plugins/rails_app/assets_image.rb +17 -8
  54. data/lib/kuby/plugins/rails_app/crdb/plugin.rb +473 -0
  55. data/lib/kuby/plugins/rails_app/crdb.rb +9 -0
  56. data/lib/kuby/plugins/rails_app/database.rb +12 -8
  57. data/lib/kuby/plugins/rails_app/generators/kuby.rb +17 -16
  58. data/lib/kuby/plugins/rails_app/plugin.rb +29 -18
  59. data/lib/kuby/plugins/rails_app/sqlite.rb +7 -3
  60. data/lib/kuby/plugins/rails_app/tasks.rake +25 -12
  61. data/lib/kuby/plugins/rails_app.rb +1 -0
  62. data/lib/kuby/plugins/system.rb +16 -0
  63. data/lib/kuby/plugins.rb +1 -0
  64. data/lib/kuby/railtie.rb +31 -1
  65. data/lib/kuby/tasks.rb +72 -5
  66. data/lib/kuby/trailing_hash.rb +2 -2
  67. data/lib/kuby/utils/sem_ver/constraint.rb +68 -0
  68. data/lib/kuby/utils/sem_ver/constraint_set.rb +25 -0
  69. data/lib/kuby/utils/sem_ver/version.rb +49 -0
  70. data/lib/kuby/utils/sem_ver.rb +17 -0
  71. data/lib/kuby/utils/which.rb +65 -0
  72. data/lib/kuby/utils.rb +7 -1
  73. data/lib/kuby/version.rb +1 -1
  74. data/lib/kuby.rb +37 -2
  75. data/rbi/kuby-core.rbi +2128 -0
  76. data/spec/docker/spec_spec.rb +50 -26
  77. data/spec/dummy/app/channels/application_cable/channel.rb +2 -1
  78. data/spec/dummy/app/channels/application_cable/connection.rb +2 -1
  79. data/spec/dummy/app/controllers/application_controller.rb +2 -1
  80. data/spec/dummy/app/jobs/application_job.rb +2 -1
  81. data/spec/dummy/app/mailers/application_mailer.rb +2 -1
  82. data/spec/dummy/app/models/application_record.rb +2 -1
  83. data/spec/dummy/config/application.rb +2 -1
  84. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -1
  85. data/spec/dummy/config/routes.rb +2 -1
  86. data/spec/dummy/test/application_system_test_case.rb +2 -1
  87. data/spec/dummy/test/channels/application_cable/connection_test.rb +2 -1
  88. data/spec/spec_helper.rb +13 -1
  89. metadata +44 -39
  90. data/lib/kuby/plugins/rails_app/mysql.rb +0 -158
  91. data/lib/kuby/plugins/rails_app/postgres.rb +0 -163
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06ed279a1b0ecaac0daed1b868610bac67e6564611360de4cd841a24827438e2
4
- data.tar.gz: f8616a5b0ab87c4fb71afa3afba0e001760b3c0855b7670b976013de3c1db5d6
3
+ metadata.gz: c537d5778b44ceab6bbd75ae91b2c8569bdba7356c25112c172ce10533a5b073
4
+ data.tar.gz: c8fda1880975e51a5e398ccb5e42474ead68e7a179ea403ded3b15ee615dc4f1
5
5
  SHA512:
6
- metadata.gz: d75bf991f55a97798152449606740b2d94c9a012ad7c17ea0b9b940c9ca9b3aad0e31baa4635ffeeec584144492d967054cdbfffa386c05c7427f1e90ac58e8f
7
- data.tar.gz: 73b7718181d0e43ab1382c70a4a22da1835da30c887c2f42bc67bcce15d811aa0efab93df3a5fd6d28e2b2ce6d6dc3a73154a4cacdadcfeb9641ca0b2ba5604c
6
+ metadata.gz: ea78f96fa54b86a8917e252af444e92465b43e9017c52e25e9e643df50095a31a15462ba48f8db1f94063aff414ce9d2eb2a9e3617e2c9581823d339c810a0af
7
+ data.tar.gz: b791c2e2190e8c16a52b1039f565f9e6f04d55bc47395d0133581503beb882019139199da14efecf2d488a26e6229e7beaf649375c5067df69db6c0c7787fcf2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,47 @@
1
+ ## 0.18.0
2
+ * Add the ability to specify your app's root directory.
3
+ - Call `app_root <path>` inside the `docker` section of your Kuby config file.
4
+ - Necessary for use-cases like apps living inside gem repos, etc.
5
+ * Add `:app_phase` to set of Docker build phases.
6
+ - Allows easily setting environment variables.
7
+ - Sets the working directory to the app root if the app's root directory has been set via the `app_root` feature described above.
8
+ * Upgrade to Nginx ingress controller v1.1.1.
9
+ - Necessary to support Kind, the local Kubernetes cluster tool (see the kuby-kind gem).
10
+ * Run `bundle lock` before installing gem dependencies.
11
+ * Fix bug causing errors when certain container registries return a 401 if the repo doesn't exist yet.
12
+ - I'm looking at you, Azure.
13
+ * Don't fail to deploy if the app doesn't use Active Record.
14
+ * Fix git merge issue causing no output when running `kuby dockerfiles`.
15
+ * Upgrade integration tests to Kubernetes 1.23.
16
+ - This upgrade is incompatible with the version of KubeDB we're currently using.
17
+ - KubeDB has been replaced with the CockroachDB operator. Kuby will no longer support KubeDB after this release.
18
+ * Add ability to deploy resources into more than one namespace.
19
+ * Remove support for MySQL and Postgres in favor of CockroachDB.
20
+ - KubeDB has moved to an incompatible licensing model and Kuby can no longer use it.
21
+ - CockroachDB is now the only managed database offering (aside from SQLite) for the following reasons:
22
+ - CRDB is cloud-native, i.e. is designed to be run on cloud platforms like Kubernetes.
23
+ - CRDB can be easily upgraded in-place while both MySQL and Postgres demand a much more manual, error-prone upgrade process that proved very difficult to automate.
24
+ - CRDB is Postgres wire-compatible, meaning those who use Postgres (and I believe that accounts for the majority of Rails devs) will hardly be impacted by this change at all. While CRDB is not feature-by-feature compatible with Postgres, the differences are unlikely to be important to the average Rails app.
25
+ * Use SSL certificates instead of usernames and passwords for database authentication.
26
+ - This is the preferred way to communicate with instances of CockroachDB (also supported by Postgres).
27
+ - Kuby uses cert-manager to establish a custom PKI for database interactions.
28
+ - The Rails generator now entirely omits the database configuration section, making config simpler.
29
+ * Avoid failing on first deploy.
30
+ - Previous versions of Kuby did not wait for the database to spin up before attempting to start the Rails app, which resulted in what appeared to be a failed deploy. Kubernetes would eventually sort everything out, but it made for a less than ideal developer experience.
31
+ - The `create_unless_exists` rake task has been superceded by the `bootstrap` rake task, which is run in an init container whenever the app boots. It is responsible for ensuring the database server is reachable and creating any users defined in the Kuby config.
32
+ * Add the ability for plugins to define their own set of rake tasks.
33
+ - These are runnable via the CLI.
34
+ * Add the ability for plugins to define a `#remove` routine, which is meant to do the opposite of whatever `#setup` does.
35
+ - It is now also possible to run a plugin's remove routine from the CLI.
36
+ * Add the ability for plugins to depend on things like Kubernetes and Helm.
37
+ - Uses semantic versioning and compares required versions to current versions.
38
+ * Avoid using the `which` command to find executables on the current PATH.
39
+ - `which` has been deprecated in at least one Linux distro (Debian), perhaps others.
40
+ - Use `Kuby::Utils.which` instead.
41
+ * Support Rails 7.
42
+ - Don't run `yarn install` if there's no package.json.
43
+ * Automatically cache Docker builds from the latest image, should it exist.
44
+
1
45
  ## 0.17.1
2
46
  * Allow storage class to be customized when using the built-in bare metal provider.
3
47
  * Fix a bug where the assets image would be built using the previous app image instead of the current one.
data/Gemfile CHANGED
@@ -5,8 +5,12 @@ gemspec
5
5
  group :development, :test do
6
6
  gem 'pry-byebug'
7
7
  gem 'rake'
8
- # lock to a specific version to prevent breaking CI when new versions come out
9
- gem 'sorbet', '= 0.5.6433'
8
+
9
+ gem 'curdle', '~> 1.2'
10
+ gem 'parlour', github: 'camertron/parlour', branch: 'initialize_void' # '~> 7.0'
11
+ gem 'tapioca', '~> 0.7'
12
+ gem 'sorbet-runtime', '= 0.5.9897'
13
+ gem 'sorbet-static', '= 0.5.9897'
10
14
  end
11
15
 
12
16
  group :test do
data/Rakefile CHANGED
@@ -1,10 +1,12 @@
1
1
  require 'bundler'
2
2
  require 'rspec/core/rake_task'
3
- require 'rubygems/package_task'
3
+ require 'curdle'
4
4
 
5
- require 'kuby'
5
+ Curdle::Tasks.install
6
6
 
7
- Bundler::GemHelper.install_tasks
7
+ require 'pry-byebug'
8
+ require 'sorbet-runtime'
9
+ require 'kuby'
8
10
 
9
11
  task default: :spec
10
12
 
data/bin/tapioca ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'tapioca' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("tapioca", "tapioca")
data/kuby-core.gemspec CHANGED
@@ -13,24 +13,22 @@ 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.6'
17
- s.add_dependency 'gli', '~> 2.0'
16
+ s.add_dependency 'docker-remote', '~> 0.8'
17
+ s.add_dependency 'gli', '~> 2.21'
18
18
  s.add_dependency 'helm-cli', '~> 0.3'
19
- # See: https://github.com/Shopify/krane/pull/720
20
- # See: https://github.com/Shopify/krane/blob/master/CHANGELOG.md#114
21
- s.add_dependency 'krane', '>= 1.1.4', '< 2.0'
22
- s.add_dependency 'kuby-cert-manager', '>= 0.3'
23
- s.add_dependency 'kube-dsl', '~> 0.4'
24
- s.add_dependency 'kuby-kube-db', '>= 0.6'
25
- s.add_dependency 'kubernetes-cli', '~> 0.3'
19
+ s.add_dependency 'krane', '~> 2.0'
20
+ s.add_dependency 'kuby-cert-manager', '~> 0.4'
21
+ s.add_dependency 'kuby-crdb', '~> 0.2'
22
+ s.add_dependency 'kube-dsl', '~> 0.7'
23
+ s.add_dependency 'kubernetes-cli', '~> 0.4'
26
24
  s.add_dependency 'railties', '>= 5.1'
27
25
  s.add_dependency 'rouge', '~> 3.0'
28
- s.add_dependency 'sorbet-runtime-stub', '~> 0.2'
26
+ s.add_dependency 'rake'
29
27
 
30
28
  s.add_development_dependency 'rspec'
31
29
 
32
30
  s.require_path = 'lib'
33
31
  s.executables << 'kuby'
34
32
 
35
- s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'kuby-core.gemspec']
33
+ s.files = Dir['{bin,lib,rbi,spec}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'kuby-core.gemspec']
36
34
  end
@@ -5,25 +5,25 @@ require 'colorized_string'
5
5
 
6
6
  module Kuby
7
7
  class BasicLogger < Logger
8
- extend T::Sig
8
+ # extend T::Sig
9
9
 
10
- sig {
11
- override.params(
12
- logdev: T.any(String, IO, StringIO, NilClass),
13
- shift_age: Integer,
14
- shift_size: Integer,
15
- level: Integer,
16
- progname: T.nilable(String),
17
- formatter: T.nilable(FormatterProcType),
18
- datetime_format: T.nilable(String),
19
- shift_period_suffix: T.nilable(String)
20
- ).void
21
- }
10
+ # T::Sig::WithoutRuntime.sig {
11
+ # override.params(
12
+ # logdev: T.any(String, IO, StringIO, NilClass),
13
+ # shift_age: Integer,
14
+ # shift_size: Integer,
15
+ # level: Integer,
16
+ # progname: T.nilable(String),
17
+ # formatter: T.nilable(FormatterProcType),
18
+ # datetime_format: T.nilable(String),
19
+ # shift_period_suffix: T.nilable(String)
20
+ # ).void
21
+ # }
22
22
  def initialize(
23
23
  logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
24
24
  progname: nil, formatter: nil, datetime_format: nil,
25
25
  shift_period_suffix: '%Y%m%d')
26
- @logdev = T.let(@logdev, T.nilable(Logger::LogDevice))
26
+ # @logdev = T.let(@logdev, T.nilable(Logger::LogDevice))
27
27
 
28
28
  super
29
29
 
@@ -32,12 +32,12 @@ module Kuby
32
32
  end
33
33
  end
34
34
 
35
- sig {
36
- override.params(
37
- progname_or_msg: T.untyped,
38
- block: T.nilable(T.proc.returns(T.untyped))
39
- ).void
40
- }
35
+ # T::Sig::WithoutRuntime.sig {
36
+ # override.params(
37
+ # progname_or_msg: T.untyped,
38
+ # block: T.nilable(T.proc.returns(T.untyped))
39
+ # ).void
40
+ # }
41
41
  def info(progname_or_msg = nil, &block)
42
42
  if block
43
43
  super(progname_or_msg) { ColorizedString[block.call].yellow }
@@ -46,12 +46,12 @@ module Kuby
46
46
  end
47
47
  end
48
48
 
49
- sig {
50
- override.params(
51
- progname_or_msg: T.untyped,
52
- block: T.nilable(T.proc.returns(T.untyped))
53
- ).void
54
- }
49
+ # T::Sig::WithoutRuntime.sig {
50
+ # override.params(
51
+ # progname_or_msg: T.untyped,
52
+ # block: T.nilable(T.proc.returns(T.untyped))
53
+ # ).void
54
+ # }
55
55
  def fatal(progname_or_msg = nil, &block)
56
56
  if block
57
57
  super(progname_or_msg) { ColorizedString[block.call].red }
@@ -61,13 +61,13 @@ module Kuby
61
61
  end
62
62
 
63
63
  # adhere to the "CLI" interface
64
- sig {
65
- params(
66
- out: T.any(IO, StringIO),
67
- err: T.any(IO, StringIO),
68
- block: T.proc.void
69
- ).void
70
- }
64
+ # T::Sig::WithoutRuntime.sig {
65
+ # params(
66
+ # out: T.any(IO, StringIO),
67
+ # err: T.any(IO, StringIO),
68
+ # block: T.proc.void
69
+ # ).void
70
+ # }
71
71
  def with_pipes(out = STDOUT, err = STDERR, &block)
72
72
  previous_logdev = @logdev&.dev || STDERR
73
73
  reopen(err)
@@ -76,7 +76,7 @@ module Kuby
76
76
  reopen(previous_logdev)
77
77
  end
78
78
 
79
- sig { returns(T.nilable(Process::Status)) }
79
+ # T::Sig::WithoutRuntime.sig { returns(T.nilable(Process::Status)) }
80
80
  def last_status
81
81
  nil
82
82
  end
data/lib/kuby/cli_base.rb CHANGED
@@ -5,39 +5,39 @@ require 'thread'
5
5
 
6
6
  module Kuby
7
7
  class CLIBase
8
- extend T::Sig
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
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
14
 
15
- sig { returns(T.nilable(Process::Status)) }
15
+ # T::Sig::WithoutRuntime.sig { returns(T.nilable(Process::Status)) }
16
16
  def last_status
17
17
  Thread.current[status_key]
18
18
  end
19
19
 
20
- sig { params(block: BeforeCallback).void }
20
+ # T::Sig::WithoutRuntime.sig { params(block: BeforeCallback).void }
21
21
  def before_execute(&block)
22
- @before_execute = T.let(@before_execute, T.nilable(T::Array[BeforeCallback]))
22
+ # @before_execute = T.let(@before_execute, T.nilable(T::Array[BeforeCallback]))
23
23
  @before_execute ||= []
24
24
  @before_execute << block
25
25
  end
26
26
 
27
- sig { params(block: AfterCallback).void }
27
+ # T::Sig::WithoutRuntime.sig { params(block: AfterCallback).void }
28
28
  def after_execute(&block)
29
- @after_execute = T.let(@after_execute, T.nilable(T::Array[AfterCallback]))
29
+ # @after_execute = T.let(@after_execute, T.nilable(T::Array[AfterCallback]))
30
30
  @after_execute ||= []
31
31
  @after_execute << block
32
32
  end
33
33
 
34
- sig {
35
- params(
36
- out: T.any(IO, StringIO),
37
- err: T.any(IO, StringIO),
38
- block: T.proc.void
39
- ).void
40
- }
34
+ # T::Sig::WithoutRuntime.sig {
35
+ # params(
36
+ # out: T.any(IO, StringIO),
37
+ # err: T.any(IO, StringIO),
38
+ # block: T.proc.void
39
+ # ).void
40
+ # }
41
41
  def with_pipes(out = STDOUT, err = STDERR, &block)
42
42
  previous_stdout = self.stdout
43
43
  previous_stderr = self.stderr
@@ -49,34 +49,34 @@ module Kuby
49
49
  self.stderr = previous_stderr
50
50
  end
51
51
 
52
- sig { returns(T.nilable(T.any(IO, StringIO))) }
52
+ # T::Sig::WithoutRuntime.sig { returns(T.nilable(T.any(IO, StringIO))) }
53
53
  def stdout
54
54
  Thread.current[stdout_key] || STDOUT
55
55
  end
56
56
 
57
- sig { params(new_stdout: T.nilable(T.any(IO, StringIO))).void }
57
+ # T::Sig::WithoutRuntime.sig { params(new_stdout: T.nilable(T.any(IO, StringIO))).void }
58
58
  def stdout=(new_stdout)
59
59
  Thread.current[stdout_key] = new_stdout
60
60
  end
61
61
 
62
- sig { returns(T.nilable(T.any(IO, StringIO))) }
62
+ # T::Sig::WithoutRuntime.sig { returns(T.nilable(T.any(IO, StringIO))) }
63
63
  def stderr
64
64
  Thread.current[stderr_key] || STDERR
65
65
  end
66
66
 
67
- sig { params(new_stderr: T.nilable(T.any(IO, StringIO))).void }
67
+ # T::Sig::WithoutRuntime.sig { params(new_stderr: T.nilable(T.any(IO, StringIO))).void }
68
68
  def stderr=(new_stderr)
69
69
  Thread.current[stderr_key] = new_stderr
70
70
  end
71
71
 
72
72
  private
73
73
 
74
- sig {
75
- params(
76
- cmd: T::Array[String],
77
- block: T.proc.params(stdin: IO).void
78
- ).void
79
- }
74
+ # T::Sig::WithoutRuntime.sig {
75
+ # params(
76
+ # cmd: T::Array[String],
77
+ # block: T.proc.params(stdin: IO).void
78
+ # ).void
79
+ # }
80
80
  def open3_w(cmd, &block)
81
81
  run_before_callbacks(cmd)
82
82
  cmd_s = cmd.join(' ')
@@ -99,20 +99,20 @@ module Kuby
99
99
  yield(p_stdin)
100
100
 
101
101
  p_stdin.close
102
- self.last_status = T.cast(wait_thread.value, Process::Status)
102
+ self.last_status = wait_thread.value
103
103
  run_after_callbacks(cmd)
104
104
  wait_thread.join
105
105
  end
106
106
  end
107
107
 
108
- sig { params(cmd: T::Array[String]).void }
108
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
109
109
  def execc(cmd)
110
110
  run_before_callbacks(cmd)
111
111
  cmd_s = cmd.join(' ')
112
112
  exec(cmd_s)
113
113
  end
114
114
 
115
- sig { params(cmd: T::Array[String]).void }
115
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
116
116
  def systemm(cmd)
117
117
  if stdout == STDOUT && stderr == STDERR
118
118
  systemm_default(cmd)
@@ -121,7 +121,7 @@ module Kuby
121
121
  end
122
122
  end
123
123
 
124
- sig { params(cmd: T::Array[String]).void }
124
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
125
125
  def systemm_default(cmd)
126
126
  run_before_callbacks(cmd)
127
127
  cmd_s = cmd.join(' ')
@@ -131,7 +131,7 @@ module Kuby
131
131
  end
132
132
  end
133
133
 
134
- sig { params(cmd: T::Array[String]).void }
134
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
135
135
  def systemm_open3(cmd)
136
136
  run_before_callbacks(cmd)
137
137
  cmd_s = cmd.join(' ')
@@ -152,14 +152,14 @@ module Kuby
152
152
  end
153
153
 
154
154
  p_stdin.close
155
- self.last_status = T.cast(wait_thread.value, Process::Status)
155
+ self.last_status = wait_thread.value
156
156
  run_after_callbacks(cmd)
157
157
  wait_thread.join
158
158
  end
159
159
  end
160
160
 
161
161
 
162
- sig { params(cmd: T::Array[String]).returns(String) }
162
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).returns(String) }
163
163
  def backticks(cmd)
164
164
  if stdout == STDOUT && stderr == STDERR
165
165
  backticks_default(cmd)
@@ -168,7 +168,7 @@ module Kuby
168
168
  end
169
169
  end
170
170
 
171
- sig { params(cmd: T::Array[String]).returns(String) }
171
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).returns(String) }
172
172
  def backticks_default(cmd)
173
173
  run_before_callbacks(cmd)
174
174
  cmd_s = cmd.join(' ')
@@ -178,7 +178,7 @@ module Kuby
178
178
  end
179
179
  end
180
180
 
181
- sig { params(cmd: T::Array[String]).returns(String) }
181
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).returns(String) }
182
182
  def backticks_open3(cmd)
183
183
  run_before_callbacks(cmd)
184
184
  cmd_s = cmd.join(' ')
@@ -200,7 +200,7 @@ module Kuby
200
200
  end
201
201
 
202
202
  p_stdin.close
203
- self.last_status = T.cast(wait_thread.value, Process::Status)
203
+ self.last_status = wait_thread.value
204
204
  run_after_callbacks(cmd)
205
205
  wait_thread.join
206
206
  end
@@ -208,32 +208,32 @@ module Kuby
208
208
  result.string
209
209
  end
210
210
 
211
- sig { params(cmd: T::Array[String]).void }
211
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
212
212
  def run_before_callbacks(cmd)
213
213
  (@before_execute || []).each { |cb| cb.call(cmd) }
214
214
  end
215
215
 
216
- sig { params(cmd: T::Array[String]).void }
216
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
217
217
  def run_after_callbacks(cmd)
218
218
  (@after_execute || []).each { |cb| cb.call(cmd, last_status) }
219
219
  end
220
220
 
221
- sig { params(status: Process::Status).void }
221
+ # T::Sig::WithoutRuntime.sig { params(status: Process::Status).void }
222
222
  def last_status=(status)
223
223
  Thread.current[status_key] = status
224
224
  end
225
225
 
226
- sig { returns(Symbol) }
226
+ # T::Sig::WithoutRuntime.sig { returns(Symbol) }
227
227
  def status_key
228
228
  raise NotImplementedError, "#{__method__} must be defined in derived classes"
229
229
  end
230
230
 
231
- sig { returns(Symbol) }
231
+ # T::Sig::WithoutRuntime.sig { returns(Symbol) }
232
232
  def stdout_key
233
233
  raise NotImplementedError, "#{__method__} must be defined in derived classes"
234
234
  end
235
235
 
236
- sig { returns(Symbol) }
236
+ # T::Sig::WithoutRuntime.sig { returns(Symbol) }
237
237
  def stderr_key
238
238
  raise NotImplementedError, "#{__method__} must be defined in derived classes"
239
239
  end
data/lib/kuby/commands.rb CHANGED
@@ -3,9 +3,12 @@
3
3
  require 'kuby/version'
4
4
  require 'gli'
5
5
 
6
+ # run the pre hook for the help command
7
+ GLI::Commands::Help.skips_pre = false
8
+
6
9
  module Kuby
7
10
  class Commands
8
- extend T::Sig
11
+ # extend T::Sig
9
12
  extend GLI::App
10
13
 
11
14
  # GLI doesn't have a wildcard option, so it's impossible to tell it to
@@ -19,12 +22,12 @@ module Kuby
19
22
  # avoid the usual series of cryptic alias_method calls (note that there
20
23
  # is no singleton class version of #prepend in the Ruby language).
21
24
  singleton_class.send(:prepend, Module.new do
22
- extend T::Sig
25
+ # extend T::Sig
23
26
 
24
- sig { params(args: T::Array[String]).void }
27
+ # T::Sig::WithoutRuntime.sig { params(args: T::Array[String]).void }
25
28
  def run(args)
26
29
  if idx = args.index('rails') || idx = args.index('rake')
27
- @rails_options = T.let(@rails_options, T.nilable(T::Array[String]))
30
+ # @rails_options = T.let(@rails_options, T.nilable(T::Array[String]))
28
31
  @rails_options = args[(idx + 1)..-1]
29
32
  super(args[0..idx])
30
33
  else
@@ -34,11 +37,24 @@ module Kuby
34
37
  end
35
38
  end)
36
39
 
37
- sig { returns(Kuby::Tasks) }
40
+ # T::Sig::WithoutRuntime.sig { returns(Kuby::Tasks) }
38
41
  def self.tasks
39
42
  Kuby::Tasks.new(Kuby.environment)
40
43
  end
41
44
 
45
+ # T::Sig::WithoutRuntime.sig {
46
+ # params(
47
+ # global_options: T::Hash[T.any(String, Symbol), T.any(String, Integer)]
48
+ # ).void
49
+ # }
50
+ def self.load_kuby_config!(global_options)
51
+ return if @kuby_config_loaded
52
+
53
+ Kuby.env = global_options[:environment] if global_options[:environment]
54
+ Kuby.load!(global_options[:config])
55
+ @kuby_config_loaded = true
56
+ end
57
+
42
58
  program_desc 'Kuby command-line interface. Kuby is a convention '\
43
59
  'over configuration approach for running Rails apps in Kubernetes.'
44
60
 
@@ -54,9 +70,35 @@ module Kuby
54
70
  default_value './kuby.rb'
55
71
  flag [:c, :config]
56
72
 
73
+ command_missing do |command_name, global_options|
74
+ load_kuby_config!(global_options)
75
+ cmd = nil
76
+
77
+ # command_name is also the name of the plugin
78
+ if plugin_klass = Kuby.plugins.find(command_name)
79
+ if plugin_klass.respond_to?(:install_commands)
80
+ desc "Run commands for the #{command_name} plugin."
81
+ cmd = command(command_name) do |c|
82
+ # the plugin now defines its own commands on c
83
+ plugin_klass.install_commands(c)
84
+ end
85
+ end
86
+ end
87
+
88
+ cmd
89
+ end
90
+
57
91
  pre do |global_options, options, args|
58
- Kuby.env = global_options[:environment] if global_options[:environment]
59
- Kuby.load!(global_options[:config])
92
+ load_kuby_config!(global_options)
93
+
94
+ Kuby.plugins.each do |plugin_name, plugin_klass|
95
+ if plugin_klass.respond_to?(:commands) && !@commands[plugin_name]
96
+ desc "Run commands for the #{plugin_name} plugin."
97
+ command plugin_name.to_sym do |c|
98
+ plugin_klass.commands(c)
99
+ end
100
+ end
101
+ end
60
102
 
61
103
  # GLI will abort unless this block returns a truthy value
62
104
  true
@@ -68,7 +110,7 @@ module Kuby
68
110
  c.flag [:a, :arg], required: false, multiple: true
69
111
 
70
112
  c.desc 'When enabled, ignores missing build arguments.'
71
- c.switch [:'ignore-missing-args'], required: false, default: false
113
+ c.switch [:'ignore-missing-args'], required: false, default_value: false
72
114
 
73
115
  c.desc 'Build only the images associated with the specified identifier(s). '\
74
116
  'Run `kuby images` for a list of all valid identifiers (note that '\
@@ -78,6 +120,9 @@ module Kuby
78
120
  c.desc 'The directory to use as the Docker build context.'
79
121
  c.flag [:c, :context], required: false
80
122
 
123
+ c.desc 'Pull the latest images from the registry and reuse any previously built layers.'
124
+ c.switch [:l, :'cache-from-latest'], required: false, default_value: true
125
+
81
126
  c.action do |global_options, options, docker_args|
82
127
  build_args = {}.tap do |build_args|
83
128
  (options[:arg] || []).each do |a|
@@ -91,7 +136,8 @@ module Kuby
91
136
  build_args, docker_args,
92
137
  only: options[:only],
93
138
  ignore_missing_args: options[:'ignore-missing-args'],
94
- context: options[:context]
139
+ context: options[:context],
140
+ cache_from_latest: options[:'cache-from-latest']
95
141
  )
96
142
  end
97
143
  end
@@ -175,7 +221,7 @@ module Kuby
175
221
  c.desc 'Prefixes the kubectl command with the namespace associated with '\
176
222
  'the current environment. For example, if the Kuby env is "production", '\
177
223
  'this option will prefix the kubectl command with "-n myapp-production".'
178
- c.switch [:N, :namespaced], default: false
224
+ c.switch [:N, :namespaced], default_value: false
179
225
  c.action do |global_options, options, args|
180
226
  if options[:namespaced]
181
227
  # sorry Demeter
@@ -187,6 +233,43 @@ module Kuby
187
233
  end
188
234
  end
189
235
 
236
+ desc 'Provides information about plugins.'
237
+ command :plugin do |rc|
238
+ rc.desc "Run a plugin's remove routine, i.e. uninstall it's resources from your cluster."
239
+ rc.command :remove do |c|
240
+ c.desc 'The plugin to remove. Run `kuby plugin list` for a list of valid plugin '\
241
+ 'identifiers.'
242
+ c.flag [:p, :plugin], required: true
243
+ c.action do |global_options, options, args|
244
+ tasks.remove_plugin(options[:plugin])
245
+ end
246
+ end
247
+
248
+ rc.desc 'List plugins.'
249
+ rc.command :list do |c|
250
+ c.desc 'Show all available plugins, not just the ones in use.'
251
+ c.switch [:a, :all], default_value: false
252
+ c.action do |global_options, options, args|
253
+ tasks.list_plugins(all: options[:all])
254
+ end
255
+ end
256
+
257
+ rc.desc "Run one of a plugin's rake tasks. Omit task names to print all tasks."
258
+ rc.arg_name 'task_name', [:multiple, :optional]
259
+ rc.command :rake do |c|
260
+ c.action do |global_options, options, args|
261
+ # Args come through as @rails_options here because of the monkeypatch
262
+ # at the top of this file. Should revisit the patch at some point because
263
+ # I think GLI's arg concept can replace it.
264
+ if @rails_options.empty?
265
+ tasks.list_rake_tasks
266
+ else
267
+ tasks.run_rake_tasks(@rails_options)
268
+ end
269
+ end
270
+ end
271
+ end
272
+
190
273
  desc 'Runs commands, etc against the Kubernetes cluster.'
191
274
  command :remote do |rc|
192
275
  rc.desc 'Tails (i.e. continuously streams) the Rails log from your running application.'
@@ -206,7 +289,7 @@ module Kuby
206
289
  rc.desc 'Runs an arbitrary command inside a running Rails pod.'
207
290
  rc.command :exec do |c|
208
291
  c.action do |global_options, options, args|
209
- tasks.remote_exec([*args, *T.unsafe(@rails_options)])
292
+ tasks.remote_exec([*args, *@rails_options])
210
293
  end
211
294
  end
212
295