kuby-core 0.8.1 → 0.9.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 +12 -1
- data/README.md +11 -1
- data/bin/kuby +4 -0
- data/kuby-core.gemspec +5 -2
- data/lib/kuby.rb +46 -18
- data/lib/kuby/basic_logger.rb +13 -0
- data/lib/kuby/cli_base.rb +81 -8
- data/lib/kuby/commands.rb +220 -0
- data/lib/kuby/definition.rb +1 -3
- data/lib/kuby/dev_setup.rb +255 -0
- data/lib/kuby/docker.rb +1 -0
- data/lib/kuby/docker/bundler_phase.rb +3 -3
- data/lib/kuby/docker/cli.rb +13 -1
- data/lib/kuby/docker/dev_spec.rb +131 -0
- data/lib/kuby/docker/dockerfile.rb +16 -1
- data/lib/kuby/docker/layer_stack.rb +4 -0
- data/lib/kuby/docker/local_tags.rb +4 -0
- data/lib/kuby/docker/metadata.rb +0 -22
- data/lib/kuby/docker/setup_phase.rb +3 -2
- data/lib/kuby/docker/spec.rb +31 -5
- data/lib/kuby/environment.rb +10 -1
- data/lib/kuby/kubernetes.rb +9 -9
- data/lib/kuby/kubernetes/deploy_task.rb +4 -0
- data/lib/kuby/kubernetes/deployer.rb +63 -11
- data/lib/kuby/kubernetes/{minikube_provider.rb → docker_desktop_provider.rb} +4 -4
- data/lib/kuby/kubernetes/provider.rb +8 -4
- data/lib/kuby/kubernetes/spec.rb +23 -22
- data/lib/kuby/plugin_registry.rb +27 -0
- data/lib/kuby/plugins/rails_app/generators/kuby.rb +3 -15
- data/lib/kuby/plugins/rails_app/plugin.rb +230 -40
- data/lib/kuby/rails_commands.rb +89 -0
- data/lib/kuby/railtie.rb +0 -4
- data/lib/kuby/tasks.rb +76 -23
- data/lib/kuby/version.rb +1 -1
- data/spec/docker/metadata_spec.rb +0 -108
- data/spec/docker/spec_spec.rb +266 -0
- data/spec/spec_helper.rb +8 -1
- metadata +44 -9
- data/lib/kuby/tasks/kuby.rake +0 -70
data/lib/kuby/railtie.rb
CHANGED
@@ -3,10 +3,6 @@ require 'rails/railtie'
|
|
3
3
|
|
4
4
|
module Kuby
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
|
-
rake_tasks do
|
7
|
-
load File.expand_path(File.join('tasks', 'kuby.rake'), __dir__)
|
8
|
-
end
|
9
|
-
|
10
6
|
initializer 'kuby.health_check_middleware' do |app|
|
11
7
|
app.middleware.use Kuby::Middleware::HealthCheck
|
12
8
|
end
|
data/lib/kuby/tasks.rb
CHANGED
@@ -21,24 +21,25 @@ module Kuby
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def build
|
24
|
+
build_args = {}
|
25
|
+
|
26
|
+
unless ENV.fetch('RAILS_MASTER_KEY', '').empty?
|
27
|
+
build_args['RAILS_MASTER_KEY'] = ENV['RAILS_MASTER_KEY']
|
28
|
+
end
|
29
|
+
|
24
30
|
docker.cli.build(
|
25
31
|
dockerfile: docker.to_dockerfile,
|
26
32
|
image_url: docker.metadata.image_url,
|
27
|
-
tags: docker.metadata.tags
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
def run
|
32
|
-
dockerfile = docker.to_dockerfile
|
33
|
-
|
34
|
-
docker.cli.run(
|
35
|
-
image_url: docker.metadata.image_url,
|
36
|
-
tag: 'latest',
|
37
|
-
ports: dockerfile.exposed_ports
|
33
|
+
tags: docker.metadata.tags,
|
34
|
+
build_args: build_args
|
38
35
|
)
|
39
36
|
end
|
40
37
|
|
41
38
|
def push
|
39
|
+
if environment.development?
|
40
|
+
fail 'Cannot push Docker images built for the development environment'
|
41
|
+
end
|
42
|
+
|
42
43
|
hostname = docker.metadata.image_hostname
|
43
44
|
|
44
45
|
unless docker.cli.auths.include?(hostname)
|
@@ -72,8 +73,8 @@ module Kuby
|
|
72
73
|
end
|
73
74
|
end
|
74
75
|
|
75
|
-
def deploy
|
76
|
-
environment.kubernetes.deploy
|
76
|
+
def deploy(tag = nil)
|
77
|
+
environment.kubernetes.deploy(tag)
|
77
78
|
end
|
78
79
|
|
79
80
|
def rollback
|
@@ -106,26 +107,64 @@ module Kuby
|
|
106
107
|
kubernetes_cli.run_cmd(['-n', namespace, 'get', 'pods'])
|
107
108
|
end
|
108
109
|
|
109
|
-
def
|
110
|
+
def remote_exec(cmd)
|
110
111
|
first_pod = get_first_pod
|
111
|
-
|
112
|
-
kubernetes_cli.exec_cmd(shell, namespace, first_pod.dig('metadata', 'name'))
|
112
|
+
kubernetes_cli.exec_cmd(cmd, namespace, first_pod.dig('metadata', 'name'))
|
113
113
|
end
|
114
114
|
|
115
|
-
def
|
115
|
+
def remote_system(cmd)
|
116
116
|
first_pod = get_first_pod
|
117
|
+
kubernetes_cli.system_cmd(cmd, namespace, first_pod.dig('metadata', 'name'))
|
118
|
+
end
|
117
119
|
|
118
|
-
|
119
|
-
|
120
|
-
|
120
|
+
def remote_shell
|
121
|
+
remote_exec(docker.distro_spec.shell_exe)
|
122
|
+
end
|
123
|
+
|
124
|
+
def remote_console
|
125
|
+
remote_exec('bundle exec rails console')
|
121
126
|
end
|
122
127
|
|
123
128
|
def remote_dbconsole
|
124
|
-
|
129
|
+
remote_exec('bundle exec rails dbconsole')
|
130
|
+
end
|
131
|
+
|
132
|
+
def remote_restart
|
133
|
+
deployment = rails_app.deployment.metadata.name
|
134
|
+
kubernetes_cli.restart_deployment(namespace, deployment)
|
135
|
+
end
|
136
|
+
|
137
|
+
def dev_deployment_ok
|
138
|
+
return true unless Kuby.environment.development?
|
125
139
|
|
126
|
-
kubernetes_cli.
|
127
|
-
'
|
140
|
+
deployments = kubernetes_cli.get_objects(
|
141
|
+
'deployments', namespace, match_labels.serialize
|
128
142
|
)
|
143
|
+
|
144
|
+
if deployments.empty?
|
145
|
+
puts 'No development environment detected.'
|
146
|
+
STDOUT.write('Set up development environment? (y/n): ')
|
147
|
+
answer = STDIN.gets.strip.downcase
|
148
|
+
return false unless answer =~ /ye?s?/
|
149
|
+
else
|
150
|
+
depl = deployments.first
|
151
|
+
deployed_checksum = depl.dig('metadata', 'annotations', 'getkuby.io/dockerfile-checksum')
|
152
|
+
current_checksum = docker.to_dockerfile.checksum
|
153
|
+
|
154
|
+
if deployed_checksum != current_checksum
|
155
|
+
puts "Development environment appears to be out-of-date."
|
156
|
+
puts "Environment checksum: #{deployed_checksum}"
|
157
|
+
puts "Current checksum: #{current_checksum}"
|
158
|
+
STDOUT.write('Update development environment? (y/n): ')
|
159
|
+
answer = STDIN.gets.strip.downcase
|
160
|
+
# return true here to prevent letting an out-of-date deployment
|
161
|
+
# stop us from running commands
|
162
|
+
return true unless answer =~ /ye?s?/
|
163
|
+
DevSetup.new(environment).run
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
true
|
129
168
|
end
|
130
169
|
|
131
170
|
private
|
@@ -135,6 +174,12 @@ module Kuby
|
|
135
174
|
'pods', namespace, match_labels.serialize
|
136
175
|
)
|
137
176
|
|
177
|
+
# consider only "Running" pods that aren't marked for deletion
|
178
|
+
pods.select! do |pod|
|
179
|
+
pod.dig('status', 'phase') == 'Running' &&
|
180
|
+
!pod.dig('metadata', 'deletionTimestamp')
|
181
|
+
end
|
182
|
+
|
138
183
|
if pods.empty?
|
139
184
|
raise Kuby::Kubernetes::MissingResourceError,
|
140
185
|
"Couldn't find any running pods in namespace '#{namespace}' :("
|
@@ -161,6 +206,14 @@ module Kuby
|
|
161
206
|
kubernetes.provider.kubernetes_cli
|
162
207
|
end
|
163
208
|
|
209
|
+
def helm_cli
|
210
|
+
kubernetes.provider.helm_cli
|
211
|
+
end
|
212
|
+
|
213
|
+
def docker_cli
|
214
|
+
docker.cli
|
215
|
+
end
|
216
|
+
|
164
217
|
def kubernetes
|
165
218
|
Kuby.environment.kubernetes
|
166
219
|
end
|
data/lib/kuby/version.rb
CHANGED
@@ -70,114 +70,6 @@ describe Kuby::Docker::Metadata do
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
describe '#tag' do
|
74
|
-
let(:tag) { make_ts_tag(Time.now) }
|
75
|
-
|
76
|
-
subject { metadata.tag }
|
77
|
-
|
78
|
-
context 'with no local or remote tags' do
|
79
|
-
it 'raises an error' do
|
80
|
-
expect { subject }.to raise_error(Kuby::Docker::MissingTagError)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'with an available remote tag' do
|
85
|
-
before { docker_remote_client.tags << tag }
|
86
|
-
|
87
|
-
it { is_expected.to eq(tag) }
|
88
|
-
end
|
89
|
-
|
90
|
-
context 'with an available local tag' do
|
91
|
-
before do
|
92
|
-
docker_cli.build(
|
93
|
-
dockerfile: nil,
|
94
|
-
image_url: docker_image_url,
|
95
|
-
tags: [tag]
|
96
|
-
)
|
97
|
-
end
|
98
|
-
|
99
|
-
it { is_expected.to eq(tag) }
|
100
|
-
end
|
101
|
-
|
102
|
-
context 'with multiple remote tags' do
|
103
|
-
let(:time) { Time.now }
|
104
|
-
|
105
|
-
before do
|
106
|
-
docker_remote_client.tags +=
|
107
|
-
[time - 5, time + 10, time - 10, time + 15].map do |t|
|
108
|
-
make_ts_tag(t)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
it { is_expected.to eq(make_ts_tag(time + 15)) }
|
113
|
-
end
|
114
|
-
|
115
|
-
context 'with multiple local and remote tags' do
|
116
|
-
let(:time) { Time.now }
|
117
|
-
|
118
|
-
before do
|
119
|
-
docker_remote_client.tags +=
|
120
|
-
[time - 5, time + 10, time - 10, time + 15].map do |t|
|
121
|
-
make_ts_tag(t)
|
122
|
-
end
|
123
|
-
|
124
|
-
docker_cli.build(
|
125
|
-
dockerfile: nil,
|
126
|
-
image_url: docker_image_url,
|
127
|
-
tags: [time - 3, time + 6, time - 6, time + 18].map do |t|
|
128
|
-
make_ts_tag(t)
|
129
|
-
end
|
130
|
-
)
|
131
|
-
end
|
132
|
-
|
133
|
-
it { is_expected.to eq(make_ts_tag(time + 18)) }
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
describe '#previous_tag' do
|
138
|
-
let(:time) { Time.now }
|
139
|
-
let(:current_tag) { make_ts_tag(time) }
|
140
|
-
|
141
|
-
before do
|
142
|
-
docker_remote_client.tags << current_tag
|
143
|
-
docker_cli.build(
|
144
|
-
dockerfile: nil,
|
145
|
-
image_url: docker_image_url,
|
146
|
-
tags: [current_tag]
|
147
|
-
)
|
148
|
-
end
|
149
|
-
|
150
|
-
subject { metadata.previous_tag(current_tag) }
|
151
|
-
|
152
|
-
context 'with no previous local or remote tag' do
|
153
|
-
it 'raises an error' do
|
154
|
-
expect { subject }.to raise_error(Kuby::Docker::MissingTagError)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
context 'with an available previous remote tag' do
|
159
|
-
let(:previous_tag) { make_ts_tag(time - 5) }
|
160
|
-
|
161
|
-
before { docker_remote_client.tags << previous_tag }
|
162
|
-
|
163
|
-
it { is_expected.to eq(previous_tag) }
|
164
|
-
end
|
165
|
-
|
166
|
-
context 'with an available previous local tag' do
|
167
|
-
let(:previous_tag) { make_ts_tag(time - 5) }
|
168
|
-
|
169
|
-
before do
|
170
|
-
docker_cli.build(
|
171
|
-
dockerfile: nil,
|
172
|
-
image_url: docker_image_url,
|
173
|
-
tags: [previous_tag]
|
174
|
-
)
|
175
|
-
end
|
176
|
-
|
177
|
-
it { is_expected.to eq(previous_tag) }
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
73
|
describe '#distro' do
|
182
74
|
subject { metadata.distro }
|
183
75
|
|
@@ -0,0 +1,266 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
describe Kuby::Docker::Spec do
|
5
|
+
let(:spec) { definition.environment.docker }
|
6
|
+
|
7
|
+
describe '#base_image' do
|
8
|
+
subject { spec.to_dockerfile.to_s }
|
9
|
+
|
10
|
+
it 'uses the default base image for Debian' do
|
11
|
+
expect(subject).to include("FROM ruby:#{RUBY_VERSION}\n")
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when the distro is set to Alpine' do
|
15
|
+
before { spec.distro(:alpine) }
|
16
|
+
|
17
|
+
it 'uses the Alpine base image' do
|
18
|
+
expect(subject).to include("FROM ruby:#{RUBY_VERSION}-alpine\n")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when the base image is set to something custom' do
|
23
|
+
before { spec.base_image('foo/bar') }
|
24
|
+
|
25
|
+
it 'uses the base image as given' do
|
26
|
+
expect(subject).to include("FROM foo/bar\n")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#working_dir' do
|
32
|
+
let(:default_working_dir) do
|
33
|
+
Kuby::Docker::SetupPhase::DEFAULT_WORKING_DIR
|
34
|
+
end
|
35
|
+
|
36
|
+
subject { spec.to_dockerfile.to_s }
|
37
|
+
|
38
|
+
it 'uses the default working dir' do
|
39
|
+
expect(subject).to(
|
40
|
+
include("WORKDIR #{default_working_dir}\n")
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when the working dir is set to something custom' do
|
45
|
+
before { spec.working_dir('/foo/bar') }
|
46
|
+
|
47
|
+
it 'uses the working dir as given' do
|
48
|
+
expect(subject).to include("WORKDIR /foo/bar\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#rails_env' do
|
54
|
+
subject { spec.to_dockerfile.to_s }
|
55
|
+
|
56
|
+
it 'uses the name of the current Kuby environment' do
|
57
|
+
expect(subject).to include("ENV RAILS_ENV=#{spec.environment.name}\n")
|
58
|
+
expect(subject).to include("ENV KUBY_ENV=#{spec.environment.name}\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when the environment is set to something custom' do
|
62
|
+
before { spec.rails_env('foobar') }
|
63
|
+
|
64
|
+
it 'uses the environment as given' do
|
65
|
+
expect(subject).to include("ENV RAILS_ENV=foobar\n")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "doesn't change the Kuby env" do
|
69
|
+
expect(subject).to include("ENV KUBY_ENV=#{spec.environment.name}\n")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#bundler_version' do
|
75
|
+
subject { spec.to_dockerfile.to_s }
|
76
|
+
|
77
|
+
it 'installs the current bundler version' do
|
78
|
+
expect(subject).to(
|
79
|
+
include("RUN gem install bundler -v #{Bundler::VERSION}\n")
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the bundler version is set to something custom' do
|
84
|
+
before { spec.bundler_version('1.17.3') }
|
85
|
+
|
86
|
+
it 'installs the given version' do
|
87
|
+
expect(subject).to include("RUN gem install bundler -v 1.17.3\n")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#gemfile' do
|
93
|
+
subject { spec.to_dockerfile.to_s }
|
94
|
+
|
95
|
+
it 'uses the default Gemfile' do
|
96
|
+
expect(subject).to include("COPY Gemfile .\n")
|
97
|
+
expect(subject).to include("COPY Gemfile.lock .\n")
|
98
|
+
expect(subject).to match(/RUN bundle install .* --gemfile Gemfile/)
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when the gemfile path is set to something custom' do
|
102
|
+
before { spec.gemfile('foo/bar/Gemfile') }
|
103
|
+
|
104
|
+
it 'uses the given gemfile' do
|
105
|
+
expect(subject).to include("COPY foo/bar/Gemfile .\n")
|
106
|
+
expect(subject).to include("COPY foo/bar/Gemfile.lock .\n")
|
107
|
+
expect(subject).to match(/RUN bundle install .* --gemfile foo\/bar\/Gemfile/)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#package' do
|
113
|
+
subject { spec.to_dockerfile.to_s }
|
114
|
+
|
115
|
+
it 'installs the given package' do
|
116
|
+
# configured in spec_helper.rb
|
117
|
+
spec.package(:fake_package)
|
118
|
+
|
119
|
+
expect(subject).to match(/apt-get install .* fake_package/m)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#files' do
|
124
|
+
subject { spec.to_dockerfile.to_s }
|
125
|
+
|
126
|
+
it 'copies the current directory contents by default' do
|
127
|
+
expect(subject).to include("COPY ./ .\n")
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when given a custom path to copy' do
|
131
|
+
before { spec.files('./foo/bar') }
|
132
|
+
|
133
|
+
it 'copies the given paths only' do
|
134
|
+
expect(subject).to include("COPY ./foo/bar .\n")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#port' do
|
140
|
+
let(:default_port) do
|
141
|
+
Kuby::Docker::WebserverPhase::DEFAULT_PORT
|
142
|
+
end
|
143
|
+
|
144
|
+
subject { spec.to_dockerfile.to_s }
|
145
|
+
|
146
|
+
it 'exposes the default port' do
|
147
|
+
expect(subject).to include("EXPOSE #{default_port}\n")
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'when given a custom port' do
|
151
|
+
before { spec.port(5555) }
|
152
|
+
|
153
|
+
it 'exposes the given port' do
|
154
|
+
expect(subject).to include("EXPOSE 5555\n")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#tag' do
|
160
|
+
let(:tag) { make_ts_tag(Time.now) }
|
161
|
+
|
162
|
+
subject { spec.tag }
|
163
|
+
|
164
|
+
context 'with no local or remote tags' do
|
165
|
+
it 'raises an error' do
|
166
|
+
expect { subject }.to raise_error(Kuby::Docker::MissingTagError)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'with an available remote tag' do
|
171
|
+
before { docker_remote_client.tags << tag }
|
172
|
+
|
173
|
+
it { is_expected.to eq(tag) }
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'with an available local tag' do
|
177
|
+
before do
|
178
|
+
docker_cli.build(
|
179
|
+
dockerfile: nil,
|
180
|
+
image_url: docker_image_url,
|
181
|
+
tags: [tag]
|
182
|
+
)
|
183
|
+
end
|
184
|
+
|
185
|
+
it { is_expected.to eq(tag) }
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'with multiple remote tags' do
|
189
|
+
let(:time) { Time.now }
|
190
|
+
|
191
|
+
before do
|
192
|
+
docker_remote_client.tags +=
|
193
|
+
[time - 5, time + 10, time - 10, time + 15].map do |t|
|
194
|
+
make_ts_tag(t)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
it { is_expected.to eq(make_ts_tag(time + 15)) }
|
199
|
+
end
|
200
|
+
|
201
|
+
context 'with multiple local and remote tags' do
|
202
|
+
let(:time) { Time.now }
|
203
|
+
|
204
|
+
before do
|
205
|
+
docker_remote_client.tags +=
|
206
|
+
[time - 5, time + 10, time - 10, time + 15].map do |t|
|
207
|
+
make_ts_tag(t)
|
208
|
+
end
|
209
|
+
|
210
|
+
docker_cli.build(
|
211
|
+
dockerfile: nil,
|
212
|
+
image_url: docker_image_url,
|
213
|
+
tags: [time - 3, time + 6, time - 6, time + 18].map do |t|
|
214
|
+
make_ts_tag(t)
|
215
|
+
end
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
it { is_expected.to eq(make_ts_tag(time + 18)) }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe '#previous_tag' do
|
224
|
+
let(:time) { Time.now }
|
225
|
+
let(:current_tag) { make_ts_tag(time) }
|
226
|
+
|
227
|
+
before do
|
228
|
+
docker_remote_client.tags << current_tag
|
229
|
+
docker_cli.build(
|
230
|
+
dockerfile: nil,
|
231
|
+
image_url: docker_image_url,
|
232
|
+
tags: [current_tag]
|
233
|
+
)
|
234
|
+
end
|
235
|
+
|
236
|
+
subject { spec.previous_tag(current_tag) }
|
237
|
+
|
238
|
+
context 'with no previous local or remote tag' do
|
239
|
+
it 'raises an error' do
|
240
|
+
expect { subject }.to raise_error(Kuby::Docker::MissingTagError)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'with an available previous remote tag' do
|
245
|
+
let(:previous_tag) { make_ts_tag(time - 5) }
|
246
|
+
|
247
|
+
before { docker_remote_client.tags << previous_tag }
|
248
|
+
|
249
|
+
it { is_expected.to eq(previous_tag) }
|
250
|
+
end
|
251
|
+
|
252
|
+
context 'with an available previous local tag' do
|
253
|
+
let(:previous_tag) { make_ts_tag(time - 5) }
|
254
|
+
|
255
|
+
before do
|
256
|
+
docker_cli.build(
|
257
|
+
dockerfile: nil,
|
258
|
+
image_url: docker_image_url,
|
259
|
+
tags: [previous_tag]
|
260
|
+
)
|
261
|
+
end
|
262
|
+
|
263
|
+
it { is_expected.to eq(previous_tag) }
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|