kuby-core 0.8.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -1
- data/Gemfile +1 -0
- data/README.md +15 -3
- data/bin/kuby +4 -0
- data/kuby-core.gemspec +7 -3
- data/lib/kuby-core.rb +1 -0
- data/lib/kuby.rb +60 -18
- data/lib/kuby/basic_logger.rb +14 -0
- data/lib/kuby/cli_base.rb +126 -4
- data/lib/kuby/commands.rb +245 -0
- data/lib/kuby/definition.rb +2 -3
- data/lib/kuby/dev_setup.rb +256 -0
- data/lib/kuby/docker.rb +4 -0
- data/lib/kuby/docker/alpine.rb +16 -12
- data/lib/kuby/docker/assets_phase.rb +5 -0
- data/lib/kuby/docker/bundler_phase.rb +39 -5
- data/lib/kuby/docker/cli.rb +60 -3
- data/lib/kuby/docker/copy_phase.rb +11 -3
- data/lib/kuby/docker/credentials.rb +1 -0
- data/lib/kuby/docker/debian.rb +14 -10
- data/lib/kuby/docker/dev_spec.rb +195 -0
- data/lib/kuby/docker/distro.rb +43 -0
- data/lib/kuby/docker/dockerfile.rb +81 -18
- data/lib/kuby/docker/errors.rb +9 -0
- data/lib/kuby/docker/inline_layer.rb +7 -0
- data/lib/kuby/docker/layer.rb +11 -0
- data/lib/kuby/docker/layer_stack.rb +47 -6
- data/lib/kuby/docker/local_tags.rb +27 -2
- data/lib/kuby/docker/metadata.rb +35 -29
- data/lib/kuby/docker/package_list.rb +22 -3
- data/lib/kuby/docker/package_phase.rb +25 -5
- data/lib/kuby/docker/packages.rb +1 -0
- data/lib/kuby/docker/packages/managed_package.rb +20 -2
- data/lib/kuby/docker/packages/nodejs.rb +8 -0
- data/lib/kuby/docker/packages/package.rb +15 -1
- data/lib/kuby/docker/packages/simple_managed_package.rb +10 -1
- data/lib/kuby/docker/packages/yarn.rb +14 -0
- data/lib/kuby/docker/remote_tags.rb +21 -2
- data/lib/kuby/docker/setup_phase.rb +37 -5
- data/lib/kuby/docker/spec.rb +114 -12
- data/lib/kuby/docker/tags.rb +37 -2
- data/lib/kuby/docker/timestamp_tag.rb +14 -2
- data/lib/kuby/docker/webserver_phase.rb +40 -5
- data/lib/kuby/docker/yarn_phase.rb +5 -0
- data/lib/kuby/environment.rb +14 -1
- data/lib/kuby/kubernetes.rb +10 -9
- data/lib/kuby/kubernetes/deploy_task.rb +5 -0
- data/lib/kuby/kubernetes/deployer.rb +67 -11
- data/lib/kuby/kubernetes/docker_config.rb +1 -0
- data/lib/kuby/kubernetes/{minikube_provider.rb → docker_desktop_provider.rb} +5 -4
- data/lib/kuby/kubernetes/errors.rb +1 -0
- data/lib/kuby/kubernetes/manifest.rb +1 -0
- data/lib/kuby/kubernetes/provider.rb +9 -4
- data/lib/kuby/kubernetes/registry_secret.rb +1 -0
- data/lib/kuby/kubernetes/spec.rb +24 -22
- data/lib/kuby/middleware.rb +1 -0
- data/lib/kuby/middleware/health_check.rb +1 -0
- data/lib/kuby/plugin.rb +1 -0
- data/lib/kuby/plugin_registry.rb +28 -0
- data/lib/kuby/plugins.rb +1 -0
- data/lib/kuby/plugins/nginx_ingress.rb +1 -0
- data/lib/kuby/plugins/rails_app.rb +1 -0
- data/lib/kuby/plugins/rails_app/asset_copy_task.rb +1 -0
- data/lib/kuby/plugins/rails_app/assets.rb +1 -0
- data/lib/kuby/plugins/rails_app/database.rb +10 -9
- data/lib/kuby/plugins/rails_app/generators/kuby.rb +45 -44
- data/lib/kuby/plugins/rails_app/mysql.rb +1 -3
- data/lib/kuby/plugins/rails_app/plugin.rb +244 -44
- data/lib/kuby/plugins/rails_app/postgres.rb +1 -0
- data/lib/kuby/plugins/rails_app/rewrite_db_config.rb +1 -0
- data/lib/kuby/plugins/rails_app/sqlite.rb +1 -0
- data/lib/kuby/rails_commands.rb +84 -0
- data/lib/kuby/railtie.rb +1 -4
- data/lib/kuby/tasks.rb +78 -23
- data/lib/kuby/trailing_hash.rb +5 -3
- data/lib/kuby/version.rb +3 -1
- data/spec/docker/metadata_spec.rb +1 -108
- data/spec/docker/spec_spec.rb +303 -0
- data/spec/docker/timestamp_tag_spec.rb +1 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +1 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +1 -0
- data/spec/dummy/app/controllers/application_controller.rb +1 -0
- data/spec/dummy/app/helpers/application_helper.rb +1 -0
- data/spec/dummy/app/jobs/application_job.rb +1 -0
- data/spec/dummy/app/mailers/application_mailer.rb +1 -0
- data/spec/dummy/app/models/application_record.rb +1 -0
- data/spec/dummy/config/application.rb +1 -0
- data/spec/dummy/config/boot.rb +1 -0
- data/spec/dummy/config/environment.rb +1 -0
- data/spec/dummy/config/environments/development.rb +1 -0
- data/spec/dummy/config/environments/production.rb +1 -0
- data/spec/dummy/config/environments/test.rb +1 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +1 -0
- data/spec/dummy/config/initializers/assets.rb +1 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +1 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +1 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +1 -0
- data/spec/dummy/config/initializers/inflections.rb +1 -0
- data/spec/dummy/config/initializers/mime_types.rb +1 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +1 -0
- data/spec/dummy/config/puma.rb +1 -0
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/dummy/config/spring.rb +1 -0
- data/spec/dummy/db/seeds.rb +1 -0
- data/spec/dummy/test/application_system_test_case.rb +1 -0
- data/spec/dummy/test/channels/application_cable/connection_test.rb +1 -0
- data/spec/dummy/test/test_helper.rb +1 -0
- data/spec/spec_helper.rb +18 -1
- data/spec/support/docker/fake_cli.rb +1 -0
- data/spec/support/docker/remote/fake_client.rb +1 -0
- data/spec/trailing_hash_spec.rb +2 -0
- metadata +62 -11
- data/lib/kuby/tasks/kuby.rake +0 -70
data/lib/kuby/docker.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
|
|
1
3
|
require 'kuby/docker/errors'
|
|
2
4
|
|
|
3
5
|
module Kuby
|
|
@@ -9,6 +11,8 @@ module Kuby
|
|
|
9
11
|
autoload :CopyPhase, 'kuby/docker/copy_phase'
|
|
10
12
|
autoload :Credentials, 'kuby/docker/credentials'
|
|
11
13
|
autoload :Debian, 'kuby/docker/debian'
|
|
14
|
+
autoload :DevSpec, 'kuby/docker/dev_spec'
|
|
15
|
+
autoload :Distro, 'kuby/docker/distro'
|
|
12
16
|
autoload :Dockerfile, 'kuby/docker/dockerfile'
|
|
13
17
|
autoload :InlineLayer, 'kuby/docker/inline_layer'
|
|
14
18
|
autoload :Layer, 'kuby/docker/layer'
|
data/lib/kuby/docker/alpine.rb
CHANGED
|
@@ -1,40 +1,43 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
|
|
1
3
|
module Kuby
|
|
2
4
|
module Docker
|
|
3
|
-
class Alpine
|
|
4
|
-
SHELL_EXE = '/bin/sh'.freeze
|
|
5
|
+
class Alpine < Distro
|
|
6
|
+
SHELL_EXE = T.let('/bin/sh'.freeze, String)
|
|
5
7
|
|
|
6
|
-
DEFAULT_PACKAGES = [
|
|
7
|
-
[:ca_certificates],
|
|
8
|
+
DEFAULT_PACKAGES = T.let([
|
|
9
|
+
[:ca_certificates, nil],
|
|
8
10
|
[:nodejs, '12.14.1'],
|
|
9
11
|
[:yarn, '1.21.1'],
|
|
10
|
-
[:c_toolchain],
|
|
11
|
-
[:tzdata]
|
|
12
|
-
].freeze
|
|
12
|
+
[:c_toolchain, nil],
|
|
13
|
+
[:tzdata, nil]
|
|
14
|
+
].freeze, T::Array[[Symbol, T.nilable(String)]])
|
|
13
15
|
|
|
16
|
+
sig { returns(Layer) }
|
|
14
17
|
attr_reader :phase
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
@phase = phase
|
|
18
|
-
end
|
|
19
|
-
|
|
19
|
+
sig { override.params(packages: T::Array[Distro::PackageImpl], into: Dockerfile).void }
|
|
20
20
|
def install(packages, into:)
|
|
21
21
|
dockerfile = into
|
|
22
22
|
install_managed(packages, dockerfile)
|
|
23
23
|
install_unmanaged(packages, dockerfile)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
sig { override.returns(T::Array[[Symbol, T.nilable(String)]]) }
|
|
26
27
|
def default_packages
|
|
27
28
|
DEFAULT_PACKAGES
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
sig { override.returns(String) }
|
|
30
32
|
def shell_exe
|
|
31
33
|
SHELL_EXE
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
private
|
|
35
37
|
|
|
38
|
+
sig { params(packages: T::Array[Distro::PackageImpl], dockerfile: Dockerfile).void }
|
|
36
39
|
def install_managed(packages, dockerfile)
|
|
37
|
-
pkgs = packages.select(&:managed?)
|
|
40
|
+
pkgs = T.cast(packages.select(&:managed?), T::Array[Distro::ManagedPackageImpl])
|
|
38
41
|
|
|
39
42
|
unless pkgs.empty?
|
|
40
43
|
package_names = pkgs.map { |pkg| pkg.package_name_for(:alpine) }
|
|
@@ -44,6 +47,7 @@ module Kuby
|
|
|
44
47
|
end
|
|
45
48
|
end
|
|
46
49
|
|
|
50
|
+
sig { params(packages: T::Array[Distro::PackageImpl], dockerfile: Dockerfile).void }
|
|
47
51
|
def install_unmanaged(packages, dockerfile)
|
|
48
52
|
packages
|
|
49
53
|
.reject(&:managed?)
|
|
@@ -1,26 +1,58 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
|
|
1
3
|
require 'pathname'
|
|
2
4
|
|
|
3
5
|
module Kuby
|
|
4
6
|
module Docker
|
|
5
7
|
class BundlerPhase < Layer
|
|
6
|
-
|
|
8
|
+
extend T::Sig
|
|
9
|
+
|
|
10
|
+
DEFAULT_WITHOUT = T.let(
|
|
11
|
+
['development', 'test', 'deploy'].freeze, T::Array[String]
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
sig { returns(T.nilable(String)) }
|
|
15
|
+
attr_reader :version
|
|
16
|
+
|
|
17
|
+
sig { params(version: String).void }
|
|
18
|
+
attr_writer :version
|
|
19
|
+
|
|
20
|
+
sig { returns(T.nilable(String)) }
|
|
21
|
+
attr_reader :gemfile
|
|
7
22
|
|
|
8
|
-
|
|
23
|
+
sig { params(gemfile: String).void }
|
|
24
|
+
attr_writer :gemfile
|
|
25
|
+
|
|
26
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
27
|
+
attr_reader :without
|
|
28
|
+
|
|
29
|
+
sig { params(without: T::Array[String]).void }
|
|
30
|
+
attr_writer :without
|
|
31
|
+
|
|
32
|
+
sig { params(environment: Environment).void }
|
|
33
|
+
def initialize(environment)
|
|
34
|
+
super
|
|
35
|
+
|
|
36
|
+
@version = T.let(@version, T.nilable(String))
|
|
37
|
+
@gemfile = T.let(@gemfile, T.nilable(String))
|
|
38
|
+
@without = T.let(@without, T.nilable(T::Array[String]))
|
|
39
|
+
end
|
|
9
40
|
|
|
41
|
+
sig { override.params(dockerfile: Dockerfile).void }
|
|
10
42
|
def apply_to(dockerfile)
|
|
11
43
|
gf = gemfile || default_gemfile
|
|
12
44
|
lf = "#{gf}.lock"
|
|
13
45
|
v = version || default_version
|
|
14
46
|
wo = without || DEFAULT_WITHOUT
|
|
15
47
|
|
|
16
|
-
dockerfile.run(
|
|
48
|
+
dockerfile.run('gem', 'install', 'bundler', '-v', v)
|
|
17
49
|
|
|
18
50
|
# bundle install
|
|
19
51
|
dockerfile.copy(gf, '.')
|
|
20
52
|
dockerfile.copy(lf, '.')
|
|
21
53
|
|
|
22
54
|
# set bundle path so docker will cache the bundle
|
|
23
|
-
dockerfile.run('mkdir ./bundle')
|
|
55
|
+
dockerfile.run('mkdir', './bundle')
|
|
24
56
|
dockerfile.env('BUNDLE_PATH=./bundle')
|
|
25
57
|
|
|
26
58
|
unless wo.empty?
|
|
@@ -35,16 +67,18 @@ module Kuby
|
|
|
35
67
|
)
|
|
36
68
|
|
|
37
69
|
# generate binstubs and add the bin directory to our path
|
|
38
|
-
dockerfile.run('bundle binstubs --all')
|
|
70
|
+
dockerfile.run('bundle', 'binstubs', '--all')
|
|
39
71
|
dockerfile.env("PATH=./bin:$PATH")
|
|
40
72
|
end
|
|
41
73
|
|
|
42
74
|
private
|
|
43
75
|
|
|
76
|
+
sig { returns(String) }
|
|
44
77
|
def default_version
|
|
45
78
|
Bundler::VERSION
|
|
46
79
|
end
|
|
47
80
|
|
|
81
|
+
sig { returns(String) }
|
|
48
82
|
def default_gemfile
|
|
49
83
|
Bundler
|
|
50
84
|
.definition
|
data/lib/kuby/docker/cli.rb
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
|
|
1
3
|
require 'json'
|
|
2
4
|
require 'open3'
|
|
5
|
+
require 'shellwords'
|
|
3
6
|
|
|
4
7
|
module Kuby
|
|
5
8
|
module Docker
|
|
6
9
|
class CLI < CLIBase
|
|
10
|
+
extend T::Sig
|
|
11
|
+
|
|
12
|
+
sig { returns(String) }
|
|
7
13
|
attr_reader :executable
|
|
8
14
|
|
|
15
|
+
sig { params(executable: T.nilable(String)).void }
|
|
9
16
|
def initialize(executable = nil)
|
|
10
|
-
@executable = executable || `which docker`.strip
|
|
17
|
+
@executable = T.let(executable || `which docker`.strip, String)
|
|
11
18
|
end
|
|
12
19
|
|
|
20
|
+
sig { returns(T.nilable(String)) }
|
|
13
21
|
def config_file
|
|
14
22
|
if File.exist?(default_config_file)
|
|
15
23
|
default_config_file
|
|
16
24
|
end
|
|
17
25
|
end
|
|
18
26
|
|
|
27
|
+
sig { returns(String) }
|
|
19
28
|
def default_config_file
|
|
20
29
|
File.join(Dir.home, '.docker', 'config.json')
|
|
21
30
|
end
|
|
22
31
|
|
|
32
|
+
sig { params(url: String, username: String, password: String).void }
|
|
23
33
|
def login(url:, username:, password:)
|
|
24
34
|
cmd = [
|
|
25
35
|
executable, 'login', url, '--username', username, '--password-stdin'
|
|
@@ -35,17 +45,30 @@ module Kuby
|
|
|
35
45
|
end
|
|
36
46
|
end
|
|
37
47
|
|
|
48
|
+
sig { returns(T::Array[String]) }
|
|
38
49
|
def auths
|
|
39
50
|
return [] unless config_file
|
|
40
51
|
|
|
41
|
-
config = JSON.parse(File.read(config_file))
|
|
52
|
+
config = JSON.parse(File.read(T.must(config_file)))
|
|
42
53
|
config.fetch('auths', {}).keys
|
|
43
54
|
end
|
|
44
55
|
|
|
45
|
-
|
|
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: {})
|
|
46
66
|
cmd = [
|
|
47
67
|
executable, 'build',
|
|
48
68
|
*tags.flat_map { |tag| ['-t', "#{image_url}:#{tag}"] },
|
|
69
|
+
*build_args.flat_map do |arg, val|
|
|
70
|
+
['--build-arg', Shellwords.shellescape("#{arg}=#{val}")]
|
|
71
|
+
end,
|
|
49
72
|
'-f-', '.'
|
|
50
73
|
]
|
|
51
74
|
|
|
@@ -59,6 +82,15 @@ module Kuby
|
|
|
59
82
|
end
|
|
60
83
|
end
|
|
61
84
|
|
|
85
|
+
sig {
|
|
86
|
+
params(
|
|
87
|
+
image_url: String,
|
|
88
|
+
tag: String,
|
|
89
|
+
env: T::Hash[T.any(Symbol, String), String],
|
|
90
|
+
ports: T::Array[T.any(String, Integer)]
|
|
91
|
+
)
|
|
92
|
+
.void
|
|
93
|
+
}
|
|
62
94
|
def run(image_url:, tag: 'latest', env: {}, ports: [])
|
|
63
95
|
cmd = [
|
|
64
96
|
executable, 'run',
|
|
@@ -72,6 +104,7 @@ module Kuby
|
|
|
72
104
|
execc(cmd)
|
|
73
105
|
end
|
|
74
106
|
|
|
107
|
+
sig { params(image_url: String).returns(T::Array[T::Hash[Symbol, String]]) }
|
|
75
108
|
def images(image_url)
|
|
76
109
|
cmd = [
|
|
77
110
|
executable, 'images', image_url,
|
|
@@ -85,6 +118,7 @@ module Kuby
|
|
|
85
118
|
end
|
|
86
119
|
end
|
|
87
120
|
|
|
121
|
+
sig { params(image_url: String, tag: String).void }
|
|
88
122
|
def push(image_url, tag)
|
|
89
123
|
systemm([
|
|
90
124
|
executable, 'push', "#{image_url}:#{tag}"
|
|
@@ -96,9 +130,32 @@ module Kuby
|
|
|
96
130
|
end
|
|
97
131
|
end
|
|
98
132
|
|
|
133
|
+
sig { params(image_url: String, tag: String).void }
|
|
134
|
+
def pull(image_url, tag)
|
|
135
|
+
systemm([
|
|
136
|
+
executable, 'pull', "#{image_url}:#{tag}"
|
|
137
|
+
])
|
|
138
|
+
|
|
139
|
+
unless last_status.success?
|
|
140
|
+
raise PullError, 'pull failed: docker command exited with '\
|
|
141
|
+
"status code #{last_status.exitstatus}"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
sig { returns(Symbol) }
|
|
99
146
|
def status_key
|
|
100
147
|
:kuby_docker_cli_last_status
|
|
101
148
|
end
|
|
149
|
+
|
|
150
|
+
sig { returns(Symbol) }
|
|
151
|
+
def stdout_key
|
|
152
|
+
:kuby_docker_stdout
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
sig { returns(Symbol) }
|
|
156
|
+
def stderr_key
|
|
157
|
+
:kuby_docker_stderr
|
|
158
|
+
end
|
|
102
159
|
end
|
|
103
160
|
end
|
|
104
161
|
end
|
|
@@ -1,19 +1,27 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
|
|
1
3
|
module Kuby
|
|
2
4
|
module Docker
|
|
3
5
|
class CopyPhase < Layer
|
|
4
|
-
|
|
6
|
+
extend T::Sig
|
|
7
|
+
|
|
8
|
+
DEFAULT_PATHS = T.let(['./'].freeze, T::Array[String])
|
|
5
9
|
|
|
10
|
+
sig { returns(T::Array[String]) }
|
|
6
11
|
attr_reader :paths
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
sig { params(environment: Environment).void }
|
|
14
|
+
def initialize(environment)
|
|
9
15
|
super
|
|
10
|
-
@paths = []
|
|
16
|
+
@paths = T.let([], T::Array[String])
|
|
11
17
|
end
|
|
12
18
|
|
|
19
|
+
sig { params(path: String).void }
|
|
13
20
|
def <<(path)
|
|
14
21
|
paths << path
|
|
15
22
|
end
|
|
16
23
|
|
|
24
|
+
sig { params(dockerfile: Dockerfile).void }
|
|
17
25
|
def apply_to(dockerfile)
|
|
18
26
|
to_copy = paths.empty? ? DEFAULT_PATHS : paths
|
|
19
27
|
to_copy.each { |path| dockerfile.copy(path, '.') }
|
data/lib/kuby/docker/debian.rb
CHANGED
|
@@ -1,38 +1,41 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
|
|
1
3
|
module Kuby
|
|
2
4
|
module Docker
|
|
3
|
-
class Debian
|
|
4
|
-
SHELL_EXE = '/bin/bash'
|
|
5
|
+
class Debian < Distro
|
|
6
|
+
SHELL_EXE = T.let('/bin/bash'.freeze, String)
|
|
5
7
|
|
|
6
|
-
DEFAULT_PACKAGES = [
|
|
7
|
-
[:ca_certificates],
|
|
8
|
+
DEFAULT_PACKAGES = T.let([
|
|
9
|
+
[:ca_certificates, nil],
|
|
8
10
|
[:nodejs, '12.14.1'],
|
|
9
11
|
[:yarn, '1.21.1']
|
|
10
|
-
].freeze
|
|
12
|
+
].freeze, T::Array[[Symbol, T.nilable(String)]])
|
|
11
13
|
|
|
14
|
+
sig { returns(Layer) }
|
|
12
15
|
attr_reader :phase
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
@phase = phase
|
|
16
|
-
end
|
|
17
|
-
|
|
17
|
+
sig { override.params(packages: T::Array[Distro::PackageImpl], into: Dockerfile).void }
|
|
18
18
|
def install(packages, into:)
|
|
19
19
|
dockerfile = into
|
|
20
20
|
install_managed(packages, dockerfile)
|
|
21
21
|
install_unmanaged(packages, dockerfile)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
sig { override.returns(T::Array[[Symbol, T.nilable(String)]]) }
|
|
24
25
|
def default_packages
|
|
25
26
|
DEFAULT_PACKAGES
|
|
26
27
|
end
|
|
27
28
|
|
|
29
|
+
sig { override.returns(String) }
|
|
28
30
|
def shell_exe
|
|
29
31
|
SHELL_EXE
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
private
|
|
33
35
|
|
|
36
|
+
sig { params(packages: T::Array[Distro::PackageImpl], dockerfile: Dockerfile).void }
|
|
34
37
|
def install_managed(packages, dockerfile)
|
|
35
|
-
pkgs = packages.select(&:managed?)
|
|
38
|
+
pkgs = T.cast(packages.select(&:managed?), T::Array[Distro::ManagedPackageImpl])
|
|
36
39
|
|
|
37
40
|
pkg_cmd = <<~CMD.strip
|
|
38
41
|
apt-get update -qq && \\
|
|
@@ -49,6 +52,7 @@ module Kuby
|
|
|
49
52
|
dockerfile.run(pkg_cmd)
|
|
50
53
|
end
|
|
51
54
|
|
|
55
|
+
sig { params(packages: T::Array[Distro::PackageImpl], dockerfile: Dockerfile).void }
|
|
52
56
|
def install_unmanaged(packages, dockerfile)
|
|
53
57
|
packages
|
|
54
58
|
.reject(&:managed?)
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
|
|
3
|
+
module Kuby
|
|
4
|
+
module Docker
|
|
5
|
+
class WebserverDevPhase < Layer
|
|
6
|
+
extend T::Sig
|
|
7
|
+
|
|
8
|
+
DEFAULT_PORT = T.let('3000'.freeze, String)
|
|
9
|
+
|
|
10
|
+
sig { params(port: String).void }
|
|
11
|
+
attr_writer :port
|
|
12
|
+
|
|
13
|
+
sig { params(environment: Environment).void }
|
|
14
|
+
def initialize(environment)
|
|
15
|
+
super
|
|
16
|
+
|
|
17
|
+
@port = T.let(@port, T.nilable(String))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
sig { override.params(dockerfile: Dockerfile).void }
|
|
21
|
+
def apply_to(dockerfile)
|
|
22
|
+
dockerfile.expose(port)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
sig { returns(String) }
|
|
26
|
+
def port
|
|
27
|
+
@port || DEFAULT_PORT
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class DevSpec
|
|
32
|
+
extend T::Sig
|
|
33
|
+
|
|
34
|
+
sig { returns(Environment) }
|
|
35
|
+
attr_reader :environment
|
|
36
|
+
|
|
37
|
+
sig { params(environment: Environment).void }
|
|
38
|
+
def initialize(environment)
|
|
39
|
+
@environment = environment
|
|
40
|
+
|
|
41
|
+
@setup_phase = T.let(@setup_phase, T.nilable(SetupPhase))
|
|
42
|
+
@package_phase = T.let(@package_phase, T.nilable(PackagePhase))
|
|
43
|
+
@webserver_phase = T.let(@webserver_phase, T.nilable(WebserverDevPhase))
|
|
44
|
+
@metadata = T.let(@metadata, T.nilable(Metadata))
|
|
45
|
+
@distro_spec = T.let(@distro_spec, T.nilable(Distro))
|
|
46
|
+
@cli = T.let(@cli, T.nilable(CLI))
|
|
47
|
+
@tags = T.let(@tags, T.nilable(LocalTags))
|
|
48
|
+
@layer_stack = T.let(@layer_stack, T.nilable(Docker::LayerStack))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
sig { params(dir: String).void }
|
|
52
|
+
def working_dir(dir)
|
|
53
|
+
setup_phase.working_dir = dir
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
sig { params(env: String).void }
|
|
57
|
+
def rails_env(env)
|
|
58
|
+
setup_phase.rails_env = env
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
sig {
|
|
62
|
+
params(
|
|
63
|
+
package_name: Symbol,
|
|
64
|
+
version: T.nilable(String)
|
|
65
|
+
)
|
|
66
|
+
.void
|
|
67
|
+
}
|
|
68
|
+
def package(package_name, version = nil)
|
|
69
|
+
package_phase.add(package_name, version)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
sig { params(distro_name: Symbol).void }
|
|
73
|
+
def distro(distro_name)
|
|
74
|
+
metadata.distro = distro_name
|
|
75
|
+
@distro_spec = nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
sig { params(port: String).void }
|
|
79
|
+
def port(port)
|
|
80
|
+
webserver_phase.port = port
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
sig {
|
|
84
|
+
params(
|
|
85
|
+
name: Symbol,
|
|
86
|
+
layer: T.nilable(Layer),
|
|
87
|
+
block: T.nilable(T.proc.params(df: Dockerfile).void)
|
|
88
|
+
)
|
|
89
|
+
.void
|
|
90
|
+
}
|
|
91
|
+
def use(name, layer = nil, &block)
|
|
92
|
+
layer_stack.use(name, layer, &block)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
sig {
|
|
96
|
+
params(
|
|
97
|
+
name: Symbol,
|
|
98
|
+
layer: T.nilable(T.any(Layer, T::Hash[Symbol, T.untyped])),
|
|
99
|
+
options: T::Hash[Symbol, T.untyped],
|
|
100
|
+
block: T.nilable(T.proc.params(df: Dockerfile).void)
|
|
101
|
+
)
|
|
102
|
+
.void
|
|
103
|
+
}
|
|
104
|
+
def insert(name, layer = nil, options = {}, &block)
|
|
105
|
+
layer_stack.insert(name, layer, options, &block)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
sig { params(name: Symbol).void }
|
|
109
|
+
def delete(name)
|
|
110
|
+
layer_stack.delete(name)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
sig { params(name: Symbol).returns(T::Boolean) }
|
|
114
|
+
def exists?(name)
|
|
115
|
+
layer_stack.includes?(name)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
sig { returns(Dockerfile) }
|
|
119
|
+
def to_dockerfile
|
|
120
|
+
Dockerfile.new.tap do |df|
|
|
121
|
+
layer_stack.each { |layer| layer.apply_to(df) }
|
|
122
|
+
df.cmd("#{distro_spec.shell_exe} -c 'while test 1; do sleep 5; done'")
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
sig { returns(SetupPhase) }
|
|
127
|
+
def setup_phase
|
|
128
|
+
@setup_phase ||= SetupPhase.new(environment)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
sig { returns(PackagePhase) }
|
|
132
|
+
def package_phase
|
|
133
|
+
@package_phase ||= PackagePhase.new(environment)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
sig { returns(WebserverDevPhase) }
|
|
137
|
+
def webserver_phase
|
|
138
|
+
@webserver_phase ||= WebserverDevPhase.new(environment)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
sig { returns(Metadata) }
|
|
142
|
+
def metadata
|
|
143
|
+
@metadata ||= Metadata.new(environment)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
sig { returns(Distro) }
|
|
147
|
+
def distro_spec
|
|
148
|
+
@distro_spec ||= if distro_klass = Kuby.distros[metadata.distro]
|
|
149
|
+
distro_klass.new(self)
|
|
150
|
+
else
|
|
151
|
+
raise MissingDistroError, "distro '#{metadata.distro}' hasn't been registered"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
sig { returns(String) }
|
|
156
|
+
def tag
|
|
157
|
+
t = ENV.fetch('KUBY_DOCKER_TAG') do
|
|
158
|
+
tags.latest_timestamp_tag
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
unless t
|
|
162
|
+
raise MissingTagError, 'could not find latest timestamped tag'
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
t.to_s
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
sig { params(current_tag: String).returns(String) }
|
|
169
|
+
def previous_tag(current_tag)
|
|
170
|
+
raise MissingTagError, 'cannot roll back in the development environment'
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
sig { returns(CLI) }
|
|
174
|
+
def cli
|
|
175
|
+
@cli ||= Docker::CLI.new
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
|
|
180
|
+
sig { returns(LocalTags) }
|
|
181
|
+
def tags
|
|
182
|
+
@tags ||= LocalTags.new(cli, metadata)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
sig { returns(Docker::LayerStack) }
|
|
186
|
+
def layer_stack
|
|
187
|
+
@layer_stack ||= Docker::LayerStack.new.tap do |stack|
|
|
188
|
+
stack.use(:setup_phase, setup_phase)
|
|
189
|
+
stack.use(:package_phase, package_phase)
|
|
190
|
+
stack.use(:webserver_phase, webserver_phase)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|