kamal 1.0.0 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7a1eccb289724a2ca99c9c5e8ffd23749a859f7080606206efec05c417fc751
4
- data.tar.gz: 8a0d9143b580ff01d820746675a98954fe75d6c5a21abcb80ed2b5a5ec0ae657
3
+ metadata.gz: 4a11bf8b2153b8bc4323e4b03e289d7c0c5e60a9dcc9012103ae701ae2c3256b
4
+ data.tar.gz: bc4b5c88e63a717fc539c71c00fb8207ee78693ade9658ac8effd3ecdd5249ab
5
5
  SHA512:
6
- metadata.gz: 153117a03e1fc92c96b6d8140096233afb792cfb9e227ace80cad5507df38969d5ef66d1342ed1ea838f43e7cef691f200b417c59a92419a9ac00c0cca4b3b6a
7
- data.tar.gz: 0fa78b7cec73a786e4e225e68cfb04a932a893ac8e7698c7361a9600b753564317089f5202ede5c83c2c7063a75d6ea1bd741b02181bf25f0f18833d561b21cd
6
+ metadata.gz: b8cbc84077617cfd72ad225cb458b0df9d36fe88b2f2a640bec9f012b4f92272d5cd62617580e75f217715be97e88c126bfe842dcdc1ab262c82db3fc9e0c746
7
+ data.tar.gz: c3e1de191ebcf4621fe15e59ee8b976491a58e8ffbd40a8862d15040837b7669f7e26372382711b118eb357035f047d920dd7817de7fc415aa5b8aa8a7e74a60
@@ -49,17 +49,21 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
49
49
  end
50
50
  end
51
51
 
52
- desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container)"
52
+ desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container; use NAME=all to boot all accessories)"
53
53
  def reboot(name)
54
54
  mutating do
55
- with_accessory(name) do |accessory|
56
- on(accessory.hosts) do
57
- execute *KAMAL.registry.login
58
- end
55
+ if name == "all"
56
+ KAMAL.accessory_names.each { |accessory_name| reboot(accessory_name) }
57
+ else
58
+ with_accessory(name) do |accessory|
59
+ on(accessory.hosts) do
60
+ execute *KAMAL.registry.login
61
+ end
59
62
 
60
- stop(name)
61
- remove_container(name)
62
- boot(name, login: false)
63
+ stop(name)
64
+ remove_container(name)
65
+ boot(name, login: false)
66
+ end
63
67
  end
64
68
  end
65
69
  end
data/lib/kamal/cli/app.rb CHANGED
@@ -147,8 +147,12 @@ class Kamal::Cli::App < Kamal::Cli::Base
147
147
  using_version(version_or_latest) do |version|
148
148
  say "Launching command with version #{version} from new container...", :magenta
149
149
  on(KAMAL.hosts) do |host|
150
- execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
151
- puts_by_host host, capture_with_info(*KAMAL.app.execute_in_new_container(cmd))
150
+ roles = KAMAL.roles_on(host)
151
+
152
+ roles.each do |role|
153
+ execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
154
+ puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_new_container(cmd))
155
+ end
152
156
  end
153
157
  end
154
158
  end
@@ -14,8 +14,8 @@ module Kamal::Cli
14
14
  class_option :version, desc: "Run commands against a specific app version"
15
15
 
16
16
  class_option :primary, type: :boolean, aliases: "-p", desc: "Run commands only on primary host instead of all"
17
- class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma)"
18
- class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma)"
17
+ class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma, supports wildcards with *)"
18
+ class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma, supports wildcards with *)"
19
19
 
20
20
  class_option :config_file, aliases: "-c", default: "config/deploy.yml", desc: "Path to config file"
21
21
  class_option :destination, aliases: "-d", desc: "Specify destination to be used for config file (staging -> deploy.staging.yml)"
@@ -24,6 +24,7 @@ module Kamal::Cli
24
24
 
25
25
  def initialize(*)
26
26
  super
27
+ @original_env = ENV.to_h.dup
27
28
  load_envs
28
29
  initialize_commander(options_with_subcommand_class_options)
29
30
  end
@@ -37,6 +38,12 @@ module Kamal::Cli
37
38
  end
38
39
  end
39
40
 
41
+ def reload_envs
42
+ ENV.clear
43
+ ENV.update(@original_env)
44
+ load_envs
45
+ end
46
+
40
47
  def options_with_subcommand_class_options
41
48
  options.merge(@_initializer.last[:class_options] || {})
42
49
  end
@@ -75,8 +82,6 @@ module Kamal::Cli
75
82
  def mutating
76
83
  return yield if KAMAL.holding_lock?
