kuby-core 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +1 -0
  4. data/README.md +4 -2
  5. data/kuby-core.gemspec +2 -1
  6. data/lib/kuby-core.rb +1 -0
  7. data/lib/kuby.rb +7 -0
  8. data/lib/kuby/basic_logger.rb +1 -0
  9. data/lib/kuby/cli_base.rb +1 -0
  10. data/lib/kuby/commands.rb +1 -0
  11. data/lib/kuby/definition.rb +1 -0
  12. data/lib/kuby/dev_setup.rb +1 -0
  13. data/lib/kuby/docker.rb +3 -0
  14. data/lib/kuby/docker/alpine.rb +16 -12
  15. data/lib/kuby/docker/assets_phase.rb +5 -0
  16. data/lib/kuby/docker/bundler_phase.rb +36 -2
  17. data/lib/kuby/docker/cli.rb +36 -2
  18. data/lib/kuby/docker/copy_phase.rb +11 -3
  19. data/lib/kuby/docker/credentials.rb +1 -0
  20. data/lib/kuby/docker/debian.rb +14 -10
  21. data/lib/kuby/docker/dev_spec.rb +82 -18
  22. data/lib/kuby/docker/distro.rb +43 -0
  23. data/lib/kuby/docker/dockerfile.rb +66 -18
  24. data/lib/kuby/docker/errors.rb +8 -0
  25. data/lib/kuby/docker/inline_layer.rb +7 -0
  26. data/lib/kuby/docker/layer.rb +11 -0
  27. data/lib/kuby/docker/layer_stack.rb +43 -6
  28. data/lib/kuby/docker/local_tags.rb +23 -2
  29. data/lib/kuby/docker/metadata.rb +35 -7
  30. data/lib/kuby/docker/package_list.rb +22 -3
  31. data/lib/kuby/docker/package_phase.rb +25 -5
  32. data/lib/kuby/docker/packages.rb +1 -0
  33. data/lib/kuby/docker/packages/managed_package.rb +20 -2
  34. data/lib/kuby/docker/packages/nodejs.rb +8 -0
  35. data/lib/kuby/docker/packages/package.rb +15 -1
  36. data/lib/kuby/docker/packages/simple_managed_package.rb +10 -1
  37. data/lib/kuby/docker/packages/yarn.rb +14 -0
  38. data/lib/kuby/docker/remote_tags.rb +21 -2
  39. data/lib/kuby/docker/setup_phase.rb +35 -4
  40. data/lib/kuby/docker/spec.rb +89 -13
  41. data/lib/kuby/docker/tags.rb +37 -2
  42. data/lib/kuby/docker/timestamp_tag.rb +14 -2
  43. data/lib/kuby/docker/webserver_phase.rb +40 -5
  44. data/lib/kuby/docker/yarn_phase.rb +5 -0
  45. data/lib/kuby/environment.rb +4 -0
  46. data/lib/kuby/kubernetes.rb +1 -0
  47. data/lib/kuby/kubernetes/deploy_task.rb +1 -0
  48. data/lib/kuby/kubernetes/deployer.rb +1 -0
  49. data/lib/kuby/kubernetes/docker_config.rb +1 -0
  50. data/lib/kuby/kubernetes/docker_desktop_provider.rb +1 -0
  51. data/lib/kuby/kubernetes/errors.rb +1 -0
  52. data/lib/kuby/kubernetes/manifest.rb +1 -0
  53. data/lib/kuby/kubernetes/provider.rb +1 -0
  54. data/lib/kuby/kubernetes/registry_secret.rb +1 -0
  55. data/lib/kuby/kubernetes/spec.rb +1 -0
  56. data/lib/kuby/middleware.rb +1 -0
  57. data/lib/kuby/middleware/health_check.rb +1 -0
  58. data/lib/kuby/plugin.rb +1 -0
  59. data/lib/kuby/plugin_registry.rb +1 -0
  60. data/lib/kuby/plugins.rb +1 -0
  61. data/lib/kuby/plugins/nginx_ingress.rb +1 -0
  62. data/lib/kuby/plugins/rails_app.rb +1 -0
  63. data/lib/kuby/plugins/rails_app/asset_copy_task.rb +1 -0
  64. data/lib/kuby/plugins/rails_app/assets.rb +1 -0
  65. data/lib/kuby/plugins/rails_app/database.rb +9 -7
  66. data/lib/kuby/plugins/rails_app/generators/kuby.rb +43 -40
  67. data/lib/kuby/plugins/rails_app/mysql.rb +1 -0
  68. data/lib/kuby/plugins/rails_app/plugin.rb +10 -5
  69. data/lib/kuby/plugins/rails_app/postgres.rb +1 -0
  70. data/lib/kuby/plugins/rails_app/rewrite_db_config.rb +1 -0
  71. data/lib/kuby/plugins/rails_app/sqlite.rb +1 -0
  72. data/lib/kuby/rails_commands.rb +1 -0
  73. data/lib/kuby/railtie.rb +1 -0
  74. data/lib/kuby/tasks.rb +1 -0
  75. data/lib/kuby/trailing_hash.rb +5 -3
  76. data/lib/kuby/version.rb +3 -1
  77. data/spec/docker/metadata_spec.rb +1 -0
  78. data/spec/docker/spec_spec.rb +37 -0
  79. data/spec/docker/timestamp_tag_spec.rb +1 -0
  80. data/spec/dummy/app/channels/application_cable/channel.rb +1 -0
  81. data/spec/dummy/app/channels/application_cable/connection.rb +1 -0
  82. data/spec/dummy/app/controllers/application_controller.rb +1 -0
  83. data/spec/dummy/app/helpers/application_helper.rb +1 -0
  84. data/spec/dummy/app/jobs/application_job.rb +1 -0
  85. data/spec/dummy/app/mailers/application_mailer.rb +1 -0
  86. data/spec/dummy/app/models/application_record.rb +1 -0
  87. data/spec/dummy/config/application.rb +1 -0
  88. data/spec/dummy/config/boot.rb +1 -0
  89. data/spec/dummy/config/environment.rb +1 -0
  90. data/spec/dummy/config/environments/development.rb +1 -0
  91. data/spec/dummy/config/environments/production.rb +1 -0
  92. data/spec/dummy/config/environments/test.rb +1 -0
  93. data/spec/dummy/config/initializers/application_controller_renderer.rb +1 -0
  94. data/spec/dummy/config/initializers/assets.rb +1 -0
  95. data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
  96. data/spec/dummy/config/initializers/content_security_policy.rb +1 -0
  97. data/spec/dummy/config/initializers/cookies_serializer.rb +1 -0
  98. data/spec/dummy/config/initializers/filter_parameter_logging.rb +1 -0
  99. data/spec/dummy/config/initializers/inflections.rb +1 -0
  100. data/spec/dummy/config/initializers/mime_types.rb +1 -0
  101. data/spec/dummy/config/initializers/wrap_parameters.rb +1 -0
  102. data/spec/dummy/config/puma.rb +1 -0
  103. data/spec/dummy/config/routes.rb +1 -0
  104. data/spec/dummy/config/spring.rb +1 -0
  105. data/spec/dummy/db/seeds.rb +1 -0
  106. data/spec/dummy/test/application_system_test_case.rb +1 -0
  107. data/spec/dummy/test/channels/application_cable/connection_test.rb +1 -0
  108. data/spec/dummy/test/test_helper.rb +1 -0
  109. data/spec/spec_helper.rb +10 -0
  110. data/spec/support/docker/fake_cli.rb +1 -0
  111. data/spec/support/docker/remote/fake_client.rb +1 -0
  112. data/spec/trailing_hash_spec.rb +2 -0
  113. metadata +20 -4