77
84
 
78
- KAMAL.config.ensure_env_available
79
-
80
85
  run_hook "pre-connect"
81
86
 
82
87
  ensure_run_directory
@@ -3,6 +3,7 @@ class Kamal::Cli::Healthcheck < Kamal::Cli::Base
3
3
 
4
4
  desc "perform", "Health check current app version"
5
5
  def perform
6
+ raise "The primary host is not configured to run Traefik" unless KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
6
7
  on(KAMAL.primary_host) do
7
8
  begin
8
9
  execute *KAMAL.healthcheck.run
@@ -38,8 +38,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base
38
38
  say "Ensure Traefik is running...", :magenta
39
39
  invoke "kamal:cli:traefik:boot", [], invoke_options
40
40
 
41
- say "Ensure app can pass healthcheck...", :magenta
42
- invoke "kamal:cli:healthcheck:perform", [], invoke_options
41
+ if KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
42
+ say "Ensure app can pass healthcheck...", :magenta
43
+ invoke "kamal:cli:healthcheck:perform", [], invoke_options
44
+ end
43
45
 
44
46
  say "Detect stale containers...", :magenta
45
47
  invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
@@ -170,6 +172,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
170
172
  end
171
173
 
172
174
  desc "envify", "Create .env by evaluating .env.erb (or .env.staging.erb -> .env.staging when using -d staging)"
175
+ option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip .env file push"
173
176
  def envify
174
177
  if destination = options[:destination]
175
178
  env_template_path = ".env.#{destination}.erb"
@@ -179,10 +182,12 @@ class Kamal::Cli::Main < Kamal::Cli::Base
179
182
  env_path = ".env"
180
183
  end
181
184
 
182
- File.write(env_path, ERB.new(File.read(env_template_path)).result, perm: 0600)
185
+ File.write(env_path, ERB.new(File.read(env_template_path), trim_mode: "-").result, perm: 0600)
183
186
 
184
- load_envs # reload new file
185
- invoke "kamal:cli:env:push", options
187
+ unless options[:skip_push]
188
+ reload_envs
189
+ invoke "kamal:cli:env:push", options
190
+ end
186
191
  end
187
192
 
188
193
  desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
@@ -83,3 +83,15 @@ registry:
83
83
  # boot:
84
84
  # limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
85
85
  # wait: 2
86
+
87
+ # Configure the role used to determine the primary_host. This host takes
88
+ # deploy locks, runs health checks during the deploy, and follow logs, etc.
89
+ #
90
+ # Caution: there's no support for role renaming yet, so be careful to cleanup
91
+ # the previous role on the deployed hosts.
92
+ # primary_role: web
93
+
94
+ # Controls if we abort when see a role with no hosts. Disabling this may be
95
+ # useful for more complex deploy configurations.
96
+ #
97
+ # allow_empty_roles: false
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ echo "Rebooted Traefik on $KAMAL_HOSTS"
@@ -32,7 +32,7 @@ fi
32
32
  current_branch=$(git branch --show-current)
33
33
 
34
34
  if [ -z "$current_branch" ]; then
35
- echo "No git remote set, aborting..." >&2
35
+ echo "Not on a git branch, aborting..." >&2
36
36
  exit 1
37
37
  fi
38
38
 
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ echo "Rebooting Traefik on $KAMAL_HOSTS..."
@@ -13,12 +13,18 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
13
13
  option :rolling, type: :boolean, default: false, desc: "Reboot traefik on hosts in sequence, rather than in parallel"
14
14
  def reboot
15
15
  mutating do
16
- on(KAMAL.traefik_hosts, in: options[:rolling] ? :sequence : :parallel) do
17
- execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug
18
- execute *KAMAL.registry.login
19
- execute *KAMAL.traefik.stop
20
- execute *KAMAL.traefik.remove_container
21
- execute *KAMAL.traefik.run
16
+ host_groups = options[:rolling] ? KAMAL.traefik_hosts : [KAMAL.traefik_hosts]
17
+ host_groups.each do |hosts|
18
+ host_list = Array(hosts).join(",")
19
+ run_hook "pre-traefik-reboot", hosts: host_list
20
+ on(hosts) do
21
+ execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug
22
+ execute *KAMAL.registry.login
23
+ execute *KAMAL.traefik.stop
24
+ execute *KAMAL.traefik.remove_container
25
+ execute *KAMAL.traefik.run
26
+ end
27
+ run_hook "post-traefik-reboot", hosts: host_list
22
28
  end
23
29
  end
24
30
  end
@@ -24,19 +24,36 @@ class Kamal::Commander
24
24
  attr_reader :specific_roles, :specific_hosts
25
25
 
26
26
  def specific_primary!
27
- self.specific_hosts = [ config.primary_web_host ]
27
+ self.specific_hosts = [ config.primary_host ]
28
28
  end
29
29
 
30
30
  def specific_roles=(role_names)
31
- @specific_roles = config.roles.select { |r| role_names.include?(r.name) } if role_names.present?
31
+ if role_names.present?
32
+ @specific_roles = Kamal::Utils.filter_specific_items(role_names, config.roles)
33
+
34
+ if @specific_roles.empty?
35
+ raise ArgumentError, "No --roles match for #{role_names.join(',')}"
36
+ end
37
+
38
+ @specific_roles
39
+ end
32
40
  end
33
41
 
34
42
  def specific_hosts=(hosts)
35
- @specific_hosts = config.all_hosts & hosts if hosts.present?
43
+ if hosts.present?
44
+ @specific_hosts = Kamal::Utils.filter_specific_items(hosts, config.all_hosts)
45
+
46
+ if @specific_hosts.empty?
47
+ raise ArgumentError, "No --hosts match for #{hosts.join(',')}"
48
+ end
49
+
50
+ @specific_hosts
51
+ end
36
52
  end
37
53
 
38
54
  def primary_host
39
- specific_hosts&.first || specific_roles&.first&.primary_host || config.primary_web_host
55
+ # Given a list of specific roles, make an effort to match up with the primary_role
56
+ specific_hosts&.first || specific_roles&.detect { |role| role.name == config.primary_role }&.primary_host || specific_roles&.first&.primary_host || config.primary_host
40
57
  end
41
58
 
42
59
  def primary_role
@@ -18,6 +18,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
18
18
  "--name", container_name,
19
19
  *(["--hostname", hostname] if hostname),
20
20
  "-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
21
+ "-e", "KAMAL_VERSION=\"#{config.version}\"",
21
22
  *role_config.env_args,
22
23
  *role_config.health_check_args,
23
24
  *config.logging_args,
@@ -18,7 +18,7 @@ module Kamal::Commands
18
18
  elsif config.ssh.proxy && config.ssh.proxy.is_a?(Net::SSH::Proxy::Command)
19
19
  cmd << " -o ProxyCommand='#{config.ssh.proxy.command_line_template}'"
20
20
  end
21
- cmd << " -t #{config.ssh.user}@#{host} '#{command.join(" ")}'"
21
+ cmd << " -t #{config.ssh.user}@#{host} -p #{config.ssh.port} '#{command.join(" ")}'"
22
22
  end
23
23
  end
24
24
 
@@ -16,6 +16,6 @@ class Kamal::Commands::Docker < Kamal::Commands::Base
16
16
 
17
17
  # Do we have superuser access to install Docker and start system services?
18
18
  def superuser?
19
- [ '[ "${EUID:-$(id -u)}" -eq 0 ]' ]
19
+ [ '[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null' ]
20
20
  end
21
21
  end
@@ -1,7 +1,7 @@
1
1
  class Kamal::Commands::Healthcheck < Kamal::Commands::Base
2
2
 
3
3
  def run
4
- web = config.role(:web)
4
+ primary = config.role(config.primary_role)
5
5
 
6
6
  docker :run,
7
7
  "--detach",
@@ -9,12 +9,12 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
9
9
  "--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
10
10
  "--label", "service=#{config.healthcheck_service}",
11
11
  "-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
12
- *web.env_args,
13
- *web.health_check_args(cord: false),
12
+ *primary.env_args,
13
+ *primary.health_check_args(cord: false),
14
14
  *config.volume_args,
15
- *web.option_args,
15
+ *primary.option_args,
16
16
  config.absolute_image,
17
- web.cmd
17
+ primary.cmd
18
18
  end
19
19
 
20
20
  def status
@@ -6,6 +6,14 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
6
6
  DEFAULT_ARGS = {
7
7
  'log.level' => 'DEBUG'
8
8
  }
9
+ DEFAULT_LABELS = {
10
+ # These ensure we serve a 502 rather than a 404 if no containers are available
11
+ "traefik.http.routers.catchall.entryPoints" => "http",
12
+ "traefik.http.routers.catchall.rule" => "PathPrefix(`/`)",
13
+ "traefik.http.routers.catchall.service" => "unavailable",
14
+ "traefik.http.routers.catchall.priority" => 1,
15
+ "traefik.http.services.unavailable.loadbalancer.server.port" => "0"
16
+ }
9
17
 
10
18
  def run
11
19
  docker :run, "--name traefik",