@@ -1,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
15
+
16
+ sig { returns(T::Hash[Symbol, Layer]) }
17
+ attr_reader :layers
7
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,11 +94,13 @@ 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
66
102
 
103
+ sig { params(name: Symbol).returns(T::Boolean) }
67
104
  def includes?(name)
68
105
  layers.include?(name)
69
106
  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
5
10
 
11
+ sig { returns(Metadata) }
12
+ attr_reader :metadata
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,10 +49,12 @@ 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
36
56
 
57
+ sig { returns(T.nilable(TimestampTag)) }
37
58
  def latest_timestamp_tag
38
59
  @latest_timestamp_tag ||= timestamp_tags.sort.last
39
60
  end
@@ -1,51 +1,76 @@
1
+ # typed: strict
2
+
1
3
  require 'uri'
2
4
 
3
5
  module Kuby
4
6
  module Docker
5
7
  class Metadata
8
+ extend T::Sig
9
+
6
10
  DEFAULT_DISTRO = :debian
7
- DEFAULT_REGISTRY_HOST = 'https://www.docker.com'.freeze
8
- DEFAULT_REGISTRY_SCHEME = 'https'
9
- LATEST_TAG = 'latest'
11
+ DEFAULT_REGISTRY_HOST = T.let('https://www.docker.com'.freeze, String)
12
+ DEFAULT_REGISTRY_SCHEME = T.let('https', String)
13
+ LATEST_TAG = T.let('latest'.freeze, String)
14
+
15
+ sig { params(image_url: String).void }
16
+ attr_writer :image_url
10
17
 