@@ -97,7 +105,7 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
97
105
  end
98
106
 
99
107
  def labels
100
- config.traefik["labels"] || []
108
+ DEFAULT_LABELS.merge(config.traefik["labels"] || {})
101
109
  end
102
110
 
103
111
  def image
@@ -70,8 +70,8 @@ class Kamal::Configuration::Accessory
70
70
 
71
71
  def directories
72
72
  specifics["directories"]&.to_h do |host_to_container_mapping|
73
- host_relative_path, container_path = host_to_container_mapping.split(":")
74
- [ expand_host_path(host_relative_path), container_path ]
73
+ host_path, container_path = host_to_container_mapping.split(":")
74
+ [ expand_host_path(host_path), container_path ]
75
75
  end || {}
76
76
  end
77
77
 
@@ -138,13 +138,17 @@ class Kamal::Configuration::Accessory
138
138
 
139
139
  def remote_directories_as_volumes
140
140
  specifics["directories"]&.collect do |host_to_container_mapping|
141
- host_relative_path, container_path = host_to_container_mapping.split(":")
142
- [ expand_host_path(host_relative_path), container_path ].join(":")
141
+ host_path, container_path = host_to_container_mapping.split(":")
142
+ [ expand_host_path(host_path), container_path ].join(":")
143
143
  end || []
144
144
  end
145
145
 
146
- def expand_host_path(host_relative_path)
147
- "#{service_data_directory}/#{host_relative_path}"
146
+ def expand_host_path(host_path)
147
+ absolute_path?(host_path) ? host_path : "#{service_data_directory}/#{host_path}"
148
+ end
149
+
150
+ def absolute_path?(path)
151
+ Pathname.new(path).absolute?
148
152
  end
149
153
 
150
154
  def service_data_directory
@@ -93,7 +93,15 @@ class Kamal::Configuration::Role
93
93
 
94
94
 
95
95
  def running_traefik?
96
- name.web? || specializations["traefik"]
96
+ if specializations["traefik"].nil?
97
+ primary?
98
+ else
99
+ specializations["traefik"]
100
+ end
101
+ end
102
+
103
+ def primary?
104
+ @config.primary_role == name
97
105
  end
98
106
 
99
107
 
@@ -185,6 +193,7 @@ class Kamal::Configuration::Role
185
193
  "traefik.http.services.#{traefik_service}.loadbalancer.server.scheme" => "http",
186
194
 
187
195
  "traefik.http.routers.#{traefik_service}.rule" => "PathPrefix(`/`)",
196
+ "traefik.http.routers.#{traefik_service}.priority" => "2",
188
197
  "traefik.http.middlewares.#{traefik_service}-retry.retry.attempts" => "5",
189
198
  "traefik.http.middlewares.#{traefik_service}-retry.retry.initialinterval" => "500ms",
190
199
  "traefik.http.routers.#{traefik_service}.middlewares" => "#{traefik_service}-retry@docker"
@@ -9,6 +9,10 @@ class Kamal::Configuration::Ssh
9
9
  config.fetch("user", "root")
10
10
  end
11
11
 
12
+ def port
13
+ config.fetch("port", 22)
14
+ end
15
+
12
16
  def proxy
13
17
  if (proxy = config["proxy"])
14
18
  Net::SSH::Proxy::Jump.new(proxy.include?("@") ? proxy : "root@#{proxy}")
@@ -18,7 +22,7 @@ class Kamal::Configuration::Ssh
18
22
  end
19
23
 
20
24
  def options
21
- { user: user, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
25
+ { user: user, port: port, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
22
26
  end
23
27
 
24
28
  def to_h
@@ -25,7 +25,9 @@ class Kamal::Configuration
25
25
 
26
26
  def load_config_file(file)
27
27
  if file.exist?
28
- YAML.load(ERB.new(IO.read(file)).result).symbolize_keys
28
+ # Newer Psych doesn't load aliases by default
29
+ load_method = YAML.respond_to?(:unsafe_load) ? :unsafe_load : :load
30
+ YAML.send(load_method, ERB.new(IO.read(file)).result).symbolize_keys
29
31
  else
30
32
  raise "Configuration file not found in #{file}"
31
33
  end
@@ -89,14 +91,21 @@ class Kamal::Configuration
89
91
  roles.flat_map(&:hosts).uniq
90
92
  end
91
93
 
92
- def primary_web_host
93
- role(:web).primary_host
94
+ def primary_host
95
+ role(primary_role)&.primary_host
94
96
  end
95
97
 
96
- def traefik_hosts
97
- roles.select(&:running_traefik?).flat_map(&:hosts).uniq
98
+ def traefik_roles
99
+ roles.select(&:running_traefik?)
98
100
  end
99
101
 
102
+ def traefik_role_names
103
+ traefik_roles.flat_map(&:name)
104
+ end
105
+
106
+ def traefik_hosts
107
+ traefik_roles.flat_map(&:hosts).uniq
108
+ end
100
109
 
101
110
  def repository
102
111
  [ raw_config.registry["server"], image ].compact.join("/")
@@ -199,23 +208,24 @@ class Kamal::Configuration
199
208
  raw_config.asset_path
200
209
  end
201
210
 
211
+ def primary_role
212
+ raw_config.primary_role || "web"
213
+ end
202
214
 
203
- def valid?
204
- ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version
215
+ def allow_empty_roles?
216
+ raw_config.allow_empty_roles
205
217
  end
206
218
 
207
- # Will raise KeyError if any secret ENVs are missing
208
- def ensure_env_available
209
- roles.collect(&:env_file).each(&:to_s)
210
219
 
211
- true
220
+ def valid?
221
+ ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version
212
222
  end
213
223
 
214
224
  def to_h
215
225
  {
216
226
  roles: role_names,
217
227
  hosts: all_hosts,
218
- primary_host: primary_web_host,
228
+ primary_host: primary_host,
219
229
  version: version,
220
230
  repository: repository,
221
231
  absolute_image: absolute_image,
@@ -254,9 +264,19 @@ class Kamal::Configuration
254
264
  raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
255
265
  end
256
266
 
257
- roles.each do |role|
258
- if role.hosts.empty?
259
- raise ArgumentError, "No servers specified for the #{role.name} role"
267
+ unless role_names.include?(primary_role)
268
+ raise ArgumentError, "The primary_role #{primary_role} isn't defined"
269
+ end
270
+
271
+ if role(primary_role).hosts.empty?
272
+ raise ArgumentError, "No servers specified for the #{primary_role} primary_role"
273
+ end
274
+
275
+ unless allow_empty_roles?
276
+ roles.each do |role|
277
+ if role.hosts.empty?
278
+ raise ArgumentError, "No servers specified for the #{role.name} role. You can ignore this with allow_empty_roles: true"
279
+ end
260
280
  end
261
281
  end
262
282
 
@@ -1,4 +1,5 @@
1
1
  require "active_support/core_ext/module/delegation"
2
+ require "sshkit"
2
3
 
3
4
  class Kamal::Utils::Sensitive
4
5
  # So SSHKit knows to redact these values.
data/lib/kamal/utils.rb CHANGED
@@ -58,4 +58,20 @@ module Kamal::Utils
58
58
  .gsub(/`/, '\\\\`')
59
59
  .gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$')
60
60
  end
61
+
62
+ # Apply a list of host or role filters, including wildcard matches
63
+ def filter_specific_items(filters, items)
64
+ matches = []
65
+
66
+ Array(filters).select do |filter|
67
+ matches += Array(items).select do |item|
68
+ # Only allow * for a wildcard
69
+ pattern = Regexp.escape(filter).gsub('\*', '.*')
70
+ # items are roles or hosts
71
+ (item.respond_to?(:name) ? item.name : item).match(/^#{pattern}$/)
72
+ end
73
+ end
74
+
75
+ matches
76
+ end
61
77
  end
data/lib/kamal/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kamal
2
- VERSION = "1.0.0"
2
+ VERSION = "1.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kamal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-19 00:00:00.000000000 Z
11
+ date: 2023-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -204,9 +204,11 @@ files:
204
204
  - lib/kamal/cli/server.rb
205
205
  - lib/kamal/cli/templates/deploy.yml
206
206
  - lib/kamal/cli/templates/sample_hooks/post-deploy.sample
207
+ - lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample
207
208
  - lib/kamal/cli/templates/sample_hooks/pre-build.sample
208
209
  - lib/kamal/cli/templates/sample_hooks/pre-connect.sample
209
210
  - lib/kamal/cli/templates/sample_hooks/pre-deploy.sample
211
+ - lib/kamal/cli/templates/sample_hooks/pre-traefik-reboot.sample
210
212
  - lib/kamal/cli/templates/template.env
211
213
  - lib/kamal/cli/traefik.rb
212
214
  - lib/kamal/commander.rb
@@ -270,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
270
272
  - !ruby/object:Gem::Version
271
273
  version: '0'
272
274
  requirements: []
273
- rubygems_version: 3.4.19
275
+ rubygems_version: 3.4.22
274
276
  signing_key:
275
277
  specification_version: 4
276
278
  summary: Deploy web apps in containers to servers running Docker with zero downtime.