11
- attr_accessor :image_url
18
+ sig { returns(Environment) }
12
19
  attr_reader :environment
13
20
 
21
+ sig { params(environment: Environment).void }
14
22
  def initialize(environment)
15
23
  @environment = environment
16
- @tags = []
24
+ @tags = T.let([], T::Array[String])
25
+
26
+ @image_url = T.let(@image_url, T.nilable(String))
27
+ @image_host = T.let(@image_host, T.nilable(String))
28
+ @image_hostname = T.let(@image_hostname, T.nilable(String))
29
+ @image_repo = T.let(@image_repo, T.nilable(String))
30
+ @distro = T.let(@distro, T.nilable(Symbol))
31
+ @full_image_uri = T.let(@full_image_uri, T.nilable(URI::Generic))
32
+ @default_image_url = T.let(@default_image_url, T.nilable(String))
33
+ @default_tags = T.let(@default_tags, T.nilable(T::Array[String]))
17
34
  end
18
35
 
36
+ sig { returns(String) }
19
37
  def image_url
20
38
  @image_url || default_image_url
21
39
  end
22
40
 
41
+ sig { returns(String) }
23
42
  def image_host
24
43
  @image_host ||= "#{full_image_uri.scheme}://#{full_image_uri.host}"
25
44
  end
26
45
 
46
+ sig { returns(String) }
27
47
  def image_hostname
28
- @image_hostname ||= URI(image_host).host
48
+ @image_hostname ||= T.must(URI(image_host).host)
29
49
  end
30
50
 
51
+ sig { returns(String) }
31
52
  def image_repo
32
- @image_repo ||= full_image_uri.path.sub(/\A[\/]+/, '')
53
+ @image_repo ||= T.must(full_image_uri.path).sub(/\A[\/]+/, '')
33
54
  end
34
55
 
56
+ sig { returns(T::Array[String]) }
35
57
  def tags
36
58
  @tags.empty? ? default_tags : @tags
37
59
  end
38
60
 
61
+ sig { returns(Symbol) }
39
62
  def distro
40
63
  @distro || DEFAULT_DISTRO
41
64
  end
42
65
 
66
+ sig { params(distro_name: Symbol).void }
43
67
  def distro=(distro_name)
44
68
  @distro = distro_name
45
69
  end
46
70
 
47
71
  private
48
72
 
73
+ sig { returns(URI::Generic) }
49
74
  def full_image_uri
50
75
  @full_image_uri ||= if image_url.include?('://')
51
76
  URI.parse(image_url)
@@ -56,17 +81,20 @@ module Kuby
56
81
  end
57
82
  end
58
83
 
84
+ sig { returns(String) }
59
85
  def default_image_url
60
86
  # assuming dockerhub by not specifying full url
61
87
  @default_image_url ||= environment.app_name.downcase
62
88
  end
63
89
 
90
+ sig { returns(T::Array[String]) }
64
91
  def default_tags
65
92
  @default_tags ||= [
66
93
  TimestampTag.new(Time.now).to_s, LATEST_TAG
67
94
  ]
68
95
  end
69
96
 
97
+ sig { params(url: String).returns(URI::Generic) }
70
98
  def parse_url(url)
71
99
  uri = URI.parse(url)
72
100
  return uri if uri.scheme
@@ -1,31 +1,50 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class PackageList
6
+ extend T::Sig
7
+ extend T::Generic
8
+
9
+ Elem = type_member(fixed: Distro::PackageImpl)
10
+
4
11
  include Enumerable
5
12
 
13
+ sig { returns(T::Array[Distro::PackageImpl]) }
6
14
  attr_reader :packages
7
15
 
16
+ sig { params(package_tuples: T::Array[[Symbol, T.nilable(String)]]).void }
8
17
  def initialize(package_tuples)
9
- @packages = []
10
- package_tuples.each { |pt| add(*pt) }
18
+ @packages = T.let([], T::Array[Distro::PackageImpl])
19
+ package_tuples.each { |name, version| add(name, version) }
11
20
  end
12
21
 
22
+ sig { params(name: Symbol).returns(T.nilable(Distro::PackageImpl)) }
13
23
  def [](name)
14
24
  packages.find { |pkg| pkg.name == name }
15
25
  end
16
26
 
27
+ sig { params(name: Symbol, version: T.nilable(String)).void }
17
28
  def add(name, version = nil)
18
- packages << Package.new(name, version)
29
+ packages << Packages::Package.new(name, version)
19
30
  end
20
31
 
32
+ sig { params(name: String).void }
21
33
  def delete(name)
22
34
  packages.delete_if { |pkg| pkg.name == name }
23
35
  end
24
36
 
37
+ sig {
38
+ override.params(
39
+ block: T.proc.params(package: Distro::PackageImpl).void
40
+ )
41
+ .void
42
+ }
25
43
  def each(&block)
26
44
  packages.each(&block)
27
45
  end
28
46
 
47
+ sig { returns(T::Boolean) }
29
48
  def empty?
30
49
  packages.empty?
31
50
  end
@@ -1,22 +1,33 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  class PackagePhase < Layer
6
+ extend T::Sig
7
+
8
+ Operation = T.type_alias { [Symbol, Symbol, T.nilable(String)] }
9
+
10
+ sig { returns(T::Array[Operation]) }
4
11
  attr_reader :operations
5
12
 
6
- def initialize(*args)
13
+ sig { params(environment: Environment).void }
14
+ def initialize(environment)
7
15
  super
8
16
 
9
- @operations = []
17
+ @operations = T.let([], T::Array[Operation])
10
18
  end
11
19
 
20
+ sig { params(package_name: Symbol, version: T.nilable(String)).void }
12
21
  def add(package_name, version = nil)
13
22
  operations << [:add, package_name, version]
14
23
  end
15
24
 
25
+ sig { params(package_name: Symbol).void }
16
26
  def remove(package_name)
17
- operations << [:remove, package_name]
27
+ operations << [:remove, package_name, nil]
18
28
  end
19
29
 
30
+ sig { override.params(dockerfile: Dockerfile).void }
20
31
  def apply_to(dockerfile)
21
32
  packages = distro_spec.default_packages.dup
22
33
 
@@ -30,19 +41,27 @@ module Kuby
30
41
  end
31
42
  end
32
43
 
33
- packages.map! do |package_name, version|
44
+ package_impls = packages.map do |package_name, version|
34
45
  get_package(package_name, version)
35
46
  end
36
47
 
37
- distro_spec.install(packages, into: dockerfile)
48
+ distro_spec.install(package_impls, into: dockerfile)
38
49
  end
39
50
 
40
51
  private
41
52
 
53
+ sig { returns(Distro) }
42
54
  def distro_spec
43
55
  environment.docker.distro_spec
44
56
  end
45
57
 
58
+ sig {
59
+ params(
60
+ package_name: Symbol,
61
+ version: T.nilable(String)
62
+ )
63
+ .returns(Distro::PackageImpl)
64
+ }
46
65
  def get_package(package_name, version)
47
66
  if package = Kuby.packages[package_name]
48
67
  package.with_version(version)
@@ -51,6 +70,7 @@ module Kuby
51
70
  end
52
71
  end
53
72
 
73
+ sig { returns(Metadata) }
54
74
  def metadata
55
75
  environment.docker.metadata
56
76
  end
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Kuby
2
3
  module Docker
3
4
  module Packages
@@ -1,14 +1,30 @@
1
+ # typed: strict
2
+
1
3
  module Kuby
2
4
  module Docker
3
5
  module Packages
4
6
  class ManagedPackage
5
- attr_reader :name, :names_per_distro
7
+ extend T::Sig
8
+
9
+ sig { returns(Symbol) }
10
+ attr_reader :name
11
+
12
+ sig { returns(T::Hash[Symbol, String]) }
13
+ attr_reader :names_per_distro
6
14
 
15
+ sig {
16
+ params(
17
+ name: Symbol,
18
+ names_per_distro: T::Hash[Symbol, String]
19
+ )
20
+ .void
21
+ }
7
22
  def initialize(name, names_per_distro)
8
23
  @name = name
9
24
  @names_per_distro = names_per_distro
10
25
  end
11
26
 
27
+ sig { params(distro: Symbol).returns(String) }
12
28
  def package_name_for(distro)
13
29
  names_per_distro.fetch(distro) do
14
30
  raise UnsupportedDistroError, "Couldn't install #{name} "\
@@ -16,10 +32,12 @@ module Kuby
16
32
  end
17
33
  end
18
34
 
19
- def with_version(*)
35
+ sig { params(ver: String).returns(T.self_type) }
36
+ def with_version(ver)
20
37
  self
21
38
  end
22
39
 
40
+ sig { returns(T::Boolean) }
23
41
  def managed?
24
42
  true
25
43
  end